ext-textarea.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. define("ace/ext/textarea",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/net","ace/ace"], function(require, exports, module) {
  2. "use strict";
  3. var event = require("../lib/event");
  4. var UA = require("../lib/useragent");
  5. var net = require("../lib/net");
  6. var ace = require("../ace");
  7. module.exports = exports = ace;
  8. var getCSSProperty = function(element, container, property) {
  9. var ret = element.style[property];
  10. if (!ret) {
  11. if (window.getComputedStyle) {
  12. ret = window.getComputedStyle(element, '').getPropertyValue(property);
  13. } else {
  14. ret = element.currentStyle[property];
  15. }
  16. }
  17. if (!ret || ret == 'auto' || ret == 'intrinsic') {
  18. ret = container.style[property];
  19. }
  20. return ret;
  21. };
  22. function applyStyles(elm, styles) {
  23. for (var style in styles) {
  24. elm.style[style] = styles[style];
  25. }
  26. }
  27. function setupContainer(element, getValue) {
  28. if (element.type != 'textarea') {
  29. throw new Error("Textarea required!");
  30. }
  31. var parentNode = element.parentNode;
  32. var container = document.createElement('div');
  33. var resizeEvent = function() {
  34. var style = 'position:relative;';
  35. [
  36. 'margin-top', 'margin-left', 'margin-right', 'margin-bottom'
  37. ].forEach(function(item) {
  38. style += item + ':' +
  39. getCSSProperty(element, container, item) + ';';
  40. });
  41. var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px");
  42. var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px");
  43. style += 'height:' + height + ';width:' + width + ';';
  44. style += 'display:inline-block;';
  45. container.setAttribute('style', style);
  46. };
  47. event.addListener(window, 'resize', resizeEvent);
  48. resizeEvent();
  49. parentNode.insertBefore(container, element.nextSibling);
  50. while (parentNode !== document) {
  51. if (parentNode.tagName.toUpperCase() === 'FORM') {
  52. var oldSumit = parentNode.onsubmit;
  53. parentNode.onsubmit = function(evt) {
  54. element.value = getValue();
  55. if (oldSumit) {
  56. oldSumit.call(this, evt);
  57. }
  58. };
  59. break;
  60. }
  61. parentNode = parentNode.parentNode;
  62. }
  63. return container;
  64. }
  65. exports.transformTextarea = function(element, options) {
  66. var isFocused = element.autofocus || document.activeElement == element;
  67. var session;
  68. var container = setupContainer(element, function() {
  69. return session.getValue();
  70. });
  71. element.style.display = 'none';
  72. container.style.background = 'white';
  73. var editorDiv = document.createElement("div");
  74. applyStyles(editorDiv, {
  75. top: "0px",
  76. left: "0px",
  77. right: "0px",
  78. bottom: "0px",
  79. border: "1px solid gray",
  80. position: "absolute"
  81. });
  82. container.appendChild(editorDiv);
  83. var settingOpener = document.createElement("div");
  84. applyStyles(settingOpener, {
  85. position: "absolute",
  86. right: "0px",
  87. bottom: "0px",
  88. cursor: "nw-resize",
  89. border: "solid 9px",
  90. borderColor: "lightblue gray gray #ceade6",
  91. zIndex: 101
  92. });
  93. var settingDiv = document.createElement("div");
  94. var settingDivStyles = {
  95. top: "0px",
  96. left: "20%",
  97. right: "0px",
  98. bottom: "0px",
  99. position: "absolute",
  100. padding: "5px",
  101. zIndex: 100,
  102. color: "white",
  103. display: "none",
  104. overflow: "auto",
  105. fontSize: "14px",
  106. boxShadow: "-5px 2px 3px gray"
  107. };
  108. if (!UA.isOldIE) {
  109. settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
  110. } else {
  111. settingDivStyles.backgroundColor = "#333";
  112. }
  113. applyStyles(settingDiv, settingDivStyles);
  114. container.appendChild(settingDiv);
  115. options = options || exports.defaultOptions;
  116. var editor = ace.edit(editorDiv);
  117. session = editor.getSession();
  118. session.setValue(element.value || element.innerHTML);
  119. if (isFocused)
  120. editor.focus();
  121. container.appendChild(settingOpener);
  122. setupApi(editor, editorDiv, settingDiv, ace, options);
  123. setupSettingPanel(settingDiv, settingOpener, editor);
  124. var state = "";
  125. event.addListener(settingOpener, "mousemove", function(e) {
  126. var rect = this.getBoundingClientRect();
  127. var x = e.clientX - rect.left, y = e.clientY - rect.top;
  128. if (x + y < (rect.width + rect.height)/2) {
  129. this.style.cursor = "pointer";
  130. state = "toggle";
  131. } else {
  132. state = "resize";
  133. this.style.cursor = "nw-resize";
  134. }
  135. });
  136. event.addListener(settingOpener, "mousedown", function(e) {
  137. e.preventDefault();
  138. if (state == "toggle") {
  139. editor.setDisplaySettings();
  140. return;
  141. }
  142. container.style.zIndex = 100000;
  143. var rect = container.getBoundingClientRect();
  144. var startX = rect.width + rect.left - e.clientX;
  145. var startY = rect.height + rect.top - e.clientY;
  146. event.capture(settingOpener, function(e) {
  147. container.style.width = e.clientX - rect.left + startX + "px";
  148. container.style.height = e.clientY - rect.top + startY + "px";
  149. editor.resize();
  150. }, function() {});
  151. });
  152. return editor;
  153. };
  154. function load(url, module, callback) {
  155. net.loadScript(url, function() {
  156. require([module], callback);
  157. });
  158. }
  159. function setupApi(editor, editorDiv, settingDiv, ace, options) {
  160. var session = editor.getSession();
  161. var renderer = editor.renderer;
  162. function toBool(value) {
  163. return value === "true" || value == true;
  164. }
  165. editor.setDisplaySettings = function(display) {
  166. if (display == null)
  167. display = settingDiv.style.display == "none";
  168. if (display) {
  169. settingDiv.style.display = "block";
  170. settingDiv.hideButton.focus();
  171. editor.on("focus", function onFocus() {
  172. editor.removeListener("focus", onFocus);
  173. settingDiv.style.display = "none";
  174. });
  175. } else {
  176. editor.focus();
  177. }
  178. };
  179. editor.$setOption = editor.setOption;
  180. editor.$getOption = editor.getOption;
  181. editor.setOption = function(key, value) {
  182. switch (key) {
  183. case "mode":
  184. editor.$setOption("mode", "ace/mode/" + value);
  185. break;
  186. case "theme":
  187. editor.$setOption("theme", "ace/theme/" + value);
  188. break;
  189. case "keybindings":
  190. switch (value) {
  191. case "vim":
  192. editor.setKeyboardHandler("ace/keyboard/vim");
  193. break;
  194. case "emacs":
  195. editor.setKeyboardHandler("ace/keyboard/emacs");
  196. break;
  197. default:
  198. editor.setKeyboardHandler(null);
  199. }
  200. break;
  201. case "wrap":
  202. case "fontSize":
  203. editor.$setOption(key, value);
  204. break;
  205. default:
  206. editor.$setOption(key, toBool(value));
  207. }
  208. };
  209. editor.getOption = function(key) {
  210. switch (key) {
  211. case "mode":
  212. return editor.$getOption("mode").substr("ace/mode/".length);
  213. break;
  214. case "theme":
  215. return editor.$getOption("theme").substr("ace/theme/".length);
  216. break;
  217. case "keybindings":
  218. var value = editor.getKeyboardHandler();
  219. switch (value && value.$id) {
  220. case "ace/keyboard/vim":
  221. return "vim";
  222. case "ace/keyboard/emacs":
  223. return "emacs";
  224. default:
  225. return "ace";
  226. }
  227. break;
  228. default:
  229. return editor.$getOption(key);
  230. }
  231. };
  232. editor.setOptions(options);
  233. return editor;
  234. }
  235. function setupSettingPanel(settingDiv, settingOpener, editor) {
  236. var BOOL = null;
  237. var desc = {
  238. mode: "Mode:",
  239. wrap: "Soft Wrap:",
  240. theme: "Theme:",
  241. fontSize: "Font Size:",
  242. showGutter: "Display Gutter:",
  243. keybindings: "Keyboard",
  244. showPrintMargin: "Show Print Margin:",
  245. useSoftTabs: "Use Soft Tabs:",
  246. showInvisibles: "Show Invisibles"
  247. };
  248. var optionValues = {
  249. mode: {
  250. text: "Plain",
  251. javascript: "JavaScript",
  252. xml: "XML",
  253. html: "HTML",
  254. css: "CSS",
  255. scss: "SCSS",
  256. python: "Python",
  257. php: "PHP",
  258. java: "Java",
  259. ruby: "Ruby",
  260. c_cpp: "C/C++",
  261. coffee: "CoffeeScript",
  262. json: "json",
  263. perl: "Perl",
  264. clojure: "Clojure",
  265. ocaml: "OCaml",
  266. csharp: "C#",
  267. haxe: "haXe",
  268. svg: "SVG",
  269. textile: "Textile",
  270. groovy: "Groovy",
  271. liquid: "Liquid",
  272. Scala: "Scala"
  273. },
  274. theme: {
  275. clouds: "Clouds",
  276. clouds_midnight: "Clouds Midnight",
  277. cobalt: "Cobalt",
  278. crimson_editor: "Crimson Editor",
  279. dawn: "Dawn",
  280. gob: "Green on Black",
  281. eclipse: "Eclipse",
  282. idle_fingers: "Idle Fingers",
  283. kr_theme: "Kr Theme",
  284. merbivore: "Merbivore",
  285. merbivore_soft: "Merbivore Soft",
  286. mono_industrial: "Mono Industrial",
  287. monokai: "Monokai",
  288. pastel_on_dark: "Pastel On Dark",
  289. solarized_dark: "Solarized Dark",
  290. solarized_light: "Solarized Light",
  291. textmate: "Textmate",
  292. twilight: "Twilight",
  293. vibrant_ink: "Vibrant Ink"
  294. },
  295. showGutter: BOOL,
  296. fontSize: {
  297. "10px": "10px",
  298. "11px": "11px",
  299. "12px": "12px",
  300. "14px": "14px",
  301. "16px": "16px"
  302. },
  303. wrap: {
  304. off: "Off",
  305. 40: "40",
  306. 80: "80",
  307. free: "Free"
  308. },
  309. keybindings: {
  310. ace: "ace",
  311. vim: "vim",
  312. emacs: "emacs"
  313. },
  314. showPrintMargin: BOOL,
  315. useSoftTabs: BOOL,
  316. showInvisibles: BOOL
  317. };
  318. var table = [];
  319. table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
  320. function renderOption(builder, option, obj, cValue) {
  321. if (!obj) {
  322. builder.push(
  323. "<input type='checkbox' title='", option, "' ",
  324. cValue + "" == "true" ? "checked='true'" : "",
  325. "'></input>"
  326. );
  327. return;
  328. }
  329. builder.push("<select title='" + option + "'>");
  330. for (var value in obj) {
  331. builder.push("<option value='" + value + "' ");
  332. if (cValue == value) {
  333. builder.push(" selected ");
  334. }
  335. builder.push(">",
  336. obj[value],
  337. "</option>");
  338. }
  339. builder.push("</select>");
  340. }
  341. for (var option in exports.defaultOptions) {
  342. table.push("<tr><td>", desc[option], "</td>");
  343. table.push("<td>");
  344. renderOption(table, option, optionValues[option], editor.getOption(option));
  345. table.push("</td></tr>");
  346. }
  347. table.push("</table>");
  348. settingDiv.innerHTML = table.join("");
  349. var onChange = function(e) {
  350. var select = e.currentTarget;
  351. editor.setOption(select.title, select.value);
  352. };
  353. var onClick = function(e) {
  354. var cb = e.currentTarget;
  355. editor.setOption(cb.title, cb.checked);
  356. };
  357. var selects = settingDiv.getElementsByTagName("select");
  358. for (var i = 0; i < selects.length; i++)
  359. selects[i].onchange = onChange;
  360. var cbs = settingDiv.getElementsByTagName("input");
  361. for (var i = 0; i < cbs.length; i++)
  362. cbs[i].onclick = onClick;
  363. var button = document.createElement("input");
  364. button.type = "button";
  365. button.value = "Hide";
  366. event.addListener(button, "click", function() {
  367. editor.setDisplaySettings(false);
  368. });
  369. settingDiv.appendChild(button);
  370. settingDiv.hideButton = button;
  371. }
  372. exports.defaultOptions = {
  373. mode: "javascript",
  374. theme: "textmate",
  375. wrap: "off",
  376. fontSize: "12px",
  377. showGutter: "false",
  378. keybindings: "ace",
  379. showPrintMargin: "false",
  380. useSoftTabs: "true",
  381. showInvisibles: "false"
  382. };
  383. }); (function() {
  384. window.require(["ace/ext/textarea"], function(m) {
  385. if (typeof module == "object" && typeof exports == "object" && module) {
  386. module.exports = m;
  387. }
  388. });
  389. })();