PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ace/ext/menu_tools/generate_settings_menu.js

https://gitlab.com/ccogeanu/ace
JavaScript | 264 lines | 119 code | 9 blank | 136 comment | 16 complexity | 2df4752c6b901e6a085848ee90c1ada0 MD5 | raw file
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Distributed under the BSD license:
  3. *
  4. * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
  5. * All rights reserved.
  6. *
  7. * Contributed to Ajax.org under the BSD license.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are met:
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * * Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * * Neither the name of Ajax.org B.V. nor the
  17. * names of its contributors may be used to endorse or promote products
  18. * derived from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  22. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  23. * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
  24. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  27. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * ***** END LICENSE BLOCK ***** */
  32. /*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
  33. /*global define*/
  34. /**
  35. * Generates the settings menu
  36. * @fileOverview Generates the settings menu.
  37. * @author <a href="mailto:matthewkastor@gmail.com">
  38. * Matthew Christopher Kastor-Inare III </a><br />
  39. * ☭ Hial Atropa!! ☭
  40. */
  41. define(function(require, exports, module) {
  42. 'use strict';
  43. var egen = require('./element_generator');
  44. var addEditorMenuOptions = require('./add_editor_menu_options').addEditorMenuOptions;
  45. var getSetFunctions = require('./get_set_functions').getSetFunctions;
  46. /**
  47. * Generates an interactive menu with settings useful to end users.
  48. * @author <a href="mailto:matthewkastor@gmail.com">
  49. * Matthew Christopher Kastor-Inare III </a><br />
  50. * ☭ Hial Atropa!! ☭
  51. * @param {ace.Editor} editor An instance of the ace editor.
  52. */
  53. module.exports.generateSettingsMenu = function generateSettingsMenu (editor) {
  54. /**
  55. * container for dom elements that will go in the menu.
  56. * @author <a href="mailto:matthewkastor@gmail.com">
  57. * Matthew Christopher Kastor-Inare III </a><br />
  58. * ☭ Hial Atropa!! ☭
  59. */
  60. var elements = [];
  61. /**
  62. * Sorts the menu entries (elements var) so they'll appear in alphabetical order
  63. * the sort is performed based on the value of the contains property
  64. * of each element. Since this is an `array.sort` the array is sorted
  65. * in place.
  66. * @author <a href="mailto:matthewkastor@gmail.com">
  67. * Matthew Christopher Kastor-Inare III </a><br />
  68. * ☭ Hial Atropa!! ☭
  69. */
  70. function cleanupElementsList() {
  71. elements.sort(function(a, b) {
  72. var x = a.getAttribute('contains');
  73. var y = b.getAttribute('contains');
  74. return x.localeCompare(y);
  75. });
  76. }
  77. /**
  78. * Wraps all dom elements contained in the elements var with a single
  79. * div.
  80. * @author <a href="mailto:matthewkastor@gmail.com">
  81. * Matthew Christopher Kastor-Inare III </a><br />
  82. * ☭ Hial Atropa!! ☭
  83. */
  84. function wrapElements() {
  85. var topmenu = document.createElement('div');
  86. topmenu.setAttribute('id', 'ace_settingsmenu');
  87. elements.forEach(function(element) {
  88. topmenu.appendChild(element);
  89. });
  90. var el = topmenu.appendChild(document.createElement('div'));
  91. var version = require("../../ace").version;
  92. el.style.padding = "1em";
  93. el.textContent = "Ace version " + version;
  94. return topmenu;
  95. }
  96. /**
  97. * Creates a new menu entry.
  98. * @author <a href="mailto:matthewkastor@gmail.com">
  99. * Matthew Christopher Kastor-Inare III </a><br />
  100. * ☭ Hial Atropa!! ☭
  101. * @param {object} obj This is a reference to the object containing the
  102. * set function. It is used to set up event listeners for when the
  103. * menu options change.
  104. * @param {string} clss Maps to the class of the dom element. This is
  105. * the name of the object containing the set function e.g. `editor`,
  106. * `session`, `renderer`.
  107. * @param {string} item This is the set function name. It maps to the
  108. * id of the dom element (check, select, input) and to the "contains"
  109. * attribute of the div holding both the element and its label.
  110. * @param {mixed} val This is the value of the setting. It is mapped to
  111. * the dom element's value, checked, or selected option accordingly.
  112. */
  113. function createNewEntry(obj, clss, item, val) {
  114. var el;
  115. var div = document.createElement('div');
  116. div.setAttribute('contains', item);
  117. div.setAttribute('class', 'ace_optionsMenuEntry');
  118. div.setAttribute('style', 'clear: both;');
  119. div.appendChild(egen.createLabel(
  120. item.replace(/^set/, '').replace(/([A-Z])/g, ' $1').trim(),
  121. item
  122. ));
  123. if (Array.isArray(val)) {
  124. el = egen.createSelection(item, val, clss);
  125. el.addEventListener('change', function(e) {
  126. try{
  127. editor.menuOptions[e.target.id].forEach(function(x) {
  128. if(x.textContent !== e.target.textContent) {
  129. delete x.selected;
  130. }
  131. });
  132. obj[e.target.id](e.target.value);
  133. } catch (err) {
  134. throw new Error(err);
  135. }
  136. });
  137. } else if(typeof val === 'boolean') {
  138. el = egen.createCheckbox(item, val, clss);
  139. el.addEventListener('change', function(e) {
  140. try{
  141. // renderer['setHighlightGutterLine'](true);
  142. obj[e.target.id](!!e.target.checked);
  143. } catch (err) {
  144. throw new Error(err);
  145. }
  146. });
  147. } else {
  148. // this aids in giving the ability to specify settings through
  149. // post and get requests.
  150. // /ace_editor.html?setMode=ace/mode/html&setOverwrite=true
  151. el = egen.createInput(item, val, clss);
  152. el.addEventListener('change', function(e) {
  153. try{
  154. if(e.target.value === 'true') {
  155. obj[e.target.id](true);
  156. } else if(e.target.value === 'false') {
  157. obj[e.target.id](false);
  158. } else {
  159. obj[e.target.id](e.target.value);
  160. }
  161. } catch (err) {
  162. throw new Error(err);
  163. }
  164. });
  165. }
  166. el.style.cssText = 'float:right;';
  167. div.appendChild(el);
  168. return div;
  169. }
  170. /**
  171. * Generates selection fields for the menu and populates their options
  172. * using information from `editor.menuOptions`
  173. * @author <a href="mailto:matthewkastor@gmail.com">
  174. * Matthew Christopher Kastor-Inare III </a><br />
  175. * ☭ Hial Atropa!! ☭
  176. * @param {string} item The set function name.
  177. * @param {object} esr A reference to the object having the set function.
  178. * @param {string} clss The name of the object containing the set function.
  179. * @param {string} fn The matching get function's function name.
  180. * @returns {DOMElement} Returns a dom element containing a selection
  181. * element populated with options. The option whose value matches that
  182. * returned from `esr[fn]()` will be selected.
  183. */
  184. function makeDropdown(item, esr, clss, fn) {
  185. var val = editor.menuOptions[item];
  186. var currentVal = esr[fn]();
  187. if (typeof currentVal == 'object')
  188. currentVal = currentVal.$id;
  189. val.forEach(function(valuex) {
  190. if (valuex.value === currentVal)
  191. valuex.selected = 'selected';
  192. });
  193. return createNewEntry(esr, clss, item, val);
  194. }
  195. /**
  196. * Processes the set functions returned from `getSetFunctions`. First it
  197. * checks for menu options defined in `editor.menuOptions`. If no
  198. * options are specified then it checks whether there is a get function
  199. * (replace set with get) for the setting. When either of those
  200. * conditions are met it will attempt to create a new entry for the
  201. * settings menu and push it into the elements array defined above.
  202. * It can only do so for get functions which return
  203. * strings, numbers, and booleans. A special case is written in for
  204. * `getMode` where it looks at the returned objects `$id` property and
  205. * forwards that through instead. Other special cases could be written
  206. * in but that would get a bit ridiculous.
  207. * @author <a href="mailto:matthewkastor@gmail.com">
  208. * Matthew Christopher Kastor-Inare III </a><br />
  209. * ☭ Hial Atropa!! ☭
  210. * @param {object} setObj An item from the array returned by
  211. * `getSetFunctions`.
  212. */
  213. function handleSet(setObj) {
  214. var item = setObj.functionName;
  215. var esr = setObj.parentObj;
  216. var clss = setObj.parentName;
  217. var val;
  218. var fn = item.replace(/^set/, 'get');
  219. if(editor.menuOptions[item] !== undefined) {
  220. // has options for select element
  221. elements.push(makeDropdown(item, esr, clss, fn));
  222. } else if(typeof esr[fn] === 'function') {
  223. // has get function
  224. try {
  225. val = esr[fn]();
  226. if(typeof val === 'object') {
  227. // setMode takes a string, getMode returns an object
  228. // the $id property of that object is the string
  229. // which may be given to setMode...
  230. val = val.$id;
  231. }
  232. // the rest of the get functions return strings,
  233. // booleans, or numbers.
  234. elements.push(
  235. createNewEntry(esr, clss, item, val)
  236. );
  237. } catch (e) {
  238. // if there are errors it is because the element
  239. // does not belong in the settings menu
  240. }
  241. }
  242. }
  243. addEditorMenuOptions(editor);
  244. // gather the set functions
  245. getSetFunctions(editor).forEach(function(setObj) {
  246. // populate the elements array with good stuff.
  247. handleSet(setObj);
  248. });
  249. // sort the menu entries in the elements list so people can find
  250. // the settings in alphabetical order.
  251. cleanupElementsList();
  252. // dump the entries from the elements list and wrap them up in a div
  253. return wrapElements();
  254. };
  255. });