ext-textarea.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], 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. var dom = require("../lib/dom");
  126. dom.importCssString(exports.cssText, exports.cssClass);
  127. });
  128. ace.define("ace/ext/textarea",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/net","ace/ace","ace/theme/textmate"], function(require, exports, module) {
  129. "use strict";
  130. var event = require("../lib/event");
  131. var UA = require("../lib/useragent");
  132. var net = require("../lib/net");
  133. var ace = require("../ace");
  134. require("../theme/textmate");
  135. module.exports = exports = ace;
  136. var getCSSProperty = function(element, container, property) {
  137. var ret = element.style[property];
  138. if (!ret) {
  139. if (window.getComputedStyle) {
  140. ret = window.getComputedStyle(element, '').getPropertyValue(property);
  141. } else {
  142. ret = element.currentStyle[property];
  143. }
  144. }
  145. if (!ret || ret == 'auto' || ret == 'intrinsic') {
  146. ret = container.style[property];
  147. }
  148. return ret;
  149. };
  150. function applyStyles(elm, styles) {
  151. for (var style in styles) {
  152. elm.style[style] = styles[style];
  153. }
  154. }
  155. function setupContainer(element, getValue) {
  156. if (element.type != 'textarea') {
  157. throw new Error("Textarea required!");
  158. }
  159. var parentNode = element.parentNode;
  160. var container = document.createElement('div');
  161. var resizeEvent = function() {
  162. var style = 'position:relative;';
  163. [
  164. 'margin-top', 'margin-left', 'margin-right', 'margin-bottom'
  165. ].forEach(function(item) {
  166. style += item + ':' +
  167. getCSSProperty(element, container, item) + ';';
  168. });
  169. var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px");
  170. var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px");
  171. style += 'height:' + height + ';width:' + width + ';';
  172. style += 'display:inline-block;';
  173. container.setAttribute('style', style);
  174. };
  175. event.addListener(window, 'resize', resizeEvent);
  176. resizeEvent();
  177. parentNode.insertBefore(container, element.nextSibling);
  178. while (parentNode !== document) {
  179. if (parentNode.tagName.toUpperCase() === 'FORM') {
  180. var oldSumit = parentNode.onsubmit;
  181. parentNode.onsubmit = function(evt) {
  182. element.value = getValue();
  183. if (oldSumit) {
  184. oldSumit.call(this, evt);
  185. }
  186. };
  187. break;
  188. }
  189. parentNode = parentNode.parentNode;
  190. }
  191. return container;
  192. }
  193. exports.transformTextarea = function(element, options) {
  194. var session;
  195. var container = setupContainer(element, function() {
  196. return session.getValue();
  197. });
  198. element.style.display = 'none';
  199. container.style.background = 'white';
  200. var editorDiv = document.createElement("div");
  201. applyStyles(editorDiv, {
  202. top: "0px",
  203. left: "0px",
  204. right: "0px",
  205. bottom: "0px",
  206. border: "1px solid gray",
  207. position: "absolute"
  208. });
  209. container.appendChild(editorDiv);
  210. var settingOpener = document.createElement("div");
  211. applyStyles(settingOpener, {
  212. position: "absolute",
  213. right: "0px",
  214. bottom: "0px",
  215. background: "red",
  216. cursor: "nw-resize",
  217. borderStyle: "solid",
  218. borderWidth: "9px 8px 10px 9px",
  219. width: "2px",
  220. borderColor: "lightblue gray gray lightblue",
  221. zIndex: 101
  222. });
  223. var settingDiv = document.createElement("div");
  224. var settingDivStyles = {
  225. top: "0px",
  226. left: "20%",
  227. right: "0px",
  228. bottom: "0px",
  229. position: "absolute",
  230. padding: "5px",
  231. zIndex: 100,
  232. color: "white",
  233. display: "none",
  234. overflow: "auto",
  235. fontSize: "14px",
  236. boxShadow: "-5px 2px 3px gray"
  237. };
  238. if (!UA.isOldIE) {
  239. settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
  240. } else {
  241. settingDivStyles.backgroundColor = "#333";
  242. }
  243. applyStyles(settingDiv, settingDivStyles);
  244. container.appendChild(settingDiv);
  245. options = options || exports.defaultOptions;
  246. var editor = ace.edit(editorDiv);
  247. session = editor.getSession();
  248. session.setValue(element.value || element.innerHTML);
  249. editor.focus();
  250. container.appendChild(settingOpener);
  251. setupApi(editor, editorDiv, settingDiv, ace, options, load);
  252. setupSettingPanel(settingDiv, settingOpener, editor);
  253. var state = "";
  254. event.addListener(settingOpener, "mousemove", function(e) {
  255. var rect = this.getBoundingClientRect();
  256. var x = e.clientX - rect.left, y = e.clientY - rect.top;
  257. if (x + y < (rect.width + rect.height)/2) {
  258. this.style.cursor = "pointer";
  259. state = "toggle";
  260. } else {
  261. state = "resize";
  262. this.style.cursor = "nw-resize";
  263. }
  264. });
  265. event.addListener(settingOpener, "mousedown", function(e) {
  266. if (state == "toggle") {
  267. editor.setDisplaySettings();
  268. return;
  269. }
  270. container.style.zIndex = 100000;
  271. var rect = container.getBoundingClientRect();
  272. var startX = rect.width + rect.left - e.clientX;
  273. var startY = rect.height + rect.top - e.clientY;
  274. event.capture(settingOpener, function(e) {
  275. container.style.width = e.clientX - rect.left + startX + "px";
  276. container.style.height = e.clientY - rect.top + startY + "px";
  277. editor.resize();
  278. }, function() {});
  279. });
  280. return editor;
  281. };
  282. function load(url, module, callback) {
  283. net.loadScript(url, function() {
  284. require([module], callback);
  285. });
  286. }
  287. function setupApi(editor, editorDiv, settingDiv, ace, options, loader) {
  288. var session = editor.getSession();
  289. var renderer = editor.renderer;
  290. loader = loader || load;
  291. function toBool(value) {
  292. return value === "true" || value == true;
  293. }
  294. editor.setDisplaySettings = function(display) {
  295. if (display == null)
  296. display = settingDiv.style.display == "none";
  297. if (display) {
  298. settingDiv.style.display = "block";
  299. settingDiv.hideButton.focus();
  300. editor.on("focus", function onFocus() {
  301. editor.removeListener("focus", onFocus);
  302. settingDiv.style.display = "none";
  303. });
  304. } else {
  305. editor.focus();
  306. }
  307. };
  308. editor.$setOption = editor.setOption;
  309. editor.$getOption = editor.getOption;
  310. editor.setOption = function(key, value) {
  311. switch (key) {
  312. case "mode":
  313. editor.$setOption("mode", "ace/mode/" + value)
  314. break;
  315. case "theme":
  316. editor.$setOption("theme", "ace/theme/" + value)
  317. break;
  318. case "keybindings":
  319. switch (value) {
  320. case "vim":
  321. editor.setKeyboardHandler("ace/keyboard/vim");
  322. break;
  323. case "emacs":
  324. editor.setKeyboardHandler("ace/keyboard/emacs");
  325. break;
  326. default:
  327. editor.setKeyboardHandler(null);
  328. }
  329. break;
  330. case "softWrap":
  331. case "fontSize":
  332. editor.$setOption(key, value);
  333. break;
  334. default:
  335. editor.$setOption(key, toBool(value));
  336. }
  337. };
  338. editor.getOption = function(key) {
  339. switch (key) {
  340. case "mode":
  341. return editor.$getOption("mode").substr("ace/mode/".length)
  342. break;
  343. case "theme":
  344. return editor.$getOption("theme").substr("ace/theme/".length)
  345. break;
  346. case "keybindings":
  347. var value = editor.getKeyboardHandler()
  348. switch (value && value.$id) {
  349. case "ace/keyboard/vim":
  350. return "vim";
  351. case "ace/keyboard/emacs":
  352. return "emacs";
  353. default:
  354. return "ace";
  355. }
  356. break;
  357. default:
  358. return editor.$getOption(key);
  359. }
  360. };
  361. editor.setOptions(options);
  362. return editor;
  363. }
  364. function setupSettingPanel(settingDiv, settingOpener, editor) {
  365. var BOOL = null;
  366. var desc = {
  367. mode: "Mode:",
  368. wrap: "Soft Wrap:",
  369. theme: "Theme:",
  370. fontSize: "Font Size:",
  371. showGutter: "Display Gutter:",
  372. keybindings: "Keyboard",
  373. showPrintMargin: "Show Print Margin:",
  374. useSoftTabs: "Use Soft Tabs:",
  375. showInvisibles: "Show Invisibles"
  376. };
  377. var optionValues = {
  378. mode: {
  379. text: "Plain",
  380. javascript: "JavaScript",
  381. xml: "XML",
  382. html: "HTML",
  383. css: "CSS",
  384. scss: "SCSS",
  385. python: "Python",
  386. php: "PHP",
  387. java: "Java",
  388. ruby: "Ruby",
  389. c_cpp: "C/C++",
  390. coffee: "CoffeeScript",
  391. json: "json",
  392. perl: "Perl",
  393. clojure: "Clojure",
  394. ocaml: "OCaml",
  395. csharp: "C#",
  396. haxe: "haXe",
  397. svg: "SVG",
  398. textile: "Textile",
  399. groovy: "Groovy",
  400. liquid: "Liquid",
  401. Scala: "Scala"
  402. },
  403. theme: {
  404. clouds: "Clouds",
  405. clouds_midnight: "Clouds Midnight",
  406. cobalt: "Cobalt",
  407. crimson_editor: "Crimson Editor",
  408. dawn: "Dawn",
  409. eclipse: "Eclipse",
  410. idle_fingers: "Idle Fingers",
  411. kr_theme: "Kr Theme",
  412. merbivore: "Merbivore",
  413. merbivore_soft: "Merbivore Soft",
  414. mono_industrial: "Mono Industrial",
  415. monokai: "Monokai",
  416. pastel_on_dark: "Pastel On Dark",
  417. solarized_dark: "Solarized Dark",
  418. solarized_light: "Solarized Light",
  419. textmate: "Textmate",
  420. twilight: "Twilight",
  421. vibrant_ink: "Vibrant Ink"
  422. },
  423. showGutter: BOOL,
  424. fontSize: {
  425. "10px": "10px",
  426. "11px": "11px",
  427. "12px": "12px",
  428. "14px": "14px",
  429. "16px": "16px"
  430. },
  431. wrap: {
  432. off: "Off",
  433. 40: "40",
  434. 80: "80",
  435. free: "Free"
  436. },
  437. keybindings: {
  438. ace: "ace",
  439. vim: "vim",
  440. emacs: "emacs"
  441. },
  442. showPrintMargin: BOOL,
  443. useSoftTabs: BOOL,
  444. showInvisibles: BOOL
  445. };
  446. var table = [];
  447. table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
  448. function renderOption(builder, option, obj, cValue) {
  449. if (!obj) {
  450. builder.push(
  451. "<input type='checkbox' title='", option, "' ",
  452. cValue + "" == "true" ? "checked='true'" : "",
  453. "'></input>"
  454. );
  455. return;
  456. }
  457. builder.push("<select title='" + option + "'>");
  458. for (var value in obj) {
  459. builder.push("<option value='" + value + "' ");
  460. if (cValue == value) {
  461. builder.push(" selected ");
  462. }
  463. builder.push(">",
  464. obj[value],
  465. "</option>");
  466. }
  467. builder.push("</select>");
  468. }
  469. for (var option in exports.defaultOptions) {
  470. table.push("<tr><td>", desc[option], "</td>");
  471. table.push("<td>");
  472. renderOption(table, option, optionValues[option], editor.getOption(option));
  473. table.push("</td></tr>");
  474. }
  475. table.push("</table>");
  476. settingDiv.innerHTML = table.join("");
  477. var onChange = function(e) {
  478. var select = e.currentTarget;
  479. editor.setOption(select.title, select.value);
  480. };
  481. var onClick = function(e) {
  482. var cb = e.currentTarget;
  483. editor.setOption(cb.title, cb.checked);
  484. };
  485. var selects = settingDiv.getElementsByTagName("select");
  486. for (var i = 0; i < selects.length; i++)
  487. selects[i].onchange = onChange;
  488. var cbs = settingDiv.getElementsByTagName("input");
  489. for (var i = 0; i < cbs.length; i++)
  490. cbs[i].onclick = onClick;
  491. var button = document.createElement("input");
  492. button.type = "button";
  493. button.value = "Hide";
  494. event.addListener(button, "click", function() {
  495. editor.setDisplaySettings(false);
  496. });
  497. settingDiv.appendChild(button);
  498. settingDiv.hideButton = button;
  499. }
  500. exports.defaultOptions = {
  501. mode: "javascript",
  502. theme: "textmate",
  503. wrap: "off",
  504. fontSize: "12px",
  505. showGutter: "false",
  506. keybindings: "ace",
  507. showPrintMargin: "false",
  508. useSoftTabs: "true",
  509. showInvisibles: "false"
  510. };
  511. });
  512. (function() {
  513. ace.require(["ace/ext/textarea"], function() {});
  514. })();