big-moving.ru/api/soft/ajaxorg/lib/ace/ext/prompt.js

473 lines
17 KiB
JavaScript
Executable File

/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2012, 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 Range = require("../range").Range;
var dom = require("../lib/dom");
var shortcuts = require("../ext/menu_tools/get_editor_keyboard_shortcuts");
var FilteredList= require("../autocomplete").FilteredList;
var AcePopup = require('../autocomplete/popup').AcePopup;
var $singleLineEditor = require('../autocomplete/popup').$singleLineEditor;
var UndoManager = require("../undomanager").UndoManager;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var overlayPage = require('./menu_tools/overlay_page').overlayPage;
var modelist = require("ace/ext/modelist");
var openPrompt;
function prompt(editor, message, options, callback) {
if (typeof message == "object") {
return prompt(editor, "", message, options);
}
if (openPrompt) {
var lastPrompt = openPrompt;
editor = lastPrompt.editor;
lastPrompt.close();
if (lastPrompt.name && lastPrompt.name == options.name)
return;
}
if (options.$type)
return prompt[options.$type](editor, callback);
var cmdLine = $singleLineEditor();
cmdLine.session.setUndoManager(new UndoManager());
cmdLine.setOption("fontSize", editor.getOption("fontSize"));
var el = dom.buildDom(["div", {class: "ace_prompt_container"}]);
var overlay = overlayPage(editor, el, done);
el.appendChild(cmdLine.container);
editor.cmdLine = cmdLine;
cmdLine.setValue(message, 1);
if (options.selection) {
cmdLine.selection.setRange({
start: cmdLine.session.doc.indexToPosition(options.selection[0]),
end: cmdLine.session.doc.indexToPosition(options.selection[1])
});
}
if (options.getCompletions) {
var popup = new AcePopup();
popup.renderer.setStyle("ace_autocomplete_inline");
popup.container.style.display = "block";
popup.container.style.maxWidth = "600px";
popup.container.style.width = "100%";
popup.container.style.marginTop = "3px";
popup.renderer.setScrollMargin(2, 2, 0, 0);
popup.autoSelect = false;
popup.renderer.$maxLines = 15;
popup.setRow(-1);
popup.on("click", function(e) {
var data = popup.getData(popup.getRow());
if (!data.error) {
cmdLine.setValue(data.value || data.name || data);
accept();
e.stop();
}
});
el.appendChild(popup.container);
updateCompletions();
}
if (options.$rules) {
var tokenizer = new Tokenizer(options.$rules);
cmdLine.session.bgTokenizer.setTokenizer(tokenizer);
}
function accept() {
var val;
if (popup.getCursorPosition().row > 0) {
val = valueFromRecentList();
} else {
val = cmdLine.getValue();
}
var curData = popup.getData(popup.getRow());
if (curData && !curData.error) {
done();
options.onAccept && options.onAccept({
value: val,
item: curData
}, cmdLine);
}
}
cmdLine.commands.bindKeys({
"Enter": accept,
"Esc|Shift-Esc": function() {
options.onCancel && options.onCancel(cmdLine.getValue(), cmdLine);
done();
},
"Up": function(editor) { popup.goTo("up"); valueFromRecentList();},
"Down": function(editor) { popup.goTo("down"); valueFromRecentList();},
"Ctrl-Up|Ctrl-Home": function(editor) { popup.goTo("start"); valueFromRecentList();},
"Ctrl-Down|Ctrl-End": function(editor) { popup.goTo("end"); valueFromRecentList();},
"Tab": function(editor) {
popup.goTo("down"); valueFromRecentList();
},
"PageUp": function(editor) { popup.gotoPageUp(); valueFromRecentList();},
"PageDown": function(editor) { popup.gotoPageDown(); valueFromRecentList();}
});
function done() {
overlay.close();
callback && callback();
openPrompt = null;
}
cmdLine.on("input", function() {
options.onInput && options.onInput();
updateCompletions();
});
function updateCompletions() {
if (options.getCompletions) {
var prefix;
if (options.getPrefix) {
prefix = options.getPrefix(cmdLine);
}
var completions = options.getCompletions(cmdLine);
popup.setData(completions, prefix);
popup.resize(true);
}
}
function valueFromRecentList() {
var current = popup.getData(popup.getRow());
if (current && !current.error)
return current.value || current.caption || current;
}
cmdLine.resize(true);
popup.resize(true);
cmdLine.focus();
openPrompt = {
close: done,
name: options.name,
editor: editor
};
}
prompt.gotoLine = function(editor, callback) {
function stringifySelection(selection) {
if (!Array.isArray(selection))
selection = [selection];
return selection.map(function(r) {
var cursor = r.isBackwards ? r.start: r.end;
var anchor = r.isBackwards ? r.end: r.start;
var row = anchor.row;
var s = (row + 1) + ":" + anchor.column;
if (anchor.row == cursor.row) {
if (anchor.column != cursor.column)
s += ">" + ":" + cursor.column;
} else {
s += ">" + (cursor.row + 1) + ":" + cursor.column;
}
return s;
}).reverse().join(", ");
}
prompt(editor, ":" + stringifySelection(editor.selection.toJSON()), {
name: "gotoLine",
selection: [1, Number.MAX_VALUE],
onAccept: function(data) {
var value = data.value;
var _history = prompt.gotoLine._history;
if (!_history)
prompt.gotoLine._history = _history = [];
if (_history.indexOf(value) != -1)
_history.splice(_history.indexOf(value), 1);
_history.unshift(value);
if (_history.length > 20) _history.length = 20;
var pos = editor.getCursorPosition();
var ranges = [];
value.replace(/^:/, "").split(/,/).map(function(str) {
var parts = str.split(/([<>:+-]|c?\d+)|[^c\d<>:+-]+/).filter(Boolean);
var i = 0;
function readPosition() {
var c = parts[i++];
if (!c) return;
if (c[0] == "c") {
var index = parseInt(c.slice(1)) || 0;
return editor.session.doc.indexToPosition(index);
}
var row = pos.row;
var column = 0;
if (/\d/.test(c)) {
row = parseInt(c) - 1;
c = parts[i++];
}
if (c == ":") {
c = parts[i++];
if (/\d/.test(c)) {
column = parseInt(c) || 0;
}
}
return {row: row, column: column};
}
pos = readPosition();
var range = Range.fromPoints(pos, pos);
if (parts[i] == ">") {
i++;
range.end = readPosition();
}
else if (parts[i] == "<") {
i++;
range.start = readPosition();
}
ranges.unshift(range);
});
editor.selection.fromJSON(ranges);
var scrollTop = editor.renderer.scrollTop;
editor.renderer.scrollSelectionIntoView(
editor.selection.anchor,
editor.selection.cursor,
0.5
);
editor.renderer.animateScrolling(scrollTop);
},
history: function() {
var undoManager = editor.session.getUndoManager();
if (!prompt.gotoLine._history)
return [];
return prompt.gotoLine._history;
},
getCompletions: function(cmdLine) {
var value = cmdLine.getValue();
var m = value.replace(/^:/, "").split(":");
var row = Math.min(parseInt(m[0]) || 1, editor.session.getLength()) - 1;
var line = editor.session.getLine(row);
var current = value + " " + line;
return [current].concat(this.history());
},
$rules: {
start: [{
regex: /\d+/,
token: "string"
}, {
regex: /[:,><+\-c]/,
token: "keyword"
}]
}
});
};
prompt.commands = function(editor, callback) {
function normalizeName(name) {
return (name || "").replace(/^./, function(x) {
return x.toUpperCase(x);
}).replace(/[a-z][A-Z]/g, function(x) {
return x[0] + " " + x[1].toLowerCase(x);
});
}
function getEditorCommandsByName(excludeCommands) {
var commandsByName = [];
var commandMap = {};
editor.keyBinding.$handlers.forEach(function(handler) {
var platform = handler.platform;
var cbn = handler.byName;
for (var i in cbn) {
var key;
if (cbn[i].bindKey && cbn[i].bindKey[platform] !== null) {
key = cbn[i].bindKey["win"];
} else {
key = "";
}
var commands = cbn[i];
var description = commands.description || normalizeName(commands.name);
if (!Array.isArray(commands))
commands = [commands];
commands.forEach(function(command) {
if (typeof command != "string")
command = command.name;
var needle = excludeCommands.find(function(el) {
return el === command;
});
if (!needle) {
if (commandMap[command]) {
commandMap[command].key += "|" + key;
} else {
commandMap[command] = {key: key, command: command, description: description};
commandsByName.push(commandMap[command]);
}
}
});
}
});
return commandsByName;
}
// exclude commands that can not be executed without args
var excludeCommandsList = ["insertstring", "inserttext", "setIndentation", "paste"];
var shortcutsArray = getEditorCommandsByName(excludeCommandsList);
shortcutsArray = shortcutsArray.map(function(item) {
return {value: item.description, meta: item.key, command: item.command};
});
prompt(editor, "", {
name: "commands",
selection: [0, Number.MAX_VALUE],
maxHistoryCount: 5,
onAccept: function(data) {
if (data.item) {
var commandName = data.item.command;
this.addToHistory(data.item);
editor.execCommand(commandName);
}
},
addToHistory: function(item) {
var history = this.history();
history.unshift(item);
delete item.message;
for (var i = 1; i < history.length; i++) {
if (history[i]["command"] == item.command ) {
history.splice(i, 1);
break;
}
}
if (this.maxHistoryCount > 0 && history.length > this.maxHistoryCount) {
history.splice(history.length - 1, 1);
}
prompt.commands.history = history;
},
history: function() {
return prompt.commands.history || [];
},
getPrefix: function(cmdLine) {
var currentPos = cmdLine.getCursorPosition();
var filterValue = cmdLine.getValue();
return filterValue.substring(0, currentPos.column);
},
getCompletions: function(cmdLine) {
function getFilteredCompletions(commands, prefix) {
var resultCommands = JSON.parse(JSON.stringify(commands));
var filtered = new FilteredList(resultCommands);
return filtered.filterCompletions(resultCommands, prefix);
}
function getUniqueCommandList(commands, usedCommands) {
if (!usedCommands || !usedCommands.length) {
return commands;
}
var excludeCommands = [];
usedCommands.forEach(function(item) {
excludeCommands.push(item.command);
});
var resultCommands = [];
commands.forEach(function(item) {
if (excludeCommands.indexOf(item.command) === -1) {
resultCommands.push(item);
}
});
return resultCommands;
}
var prefix = this.getPrefix(cmdLine);
var recentlyUsedCommands = getFilteredCompletions(this.history(), prefix);
var otherCommands = getUniqueCommandList(shortcutsArray, recentlyUsedCommands);
otherCommands = getFilteredCompletions(otherCommands, prefix);
if (recentlyUsedCommands.length && otherCommands.length) {
recentlyUsedCommands[0]["message"] = " Recently used";
otherCommands[0]["message"] = " Other commands";
}
var completions = recentlyUsedCommands.concat(otherCommands);
return completions.length > 0 ? completions : [{
value: "No matching commands",
error: 1
}];
}
});
};
prompt.modes = function(editor, callback) {
var modesArray = modelist.modes;
modesArray = modesArray.map(function(item) {
return {value: item.caption, mode: item.name};
});
prompt(editor, "", {
name: "modes",
selection: [0, Number.MAX_VALUE],
onAccept: function(data) {
if (data.item) {
var modeName = "ace/mode/" + data.item.mode;
editor.session.setMode(modeName);
}
},
getPrefix: function(cmdLine) {
var currentPos = cmdLine.getCursorPosition();
var filterValue = cmdLine.getValue();
return filterValue.substring(0, currentPos.column);
},
getCompletions: function(cmdLine) {
function getFilteredCompletions(modes, prefix) {
var resultCommands = JSON.parse(JSON.stringify(modes));
var filtered = new FilteredList(resultCommands);
return filtered.filterCompletions(resultCommands, prefix);
}
var prefix = this.getPrefix(cmdLine);
var completions = getFilteredCompletions(modesArray, prefix);
return completions.length > 0 ? completions : [{
"caption": "No mode matching",
"value": "No mode matching",
"error": 1
}];
}
});
};
dom.importCssString(".ace_prompt_container {\
max-width: 600px;\
width: 100%;\
margin: 20px auto;\
padding: 3px;\
background: white;\
border-radius: 2px;\
box-shadow: 0px 2px 3px 0px #555;\
}");
exports.prompt = prompt;
});