AceTextEditor.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright (C) 2011 Google Inc. All rights reserved.
  3. * Copyright (C) 2010 Apple Inc. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. importScript("ace/ace.js");
  32. /**
  33. * @constructor
  34. * @extends {WebInspector.View}
  35. * @implements {WebInspector.TextEditor}
  36. * @param {?string} url
  37. * @param {WebInspector.TextEditorDelegate} delegate
  38. */
  39. WebInspector.AceTextEditor = function(url, delegate)
  40. {
  41. WebInspector.View.call(this);
  42. this._delegate = delegate;
  43. this._url = url;
  44. this.element.className = "ace-editor-container source-code";
  45. var prefix = window.flattenImports ? "" : "ace/";
  46. ace.config.setModuleUrl("ace/mode/javascript", prefix + "mode_javascript.js");
  47. ace.config.setModuleUrl("ace/mode/javascript", prefix + "mode_css.js");
  48. ace.config.setModuleUrl("ace/mode/javascript", prefix + "mode_html.js");
  49. ace.config.setModuleUrl("ace/theme/textmate", prefix + "theme_textmate.js");
  50. this._aceEditor = window.ace.edit(this.element);
  51. this._aceEditor.setShowFoldWidgets(false);
  52. this._aceEditor.session.setFixedGutterWidth(true);
  53. this._aceEditor.on("gutterclick", this._gutterClick.bind(this));
  54. this._aceEditor.on("change", this._onTextChange.bind(this));
  55. this._aceEditor.setHighlightActiveLine(false);
  56. this._aceEditor.session.setUseWorker(false);
  57. this.registerRequiredCSS("ace/acedevtools.css");
  58. this._attributes = [];
  59. }
  60. WebInspector.AceTextEditor.prototype = {
  61. _updateBreakpoints: function()
  62. {
  63. this._aceEditor.session.clearBreakpoints();
  64. for(var i in this._attributes) {
  65. var breakpoint = this.getAttribute(i, "ace_breakpoint");
  66. if (!breakpoint)
  67. continue;
  68. var className = breakpoint.conditional ? "webkit-breakpoint-conditional" : "webkit-breakpoint";
  69. if (breakpoint.disabled) className += " webkit-breakpoint-disabled";
  70. this._aceEditor.session.setBreakpoint(i, className);
  71. }
  72. },
  73. _updateLineAttributes: function(delta) {
  74. var range = delta.range;
  75. var length, insertionIndex;
  76. if (range.end.row === range.start.row)
  77. return;
  78. if (delta.action === "insertText") {
  79. length = range.end.row - range.start.row;
  80. insertionIndex = range.start.column === 0 ? range.start.row: range.start.row + 1;
  81. } else if (delta.action === "insertLines") {
  82. length = range.end.row - range.start.row;
  83. insertionIndex = range.start.row;
  84. } else if (delta.action === "removeText") {
  85. length = range.start.row - range.end.row;
  86. insertionIndex = range.start.row;
  87. } else if (delta.action === "removeLines") {
  88. length = range.start.row - range.end.row;
  89. insertionIndex = range.start.row;
  90. }
  91. if (length > 0) {
  92. var spliceArguments = new Array(length);
  93. spliceArguments.unshift(insertionIndex, 0);
  94. Array.prototype.splice.apply(this._attributes, spliceArguments);
  95. } else if (length < 0) {
  96. this._attributes.splice(insertionIndex, -length);
  97. }
  98. this._updateBreakpoints();
  99. },
  100. _onTextChange: function(event)
  101. {
  102. this._updateLineAttributes(event.data);
  103. this._delegate.onTextChanged(null, null);
  104. },
  105. _gutterClick: function(event)
  106. {
  107. var lineNumber = parseInt(event.domEvent.target.textContent) - 1;
  108. this.dispatchEventToListeners(WebInspector.TextEditor.Events.GutterClick, { lineNumber: lineNumber, event: event.domEvent });
  109. },
  110. /**
  111. * @param {string} mimeType
  112. */
  113. set mimeType(mimeType)
  114. {
  115. switch(mimeType) {
  116. case "text/html":
  117. this._aceEditor.getSession().setMode("ace/mode/html");
  118. break;
  119. case "text/css":
  120. this._aceEditor.getSession().setMode("ace/mode/css");
  121. break;
  122. case "text/javascript":
  123. this._aceEditor.getSession().setMode("ace/mode/javascript");
  124. break;
  125. }
  126. },
  127. /**
  128. * @param {boolean} readOnly
  129. */
  130. setReadOnly: function(readOnly)
  131. {
  132. this._aceEditor.setReadOnly(readOnly);
  133. },
  134. /**
  135. * @return {boolean}
  136. */
  137. readOnly: function()
  138. {
  139. return this._aceEditor.getReadOnly();
  140. },
  141. focus: function()
  142. {
  143. this._aceEditor.focus();
  144. },
  145. /**
  146. * @return {Element}
  147. */
  148. defaultFocusedElement: function()
  149. {
  150. return this.element.firstChild;
  151. },
  152. /**
  153. * @param {string} regex
  154. * @param {string} cssClass
  155. * @return {WebInspector.TextEditorMainPanel.HighlightDescriptor}
  156. */
  157. highlightRegex: function(regex, cssClass)
  158. {
  159. console.log("aceEditor.highlightRegex not implemented");
  160. },
  161. /**
  162. * @param {WebInspector.TextRange} range
  163. * @param {string} cssClass
  164. */
  165. highlightRange: function(range, cssClass)
  166. {
  167. console.log("aceEditor.highlightRange not implemented");
  168. },
  169. /**
  170. * @param {WebInspector.TextEditorMainPanel.HighlightDescriptor} highlightDescriptor
  171. */
  172. removeHighlight: function(highlightDescriptor)
  173. {
  174. console.log("aceEditor.removeHighlight not implemented");
  175. },
  176. /**
  177. * @param {number} lineNumber
  178. */
  179. revealLine: function(lineNumber) {
  180. this._aceEditor.scrollToLine(lineNumber, false, true);
  181. },
  182. /**
  183. * @param {number} lineNumber
  184. * @param {boolean} disabled
  185. * @param {boolean} conditional
  186. */
  187. addBreakpoint: function(lineNumber, disabled, conditional)
  188. {
  189. this.setAttribute(lineNumber, "ace_breakpoint", {
  190. disabled: disabled,
  191. conditional: conditional
  192. });
  193. this._updateBreakpoints();
  194. },
  195. /**
  196. * @param {number} lineNumber
  197. */
  198. removeBreakpoint: function(lineNumber)
  199. {
  200. this.removeAttribute(lineNumber, "ace_breakpoint");
  201. this._updateBreakpoints();
  202. },
  203. /**
  204. * @param {number} lineNumber
  205. */
  206. setExecutionLine: function(lineNumber)
  207. {
  208. this._executionLine = lineNumber;
  209. const Range = ace.require('ace/range').Range;
  210. this._executionLineMarker = this._aceEditor.session.addMarker(new Range(lineNumber, 0, lineNumber, Infinity), "webkit-execution-line", "fullLine");
  211. this._aceEditor.session.addGutterDecoration(lineNumber, "webkit-gutter-execution-line");
  212. },
  213. /**
  214. * @param {WebInspector.TextRange} range
  215. * @return {string}
  216. */
  217. copyRange: function(range)
  218. {
  219. console.log("aceEditor.copyRange not implemented");
  220. return "";
  221. },
  222. clearExecutionLine: function()
  223. {
  224. this._aceEditor.session.removeMarker(this._executionLineMarker);
  225. this._aceEditor.session.removeGutterDecoration(this._executionLine, "webkit-gutter-execution-line");
  226. },
  227. /**
  228. * @param {number} lineNumber
  229. * @param {Element} element
  230. */
  231. addDecoration: function(lineNumber, element)
  232. {
  233. console.log("aceEditor.addDecoration not implemented");
  234. },
  235. /**
  236. * @param {number} lineNumber
  237. * @param {Element} element
  238. */
  239. removeDecoration: function(lineNumber, element)
  240. {
  241. console.log("aceEditor.removeDecoration not implemented");
  242. },
  243. /**
  244. * @param {WebInspector.TextRange} range
  245. */
  246. markAndRevealRange: function(range)
  247. {
  248. console.log("aceEditor.markAndRevealRange not implemented");
  249. },
  250. /**
  251. * @param {number} lineNumber
  252. */
  253. highlightLine: function(lineNumber)
  254. {
  255. console.log("aceEditor.highlightLine not implemented");
  256. },
  257. clearLineHighlight: function() {
  258. console.log("aceEditor.clearLineHighlight not implemented");
  259. },
  260. /**
  261. * @return {Array.<Element>}
  262. */
  263. elementsToRestoreScrollPositionsFor: function()
  264. {
  265. return [];
  266. },
  267. /**
  268. * @param {WebInspector.TextEditor} textEditor
  269. */
  270. inheritScrollPositions: function(textEditor)
  271. {
  272. console.log("aceEditor.inheritScrollPositions not implemented");
  273. },
  274. beginUpdates: function() { },
  275. endUpdates: function() { },
  276. onResize: function() { },
  277. /**
  278. * @param {WebInspector.TextRange} range
  279. * @param {string} text
  280. * @return {WebInspector.TextRange}
  281. */
  282. editRange: function(range, text)
  283. {
  284. console.log("aceEditor.editRange not implemented");
  285. },
  286. /**
  287. * @param {number} lineNumber
  288. */
  289. scrollToLine: function(lineNumber)
  290. {
  291. this._aceEditor.scrollToLine(lineNumber, false, true);
  292. },
  293. /**
  294. * @return {WebInspector.TextRange}
  295. */
  296. selection: function()
  297. {
  298. console.log("aceEditor.selection not implemented");
  299. },
  300. /**
  301. * @return {WebInspector.TextRange?}
  302. */
  303. lastSelection: function()
  304. {
  305. console.log("aceEditor.lastSelection not implemented");
  306. },
  307. /**
  308. * @param {WebInspector.TextRange} textRange
  309. */
  310. setSelection: function(textRange)
  311. {
  312. this._aceEditor.scrollToLine(textRange.startLine, true);
  313. },
  314. /**
  315. * @param {string} text
  316. */
  317. setText: function(text)
  318. {
  319. this._aceEditor.getSession().setValue(text);
  320. },
  321. /**
  322. * @return {string}
  323. */
  324. text: function()
  325. {
  326. return this._aceEditor.getSession().getValue();
  327. },
  328. /**
  329. * @return {WebInspector.TextRange}
  330. */
  331. range: function()
  332. {
  333. console.log("aceEditor.range not implemented");
  334. },
  335. /**
  336. * @param {number} lineNumber
  337. * @return {string}
  338. */
  339. line: function(lineNumber)
  340. {
  341. return this._aceEditor.getSession().getLine(lineNumber);
  342. },
  343. /**
  344. * @return {number}
  345. */
  346. get linesCount() {
  347. return this._aceEditor.getSession().getLength();
  348. },
  349. /**
  350. * @param {number} line
  351. * @param {string} name
  352. * @return {Object|null} value
  353. */
  354. getAttribute: function(line, name)
  355. {
  356. var attrs = this._attributes[line];
  357. return attrs ? attrs[name] : null;
  358. },
  359. /**
  360. * @param {number} line
  361. * @param {string} name
  362. * @param {Object?} value
  363. */
  364. setAttribute: function(line, name, value)
  365. {
  366. var attrs = this._attributes[line];
  367. if (!attrs) {
  368. attrs = {};
  369. this._attributes[line] = attrs;
  370. }
  371. attrs[name] = value;
  372. },
  373. /**
  374. * @param {number} line
  375. * @param {string} name
  376. */
  377. removeAttribute: function(line, name)
  378. {
  379. var attrs = this._attributes[line];
  380. if (attrs)
  381. delete attrs[name];
  382. },
  383. wasShown: function() { },
  384. __proto__: WebInspector.View.prototype
  385. }