demo.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Distributed under the BSD license:
  3. *
  4. * Copyright (c) 2010, Ajax.org B.V.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  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 copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Ajax.org B.V. nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * ***** END LICENSE BLOCK ***** */
  30. define(function(require, exports, module) {
  31. "use strict";
  32. require("ace/lib/fixoldbrowsers");
  33. require("ace/multi_select");
  34. require("ace/ext/spellcheck");
  35. require("./inline_editor");
  36. require("./dev_util");
  37. require("./file_drop");
  38. var config = require("ace/config");
  39. config.init();
  40. var env = {};
  41. var dom = require("ace/lib/dom");
  42. var net = require("ace/lib/net");
  43. var lang = require("ace/lib/lang");
  44. var useragent = require("ace/lib/useragent");
  45. var event = require("ace/lib/event");
  46. var theme = require("ace/theme/textmate");
  47. var EditSession = require("ace/edit_session").EditSession;
  48. var UndoManager = require("ace/undomanager").UndoManager;
  49. var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
  50. var Renderer = require("ace/virtual_renderer").VirtualRenderer;
  51. var Editor = require("ace/editor").Editor;
  52. var whitespace = require("ace/ext/whitespace");
  53. var doclist = require("./doclist");
  54. var modelist = require("ace/ext/modelist");
  55. var themelist = require("ace/ext/themelist");
  56. var layout = require("./layout");
  57. var TokenTooltip = require("./token_tooltip").TokenTooltip;
  58. var util = require("./util");
  59. var saveOption = util.saveOption;
  60. var fillDropdown = util.fillDropdown;
  61. var bindCheckbox = util.bindCheckbox;
  62. var bindDropdown = util.bindDropdown;
  63. var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabstopsLite;
  64. var IncrementalSearch = require("ace/incremental_search").IncrementalSearch;
  65. var workerModule = require("ace/worker/worker_client");
  66. if (location.href.indexOf("noworker") !== -1) {
  67. workerModule.WorkerClient = workerModule.UIWorkerClient;
  68. }
  69. /*********** create editor ***************************/
  70. var container = document.getElementById("editor-container");
  71. // Splitting.
  72. var Split = require("ace/split").Split;
  73. var split = new Split(container, theme, 1);
  74. env.editor = split.getEditor(0);
  75. split.on("focus", function(editor) {
  76. env.editor = editor;
  77. updateUIEditorOptions();
  78. });
  79. env.split = split;
  80. window.env = env;
  81. var consoleEl = dom.createElement("div");
  82. container.parentNode.appendChild(consoleEl);
  83. consoleEl.style.cssText = "position:fixed; bottom:1px; right:0;\
  84. border:1px solid #baf; z-index:100";
  85. var cmdLine = new layout.singleLineEditor(consoleEl);
  86. cmdLine.editor = env.editor;
  87. env.editor.cmdLine = cmdLine;
  88. env.editor.showCommandLine = function(val) {
  89. this.cmdLine.focus();
  90. if (typeof val == "string")
  91. this.cmdLine.setValue(val, 1);
  92. };
  93. /**
  94. * This demonstrates how you can define commands and bind shortcuts to them.
  95. */
  96. env.editor.commands.addCommands([{
  97. name: "gotoline",
  98. bindKey: {win: "Ctrl-L", mac: "Command-L"},
  99. exec: function(editor, line) {
  100. if (typeof line == "object") {
  101. var arg = this.name + " " + editor.getCursorPosition().row;
  102. editor.cmdLine.setValue(arg, 1);
  103. editor.cmdLine.focus();
  104. return;
  105. }
  106. line = parseInt(line, 10);
  107. if (!isNaN(line))
  108. editor.gotoLine(line);
  109. },
  110. readOnly: true
  111. }, {
  112. name: "snippet",
  113. bindKey: {win: "Alt-C", mac: "Command-Alt-C"},
  114. exec: function(editor, needle) {
  115. if (typeof needle == "object") {
  116. editor.cmdLine.setValue("snippet ", 1);
  117. editor.cmdLine.focus();
  118. return;
  119. }
  120. var s = snippetManager.getSnippetByName(needle, editor);
  121. if (s)
  122. snippetManager.insertSnippet(editor, s.content);
  123. },
  124. readOnly: true
  125. }, {
  126. name: "focusCommandLine",
  127. bindKey: "shift-esc|ctrl-`",
  128. exec: function(editor, needle) { editor.cmdLine.focus(); },
  129. readOnly: true
  130. }, {
  131. name: "nextFile",
  132. bindKey: "Ctrl-tab",
  133. exec: function(editor) { doclist.cycleOpen(editor, 1); },
  134. readOnly: true
  135. }, {
  136. name: "previousFile",
  137. bindKey: "Ctrl-shift-tab",
  138. exec: function(editor) { doclist.cycleOpen(editor, -1); },
  139. readOnly: true
  140. }, {
  141. name: "execute",
  142. bindKey: "ctrl+enter",
  143. exec: function(editor) {
  144. try {
  145. var r = window.eval(editor.getCopyText() || editor.getValue());
  146. } catch(e) {
  147. r = e;
  148. }
  149. editor.cmdLine.setValue(r + "");
  150. },
  151. readOnly: true
  152. }, {
  153. name: "showKeyboardShortcuts",
  154. bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"},
  155. exec: function(editor) {
  156. config.loadModule("ace/ext/keybinding_menu", function(module) {
  157. module.init(editor);
  158. editor.showKeyboardShortcuts();
  159. });
  160. }
  161. }, {
  162. name: "increaseFontSize",
  163. bindKey: "Ctrl-=|Ctrl-+",
  164. exec: function(editor) {
  165. var size = parseInt(editor.getFontSize(), 10) || 12;
  166. editor.setFontSize(size + 1);
  167. }
  168. }, {
  169. name: "decreaseFontSize",
  170. bindKey: "Ctrl+-|Ctrl-_",
  171. exec: function(editor) {
  172. var size = parseInt(editor.getFontSize(), 10) || 12;
  173. editor.setFontSize(Math.max(size - 1 || 1));
  174. }
  175. }, {
  176. name: "resetFontSize",
  177. bindKey: "Ctrl+0|Ctrl-Numpad0",
  178. exec: function(editor) {
  179. editor.setFontSize(12);
  180. }
  181. }]);
  182. env.editor.commands.addCommands(whitespace.commands);
  183. cmdLine.commands.bindKeys({
  184. "Shift-Return|Ctrl-Return|Alt-Return": function(cmdLine) { cmdLine.insert("\n"); },
  185. "Esc|Shift-Esc": function(cmdLine){ cmdLine.editor.focus(); },
  186. "Return": function(cmdLine){
  187. var command = cmdLine.getValue().split(/\s+/);
  188. var editor = cmdLine.editor;
  189. editor.commands.exec(command[0], editor, command[1]);
  190. editor.focus();
  191. }
  192. });
  193. cmdLine.commands.removeCommands(["find", "gotoline", "findall", "replace", "replaceall"]);
  194. var commands = env.editor.commands;
  195. commands.addCommand({
  196. name: "save",
  197. bindKey: {win: "Ctrl-S", mac: "Command-S"},
  198. exec: function(arg) {
  199. var session = env.editor.session;
  200. var name = session.name.match(/[^\/]+$/);
  201. localStorage.setItem(
  202. "saved_file:" + name,
  203. session.getValue()
  204. );
  205. env.editor.cmdLine.setValue("saved "+ name);
  206. }
  207. });
  208. commands.addCommand({
  209. name: "load",
  210. bindKey: {win: "Ctrl-O", mac: "Command-O"},
  211. exec: function(arg) {
  212. var session = env.editor.session;
  213. var name = session.name.match(/[^\/]+$/);
  214. var value = localStorage.getItem("saved_file:" + name);
  215. if (typeof value == "string") {
  216. session.setValue(value);
  217. env.editor.cmdLine.setValue("loaded "+ name);
  218. } else {
  219. env.editor.cmdLine.setValue("no previuos value saved for "+ name);
  220. }
  221. }
  222. });
  223. var keybindings = {
  224. ace: null, // Null = use "default" keymapping
  225. vim: require("ace/keyboard/vim").handler,
  226. emacs: "ace/keyboard/emacs",
  227. // This is a way to define simple keyboard remappings
  228. custom: new HashHandler({
  229. "gotoright": "Tab",
  230. "indent": "]",
  231. "outdent": "[",
  232. "gotolinestart": "^",
  233. "gotolineend": "$"
  234. })
  235. };
  236. /*********** manage layout ***************************/
  237. var consoleHeight = 20;
  238. function onResize() {
  239. var left = env.split.$container.offsetLeft;
  240. var width = document.documentElement.clientWidth - left;
  241. container.style.width = width + "px";
  242. container.style.height = document.documentElement.clientHeight - consoleHeight + "px";
  243. env.split.resize();
  244. consoleEl.style.width = width + "px";
  245. cmdLine.resize();
  246. }
  247. window.onresize = onResize;
  248. onResize();
  249. /*********** options panel ***************************/
  250. var docEl = document.getElementById("doc");
  251. var modeEl = document.getElementById("mode");
  252. var wrapModeEl = document.getElementById("soft_wrap");
  253. var themeEl = document.getElementById("theme");
  254. var foldingEl = document.getElementById("folding");
  255. var selectStyleEl = document.getElementById("select_style");
  256. var highlightActiveEl = document.getElementById("highlight_active");
  257. var showHiddenEl = document.getElementById("show_hidden");
  258. var showGutterEl = document.getElementById("show_gutter");
  259. var showPrintMarginEl = document.getElementById("show_print_margin");
  260. var highlightSelectedWordE = document.getElementById("highlight_selected_word");
  261. var showHScrollEl = document.getElementById("show_hscroll");
  262. var showVScrollEl = document.getElementById("show_vscroll");
  263. var animateScrollEl = document.getElementById("animate_scroll");
  264. var softTabEl = document.getElementById("soft_tab");
  265. var behavioursEl = document.getElementById("enable_behaviours");
  266. fillDropdown(docEl, doclist.all);
  267. fillDropdown(modeEl, modelist.modes);
  268. var modesByName = modelist.modesByName;
  269. bindDropdown("mode", function(value) {
  270. env.editor.session.setMode(modesByName[value].mode || modesByName.text.mode);
  271. env.editor.session.modeName = value;
  272. });
  273. doclist.history = doclist.docs.map(function(doc) {
  274. return doc.name;
  275. });
  276. doclist.history.index = 0;
  277. doclist.cycleOpen = function(editor, dir) {
  278. var h = this.history;
  279. h.index += dir;
  280. if (h.index >= h.length)
  281. h.index = 0;
  282. else if (h.index <= 0)
  283. h.index = h.length - 1;
  284. var s = h[h.index];
  285. docEl.value = s;
  286. docEl.onchange();
  287. };
  288. doclist.addToHistory = function(name) {
  289. var h = this.history;
  290. var i = h.indexOf(name);
  291. if (i != h.index) {
  292. if (i != -1)
  293. h.splice(i, 1);
  294. h.index = h.push(name);
  295. }
  296. };
  297. bindDropdown("doc", function(name) {
  298. doclist.loadDoc(name, function(session) {
  299. if (!session)
  300. return;
  301. doclist.addToHistory(session.name);
  302. session = env.split.setSession(session);
  303. whitespace.detectIndentation(session);
  304. updateUIEditorOptions();
  305. env.editor.focus();
  306. });
  307. });
  308. function updateUIEditorOptions() {
  309. var editor = env.editor;
  310. var session = editor.session;
  311. session.setFoldStyle(foldingEl.value);
  312. saveOption(docEl, session.name);
  313. saveOption(modeEl, session.modeName || "text");
  314. saveOption(wrapModeEl, session.getUseWrapMode() ? session.getWrapLimitRange().min || "free" : "off");
  315. saveOption(selectStyleEl, editor.getSelectionStyle() == "line");
  316. saveOption(themeEl, editor.getTheme());
  317. saveOption(highlightActiveEl, editor.getHighlightActiveLine());
  318. saveOption(showHiddenEl, editor.getShowInvisibles());
  319. saveOption(showGutterEl, editor.renderer.getShowGutter());
  320. saveOption(showPrintMarginEl, editor.renderer.getShowPrintMargin());
  321. saveOption(highlightSelectedWordE, editor.getHighlightSelectedWord());
  322. saveOption(showHScrollEl, editor.renderer.getHScrollBarAlwaysVisible());
  323. saveOption(animateScrollEl, editor.getAnimatedScroll());
  324. saveOption(softTabEl, session.getUseSoftTabs());
  325. saveOption(behavioursEl, editor.getBehavioursEnabled());
  326. }
  327. themelist.themes.forEach(function(x){ x.value = x.theme });
  328. fillDropdown(themeEl, {
  329. Bright: themelist.themes.filter(function(x){return !x.isDark}),
  330. Dark: themelist.themes.filter(function(x){return x.isDark}),
  331. });
  332. event.addListener(themeEl, "mouseover", function(e){
  333. themeEl.desiredValue = e.target.value;
  334. if (!themeEl.$timer)
  335. themeEl.$timer = setTimeout(themeEl.updateTheme);
  336. });
  337. event.addListener(themeEl, "mouseout", function(e){
  338. themeEl.desiredValue = null;
  339. if (!themeEl.$timer)
  340. themeEl.$timer = setTimeout(themeEl.updateTheme, 20);
  341. });
  342. themeEl.updateTheme = function(){
  343. env.split.setTheme((themeEl.desiredValue || themeEl.selectedValue));
  344. themeEl.$timer = null;
  345. };
  346. bindDropdown("theme", function(value) {
  347. if (!value)
  348. return;
  349. env.editor.setTheme(value);
  350. themeEl.selectedValue = value;
  351. });
  352. bindDropdown("keybinding", function(value) {
  353. env.editor.setKeyboardHandler(keybindings[value]);
  354. });
  355. bindDropdown("fontsize", function(value) {
  356. env.split.setFontSize(value);
  357. });
  358. bindDropdown("folding", function(value) {
  359. env.editor.session.setFoldStyle(value);
  360. env.editor.setShowFoldWidgets(value !== "manual");
  361. });
  362. bindDropdown("soft_wrap", function(value) {
  363. env.editor.setOption("wrap", value);
  364. });
  365. bindCheckbox("select_style", function(checked) {
  366. env.editor.setOption("selectionStyle", checked ? "line" : "text");
  367. });
  368. bindCheckbox("highlight_active", function(checked) {
  369. env.editor.setHighlightActiveLine(checked);
  370. });
  371. bindCheckbox("show_hidden", function(checked) {
  372. env.editor.setShowInvisibles(checked);
  373. });
  374. bindCheckbox("display_indent_guides", function(checked) {
  375. env.editor.setDisplayIndentGuides(checked);
  376. });
  377. bindCheckbox("show_gutter", function(checked) {
  378. env.editor.renderer.setShowGutter(checked);
  379. });
  380. bindCheckbox("show_print_margin", function(checked) {
  381. env.editor.renderer.setShowPrintMargin(checked);
  382. });
  383. bindCheckbox("highlight_selected_word", function(checked) {
  384. env.editor.setHighlightSelectedWord(checked);
  385. });
  386. bindCheckbox("show_hscroll", function(checked) {
  387. env.editor.setOption("hScrollBarAlwaysVisible", checked);
  388. });
  389. bindCheckbox("show_vscroll", function(checked) {
  390. env.editor.setOption("vScrollBarAlwaysVisible", checked);
  391. });
  392. bindCheckbox("animate_scroll", function(checked) {
  393. env.editor.setAnimatedScroll(checked);
  394. });
  395. bindCheckbox("soft_tab", function(checked) {
  396. env.editor.session.setUseSoftTabs(checked);
  397. });
  398. bindCheckbox("enable_behaviours", function(checked) {
  399. env.editor.setBehavioursEnabled(checked);
  400. });
  401. bindCheckbox("fade_fold_widgets", function(checked) {
  402. env.editor.setFadeFoldWidgets(checked);
  403. });
  404. bindCheckbox("read_only", function(checked) {
  405. env.editor.setReadOnly(checked);
  406. });
  407. bindCheckbox("scrollPastEnd", function(checked) {
  408. env.editor.setOption("scrollPastEnd", checked);
  409. });
  410. bindDropdown("split", function(value) {
  411. var sp = env.split;
  412. if (value == "none") {
  413. sp.setSplits(1);
  414. } else {
  415. var newEditor = (sp.getSplits() == 1);
  416. sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE);
  417. sp.setSplits(2);
  418. if (newEditor) {
  419. var session = sp.getEditor(0).session;
  420. var newSession = sp.setSession(session, 1);
  421. newSession.name = session.name;
  422. }
  423. }
  424. });
  425. bindCheckbox("elastic_tabstops", function(checked) {
  426. env.editor.setOption("useElasticTabstops", checked);
  427. });
  428. var iSearchCheckbox = bindCheckbox("isearch", function(checked) {
  429. env.editor.setOption("useIncrementalSearch", checked);
  430. });
  431. env.editor.addEventListener('incrementalSearchSettingChanged', function(event) {
  432. iSearchCheckbox.checked = event.isEnabled;
  433. });
  434. function synchroniseScrolling() {
  435. var s1 = env.split.$editors[0].session;
  436. var s2 = env.split.$editors[1].session;
  437. s1.on('changeScrollTop', function(pos) {s2.setScrollTop(pos)});
  438. s2.on('changeScrollTop', function(pos) {s1.setScrollTop(pos)});
  439. s1.on('changeScrollLeft', function(pos) {s2.setScrollLeft(pos)});
  440. s2.on('changeScrollLeft', function(pos) {s1.setScrollLeft(pos)});
  441. }
  442. bindCheckbox("highlight_token", function(checked) {
  443. var editor = env.editor;
  444. if (editor.tokenTooltip && !checked) {
  445. editor.tokenTooltip.destroy();
  446. delete editor.tokenTooltip;
  447. } else if (checked) {
  448. editor.tokenTooltip = new TokenTooltip(editor);
  449. }
  450. });
  451. var StatusBar = require("ace/ext/statusbar").StatusBar;
  452. new StatusBar(env.editor, cmdLine.container);
  453. var Emmet = require("ace/ext/emmet");
  454. net.loadScript("https://cloud9ide.github.io/emmet-core/emmet.js", function() {
  455. Emmet.setCore(window.emmet);
  456. env.editor.setOption("enableEmmet", true);
  457. });
  458. // require("ace/placeholder").PlaceHolder;
  459. var snippetManager = require("ace/snippets").snippetManager;
  460. env.editSnippets = function() {
  461. var sp = env.split;
  462. if (sp.getSplits() == 2) {
  463. sp.setSplits(1);
  464. return;
  465. }
  466. sp.setSplits(1);
  467. sp.setSplits(2);
  468. sp.setOrientation(sp.BESIDE);
  469. var editor = sp.$editors[1];
  470. var id = sp.$editors[0].session.$mode.$id || "";
  471. var m = snippetManager.files[id];
  472. if (!doclist["snippets/" + id]) {
  473. var text = m.snippetText;
  474. var s = doclist.initDoc(text, "", {});
  475. s.setMode("ace/mode/snippets");
  476. doclist["snippets/" + id] = s;
  477. }
  478. editor.on("blur", function() {
  479. m.snippetText = editor.getValue();
  480. snippetManager.unregister(m.snippets);
  481. m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope);
  482. snippetManager.register(m.snippets);
  483. });
  484. sp.$editors[0].once("changeMode", function() {
  485. sp.setSplits(1);
  486. });
  487. editor.setSession(doclist["snippets/" + id], 1);
  488. editor.focus();
  489. };
  490. require("ace/ext/language_tools");
  491. env.editor.setOptions({
  492. enableBasicAutocompletion: true,
  493. enableLiveAutocompletion: false,
  494. enableSnippets: true
  495. });
  496. var beautify = require("ace/ext/beautify");
  497. env.editor.commands.addCommands(beautify.commands);
  498. });