ext-textarea.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. ace.define("ace/theme/textmate",[], function(require, exports, module) {
  2. "use strict";
  3. exports.isDark = false;
  4. exports.cssClass = "ace-tm";
  5. exports.cssText = ".ace-tm .ace_gutter {\
  6. background: #f0f0f0;\
  7. color: #333;\
  8. }\
  9. .ace-tm .ace_print-margin {\
  10. width: 1px;\
  11. background: #e8e8e8;\
  12. }\
  13. .ace-tm .ace_fold {\
  14. background-color: #6B72E6;\
  15. }\
  16. .ace-tm {\
  17. background-color: #FFFFFF;\
  18. color: black;\
  19. }\
  20. .ace-tm .ace_cursor {\
  21. color: black;\
  22. }\
  23. .ace-tm .ace_invisible {\
  24. color: rgb(191, 191, 191);\
  25. }\
  26. .ace-tm .ace_storage,\
  27. .ace-tm .ace_keyword {\
  28. color: blue;\
  29. }\
  30. .ace-tm .ace_constant {\
  31. color: rgb(197, 6, 11);\
  32. }\
  33. .ace-tm .ace_constant.ace_buildin {\
  34. color: rgb(88, 72, 246);\
  35. }\
  36. .ace-tm .ace_constant.ace_language {\
  37. color: rgb(88, 92, 246);\
  38. }\
  39. .ace-tm .ace_constant.ace_library {\
  40. color: rgb(6, 150, 14);\
  41. }\
  42. .ace-tm .ace_invalid {\
  43. background-color: rgba(255, 0, 0, 0.1);\
  44. color: red;\
  45. }\
  46. .ace-tm .ace_support.ace_function {\
  47. color: rgb(60, 76, 114);\
  48. }\
  49. .ace-tm .ace_support.ace_constant {\
  50. color: rgb(6, 150, 14);\
  51. }\
  52. .ace-tm .ace_support.ace_type,\
  53. .ace-tm .ace_support.ace_class {\
  54. color: rgb(109, 121, 222);\
  55. }\
  56. .ace-tm .ace_keyword.ace_operator {\
  57. color: rgb(104, 118, 135);\
  58. }\
  59. .ace-tm .ace_string {\
  60. color: rgb(3, 106, 7);\
  61. }\
  62. .ace-tm .ace_comment {\
  63. color: rgb(76, 136, 107);\
  64. }\
  65. .ace-tm .ace_comment.ace_doc {\
  66. color: rgb(0, 102, 255);\
  67. }\
  68. .ace-tm .ace_comment.ace_doc.ace_tag {\
  69. color: rgb(128, 159, 191);\
  70. }\
  71. .ace-tm .ace_constant.ace_numeric {\
  72. color: rgb(0, 0, 205);\
  73. }\
  74. .ace-tm .ace_variable {\
  75. color: rgb(49, 132, 149);\
  76. }\
  77. .ace-tm .ace_xml-pe {\
  78. color: rgb(104, 104, 91);\
  79. }\
  80. .ace-tm .ace_entity.ace_name.ace_function {\
  81. color: #0000A2;\
  82. }\
  83. .ace-tm .ace_heading {\
  84. color: rgb(12, 7, 255);\
  85. }\
  86. .ace-tm .ace_list {\
  87. color:rgb(185, 6, 144);\
  88. }\
  89. .ace-tm .ace_meta.ace_tag {\
  90. color:rgb(0, 22, 142);\
  91. }\
  92. .ace-tm .ace_string.ace_regex {\
  93. color: rgb(255, 0, 0)\
  94. }\
  95. .ace-tm .ace_marker-layer .ace_selection {\
  96. background: rgb(181, 213, 255);\
  97. }\
  98. .ace-tm.ace_multiselect .ace_selection.ace_start {\
  99. box-shadow: 0 0 3px 0px white;\
  100. }\
  101. .ace-tm .ace_marker-layer .ace_step {\
  102. background: rgb(252, 255, 0);\
  103. }\
  104. .ace-tm .ace_marker-layer .ace_stack {\
  105. background: rgb(164, 229, 101);\
  106. }\
  107. .ace-tm .ace_marker-layer .ace_bracket {\
  108. margin: -1px 0 0 -1px;\
  109. border: 1px solid rgb(192, 192, 192);\
  110. }\
  111. .ace-tm .ace_marker-layer .ace_active-line {\
  112. background: rgba(0, 0, 0, 0.07);\
  113. }\
  114. .ace-tm .ace_gutter-active-line {\
  115. background-color : #dcdcdc;\
  116. }\
  117. .ace-tm .ace_marker-layer .ace_selected-word {\
  118. background: rgb(250, 250, 255);\
  119. border: 1px solid rgb(200, 200, 250);\
  120. }\
  121. .ace-tm .ace_indent-guide {\
  122. background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\
  123. }\
  124. ";
  125. exports.$id = "ace/theme/textmate";
  126. var dom = require("../lib/dom");
  127. dom.importCssString(exports.cssText, exports.cssClass);
  128. });
  129. ace.define("ace/ext/textarea",[], function(require, exports, module) {
  130. "use strict";
  131. var event = require("../lib/event");
  132. var UA = require("../lib/useragent");
  133. var net = require("../lib/net");
  134. var ace = require("../ace");
  135. require("../theme/textmate");
  136. module.exports = exports = ace;
  137. var getCSSProperty = function(element, container, property) {
  138. var ret = element.style[property];
  139. if (!ret) {
  140. if (window.getComputedStyle) {
  141. ret = window.getComputedStyle(element, '').getPropertyValue(property);
  142. } else {
  143. ret = element.currentStyle[property];
  144. }
  145. }
  146. if (!ret || ret == 'auto' || ret == 'intrinsic') {
  147. ret = container.style[property];
  148. }
  149. return ret;
  150. };
  151. function applyStyles(elm, styles) {
  152. for (var style in styles) {
  153. elm.style[style] = styles[style];
  154. }
  155. }
  156. function setupContainer(element, getValue) {
  157. if (element.type != 'textarea') {
  158. throw new Error("Textarea required!");
  159. }
  160. var parentNode = element.parentNode;
  161. var container = document.createElement('div');
  162. //
  163. var resizeEvent = function() {
  164. var style = 'position:relative;';
  165. [
  166. 'margin-top', 'margin-left', 'margin-right', 'margin-bottom'
  167. ].forEach(function(item) {
  168. style += item + ':' +
  169. getCSSProperty(element, container, item) + ';';
  170. });
  171. var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px");
  172. var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px");
  173. style += 'height:' + height + ';width:' + width + ';';
  174. style += 'display:inline-block;';
  175. container.setAttribute('style', style);
  176. };
  177. event.addListener(window, 'resize', resizeEvent);
  178. resizeEvent();
  179. parentNode.insertBefore(container, element.nextSibling);
  180. while (parentNode !== document) {
  181. if (parentNode.tagName.toUpperCase() === 'FORM') {
  182. var oldSumit = parentNode.onsubmit;
  183. parentNode.onsubmit = function(evt) {
  184. element.value = getValue();
  185. if (oldSumit) {
  186. oldSumit.call(this, evt);
  187. }
  188. };
  189. break;
  190. }
  191. parentNode = parentNode.parentNode;
  192. }
  193. return container;
  194. }
  195. exports.transformTextarea = function(element, options) {
  196. var isFocused = element.autofocus || document.activeElement == element;
  197. var session;
  198. var container = setupContainer(element, function() {
  199. return session.getValue();
  200. });
  201. element.style.display = 'none';
  202. container.style.background = 'white';
  203. //
  204. var editorDiv = document.createElement("div");
  205. applyStyles(editorDiv, {
  206. top: "0px",
  207. left: "0px",
  208. right: "0px",
  209. bottom: "0px",
  210. border: "1px solid gray",
  211. position: "absolute"
  212. });
  213. container.appendChild(editorDiv);
  214. var settingOpener = document.createElement("div");
  215. applyStyles(settingOpener, {
  216. position: "absolute",
  217. right: "0px",
  218. bottom: "0px",
  219. cursor: "nw-resize",
  220. border: "solid 9px",
  221. borderColor: "lightblue gray gray #ceade6",
  222. zIndex: 101
  223. });
  224. var settingDiv = document.createElement("div");
  225. var settingDivStyles = {
  226. top: "0px",
  227. left: "20%",
  228. right: "0px",
  229. bottom: "0px",
  230. position: "absolute",
  231. padding: "5px",
  232. zIndex: 100,
  233. color: "white",
  234. display: "none",
  235. overflow: "auto",
  236. fontSize: "14px",
  237. boxShadow: "-5px 2px 3px gray"
  238. };
  239. if (!UA.isOldIE) {
  240. settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
  241. } else {
  242. settingDivStyles.backgroundColor = "#333";
  243. }
  244. applyStyles(settingDiv, settingDivStyles);
  245. container.appendChild(settingDiv);
  246. options = options || exports.defaultOptions;
  247. var editor = ace.edit(editorDiv);
  248. session = editor.getSession();
  249. session.setValue(element.value || element.innerHTML);
  250. if (isFocused)
  251. editor.focus();
  252. container.appendChild(settingOpener);
  253. setupApi(editor, editorDiv, settingDiv, ace, options);
  254. setupSettingPanel(settingDiv, settingOpener, editor);
  255. var state = "";
  256. event.addListener(settingOpener, "mousemove", function(e) {
  257. var rect = this.getBoundingClientRect();
  258. var x = e.clientX - rect.left, y = e.clientY - rect.top;
  259. if (x + y < (rect.width + rect.height)/2) {
  260. this.style.cursor = "pointer";
  261. state = "toggle";
  262. } else {
  263. state = "resize";
  264. this.style.cursor = "nw-resize";
  265. }
  266. });
  267. event.addListener(settingOpener, "mousedown", function(e) {
  268. e.preventDefault();
  269. if (state == "toggle") {
  270. editor.setDisplaySettings();
  271. return;
  272. }
  273. container.style.zIndex = 100000;
  274. var rect = container.getBoundingClientRect();
  275. var startX = rect.width + rect.left - e.clientX;
  276. var startY = rect.height + rect.top - e.clientY;
  277. event.capture(settingOpener, function(e) {
  278. container.style.width = e.clientX - rect.left + startX + "px";
  279. container.style.height = e.clientY - rect.top + startY + "px";
  280. editor.resize();
  281. }, function() {});
  282. });
  283. return editor;
  284. };
  285. function load(url, module, callback) {
  286. net.loadScript(url, function() {
  287. require([module], callback);
  288. });
  289. }
  290. function setupApi(editor, editorDiv, settingDiv, ace, options) {
  291. var session = editor.getSession();
  292. var renderer = editor.renderer;
  293. function toBool(value) {
  294. return value === "true" || value == true;
  295. }
  296. editor.setDisplaySettings = function(display) {
  297. if (display == null)
  298. display = settingDiv.style.display == "none";
  299. if (display) {
  300. settingDiv.style.display = "block";
  301. settingDiv.hideButton.focus();
  302. editor.on("focus", function onFocus() {
  303. editor.removeListener("focus", onFocus);
  304. settingDiv.style.display = "none";
  305. });
  306. } else {
  307. editor.focus();
  308. }
  309. };
  310. editor.$setOption = editor.setOption;
  311. editor.$getOption = editor.getOption;
  312. editor.setOption = function(key, value) {
  313. switch (key) {
  314. case "mode":
  315. editor.$setOption("mode", "ace/mode/" + value);
  316. break;
  317. case "theme":
  318. editor.$setOption("theme", "ace/theme/" + value);
  319. break;
  320. case "keybindings":
  321. switch (value) {
  322. case "vim":
  323. editor.setKeyboardHandler("ace/keyboard/vim");
  324. break;
  325. case "emacs":
  326. editor.setKeyboardHandler("ace/keyboard/emacs");
  327. break;
  328. default:
  329. editor.setKeyboardHandler(null);
  330. }
  331. break;
  332. case "wrap":
  333. case "fontSize":
  334. editor.$setOption(key, value);
  335. break;
  336. default:
  337. editor.$setOption(key, toBool(value));
  338. }
  339. };
  340. editor.getOption = function(key) {
  341. switch (key) {
  342. case "mode":
  343. return editor.$getOption("mode").substr("ace/mode/".length);
  344. break;
  345. case "theme":
  346. return editor.$getOption("theme").substr("ace/theme/".length);
  347. break;
  348. case "keybindings":
  349. var value = editor.getKeyboardHandler();
  350. switch (value && value.$id) {
  351. case "ace/keyboard/vim":
  352. return "vim";
  353. case "ace/keyboard/emacs":
  354. return "emacs";
  355. default:
  356. return "ace";
  357. }
  358. break;
  359. default:
  360. return editor.$getOption(key);
  361. }
  362. };
  363. editor.setOptions(options);
  364. return editor;
  365. }
  366. function setupSettingPanel(settingDiv, settingOpener, editor) {
  367. var BOOL = null;
  368. var desc = {
  369. mode: "Mode:",
  370. wrap: "Soft Wrap:",
  371. theme: "Theme:",
  372. fontSize: "Font Size:",
  373. showGutter: "Display Gutter:",
  374. keybindings: "Keyboard",
  375. showPrintMargin: "Show Print Margin:",
  376. useSoftTabs: "Use Soft Tabs:",
  377. showInvisibles: "Show Invisibles"
  378. };
  379. var optionValues = {
  380. mode: {
  381. text: "Plain",
  382. javascript: "JavaScript",
  383. xml: "XML",
  384. html: "HTML",
  385. css: "CSS",
  386. scss: "SCSS",
  387. python: "Python",
  388. php: "PHP",
  389. java: "Java",
  390. ruby: "Ruby",
  391. c_cpp: "C/C++",
  392. coffee: "CoffeeScript",
  393. json: "json",
  394. perl: "Perl",
  395. clojure: "Clojure",
  396. ocaml: "OCaml",
  397. csharp: "C#",
  398. haxe: "haXe",
  399. svg: "SVG",
  400. textile: "Textile",
  401. groovy: "Groovy",
  402. liquid: "Liquid",
  403. Scala: "Scala"
  404. },
  405. theme: {
  406. clouds: "Clouds",
  407. clouds_midnight: "Clouds Midnight",
  408. cobalt: "Cobalt",
  409. crimson_editor: "Crimson Editor",
  410. dawn: "Dawn",
  411. gob: "Green on Black",
  412. eclipse: "Eclipse",
  413. idle_fingers: "Idle Fingers",
  414. kr_theme: "Kr Theme",
  415. merbivore: "Merbivore",
  416. merbivore_soft: "Merbivore Soft",
  417. mono_industrial: "Mono Industrial",
  418. monokai: "Monokai",
  419. pastel_on_dark: "Pastel On Dark",
  420. solarized_dark: "Solarized Dark",
  421. solarized_light: "Solarized Light",
  422. textmate: "Textmate",
  423. twilight: "Twilight",
  424. vibrant_ink: "Vibrant Ink"
  425. },
  426. showGutter: BOOL,
  427. fontSize: {
  428. "10px": "10px",
  429. "11px": "11px",
  430. "12px": "12px",
  431. "14px": "14px",
  432. "16px": "16px"
  433. },
  434. wrap: {
  435. off: "Off",
  436. 40: "40",
  437. 80: "80",
  438. free: "Free"
  439. },
  440. keybindings: {
  441. ace: "ace",
  442. vim: "vim",
  443. emacs: "emacs"
  444. },
  445. showPrintMargin: BOOL,
  446. useSoftTabs: BOOL,
  447. showInvisibles: BOOL
  448. };
  449. var table = [];
  450. table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
  451. function renderOption(builder, option, obj, cValue) {
  452. if (!obj) {
  453. builder.push(
  454. "<input type='checkbox' title='", option, "' ",
  455. cValue + "" == "true" ? "checked='true'" : "",
  456. "'></input>"
  457. );
  458. return;
  459. }
  460. builder.push("<select title='" + option + "'>");
  461. for (var value in obj) {
  462. builder.push("<option value='" + value + "' ");
  463. if (cValue == value) {
  464. builder.push(" selected ");
  465. }
  466. builder.push(">",
  467. obj[value],
  468. "</option>");
  469. }
  470. builder.push("</select>");
  471. }
  472. for (var option in exports.defaultOptions) {
  473. table.push("<tr><td>", desc[option], "</td>");
  474. table.push("<td>");
  475. renderOption(table, option, optionValues[option], editor.getOption(option));
  476. table.push("</td></tr>");
  477. }
  478. table.push("</table>");
  479. settingDiv.innerHTML = table.join("");
  480. var onChange = function(e) {
  481. var select = e.currentTarget;
  482. editor.setOption(select.title, select.value);
  483. };
  484. var onClick = function(e) {
  485. var cb = e.currentTarget;
  486. editor.setOption(cb.title, cb.checked);
  487. };
  488. var selects = settingDiv.getElementsByTagName("select");
  489. for (var i = 0; i < selects.length; i++)
  490. selects[i].onchange = onChange;
  491. var cbs = settingDiv.getElementsByTagName("input");
  492. for (var i = 0; i < cbs.length; i++)
  493. cbs[i].onclick = onClick;
  494. var button = document.createElement("input");
  495. button.type = "button";
  496. button.value = "Hide";
  497. event.addListener(button, "click", function() {
  498. editor.setDisplaySettings(false);
  499. });
  500. settingDiv.appendChild(button);
  501. settingDiv.hideButton = button;
  502. }
  503. exports.defaultOptions = {
  504. mode: "javascript",
  505. theme: "textmate",
  506. wrap: "off",
  507. fontSize: "12px",
  508. showGutter: "false",
  509. keybindings: "ace",
  510. showPrintMargin: "false",
  511. useSoftTabs: "true",
  512. showInvisibles: "false"
  513. };
  514. });
  515. (function() {
  516. ace.require(["ace/ext/textarea"], function(m) {
  517. if (typeof module == "object" && typeof exports == "object" && module) {
  518. module.exports = m;
  519. }
  520. });
  521. })();