You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2013/10/29 16:40:27 UTC
[42/51] [partial] working replacement
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/searchbox.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/searchbox.js b/src/fauxton/assets/js/libs/ace/ext/searchbox.js
new file mode 100644
index 0000000..fbbaa8f
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/searchbox.js
@@ -0,0 +1,286 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var dom = require("../lib/dom");
+var lang = require("../lib/lang");
+var event = require("../lib/event");
+var searchboxCss = require("../requirejs/text!./searchbox.css");
+var HashHandler = require("../keyboard/hash_handler").HashHandler;
+var keyUtil = require("../lib/keys");
+
+dom.importCssString(searchboxCss, "ace_searchbox");
+
+var html = '<div class="ace_search right">\
+ <button type="button" action="hide" class="ace_searchbtn_close"></button>\
+ <div class="ace_search_form">\
+ <input class="ace_search_field" placeholder="Search for" spellcheck="false"></input>\
+ <button type="button" action="findNext" class="ace_searchbtn next"></button>\
+ <button type="button" action="findPrev" class="ace_searchbtn prev"></button>\
+ </div>\
+ <div class="ace_replace_form">\
+ <input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>\
+ <button type="button" action="replaceAndFindNext" class="ace_replacebtn">Replace</button>\
+ <button type="button" action="replaceAll" class="ace_replacebtn">All</button>\
+ </div>\
+ <div class="ace_search_options">\
+ <span action="toggleRegexpMode" class="ace_button" title="RegExp Search">.*</span>\
+ <span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>\
+ <span action="toggleWholeWords" class="ace_button" title="Whole Word Search">\\b</span>\
+ </div>\
+</div>'.replace(/>\s+/g, ">");
+
+var SearchBox = function(editor, range, showReplaceForm) {
+ var div = dom.createElement("div");
+ div.innerHTML = html;
+ this.element = div.firstChild;
+
+ this.$init();
+ this.setEditor(editor);
+};
+
+(function() {
+ this.setEditor = function(editor) {
+ editor.searchBox = this;
+ editor.container.appendChild(this.element);
+ this.editor = editor;
+ };
+
+ this.$initElements = function(sb) {
+ this.searchBox = sb.querySelector(".ace_search_form");
+ this.replaceBox = sb.querySelector(".ace_replace_form");
+ this.searchOptions = sb.querySelector(".ace_search_options");
+ this.regExpOption = sb.querySelector("[action=toggleRegexpMode]");
+ this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]");
+ this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]");
+ this.searchInput = this.searchBox.querySelector(".ace_search_field");
+ this.replaceInput = this.replaceBox.querySelector(".ace_search_field");
+ };
+
+ this.$init = function() {
+ var sb = this.element;
+
+ this.$initElements(sb);
+
+ var _this = this;
+ event.addListener(sb, "mousedown", function(e) {
+ setTimeout(function(){
+ _this.activeInput.focus();
+ }, 0);
+ event.stopPropagation(e);
+ });
+ event.addListener(sb, "click", function(e) {
+ var t = e.target || e.srcElement;
+ var action = t.getAttribute("action");
+ if (action && _this[action])
+ _this[action]();
+ else if (_this.$searchBarKb.commands[action])
+ _this.$searchBarKb.commands[action].exec(_this);
+ event.stopPropagation(e);
+ });
+
+ event.addCommandKeyListener(sb, function(e, hashId, keyCode) {
+ var keyString = keyUtil.keyCodeToString(keyCode);
+ var command = _this.$searchBarKb.findKeyCommand(hashId, keyString);
+ if (command && command.exec) {
+ command.exec(_this);
+ event.stopEvent(e);
+ }
+ });
+
+ this.$onChange = lang.delayedCall(function() {
+ _this.find(false, false);
+ });
+
+ event.addListener(this.searchInput, "input", function() {
+ _this.$onChange.schedule(20);
+ });
+ event.addListener(this.searchInput, "focus", function() {
+ _this.activeInput = _this.searchInput;
+ _this.searchInput.value && _this.highlight();
+ });
+ event.addListener(this.replaceInput, "focus", function() {
+ _this.activeInput = _this.replaceInput;
+ _this.searchInput.value && _this.highlight();
+ });
+ };
+
+ //keybinging outsite of the searchbox
+ this.$closeSearchBarKb = new HashHandler([{
+ bindKey: "Esc",
+ name: "closeSearchBar",
+ exec: function(editor) {
+ editor.searchBox.hide();
+ }
+ }]);
+
+ //keybinging outsite of the searchbox
+ this.$searchBarKb = new HashHandler();
+ this.$searchBarKb.bindKeys({
+ "Ctrl-f|Command-f|Ctrl-H|Command-Option-F": function(sb) {
+ var isReplace = sb.isReplace = !sb.isReplace;
+ sb.replaceBox.style.display = isReplace ? "" : "none";
+ sb[isReplace ? "replaceInput" : "searchInput"].focus();
+ },
+ "Ctrl-G|Command-G": function(sb) {
+ sb.findNext();
+ },
+ "Ctrl-Shift-G|Command-Shift-G": function(sb) {
+ sb.findPrev();
+ },
+ "esc": function(sb) {
+ setTimeout(function() { sb.hide();});
+ },
+ "Return": function(sb) {
+ if (sb.activeInput == sb.replaceInput)
+ sb.replace();
+ sb.findNext();
+ },
+ "Shift-Return": function(sb) {
+ if (sb.activeInput == sb.replaceInput)
+ sb.replace();
+ sb.findPrev();
+ },
+ "Tab": function(sb) {
+ (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus();
+ }
+ });
+
+ this.$searchBarKb.addCommands([{
+ name: "toggleRegexpMode",
+ bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"},
+ exec: function(sb) {
+ sb.regExpOption.checked = !sb.regExpOption.checked;
+ sb.$syncOptions();
+ }
+ }, {
+ name: "toggleCaseSensitive",
+ bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"},
+ exec: function(sb) {
+ sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked;
+ sb.$syncOptions();
+ }
+ }, {
+ name: "toggleWholeWords",
+ bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"},
+ exec: function(sb) {
+ sb.wholeWordOption.checked = !sb.wholeWordOption.checked;
+ sb.$syncOptions();
+ }
+ }]);
+
+ this.$syncOptions = function() {
+ dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked);
+ dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked);
+ dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked);
+ this.find(false, false);
+ };
+
+ this.highlight = function(re) {
+ this.editor.session.highlight(re || this.editor.$search.$options.re);
+ this.editor.renderer.updateBackMarkers()
+ };
+ this.find = function(skipCurrent, backwards) {
+ var range = this.editor.find(this.searchInput.value, {
+ skipCurrent: skipCurrent,
+ backwards: backwards,
+ wrap: true,
+ regExp: this.regExpOption.checked,
+ caseSensitive: this.caseSensitiveOption.checked,
+ wholeWord: this.wholeWordOption.checked
+ });
+ var noMatch = !range && this.searchInput.value;
+ dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
+ this.editor._emit("findSearchBox", { match: !noMatch });
+ this.highlight();
+ };
+ this.findNext = function() {
+ this.find(true, false);
+ };
+ this.findPrev = function() {
+ this.find(true, true);
+ };
+ this.replace = function() {
+ if (!this.editor.getReadOnly())
+ this.editor.replace(this.replaceInput.value);
+ };
+ this.replaceAndFindNext = function() {
+ if (!this.editor.getReadOnly()) {
+ this.editor.replace(this.replaceInput.value);
+ this.findNext()
+ }
+ };
+ this.replaceAll = function() {
+ if (!this.editor.getReadOnly())
+ this.editor.replaceAll(this.replaceInput.value);
+ };
+
+ this.hide = function() {
+ this.element.style.display = "none";
+ this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb);
+ this.editor.focus();
+ };
+ this.show = function(value, isReplace) {
+ this.element.style.display = "";
+ this.replaceBox.style.display = isReplace ? "" : "none";
+
+ this.isReplace = isReplace;
+
+ if (value)
+ this.searchInput.value = value;
+ this.searchInput.focus();
+ this.searchInput.select();
+
+ this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);
+ };
+
+}).call(SearchBox.prototype);
+
+exports.SearchBox = SearchBox;
+
+exports.Search = function(editor, isReplace) {
+ var sb = editor.searchBox || new SearchBox(editor);
+ sb.show(editor.session.getTextRange(), isReplace);
+};
+
+});
+
+
+/* ------------------------------------------------------------------------------------------
+ * TODO
+ * --------------------------------------------------------------------------------------- */
+/*
+- move search form to the left if it masks current word
+- includ all options that search has. ex: regex
+- searchbox.searchbox is not that pretty. we should have just searchbox
+- disable prev button if it makes sence
+*/
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/settings_menu.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/settings_menu.js b/src/fauxton/assets/js/libs/ace/ext/settings_menu.js
new file mode 100644
index 0000000..44f6d6a
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/settings_menu.js
@@ -0,0 +1,76 @@
+/* ***** 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, require */
+
+/**
+ * Show Settings Menu
+ * @fileOverview Show Settings Menu <br />
+ * Displays an interactive settings menu mostly generated on the fly based on
+ * the current state of the editor.
+ * @author <a href="mailto:matthewkastor@gmail.com">
+ * Matthew Christopher Kastor-Inare III </a><br />
+ * ☭ Hial Atropa!! ☭
+ */
+
+define(function(require, exports, module) {
+"use strict";
+var generateSettingsMenu = require('./menu_tools/generate_settings_menu').generateSettingsMenu;
+var overlayPage = require('./menu_tools/overlay_page').overlayPage;
+/**
+ * This displays the settings menu if it is not already being shown.
+ * @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.
+ */
+function showSettingsMenu(editor) {
+ // make sure the menu isn't open already.
+ var sm = document.getElementById('ace_settingsmenu');
+ if (!sm)
+ overlayPage(editor, generateSettingsMenu(editor), '0', '0', '0');
+}
+
+/**
+ * Initializes the settings menu extension. It adds the showSettingsMenu
+ * method to the given editor object and adds the showSettingsMenu command
+ * to the editor with appropriate keyboard shortcuts.
+ * @param {ace.Editor} editor An instance of the Editor.
+ */
+module.exports.init = function(editor) {
+ var Editor = require("ace/editor").Editor;
+ Editor.prototype.showSettingsMenu = function() {
+ showSettingsMenu(this);
+ };
+};
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/spellcheck.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/spellcheck.js b/src/fauxton/assets/js/libs/ace/ext/spellcheck.js
new file mode 100644
index 0000000..08bf218
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/spellcheck.js
@@ -0,0 +1,69 @@
+define(function(require, exports, module) {
+"use strict";
+var event = require("../lib/event");
+
+exports.contextMenuHandler = function(e){
+ var host = e.target;
+ var text = host.textInput.getElement();
+ if (!host.selection.isEmpty())
+ return;
+ var c = host.getCursorPosition();
+ var r = host.session.getWordRange(c.row, c.column);
+ var w = host.session.getTextRange(r);
+
+ host.session.tokenRe.lastIndex = 0;
+ if (!host.session.tokenRe.test(w))
+ return;
+ var PLACEHOLDER = "\x01\x01";
+ var value = w + " " + PLACEHOLDER;
+ text.value = value;
+ text.setSelectionRange(w.length, w.length + 1);
+ text.setSelectionRange(0, 0);
+ text.setSelectionRange(0, w.length);
+
+ var afterKeydown = false;
+ event.addListener(text, "keydown", function onKeydown() {
+ event.removeListener(text, "keydown", onKeydown);
+ afterKeydown = true;
+ });
+
+ host.textInput.setInputHandler(function(newVal) {
+ console.log(newVal , value, text.selectionStart, text.selectionEnd)
+ if (newVal == value)
+ return '';
+ if (newVal.lastIndexOf(value, 0) === 0)
+ return newVal.slice(value.length);
+ if (newVal.substr(text.selectionEnd) == value)
+ return newVal.slice(0, -value.length);
+ if (newVal.slice(-2) == PLACEHOLDER) {
+ var val = newVal.slice(0, -2);
+ if (val.slice(-1) == " ") {
+ if (afterKeydown)
+ return val.substring(0, text.selectionEnd);
+ val = val.slice(0, -1);
+ host.session.replace(r, val);
+ return "";
+ }
+ }
+
+ return newVal;
+ });
+};
+// todo support highlighting with typo.js
+var Editor = require("../editor").Editor;
+require("../config").defineOptions(Editor.prototype, "editor", {
+ spellcheck: {
+ set: function(val) {
+ var text = this.textInput.getElement();
+ text.spellcheck = !!val;
+ if (!val)
+ this.removeListener("nativecontextmenu", exports.contextMenuHandler);
+ else
+ this.on("nativecontextmenu", exports.contextMenuHandler);
+ },
+ value: true
+ }
+});
+
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/split.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/split.js b/src/fauxton/assets/js/libs/ace/ext/split.js
new file mode 100644
index 0000000..8316562
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/split.js
@@ -0,0 +1,40 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+/**
+ * this is experimental, and subject to change, use at your own risk!
+ */
+module.exports = require("../split");
+
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/static.css
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/static.css b/src/fauxton/assets/js/libs/ace/ext/static.css
new file mode 100644
index 0000000..bd47978
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/static.css
@@ -0,0 +1,23 @@
+.ace_static_highlight {
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;
+ font-size: 12px;
+}
+
+.ace_static_highlight .ace_gutter {
+ width: 25px !important;
+ display: block;
+ float: left;
+ text-align: right;
+ padding: 0 3px 0 0;
+ margin-right: 3px;
+ position: static !important;
+}
+
+.ace_static_highlight .ace_line { clear: both; }
+
+.ace_static_highlight .ace_gutter-cell {
+ -moz-user-select: -moz-none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/static_highlight.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/static_highlight.js b/src/fauxton/assets/js/libs/ace/ext/static_highlight.js
new file mode 100644
index 0000000..2119653
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/static_highlight.js
@@ -0,0 +1,180 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var EditSession = require("../edit_session").EditSession;
+var TextLayer = require("../layer/text").Text;
+var baseStyles = require("../requirejs/text!./static.css");
+var config = require("../config");
+var dom = require("../lib/dom");
+/**
+ * Transforms a given input code snippet into HTML using the given mode
+ *
+ * @param {string} input Code snippet
+ * @param {string|mode} mode String specifying the mode to load such as
+ * `ace/mode/javascript` or, a mode loaded from `/ace/mode`
+ * (use 'ServerSideHiglighter.getMode').
+ * @param {string|theme} theme String specifying the theme to load such as
+ * `ace/theme/twilight` or, a theme loaded from `/ace/theme`.
+ * @param {number} lineStart A number indicating the first line number. Defaults
+ * to 1.
+ * @param {boolean} disableGutter Specifies whether or not to disable the gutter.
+ * `true` disables the gutter, `false` enables the gutter. Defaults to `false`.
+ * @param {function} callback When specifying the mode or theme as a string,
+ * this method has no return value and you must specify a callback function. The
+ * callback will receive the rendered object containing the properties `html`
+ * and `css`.
+ * @returns {object} An object containing the properties `html` and `css`.
+ */
+
+exports.render = function(input, mode, theme, lineStart, disableGutter, callback) {
+ var waiting = 0;
+ var modeCache = EditSession.prototype.$modes;
+
+ // if either the theme or the mode were specified as objects
+ // then we need to lazily load them.
+ if (typeof theme == "string") {
+ waiting++;
+ config.loadModule(['theme', theme], function(m) {
+ theme = m;
+ --waiting || done();
+ });
+ }
+
+ if (typeof mode == "string") {
+ waiting++;
+ config.loadModule(['mode', mode], function(m) {
+ if (!modeCache[mode]) modeCache[mode] = new m.Mode();
+ mode = modeCache[mode];
+ --waiting || done();
+ });
+ }
+
+ // loads or passes the specified mode module then calls renderer
+ function done() {
+ var result = exports.renderSync(input, mode, theme, lineStart, disableGutter);
+ return callback ? callback(result) : result;
+ }
+ return waiting || done();
+};
+
+/*
+ * Transforms a given input code snippet into HTML using the given mode
+ * @param {string} input Code snippet
+ * @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
+ * @param {string} r Code snippet
+ * @returns {object} An object containing: html, css
+ */
+
+exports.renderSync = function(input, mode, theme, lineStart, disableGutter) {
+ lineStart = parseInt(lineStart || 1, 10);
+
+ var session = new EditSession("");
+ session.setUseWorker(false);
+ session.setMode(mode);
+
+ var textLayer = new TextLayer(document.createElement("div"));
+ textLayer.setSession(session);
+ textLayer.config = {
+ characterWidth: 10,
+ lineHeight: 20
+ };
+
+ session.setValue(input);
+
+ var stringBuilder = [];
+ var length = session.getLength();
+
+ for(var ix = 0; ix < length; ix++) {
+ stringBuilder.push("<div class='ace_line'>");
+ if (!disableGutter)
+ stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + (ix + lineStart) + "</span>");
+ textLayer.$renderLine(stringBuilder, ix, true, false);
+ stringBuilder.push("</div>");
+ }
+
+ // let's prepare the whole html
+ var html = "<div class='" + theme.cssClass + "'>" +
+ "<div class='ace_static_highlight'>" +
+ stringBuilder.join("") +
+ "</div>" +
+ "</div>";
+
+ textLayer.destroy();
+
+ return {
+ css: baseStyles + theme.cssText,
+ html: html
+ };
+};
+
+
+
+exports.highlight = function(el, opts, callback) {
+ var m = el.className.match(/lang-(\w+)/);
+ var mode = opts.mode || m && ("ace/mode/" + m[1]);
+ if (!mode)
+ return false;
+ var theme = opts.theme || "ace/theme/textmate";
+
+ var data = "";
+ var nodes = [];
+
+ if (el.firstElementChild) {
+ var textLen = 0;
+ for (var i = 0; i < el.childNodes.length; i++) {
+ var ch = el.childNodes[i];
+ if (ch.nodeType == 3) {
+ textLen += ch.data.length;
+ data += ch.data;
+ } else {
+ nodes.push(textLen, ch);
+ }
+ }
+ } else {
+ data = dom.getInnerText(el);
+ }
+
+ exports.render(data, mode, theme, 1, true, function (highlighted) {
+ dom.importCssString(highlighted.css, "ace_highlight");
+ el.innerHTML = highlighted.html;
+ var container = el.firstChild.firstChild
+ for (var i = 0; i < nodes.length; i += 2) {
+ var pos = highlighted.session.doc.indexToPosition(nodes[i])
+ var node = nodes[i + 1];
+ var lineEl = container.children[pos.row];
+ lineEl && lineEl.appendChild(nodes[i+1]);
+ }
+ callback && callback();
+ });
+};
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/static_highlight_test.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/static_highlight_test.js b/src/fauxton/assets/js/libs/ace/ext/static_highlight_test.js
new file mode 100644
index 0000000..bdbecbf
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/static_highlight_test.js
@@ -0,0 +1,89 @@
+if (typeof process !== "undefined") {
+ require("amd-loader");
+ require("../test/mockdom");
+}
+
+define(function(require, exports, module) {
+"use strict";
+
+var assert = require("assert");
+var highlighter = require("./static_highlight");
+var JavaScriptMode = require("../mode/javascript").Mode;
+var TextMode = require("../mode/text").Mode;
+
+// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
+module.exports = {
+ timeout: 10000,
+
+ "test simple snippet": function(next) {
+ var theme = require("../theme/tomorrow");
+ var snippet = [
+ "/** this is a function",
+ "*",
+ "*/",
+ "function hello (a, b, c) {",
+ " console.log(a * b + c + 'sup$');",
+ "}"
+ ].join("\n");
+ var mode = new JavaScriptMode();
+
+ var result = highlighter.render(snippet, mode, theme);
+ assert.equal(result.html, "<div class='ace-tomorrow'><div class='ace_static_highlight'><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>1</span><span class='ace_comment ace_doc'>/**\xa0this\xa0is\xa0a\xa0function</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>2</span><span class='ace_comment ace_doc'>*</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>3</span><span class='ace_comment ace_doc'>*/</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>4</span><span class='ace_storage ace_type'>function</span>\xa0<span class='ace_entity ace_name ace_function'>hello</span>\xa0<span class='ace_paren ace_lparen'>(</span><span class='ace_variable ace_parameter'>a</span><span class='ace_punctuation ace_operator'>,\xa0</span><span class='ace_variable ace_parameter'>b</span><span class='ace_punctuation ace_operator'>,\xa0</span>
<span class='ace_variable ace_parameter'>c</span><span class='ace_paren ace_rparen'>)</span>\xa0<span class='ace_paren ace_lparen'>{</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>5</span>\xa0\xa0\xa0\xa0<span class='ace_storage ace_type'>console</span><span class='ace_punctuation ace_operator'>.</span><span class='ace_support ace_function ace_firebug'>log</span><span class='ace_paren ace_lparen'>(</span><span class='ace_identifier'>a</span>\xa0<span class='ace_keyword ace_operator'>*</span>\xa0<span class='ace_identifier'>b</span>\xa0<span class='ace_keyword ace_operator'>+</span>\xa0<span class='ace_identifier'>c</span>\xa0<span class='ace_keyword ace_operator'>+</span>\xa0<span class='ace_string'>'sup$'</span><span class='ace_paren ace_rparen'>)</span><span class='ace_punctuation ace_operator'>;</span></div><div class='ace_line'><span class='ace_gutter ace_gutter-cell' unselectable='on'>6</span><span class='ace_paren ace_rparen'>}</sp
an></div></div></div>");
+ assert.ok(!!result.css);
+ next();
+ },
+
+ "test css from theme is used": function(next) {
+ var theme = require("../theme/tomorrow");
+ var snippet = [
+ "/** this is a function",
+ "*",
+ "*/",
+ "function hello (a, b, c) {",
+ " console.log(a * b + c + 'sup?');",
+ "}"
+ ].join("\n");
+ var mode = new JavaScriptMode();
+
+ var result = highlighter.render(snippet, mode, theme);
+
+ assert.ok(result.css.indexOf(theme.cssText) !== -1);
+
+ next();
+ },
+
+ "test theme classname should be in output html": function(next) {
+ var theme = require("../theme/tomorrow");
+ var snippet = [
+ "/** this is a function",
+ "*",
+ "*/",
+ "function hello (a, b, c) {",
+ " console.log(a * b + c + 'sup?');",
+ "}"
+ ].join("\n");
+ var mode = new JavaScriptMode();
+
+ var result = highlighter.render(snippet, mode, theme);
+ assert.equal(!!result.html.match(/<div class='ace-tomorrow'>/), true);
+
+ next();
+ },
+
+ "test js string replace specials": function(next) {
+ var theme = require("../theme/tomorrow");
+ var snippet = "$'$1$2$$$&";
+ var mode = new TextMode();
+
+ var result = highlighter.render(snippet, mode, theme);
+ assert.ok(result.html.indexOf(snippet) != -1);
+
+ next();
+ }
+};
+
+});
+
+if (typeof module !== "undefined" && module === require.main) {
+ require("asyncjs").test.testcase(module.exports).exec();
+}
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/statusbar.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/statusbar.js b/src/fauxton/assets/js/libs/ace/ext/statusbar.js
new file mode 100644
index 0000000..666febf
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/statusbar.js
@@ -0,0 +1,49 @@
+define(function(require, exports, module) {
+"use strict";
+/** simple statusbar **/
+var dom = require("ace/lib/dom");
+var lang = require("ace/lib/lang");
+
+var StatusBar = function(editor, parentNode) {
+ this.element = dom.createElement("div");
+ this.element.className = "ace_status-indicator";
+ this.element.style.cssText = "display: inline-block;";
+ parentNode.appendChild(this.element);
+
+ var statusUpdate = lang.delayedCall(function(){
+ this.updateStatus(editor)
+ }.bind(this));
+ editor.on("changeStatus", function() {
+ statusUpdate.schedule(100);
+ });
+ editor.on("changeSelection", function() {
+ statusUpdate.schedule(100);
+ });
+};
+
+(function(){
+ this.updateStatus = function(editor) {
+ var status = [];
+ function add(str, separator) {
+ str && status.push(str, separator || "|");
+ }
+
+ if (editor.$vimModeHandler)
+ add(editor.$vimModeHandler.getStatusText());
+ else if (editor.commands.recording)
+ add("REC");
+
+ var c = editor.selection.lead;
+ add(c.row + ":" + c.column, " ");
+ if (!editor.selection.isEmpty()) {
+ var r = editor.getSelectionRange();
+ add("(" + (r.end.row - r.start.row) + ":" +(r.end.column - r.start.column) + ")");
+ }
+ status.pop();
+ this.element.textContent = status.join("");
+ };
+}).call(StatusBar.prototype);
+
+exports.StatusBar = StatusBar;
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/textarea.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/textarea.js b/src/fauxton/assets/js/libs/ace/ext/textarea.js
new file mode 100644
index 0000000..86b299e
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/textarea.js
@@ -0,0 +1,547 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var event = require("../lib/event");
+var UA = require("../lib/useragent");
+var net = require("../lib/net");
+var ace = require("../ace");
+
+require("../theme/textmate");
+
+module.exports = exports = ace;
+
+/*
+ * Returns the CSS property of element.
+ * 1) If the CSS property is on the style object of the element, use it, OR
+ * 2) Compute the CSS property
+ *
+ * If the property can't get computed, is 'auto' or 'intrinsic', the former
+ * calculated property is used (this can happen in cases where the textarea
+ * is hidden and has no dimension styles).
+ */
+var getCSSProperty = function(element, container, property) {
+ var ret = element.style[property];
+
+ if (!ret) {
+ if (window.getComputedStyle) {
+ ret = window.getComputedStyle(element, '').getPropertyValue(property);
+ } else {
+ ret = element.currentStyle[property];
+ }
+ }
+
+ if (!ret || ret == 'auto' || ret == 'intrinsic') {
+ ret = container.style[property];
+ }
+ return ret;
+};
+
+function applyStyles(elm, styles) {
+ for (var style in styles) {
+ elm.style[style] = styles[style];
+ }
+}
+
+function setupContainer(element, getValue) {
+ if (element.type != 'textarea') {
+ throw new Error("Textarea required!");
+ }
+
+ var parentNode = element.parentNode;
+
+ // This will hold the editor.
+ var container = document.createElement('div');
+
+ // To put Ace in the place of the textarea, we have to copy a few of the
+ // textarea's style attributes to the div container.
+ //
+ // The problem is that the properties have to get computed (they might be
+ // defined by a CSS file on the page - you can't access such rules that
+ // apply to an element via elm.style). Computed properties are converted to
+ // pixels although the dimension might be given as percentage. When the
+ // window resizes, the dimensions defined by percentages changes, so the
+ // properties have to get recomputed to get the new/true pixels.
+ var resizeEvent = function() {
+ var style = 'position:relative;';
+ [
+ 'margin-top', 'margin-left', 'margin-right', 'margin-bottom'
+ ].forEach(function(item) {
+ style += item + ':' +
+ getCSSProperty(element, container, item) + ';';
+ });
+
+ // Calculating the width/height of the textarea is somewhat tricky. To
+ // do it right, you have to include the paddings to the sides as well
+ // (eg. width = width + padding-left, -right). This works well, as
+ // long as the width of the element is not set or given in pixels. In
+ // this case and after the textarea is hidden, getCSSProperty(element,
+ // container, 'width') will still return pixel value. If the element
+ // has realtiv dimensions (e.g. width='95<percent>')
+ // getCSSProperty(...) will return pixel values only as long as the
+ // textarea is visible. After it is hidden getCSSProperty will return
+ // the relative dimensions as they are set on the element (in the case
+ // of width, 95<percent>).
+ // Making the sum of pixel vaules (e.g. padding) and realtive values
+ // (e.g. <percent>) is not possible. As such the padding styles are
+ // ignored.
+
+ // The complete width is the width of the textarea + the padding
+ // to the left and right.
+ var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px");
+ var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px");
+ style += 'height:' + height + ';width:' + width + ';';
+
+ // Set the display property to 'inline-block'.
+ style += 'display:inline-block;';
+ container.setAttribute('style', style);
+ };
+ event.addListener(window, 'resize', resizeEvent);
+
+ // Call the resizeEvent once, so that the size of the container is
+ // calculated.
+ resizeEvent();
+
+ // Insert the div container after the element.
+ parentNode.insertBefore(container, element.nextSibling);
+
+ // Override the forms onsubmit function. Set the innerHTML and value
+ // of the textarea before submitting.
+ while (parentNode !== document) {
+ if (parentNode.tagName.toUpperCase() === 'FORM') {
+ var oldSumit = parentNode.onsubmit;
+ // Override the onsubmit function of the form.
+ parentNode.onsubmit = function(evt) {
+ element.value = getValue();
+ // If there is a onsubmit function already, then call
+ // it with the current context and pass the event.
+ if (oldSumit) {
+ oldSumit.call(this, evt);
+ }
+ };
+ break;
+ }
+ parentNode = parentNode.parentNode;
+ }
+ return container;
+}
+
+exports.transformTextarea = function(element, loader) {
+ var session;
+ var container = setupContainer(element, function() {
+ return session.getValue();
+ });
+
+ // Hide the element.
+ element.style.display = 'none';
+ container.style.background = 'white';
+
+ //
+ var editorDiv = document.createElement("div");
+ applyStyles(editorDiv, {
+ top: "0px",
+ left: "0px",
+ right: "0px",
+ bottom: "0px",
+ border: "1px solid gray",
+ position: "absolute"
+ });
+ container.appendChild(editorDiv);
+
+ var settingOpener = document.createElement("div");
+ applyStyles(settingOpener, {
+ position: "absolute",
+ right: "0px",
+ bottom: "0px",
+ background: "red",
+ cursor: "nw-resize",
+ borderStyle: "solid",
+ borderWidth: "9px 8px 10px 9px",
+ width: "2px",
+ borderColor: "lightblue gray gray lightblue",
+ zIndex: 101
+ });
+
+ var settingDiv = document.createElement("div");
+ var settingDivStyles = {
+ top: "0px",
+ left: "20%",
+ right: "0px",
+ bottom: "0px",
+ position: "absolute",
+ padding: "5px",
+ zIndex: 100,
+ color: "white",
+ display: "none",
+ overflow: "auto",
+ fontSize: "14px",
+ boxShadow: "-5px 2px 3px gray"
+ };
+ if (!UA.isOldIE) {
+ settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
+ } else {
+ settingDivStyles.backgroundColor = "#333";
+ }
+
+ applyStyles(settingDiv, settingDivStyles);
+ container.appendChild(settingDiv);
+
+ // Power up ace on the textarea:
+ var options = {};
+
+ var editor = ace.edit(editorDiv);
+ session = editor.getSession();
+
+ session.setValue(element.value || element.innerHTML);
+ editor.focus();
+
+ // Add the settingPanel opener to the editor's div.
+ container.appendChild(settingOpener);
+
+ // Create the API.
+ setupApi(editor, editorDiv, settingDiv, ace, options, loader);
+
+ // Create the setting's panel.
+ setupSettingPanel(settingDiv, settingOpener, editor, options);
+
+ var state = "";
+ event.addListener(settingOpener, "mousemove", function(e) {
+ var rect = this.getBoundingClientRect();
+ var x = e.clientX - rect.left, y = e.clientY - rect.top;
+ if (x + y < (rect.width + rect.height)/2) {
+ this.style.cursor = "pointer";
+ state = "toggle";
+ } else {
+ state = "resize";
+ this.style.cursor = "nw-resize";
+ }
+ });
+
+ event.addListener(settingOpener, "mousedown", function(e) {
+ if (state == "toggle") {
+ editor.setDisplaySettings();
+ return;
+ }
+ container.style.zIndex = 100000;
+ var rect = container.getBoundingClientRect();
+ var startX = rect.width + rect.left - e.clientX;
+ var startY = rect.height + rect.top - e.clientY;
+ event.capture(settingOpener, function(e) {
+ container.style.width = e.clientX - rect.left + startX + "px";
+ container.style.height = e.clientY - rect.top + startY + "px";
+ editor.resize();
+ }, function() {});
+ });
+
+ return editor;
+};
+
+function load(url, module, callback) {
+ net.loadScript(url, function() {
+ require([module], callback);
+ });
+}
+
+function setupApi(editor, editorDiv, settingDiv, ace, options, loader) {
+ var session = editor.getSession();
+ var renderer = editor.renderer;
+ loader = loader || load;
+
+ function toBool(value) {
+ return value === "true" || value == true;
+ }
+
+ editor.setDisplaySettings = function(display) {
+ if (display == null)
+ display = settingDiv.style.display == "none";
+ if (display) {
+ settingDiv.style.display = "block";
+ settingDiv.hideButton.focus();
+ editor.on("focus", function onFocus() {
+ editor.removeListener("focus", onFocus);
+ settingDiv.style.display = "none";
+ });
+ } else {
+ editor.focus();
+ }
+ };
+
+ editor.$setOption = editor.setOption;
+ editor.setOption = function(key, value) {
+ if (options[key] == value) return;
+
+ switch (key) {
+ case "mode":
+ if (value != "text") {
+ // Load the required mode file. Files get loaded only once.
+ loader("mode-" + value + ".js", "ace/mode/" + value, function() {
+ var aceMode = require("../mode/" + value).Mode;
+ session.setMode(new aceMode());
+ });
+ } else {
+ session.setMode(new (require("../mode/text").Mode));
+ }
+ break;
+
+ case "theme":
+ if (value != "textmate") {
+ // Load the required theme file. Files get loaded only once.
+ loader("theme-" + value + ".js", "ace/theme/" + value, function() {
+ editor.setTheme("ace/theme/" + value);
+ });
+ } else {
+ editor.setTheme("ace/theme/textmate");
+ }
+ break;
+
+ case "fontSize":
+ editorDiv.style.fontSize = value;
+ break;
+
+ case "keybindings":
+ switch (value) {
+ case "vim":
+ editor.setKeyboardHandler("ace/keyboard/vim");
+ break;
+ case "emacs":
+ editor.setKeyboardHandler("ace/keyboard/emacs");
+ break;
+ default:
+ editor.setKeyboardHandler(null);
+ }
+ break;
+
+ case "softWrap":
+ switch (value) {
+ case "off":
+ session.setUseWrapMode(false);
+ renderer.setPrintMarginColumn(80);
+ break;
+ case "40":
+ session.setUseWrapMode(true);
+ session.setWrapLimitRange(40, 40);
+ renderer.setPrintMarginColumn(40);
+ break;
+ case "80":
+ session.setUseWrapMode(true);
+ session.setWrapLimitRange(80, 80);
+ renderer.setPrintMarginColumn(80);
+ break;
+ case "free":
+ session.setUseWrapMode(true);
+ session.setWrapLimitRange(null, null);
+ renderer.setPrintMarginColumn(80);
+ break;
+ }
+ break;
+
+ default:
+ editor.$setOption(key, toBool(value));
+ }
+
+ options[key] = value;
+ };
+
+ editor.getOption = function(key) {
+ return options[key];
+ };
+
+ editor.getOptions = function() {
+ return options;
+ };
+
+ editor.setOptions(exports.options);
+
+ return editor;
+}
+
+function setupSettingPanel(settingDiv, settingOpener, editor, options) {
+ var BOOL = null;
+
+ var desc = {
+ mode: "Mode:",
+ gutter: "Display Gutter:",
+ theme: "Theme:",
+ fontSize: "Font Size:",
+ softWrap: "Soft Wrap:",
+ keybindings: "Keyboard",
+ showPrintMargin: "Show Print Margin:",
+ useSoftTabs: "Use Soft Tabs:",
+ showInvisibles: "Show Invisibles"
+ };
+
+ var optionValues = {
+ mode: {
+ text: "Plain",
+ javascript: "JavaScript",
+ xml: "XML",
+ html: "HTML",
+ css: "CSS",
+ scss: "SCSS",
+ python: "Python",
+ php: "PHP",
+ java: "Java",
+ ruby: "Ruby",
+ c_cpp: "C/C++",
+ coffee: "CoffeeScript",
+ json: "json",
+ perl: "Perl",
+ clojure: "Clojure",
+ ocaml: "OCaml",
+ csharp: "C#",
+ haxe: "haXe",
+ svg: "SVG",
+ textile: "Textile",
+ groovy: "Groovy",
+ liquid: "Liquid",
+ Scala: "Scala"
+ },
+ theme: {
+ clouds: "Clouds",
+ clouds_midnight: "Clouds Midnight",
+ cobalt: "Cobalt",
+ crimson_editor: "Crimson Editor",
+ dawn: "Dawn",
+ eclipse: "Eclipse",
+ idle_fingers: "Idle Fingers",
+ kr_theme: "Kr Theme",
+ merbivore: "Merbivore",
+ merbivore_soft: "Merbivore Soft",
+ mono_industrial: "Mono Industrial",
+ monokai: "Monokai",
+ pastel_on_dark: "Pastel On Dark",
+ solarized_dark: "Solarized Dark",
+ solarized_light: "Solarized Light",
+ textmate: "Textmate",
+ twilight: "Twilight",
+ vibrant_ink: "Vibrant Ink"
+ },
+ gutter: BOOL,
+ fontSize: {
+ "10px": "10px",
+ "11px": "11px",
+ "12px": "12px",
+ "14px": "14px",
+ "16px": "16px"
+ },
+ softWrap: {
+ off: "Off",
+ 40: "40",
+ 80: "80",
+ free: "Free"
+ },
+ keybindings: {
+ ace: "ace",
+ vim: "vim",
+ emacs: "emacs"
+ },
+ showPrintMargin: BOOL,
+ useSoftTabs: BOOL,
+ showInvisibles: BOOL
+ };
+
+ var table = [];
+ table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
+
+ function renderOption(builder, option, obj, cValue) {
+ if (!obj) {
+ builder.push(
+ "<input type='checkbox' title='", option, "' ",
+ cValue == "true" ? "checked='true'" : "",
+ "'></input>"
+ );
+ return;
+ }
+ builder.push("<select title='" + option + "'>");
+ for (var value in obj) {
+ builder.push("<option value='" + value + "' ");
+
+ if (cValue == value) {
+ builder.push(" selected ");
+ }
+
+ builder.push(">",
+ obj[value],
+ "</option>");
+ }
+ builder.push("</select>");
+ }
+
+ for (var option in options) {
+ table.push("<tr><td>", desc[option], "</td>");
+ table.push("<td>");
+ renderOption(table, option, optionValues[option], options[option]);
+ table.push("</td></tr>");
+ }
+ table.push("</table>");
+ settingDiv.innerHTML = table.join("");
+
+ var onChange = function(e) {
+ var select = e.currentTarget;
+ editor.setOption(select.title, select.value);
+ };
+ var onClick = function(e) {
+ var cb = e.currentTarget;
+ editor.setOption(cb.title, cb.checked);
+ };
+ var selects = settingDiv.getElementsByTagName("select");
+ for (var i = 0; i < selects.length; i++)
+ selects[i].onchange = onChange;
+ var cbs = settingDiv.getElementsByTagName("input");
+ for (var i = 0; i < cbs.length; i++)
+ cbs[i].onclick = onClick;
+
+
+ var button = document.createElement("input");
+ button.type = "button";
+ button.value = "Hide";
+ event.addListener(button, "click", function() {
+ editor.setDisplaySettings(false);
+ });
+ settingDiv.appendChild(button);
+ settingDiv.hideButton = button;
+}
+
+// Default startup options.
+exports.options = {
+ mode: "text",
+ theme: "textmate",
+ gutter: "false",
+ fontSize: "12px",
+ softWrap: "off",
+ keybindings: "ace",
+ showPrintMargin: "false",
+ useSoftTabs: "true",
+ showInvisibles: "false"
+};
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/themelist.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/themelist.js b/src/fauxton/assets/js/libs/ace/ext/themelist.js
new file mode 100644
index 0000000..1032f72
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/themelist.js
@@ -0,0 +1,79 @@
+/* ***** 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, require */
+
+/**
+ * Generates a list of themes available when ace was built.
+ * @fileOverview Generates a list of themes available when ace was built.
+ * @author <a href="mailto:matthewkastor@gmail.com">
+ * Matthew Christopher Kastor-Inare III </a><br />
+ * ☭ Hial Atropa!! ☭
+ */
+
+define(function(require, exports, module) {
+"use strict";
+
+/**
+ * An array containing information about available themes.
+ */
+module.exports.themes = require('ace/ext/themelist_utils/themes').themes;
+
+/**
+ * Creates a theme description.
+ * @param {string} name The file name of the theme.
+ * @returns {ThemeDescription} Returns a theme description object which has
+ * three properties: the name gives the filename, the desc gives a menu
+ * friendly name, and the theme gives the string to set the theme with
+ * `setTheme`
+ */
+module.exports.ThemeDescription = function(name) {
+ this.name = name;
+ this.desc = name.split('_'
+ ).map(
+ function(namePart) {
+ return namePart[0].toUpperCase() + namePart.slice(1);
+ }
+ ).join(' ');
+ this.theme = "ace/theme/" + name;
+};
+
+module.exports.themesByName = {};
+
+module.exports.themes = module.exports.themes.map(function(name) {
+ module.exports.themesByName[name] = new module.exports.ThemeDescription(name);
+ return module.exports.themesByName[name];
+});
+
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/themelist_utils/themes.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/themelist_utils/themes.js b/src/fauxton/assets/js/libs/ace/ext/themelist_utils/themes.js
new file mode 100644
index 0000000..2e490c9
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/themelist_utils/themes.js
@@ -0,0 +1,36 @@
+define(function(require, exports, module) {
+
+module.exports.themes = [
+ "ambiance",
+ "chaos",
+ "chrome",
+ "clouds",
+ "clouds_midnight",
+ "cobalt",
+ "crimson_editor",
+ "dawn",
+ "dreamweaver",
+ "eclipse",
+ "github",
+ "idle_fingers",
+ "kr_theme",
+ "merbivore",
+ "merbivore_soft",
+ "mono_industrial",
+ "monokai",
+ "pastel_on_dark",
+ "solarized_dark",
+ "solarized_light",
+ "terminal",
+ "textmate",
+ "tomorrow",
+ "tomorrow_night",
+ "tomorrow_night_blue",
+ "tomorrow_night_bright",
+ "tomorrow_night_eighties",
+ "twilight",
+ "vibrant_ink",
+ "xcode"
+];
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/ext/whitespace.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/ext/whitespace.js b/src/fauxton/assets/js/libs/ace/ext/whitespace.js
new file mode 100644
index 0000000..83486fb
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/ext/whitespace.js
@@ -0,0 +1,212 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var lang = require("../lib/lang");
+
+// based on http://www.freehackers.org/Indent_Finder
+exports.$detectIndentation = function(lines, fallback) {
+ var stats = [];
+ var changes = [];
+ var tabIndents = 0;
+ var prevSpaces = 0;
+ var max = Math.min(lines.length, 1000);
+ for (var i = 0; i < max; i++) {
+ var line = lines[i];
+ // ignore empty and comment lines
+ if (!/^\s*[^*+\-\s]/.test(line))
+ continue;
+
+ var tabs = line.match(/^\t*/)[0].length;
+ if (line[0] == "\t")
+ tabIndents++;
+
+ var spaces = line.match(/^ */)[0].length;
+ if (spaces && line[spaces] != "\t") {
+ var diff = spaces - prevSpaces;
+ if (diff > 0 && !(prevSpaces%diff) && !(spaces%diff))
+ changes[diff] = (changes[diff] || 0) + 1;
+
+ stats[spaces] = (stats[spaces] || 0) + 1;
+ }
+ prevSpaces = spaces;
+
+ // ignore lines ending with backslash
+ while (line[line.length - 1] == "\\")
+ line = lines[i++];
+ }
+
+ function getScore(indent) {
+ var score = 0;
+ for (var i = indent; i < stats.length; i += indent)
+ score += stats[i] || 0;
+ return score;
+ }
+
+ var changesTotal = changes.reduce(function(a,b){return a+b}, 0);
+
+ var first = {score: 0, length: 0};
+ var spaceIndents = 0;
+ for (var i = 1; i < 12; i++) {
+ if (i == 1) {
+ spaceIndents = getScore(i);
+ var score = 1;
+ } else
+ var score = getScore(i) / spaceIndents;
+
+ if (changes[i]) {
+ score += changes[i] / changesTotal;
+ }
+
+ if (score > first.score)
+ first = {score: score, length: i};
+ }
+
+ if (first.score && first.score > 1.4)
+ var tabLength = first.length;
+
+ if (tabIndents > spaceIndents + 1)
+ return {ch: "\t", length: tabLength};
+
+ if (spaceIndents + 1 > tabIndents)
+ return {ch: " ", length: tabLength};
+};
+
+exports.detectIndentation = function(session) {
+ var lines = session.getLines(0, 1000);
+ var indent = exports.$detectIndentation(lines) || {};
+
+ if (indent.ch)
+ session.setUseSoftTabs(indent.ch == " ");
+
+ if (indent.length)
+ session.setTabSize(indent.length);
+ return indent;
+};
+
+exports.trimTrailingSpace = function(session, trimEmpty) {
+ var doc = session.getDocument();
+ var lines = doc.getAllLines();
+
+ var min = trimEmpty ? -1 : 0;
+
+ for (var i = 0, l=lines.length; i < l; i++) {
+ var line = lines[i];
+ var index = line.search(/\s+$/);
+
+ if (index > min)
+ doc.removeInLine(i, index, line.length);
+ }
+};
+
+exports.convertIndentation = function(session, ch, len) {
+ var oldCh = session.getTabString()[0];
+ var oldLen = session.getTabSize();
+ if (!len) len = oldLen;
+ if (!ch) ch = oldCh;
+
+ var tab = ch == "\t" ? ch: lang.stringRepeat(ch, len);
+
+ var doc = session.doc;
+ var lines = doc.getAllLines();
+
+ var cache = {};
+ var spaceCache = {};
+ for (var i = 0, l=lines.length; i < l; i++) {
+ var line = lines[i];
+ var match = line.match(/^\s*/)[0];
+ if (match) {
+ var w = session.$getStringScreenWidth(match)[0];
+ var tabCount = Math.floor(w/oldLen);
+ var reminder = w%oldLen;
+ var toInsert = cache[tabCount] || (cache[tabCount] = lang.stringRepeat(tab, tabCount));
+ toInsert += spaceCache[reminder] || (spaceCache[reminder] = lang.stringRepeat(" ", reminder));
+
+ if (toInsert != match) {
+ doc.removeInLine(i, 0, match.length);
+ doc.insertInLine({row: i, column: 0}, toInsert);
+ }
+ }
+ }
+ session.setTabSize(len);
+ session.setUseSoftTabs(ch == " ");
+};
+
+exports.$parseStringArg = function(text) {
+ var indent = {};
+ if (/t/.test(text))
+ indent.ch = "\t";
+ else if (/s/.test(text))
+ indent.ch = " ";
+ var m = text.match(/\d+/);
+ if (m)
+ indent.length = parseInt(m[0], 10);
+ return indent;
+};
+
+exports.$parseArg = function(arg) {
+ if (!arg)
+ return {};
+ if (typeof arg == "string")
+ return exports.$parseStringArg(arg);
+ if (typeof arg.text == "string")
+ return exports.$parseStringArg(arg.text);
+ return arg;
+};
+
+exports.commands = [{
+ name: "detectIndentation",
+ exec: function(editor) {
+ exports.detectIndentation(editor.session);
+ // todo show message?
+ }
+}, {
+ name: "trimTrailingSpace",
+ exec: function(editor) {
+ exports.trimTrailingSpace(editor.session);
+ }
+}, {
+ name: "convertIndentation",
+ exec: function(editor, arg) {
+ var indent = exports.$parseArg(arg);
+ exports.convertIndentation(editor.session, indent.ch, indent.length);
+ }
+}, {
+ name: "setIndentation",
+ exec: function(editor, arg) {
+ var indent = exports.$parseArg(arg);
+ indent.length && editor.session.setTabSize(indent.length);
+ indent.ch && editor.session.setUseSoftTabs(indent.ch == " ");
+ }
+}];
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/incremental_search.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/incremental_search.js b/src/fauxton/assets/js/libs/ace/incremental_search.js
new file mode 100644
index 0000000..e6fa892
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/incremental_search.js
@@ -0,0 +1,259 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("./lib/oop");
+var Range = require("./range").Range;
+var Search = require("./search").Search;
+var SearchHighlight = require("./search_highlight").SearchHighlight;
+var iSearchCommandModule = require("./commands/incremental_search_commands");
+var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler;
+
+/**
+ * @class IncrementalSearch
+ *
+ * Implements immediate searching while the user is typing. When incremental
+ * search is activated, keystrokes into the editor will be used for composing
+ * a search term. Immediately after every keystroke the search is updated:
+ * - so-far-matching characters are highlighted
+ * - the cursor is moved to the next match
+ *
+ **/
+
+
+/**
+ *
+ *
+ * Creates a new `IncrementalSearch` object.
+ *
+ * @constructor
+ **/
+function IncrementalSearch() {
+ this.$options = {wrap: false, skipCurrent: false};
+ this.$keyboardHandler = new ISearchKbd(this);
+}
+
+oop.inherits(IncrementalSearch, Search);
+
+;(function() {
+
+ this.activate = function(ed, backwards) {
+ this.$editor = ed;
+ this.$startPos = this.$currentPos = ed.getCursorPosition();
+ this.$options.needle = '';
+ this.$options.backwards = backwards;
+ ed.keyBinding.addKeyboardHandler(this.$keyboardHandler);
+ this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this));
+ this.selectionFix(ed);
+ this.statusMessage(true);
+ }
+
+ this.deactivate = function(reset) {
+ this.cancelSearch(reset);
+ this.$editor.keyBinding.removeKeyboardHandler(this.$keyboardHandler);
+ if (this.$mousedownHandler) {
+ this.$editor.removeEventListener('mousedown', this.$mousedownHandler);
+ delete this.$mousedownHandler;
+ }
+ this.message('');
+ }
+
+ this.selectionFix = function(editor) {
+ // Fix selection bug: When clicked inside the editor
+ // editor.selection.$isEmpty is false even if the mouse click did not
+ // open a selection. This is interpreted by the move commands to
+ // extend the selection. To only extend the selection when there is
+ // one, we clear it here
+ if (editor.selection.isEmpty() && !editor.session.$emacsMark) {
+ editor.clearSelection();
+ }
+ }
+
+ this.highlight = function(regexp) {
+ var sess = this.$editor.session,
+ hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker(
+ new SearchHighlight(null, "ace_isearch-result", "text"));
+ hl.setRegexp(regexp);
+ sess._emit("changeBackMarker"); // force highlight layer redraw
+ }
+
+ this.cancelSearch = function(reset) {
+ var e = this.$editor;
+ this.$prevNeedle = this.$options.needle;
+ this.$options.needle = '';
+ if (reset) {
+ e.moveCursorToPosition(this.$startPos);
+ this.$currentPos = this.$startPos;
+ } else {
+ e.pushEmacsMark && e.pushEmacsMark(this.$startPos, false);
+ }
+ this.highlight(null);
+ return Range.fromPoints(this.$currentPos, this.$currentPos);
+ }
+
+ this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) {
+ if (!this.$editor) return null;
+ var options = this.$options;
+
+ // get search term
+ if (needleUpdateFunc) {
+ options.needle = needleUpdateFunc.call(this, options.needle || '') || '';
+ }
+ if (options.needle.length === 0) {
+ this.statusMessage(true);
+ return this.cancelSearch(true);
+ };
+
+ // try to find the next occurence and enable highlighting marker
+ options.start = this.$currentPos;
+ var session = this.$editor.session,
+ found = this.find(session);
+ if (found) {
+ if (options.backwards) found = Range.fromPoints(found.end, found.start);
+ this.$editor.moveCursorToPosition(found.end);
+ if (moveToNext) this.$currentPos = found.end;
+ // highlight after cursor move, so selection works properly
+ this.highlight(options.re)
+ }
+
+ this.statusMessage(found);
+
+ return found;
+ }
+
+ this.addChar = function(c) {
+ return this.highlightAndFindWithNeedle(false, function(needle) {
+ return needle + c;
+ });
+ }
+
+ this.removeChar = function(c) {
+ return this.highlightAndFindWithNeedle(false, function(needle) {
+ return needle.length > 0 ? needle.substring(0, needle.length-1) : needle;
+ });
+ }
+
+ this.next = function(options) {
+ // try to find the next occurence of whatever we have searched for
+ // earlier.
+ // options = {[backwards: BOOL], [useCurrentOrPrevSearch: BOOL]}
+ options = options || {};
+ this.$options.backwards = !!options.backwards;
+ this.$currentPos = this.$editor.getCursorPosition();
+ return this.highlightAndFindWithNeedle(true, function(needle) {
+ return options.useCurrentOrPrevSearch && needle.length === 0 ?
+ this.$prevNeedle || '' : needle;
+ });
+ }
+
+ this.onMouseDown = function(evt) {
+ // when mouse interaction happens then we quit incremental search
+ this.deactivate();
+ return true;
+ }
+
+ this.statusMessage = function(found) {
+ var options = this.$options, msg = '';
+ msg += options.backwards ? 'reverse-' : '';
+ msg += 'isearch: ' + options.needle;
+ msg += found ? '' : ' (not found)';
+ this.message(msg);
+ }
+
+ this.message = function(msg) {
+ if (this.$editor.showCommandLine) {
+ this.$editor.showCommandLine(msg);
+ this.$editor.focus();
+ } else {
+ console.log(msg);
+ }
+ }
+
+}).call(IncrementalSearch.prototype);
+
+
+exports.IncrementalSearch = IncrementalSearch;
+
+
+/**
+ *
+ * Config settings for enabling/disabling [[IncrementalSearch `IncrementalSearch`]].
+ *
+ **/
+
+var dom = require('./lib/dom');
+dom.importCssString && dom.importCssString("\
+.ace_marker-layer .ace_isearch-result {\
+ position: absolute;\
+ z-index: 6;\
+ -moz-box-sizing: border-box;\
+ -webkit-box-sizing: border-box;\
+ box-sizing: border-box;\
+}\
+div.ace_isearch-result {\
+ border-radius: 4px;\
+ background-color: rgba(255, 200, 0, 0.5);\
+ box-shadow: 0 0 4px rgb(255, 200, 0);\
+}\
+.ace_dark div.ace_isearch-result {\
+ background-color: rgb(100, 110, 160);\
+ box-shadow: 0 0 4px rgb(80, 90, 140);\
+}", "incremental-search-highlighting");
+
+// support for default keyboard handler
+var commands = require("./commands/command_manager");
+(function() {
+ this.setupIncrementalSearch = function(editor, val) {
+ if (this.usesIncrementalSearch == val) return;
+ this.usesIncrementalSearch = val;
+ var iSearchCommands = iSearchCommandModule.iSearchStartCommands;
+ var method = val ? 'addCommands' : 'removeCommands';
+ this[method](iSearchCommands);
+ };
+}).call(commands.CommandManager.prototype);
+
+// incremental search config option
+var Editor = require("./editor").Editor;
+require("./config").defineOptions(Editor.prototype, "editor", {
+ useIncrementalSearch: {
+ set: function(val) {
+ this.keyBinding.$handlers.forEach(function(handler) {
+ if (handler.setupIncrementalSearch) {
+ handler.setupIncrementalSearch(this, val);
+ }
+ });
+ this._emit('incrementalSearchSettingChanged', {isEnabled: val});
+ }
+ }
+});
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/9abd128c/src/fauxton/assets/js/libs/ace/incremental_search_test.js
----------------------------------------------------------------------
diff --git a/src/fauxton/assets/js/libs/ace/incremental_search_test.js b/src/fauxton/assets/js/libs/ace/incremental_search_test.js
new file mode 100644
index 0000000..c351d8e
--- /dev/null
+++ b/src/fauxton/assets/js/libs/ace/incremental_search_test.js
@@ -0,0 +1,208 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 ***** */
+
+if (typeof process !== "undefined") {
+ require("amd-loader");
+}
+
+define(function(require, exports, module) {
+"use strict";
+
+var EditSession = require("./edit_session").EditSession;
+var Editor = require("./editor").Editor;
+var MockRenderer = require("./test/mockrenderer").MockRenderer;
+var Range = require("./range").Range;
+var assert = require("./test/assertions");
+var IncrementalSearch = require("./incremental_search").IncrementalSearch;
+
+var editor, iSearch;
+function testRanges(str, ranges) {
+ ranges = ranges || editor.selection.getAllRanges();
+ assert.equal(ranges + "", str + "");
+}
+
+// force "rerender"
+function callHighlighterUpdate() {
+ var session = editor.session,
+ ranges = [],
+ mockMarkerLayer = {
+ drawSingleLineMarker: function(_, markerRanges) {
+ ranges = ranges.concat(markerRanges);
+ }
+ }
+ session.$isearchHighlight.update([], mockMarkerLayer, session, {
+ firstRow: 0, lastRow: session.getRowLength()});
+ return ranges;
+}
+
+module.exports = {
+
+ name: "ACE incremental_search.js",
+
+ setUp: function() {
+ var session = new EditSession(["abc123", "xyz124"]);
+ editor = new Editor(new MockRenderer(), session);
+ iSearch = new IncrementalSearch();
+ },
+
+ "test: keyboard handler setup" : function() {
+ iSearch.activate(editor);
+ assert.equal(editor.getKeyboardHandler(), iSearch.$keyboardHandler);
+ iSearch.deactivate();
+ assert.notEqual(editor.getKeyboardHandler(), iSearch.$keyboardHandler);
+ },
+
+ "test: isearch highlight setup" : function() {
+ var sess = editor.session;
+ iSearch.activate(editor);
+ iSearch.highlight('foo');
+ var highl = sess.$isearchHighlight.id;
+ assert.ok(sess.$isearchHighlight, 'session has no isearch highlighter');
+ assert.equal(sess.getMarkers()[highl.id], highl.id, 'isearch highlight not in markers');
+ iSearch.deactivate();
+ iSearch.activate(editor);
+ iSearch.highlight('bar');
+ var highl2 = sess.$isearchHighlight.id;
+ assert.equal(highl2, highl, 'multiple isearch highlights');
+ },
+
+ "test: find simple text incrementally" : function() {
+ iSearch.activate(editor);
+ var range = iSearch.addChar('1'), // "1"
+ highlightRanges = callHighlighterUpdate(editor.session);
+ testRanges("Range: [0/3] -> [0/4]", [range], "range");
+ testRanges("Range: [0/3] -> [0/4],Range: [1/3] -> [1/4]", highlightRanges, "highlight");
+
+ range = iSearch.addChar('2'); // "12"
+ highlightRanges = callHighlighterUpdate(editor.session);
+ testRanges("Range: [0/3] -> [0/5]", [range], "range");
+ testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight");
+
+ range = iSearch.addChar('3'); // "123"
+ highlightRanges = callHighlighterUpdate(editor.session);
+ testRanges("Range: [0/3] -> [0/6]", [range], "range");
+ testRanges("Range: [0/3] -> [0/6]", highlightRanges, "highlight");
+
+ range = iSearch.removeChar(); // "12"
+ highlightRanges = callHighlighterUpdate(editor.session);
+ testRanges("Range: [0/3] -> [0/5]", [range], "range");
+ testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight");
+ },
+
+ "test: forward / backward" : function() {
+ iSearch.activate(editor);
+ iSearch.addChar('1'); iSearch.addChar('2');
+ var range = iSearch.next();
+ testRanges("Range: [1/3] -> [1/5]", [range], "range");
+
+ range = iSearch.next(); // nothing to find
+ testRanges("", [range], "range");
+
+ range = iSearch.next({backwards: true}); // backwards
+ testRanges("Range: [1/5] -> [1/3]", [range], "range");
+ },
+
+ "test: cancelSearch" : function() {
+ iSearch.activate(editor);
+ iSearch.addChar('1'); iSearch.addChar('2');
+ var range = iSearch.cancelSearch(true);
+ testRanges("Range: [0/0] -> [0/0]", [range], "range");
+
+ iSearch.addChar('1'); range = iSearch.addChar('2');
+ testRanges("Range: [0/3] -> [0/5]", [range], "range");
+ },
+
+ "test: failing search keeps pos" : function() {
+ iSearch.activate(editor);
+ iSearch.addChar('1'); iSearch.addChar('2');
+ var range = iSearch.addChar('x');
+ testRanges("", [range], "range");
+ assert.position(editor.getCursorPosition(), 0, 5);
+ },
+
+ "test: backwards search" : function() {
+ editor.moveCursorTo(1,0);
+ iSearch.activate(editor, true);
+ iSearch.addChar('1'); var range = iSearch.addChar('2');;
+ testRanges("Range: [0/5] -> [0/3]", [range], "range");
+ assert.position(editor.getCursorPosition(), 0, 3);
+ },
+
+ "test: forwards then backwards, same result, reoriented range" : function() {
+ iSearch.activate(editor);
+ iSearch.addChar('1'); var range = iSearch.addChar('2');;
+ testRanges("Range: [0/3] -> [0/5]", [range], "range");
+ assert.position(editor.getCursorPosition(), 0, 5);
+
+ range = iSearch.next({backwards: true});
+ testRanges("Range: [0/5] -> [0/3]", [range], "range");
+ assert.position(editor.getCursorPosition(), 0, 3);
+ },
+
+ "test: reuse prev search via option" : function() {
+ iSearch.activate(editor);
+ iSearch.addChar('1'); iSearch.addChar('2');;
+ assert.position(editor.getCursorPosition(), 0, 5);
+ iSearch.deactivate();
+
+ iSearch.activate(editor);
+ iSearch.next({backwards: false, useCurrentOrPrevSearch: true});
+ assert.position(editor.getCursorPosition(), 1, 5);
+ },
+
+ "test: don't extend selection range if selection is empty" : function() {
+ iSearch.activate(editor);
+ iSearch.addChar('1'); iSearch.addChar('2');;
+ testRanges("Range: [0/5] -> [0/5]", [editor.getSelectionRange()], "sel range");
+ },
+
+ "test: extend selection range if selection exists" : function() {
+ iSearch.activate(editor);
+ editor.selection.selectTo(0, 1);
+ iSearch.addChar('1'); iSearch.addChar('2');;
+ testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range");
+ },
+
+ "test: extend selection in emacs mark mode" : function() {
+ var emacs = require('./keyboard/emacs');
+ editor.keyBinding.addKeyboardHandler(emacs.handler);
+ emacs.handler.commands.setMark.exec(editor);
+ iSearch.activate(editor);
+ iSearch.addChar('1'); iSearch.addChar('2');;
+ testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range");
+ }
+
+};
+
+});
+
+if (typeof module !== "undefined" && module === require.main) {
+ require("asyncjs").test.testcase(module.exports).exec()
+}