/lib/ace/ext/menu_tools/generate_settings_menu.js
JavaScript | 264 lines | 119 code | 9 blank | 136 comment | 16 complexity | 2df4752c6b901e6a085848ee90c1ada0 MD5 | raw file
- /* ***** BEGIN LICENSE BLOCK *****
- * Distributed under the BSD license:
- *
- * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl
- * All rights reserved.
- *
- * Contributed to Ajax.org under the BSD license.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Ajax.org B.V. nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ***** END LICENSE BLOCK ***** */
- /*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/
- /*global define*/
- /**
- * Generates the settings menu
- * @fileOverview Generates the settings menu.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- */
- define(function(require, exports, module) {
- 'use strict';
- var egen = require('./element_generator');
- var addEditorMenuOptions = require('./add_editor_menu_options').addEditorMenuOptions;
- var getSetFunctions = require('./get_set_functions').getSetFunctions;
- /**
- * Generates an interactive menu with settings useful to end users.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- * @param {ace.Editor} editor An instance of the ace editor.
- */
- module.exports.generateSettingsMenu = function generateSettingsMenu (editor) {
- /**
- * container for dom elements that will go in the menu.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- */
- var elements = [];
- /**
- * Sorts the menu entries (elements var) so they'll appear in alphabetical order
- * the sort is performed based on the value of the contains property
- * of each element. Since this is an `array.sort` the array is sorted
- * in place.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- */
- function cleanupElementsList() {
- elements.sort(function(a, b) {
- var x = a.getAttribute('contains');
- var y = b.getAttribute('contains');
- return x.localeCompare(y);
- });
- }
- /**
- * Wraps all dom elements contained in the elements var with a single
- * div.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- */
- function wrapElements() {
- var topmenu = document.createElement('div');
- topmenu.setAttribute('id', 'ace_settingsmenu');
- elements.forEach(function(element) {
- topmenu.appendChild(element);
- });
-
- var el = topmenu.appendChild(document.createElement('div'));
- var version = require("../../ace").version;
- el.style.padding = "1em";
- el.textContent = "Ace version " + version;
-
- return topmenu;
- }
- /**
- * Creates a new menu entry.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- * @param {object} obj This is a reference to the object containing the
- * set function. It is used to set up event listeners for when the
- * menu options change.
- * @param {string} clss Maps to the class of the dom element. This is
- * the name of the object containing the set function e.g. `editor`,
- * `session`, `renderer`.
- * @param {string} item This is the set function name. It maps to the
- * id of the dom element (check, select, input) and to the "contains"
- * attribute of the div holding both the element and its label.
- * @param {mixed} val This is the value of the setting. It is mapped to
- * the dom element's value, checked, or selected option accordingly.
- */
- function createNewEntry(obj, clss, item, val) {
- var el;
- var div = document.createElement('div');
- div.setAttribute('contains', item);
- div.setAttribute('class', 'ace_optionsMenuEntry');
- div.setAttribute('style', 'clear: both;');
- div.appendChild(egen.createLabel(
- item.replace(/^set/, '').replace(/([A-Z])/g, ' $1').trim(),
- item
- ));
- if (Array.isArray(val)) {
- el = egen.createSelection(item, val, clss);
- el.addEventListener('change', function(e) {
- try{
- editor.menuOptions[e.target.id].forEach(function(x) {
- if(x.textContent !== e.target.textContent) {
- delete x.selected;
- }
- });
- obj[e.target.id](e.target.value);
- } catch (err) {
- throw new Error(err);
- }
- });
- } else if(typeof val === 'boolean') {
- el = egen.createCheckbox(item, val, clss);
- el.addEventListener('change', function(e) {
- try{
- // renderer['setHighlightGutterLine'](true);
- obj[e.target.id](!!e.target.checked);
- } catch (err) {
- throw new Error(err);
- }
- });
- } else {
- // this aids in giving the ability to specify settings through
- // post and get requests.
- // /ace_editor.html?setMode=ace/mode/html&setOverwrite=true
- el = egen.createInput(item, val, clss);
- el.addEventListener('change', function(e) {
- try{
- if(e.target.value === 'true') {
- obj[e.target.id](true);
- } else if(e.target.value === 'false') {
- obj[e.target.id](false);
- } else {
- obj[e.target.id](e.target.value);
- }
- } catch (err) {
- throw new Error(err);
- }
- });
- }
- el.style.cssText = 'float:right;';
- div.appendChild(el);
- return div;
- }
- /**
- * Generates selection fields for the menu and populates their options
- * using information from `editor.menuOptions`
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- * @param {string} item The set function name.
- * @param {object} esr A reference to the object having the set function.
- * @param {string} clss The name of the object containing the set function.
- * @param {string} fn The matching get function's function name.
- * @returns {DOMElement} Returns a dom element containing a selection
- * element populated with options. The option whose value matches that
- * returned from `esr[fn]()` will be selected.
- */
- function makeDropdown(item, esr, clss, fn) {
- var val = editor.menuOptions[item];
- var currentVal = esr[fn]();
- if (typeof currentVal == 'object')
- currentVal = currentVal.$id;
- val.forEach(function(valuex) {
- if (valuex.value === currentVal)
- valuex.selected = 'selected';
- });
- return createNewEntry(esr, clss, item, val);
- }
- /**
- * Processes the set functions returned from `getSetFunctions`. First it
- * checks for menu options defined in `editor.menuOptions`. If no
- * options are specified then it checks whether there is a get function
- * (replace set with get) for the setting. When either of those
- * conditions are met it will attempt to create a new entry for the
- * settings menu and push it into the elements array defined above.
- * It can only do so for get functions which return
- * strings, numbers, and booleans. A special case is written in for
- * `getMode` where it looks at the returned objects `$id` property and
- * forwards that through instead. Other special cases could be written
- * in but that would get a bit ridiculous.
- * @author <a href="mailto:matthewkastor@gmail.com">
- * Matthew Christopher Kastor-Inare III </a><br />
- * ☭ Hial Atropa!! ☭
- * @param {object} setObj An item from the array returned by
- * `getSetFunctions`.
- */
- function handleSet(setObj) {
- var item = setObj.functionName;
- var esr = setObj.parentObj;
- var clss = setObj.parentName;
- var val;
- var fn = item.replace(/^set/, 'get');
- if(editor.menuOptions[item] !== undefined) {
- // has options for select element
- elements.push(makeDropdown(item, esr, clss, fn));
- } else if(typeof esr[fn] === 'function') {
- // has get function
- try {
- val = esr[fn]();
- if(typeof val === 'object') {
- // setMode takes a string, getMode returns an object
- // the $id property of that object is the string
- // which may be given to setMode...
- val = val.$id;
- }
- // the rest of the get functions return strings,
- // booleans, or numbers.
- elements.push(
- createNewEntry(esr, clss, item, val)
- );
- } catch (e) {
- // if there are errors it is because the element
- // does not belong in the settings menu
- }
- }
- }
- addEditorMenuOptions(editor);
- // gather the set functions
- getSetFunctions(editor).forEach(function(setObj) {
- // populate the elements array with good stuff.
- handleSet(setObj);
- });
- // sort the menu entries in the elements list so people can find
- // the settings in alphabetical order.
- cleanupElementsList();
- // dump the entries from the elements list and wrap them up in a div
- return wrapElements();
- };
- });