ace/demo/kitchen-sink/demo.js
Garen Torikian 3bbfc457ae Minor updates
2012-09-11 10:20:22 +04:00

774 lines
24 KiB
JavaScript

/* ***** 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";
require("ace/lib/fixoldbrowsers");
require("ace/config").init();
var env = {};
var dom = require("ace/lib/dom");
var net = require("ace/lib/net");
var lang = require("ace/lib/lang");
var useragent = require("ace/lib/useragent");
var event = require("ace/lib/event");
var theme = require("ace/theme/textmate");
var EditSession = require("ace/edit_session").EditSession;
var UndoManager = require("ace/undomanager").UndoManager;
var vim = require("ace/keyboard/vim").handler;
var emacs = require("ace/keyboard/emacs").handler;
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
var Renderer = require("ace/virtual_renderer").VirtualRenderer;
var Editor = require("ace/editor").Editor;
var MultiSelect = require("ace/multi_select").MultiSelect;
// workers do not work for file:
if (location.protocol == "file:")
EditSession.prototype.$useWorker = false;
/************** modes ***********************/
var modes = [];
function getModeFromPath(path) {
var mode = modesByName.text;
for (var i = 0; i < modes.length; i++) {
if (modes[i].supportsFile(path)) {
mode = modes[i];
break;
}
}
return mode;
};
var Mode = function(name, desc, extensions) {
this.name = name;
this.desc = desc;
this.mode = "ace/mode/" + name;
this.extRe = new RegExp("^.*\\.(" + extensions + ")$", "g");
};
Mode.prototype.supportsFile = function(filename) {
return filename.match(this.extRe);
};
var modesByName = {
c9search: ["C9Search" , "c9search_results"],
coffee: ["CoffeeScript" , "coffee|^Cakefile"],
coldfusion: ["ColdFusion" , "cfm"],
csharp: ["C#" , "cs"],
css: ["CSS" , "css"],
diff: ["Diff" , "diff|patch"],
glsl: ["Glsl" , "glsl|frag|vert"],
golang: ["Go" , "go"],
groovy: ["Groovy" , "groovy"],
haxe: ["haXe" , "hx"],
html: ["HTML" , "htm|html|xhtml"],
c_cpp: ["C/C++" , "c|cc|cpp|cxx|h|hh|hpp"],
clojure: ["Clojure" , "clj"],
jade: ["Jade" , "jade"],
java: ["Java" , "java"],
javascript: ["JavaScript" , "js"],
json: ["JSON" , "json"],
jsx: ["JSX" , "jsx"],
latex: ["LaTeX" , "latex|tex|ltx|bib"],
less: ["LESS" , "less"],
liquid: ["Liquid" , "liquid"],
lua: ["Lua" , "lua"],
luapage: ["LuaPage" , "lp"], // http://keplerproject.github.com/cgilua/manual.html#templates
markdown: ["Markdown" , "md|markdown"],
ocaml: ["OCaml" , "ml|mli"],
perl: ["Perl" , "pl|pm"],
pgsql: ["pgSQL" , "pgsql"],
php: ["PHP" , "php|phtml"],
powershell: ["Powershell" , "ps1"],
python: ["Python" , "py"],
ruby: ["Ruby" , "ru|gemspec|rake|rb"],
scad: ["OpenSCAD" , "scad"],
scala: ["Scala" , "scala"],
scss: ["SCSS" , "scss|sass"],
sh: ["SH" , "sh|bash|bat"],
sql: ["SQL" , "sql"],
svg: ["SVG" , "svg"],
tcl: ["Tcl" , "tcl"],
text: ["Text" , "txt"],
textile: ["Textile" , "textile"],
xml: ["XML" , "xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl"],
xquery: ["XQuery" , "xq"],
yaml: ["YAML" , "yaml"]
};
for (var name in modesByName) {
var mode = modesByName[name];
mode = new Mode(name, mode[0], mode[1])
modesByName[name] = mode;
modes.push(mode);
}
/*********** demo documents ***************************/
var fileCache = {};
function initDoc(file, path, doc) {
if (doc.prepare)
file = doc.prepare(file);
var session = new EditSession(file);
session.setUndoManager(new UndoManager());
doc.session = session;
doc.path = path;
if (doc.wrapped) {
session.setUseWrapMode(true);
session.setWrapLimitRange(80, 80);
}
var mode = getModeFromPath(path)
session.modeName = mode.name;
session.setMode(mode.mode);
}
function makeHuge(txt) {
for (var i = 0; i < 5; i++)
txt += txt;
return txt
}
var docs = {
"docs/javascript.js": "JavaScript",
"docs/clojure.clj": "Clojure",
"docs/coffeescript.coffee": "Coffeescript",
"docs/coldfusion.cfm": "ColdFusion",
"docs/cpp.cpp": "C/C++",
"docs/csharp.cs": "C#",
"docs/css.css": "CSS",
"docs/diff.diff": "Diff",
"docs/glsl.glsl": "Glsl",
"docs/golang.go": "Go",
"docs/groovy.groovy": "Groovy",
"docs/Haxe.hx": "haXe",
"docs/html.html": "HTML",
"docs/jade.jade": "Jade",
"docs/java.java": "Java",
"docs/json.json": "JSON",
"docs/jsx.jsx": "JSX",
"docs/latex.tex": {name: "LaTeX", wrapped: true},
"docs/less.less": "LESS",
"docs/liquid.liquid": "Liquid",
"docs/lua.lua": "Lua",
"docs/luapage.lp": "LuaPage",
"docs/markdown.md": {name: "Markdown", wrapped: true},
"docs/ocaml.ml": "OCaml",
"docs/OpenSCAD.scad": "OpenSCAD",
"docs/perl.pl": "Perl",
"docs/pgsql.pgsql": {name: "pgSQL", wrapped: true},
"docs/php.php": "PHP",
"docs/plaintext.txt": {name: "Plain Text", prepare: makeHuge, wrapped: true},
"docs/powershell.ps1": "Powershell",
"docs/python.py": "Python",
"docs/ruby.rb": "Ruby",
"docs/scala.scala": "Scala",
"docs/scss.scss": "SCSS",
"docs/sh.sh": "SH",
"docs/sql.sql": {name: "SQL", wrapped: true},
"docs/svg.svg": "SVG",
"docs/tcl.tcl": "Tcl",
"docs/textile.textile": {name: "Textile", wrapped: true},
"docs/xml.xml": "XML",
"docs/xquery.xq": "XQuery",
"docs/yaml.yaml": "YAML",
"docs/c9search.c9search_results": "C9 Search Results"
}
var ownSource = {
/* filled from require*/
};
var hugeDocs = {
"build/src/ace.js": "",
"build/src-min/ace.js": ""
};
if (window.require && window.require.s) try {
for (var path in window.require.s.contexts._.loaded) {
if (path.indexOf("!") != -1)
path = path.split("!").pop();
else
path = path + ".js";
ownSource[path] = ""
}
} catch(e) {}
function prepareDocList(docs) {
var list = []
for (var path in docs) {
var doc = docs[path];
if (typeof doc != "object")
doc = {name: doc || path};
doc.path = path;
doc.desc = doc.name.replace(/^(ace|docs|demo|build)\//, "");
if (doc.desc.length > 18)
doc.desc = doc.desc.slice(0, 7) + ".." + doc.desc.slice(-9)
fileCache[doc.name] = doc;
list.push(doc);
};
return list;
}
docs = prepareDocList(docs);
ownSource = prepareDocList(ownSource);
hugeDocs = prepareDocList(hugeDocs);
/*********** create editor ***************************/
var container = document.getElementById("editor");
// Splitting.
var Split = require("ace/split").Split;
var split = new Split(container, theme, 1);
env.editor = split.getEditor(0);
split.on("focus", function(editor) {
env.editor = editor;
updateUIEditorOptions();
});
env.split = split;
window.env = env;
window.ace = env.editor;
env.editor.setAnimatedScroll(true);
var consoleEl = dom.createElement("div");
container.parentNode.appendChild(consoleEl);
consoleEl.style.position="fixed"
consoleEl.style.bottom = "1px"
consoleEl.style.right = 0
consoleEl.style.background = "white"
consoleEl.style.border = "1px solid #baf"
consoleEl.style.zIndex = "100"
var cmdLine = new singleLineEditor(consoleEl);
cmdLine.editor = env.editor;
env.editor.cmdLine = cmdLine;
env.editor.commands.addCommands([{
name: "gotoline",
bindKey: {win: "Ctrl-L", mac: "Command-L"},
exec: function(editor, line) {
if (typeof line == "object") {
var arg = this.name + " " + editor.getCursorPosition().row;
editor.cmdLine.setValue(arg, 1)
editor.cmdLine.focus()
return
}
line = parseInt(line, 10);
if (!isNaN(line))
editor.gotoLine(line);
},
readOnly: true
}, {
name: "find",
bindKey: {win: "Ctrl-F", mac: "Command-F"},
exec: function(editor, needle) {
if (typeof needle == "object") {
var arg = this.name + " " + editor.getCopyText()
editor.cmdLine.setValue(arg, 1)
editor.cmdLine.focus()
return
}
editor.find(needle);
},
readOnly: true
}, {
name: "focusCommandLine",
bindKey: "shift-esc",
exec: function(editor, needle) { editor.cmdLine.focus(); },
readOnly: true
}])
cmdLine.commands.bindKeys({
"Shift-Return|Ctrl-Return|Alt-Return": function(cmdLine) { cmdLine.insert("\n")},
"Esc|Shift-Esc": function(cmdLine){ cmdLine.editor.focus(); },
"Return": function(cmdLine){
var command = cmdLine.getValue().split(/\s+/);
var editor = cmdLine.editor;
editor.commands.exec(command[0], editor, command[1]);
editor.focus();
},
})
cmdLine.commands.removeCommands(["find", "gotoline", "findall", "replace", "replaceall"])
/**
* This demonstrates how you can define commands and bind shortcuts to them.
*/
var commands = env.editor.commands;
commands.addCommand({
name: "save",
bindKey: {win: "Ctrl-S", mac: "Command-S"},
exec: function() {alert("Fake Save File");}
});
var keybindings = {
// Null = use "default" keymapping
ace: null,
vim: vim,
emacs: emacs,
// This is a way to define simple keyboard remappings
custom: new HashHandler({
"gotoright": "Tab",
"indent": "]",
"outdent": "[",
"gotolinestart": "^",
"gotolineend": "$"
})
};
/*********** manage layout ***************************/
var consoleHight = 20;
function onResize() {
var left = env.split.$container.offsetLeft;
var width = document.documentElement.clientWidth - left;
container.style.width = width + "px";
container.style.height = document.documentElement.clientHeight - consoleHight + "px";
env.split.resize();
consoleEl.style.width = width + "px";
cmdLine.resize()
}
window.onresize = onResize;
onResize();
/*********** options pane ***************************/
var docEl = document.getElementById("doc");
var modeEl = document.getElementById("mode");
var wrapModeEl = document.getElementById("soft_wrap");
var themeEl = document.getElementById("theme");
var foldingEl = document.getElementById("folding");
var selectStyleEl = document.getElementById("select_style");
var highlightActiveEl = document.getElementById("highlight_active");
var showHiddenEl = document.getElementById("show_hidden");
var showGutterEl = document.getElementById("show_gutter");
var showPrintMarginEl = document.getElementById("show_print_margin");
var highlightSelectedWordE = document.getElementById("highlight_selected_word");
var showHScrollEl = document.getElementById("show_hscroll");
var animateScrollEl = document.getElementById("animate_scroll");
var softTabEl = document.getElementById("soft_tab");
var behavioursEl = document.getElementById("enable_behaviours");
var group = document.createElement("optgroup");
group.setAttribute("label", "Mode Examples");
fillDropdown(docs, group);
docEl.appendChild(group);
var group = document.createElement("optgroup");
group.setAttribute("label", "Huge documents");
fillDropdown(hugeDocs, group);
docEl.appendChild(group);
var group = document.createElement("optgroup");
group.setAttribute("label", "own source");
fillDropdown(ownSource, group);
docEl.appendChild(group);
fillDropdown(modes, modeEl);
bindDropdown("mode", function(value) {
env.editor.getSession().setMode(modesByName[value].mode || modesByName.text.mode);
env.editor.getSession().modeName = value;
});
bindDropdown("doc", function(name) {
var doc = fileCache[name];
if (!doc)
return;
if (doc.session)
return setSession(doc.session)
//@todo do something while waiting
// env.editor.setSession(emptySession || (emptySession = new EditSession("")))
var path = doc.path;
var parts = path.split("/");
if (parts[0] == "docs")
path = "demo/kitchen-sink/" + path;
else if (parts[0] == "ace")
path = "lib/" + path;
net.get(path, function(x) {
initDoc(x, path, doc);
setSession(doc.session)
})
function setSession(session) {
var session = env.split.setSession(session);
updateUIEditorOptions();
env.editor.focus();
}
});
function updateUIEditorOptions() {
var editor = env.editor;
var session = editor.session;
session.setFoldStyle(foldingEl.value);
saveOption(docEl, session.name);
saveOption(modeEl, session.modeName || "text");
saveOption(wrapModeEl, session.getUseWrapMode() ? session.getWrapLimitRange().min || "free" : "off");
saveOption(selectStyleEl, editor.getSelectionStyle() == "line");
saveOption(themeEl, editor.getTheme());
saveOption(highlightActiveEl, editor.getHighlightActiveLine());
saveOption(showHiddenEl, editor.getShowInvisibles());
saveOption(showGutterEl, editor.renderer.getShowGutter());
saveOption(showPrintMarginEl, editor.renderer.getShowPrintMargin());
saveOption(highlightSelectedWordE, editor.getHighlightSelectedWord());
saveOption(showHScrollEl, editor.renderer.getHScrollBarAlwaysVisible());
saveOption(animateScrollEl, editor.getAnimatedScroll());
saveOption(softTabEl, session.getUseSoftTabs());
saveOption(behavioursEl, editor.getBehavioursEnabled());
}
function saveOption(el, val) {
if (!el.onchange && !el.onclick)
return;
if ("checked" in el) {
if (val !== undefined)
el.checked = val;
localStorage && localStorage.setItem(el.id, el.checked ? 1 : 0);
}
else {
if (val !== undefined)
el.value = val;
localStorage && localStorage.setItem(el.id, el.value);
}
}
event.addListener(themeEl, "mouseover", function(e){
this.desiredValue = e.target.value;
if (!this.$timer)
this.$timer = setTimeout(this.updateTheme);
})
event.addListener(themeEl, "mouseout", function(e){
this.desiredValue = null;
if (!this.$timer)
this.$timer = setTimeout(this.updateTheme, 20);
})
themeEl.updateTheme = function(){
env.split.setTheme(themeEl.desiredValue || themeEl.selectedValue);
themeEl.$timer = null;
}
bindDropdown("theme", function(value) {
if (!value)
return;
env.editor.setTheme(value);
themeEl.selectedValue = value;
});
bindDropdown("keybinding", function(value) {
env.editor.setKeyboardHandler(keybindings[value]);
});
bindDropdown("fontsize", function(value) {
env.split.setFontSize(value);
});
bindDropdown("folding", function(value) {
env.editor.getSession().setFoldStyle(value);
env.editor.setShowFoldWidgets(value !== "manual");
});
bindDropdown("soft_wrap", function(value) {
var session = env.editor.getSession();
var renderer = env.editor.renderer;
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;
}
});
bindCheckbox("select_style", function(checked) {
env.editor.setSelectionStyle(checked ? "line" : "text");
});
bindCheckbox("highlight_active", function(checked) {
env.editor.setHighlightActiveLine(checked);
});
bindCheckbox("show_hidden", function(checked) {
env.editor.setShowInvisibles(checked);
});
bindCheckbox("display_indent_guides", function(checked) {
env.editor.setDisplayIndentGuides(checked);
});
bindCheckbox("show_gutter", function(checked) {
env.editor.renderer.setShowGutter(checked);
});
bindCheckbox("show_print_margin", function(checked) {
env.editor.renderer.setShowPrintMargin(checked);
});
bindCheckbox("highlight_selected_word", function(checked) {
env.editor.setHighlightSelectedWord(checked);
});
bindCheckbox("show_hscroll", function(checked) {
env.editor.renderer.setHScrollBarAlwaysVisible(checked);
});
bindCheckbox("animate_scroll", function(checked) {
env.editor.setAnimatedScroll(checked);
});
bindCheckbox("soft_tab", function(checked) {
env.editor.getSession().setUseSoftTabs(checked);
});
bindCheckbox("enable_behaviours", function(checked) {
env.editor.setBehavioursEnabled(checked);
});
bindCheckbox("fade_fold_widgets", function(checked) {
env.editor.setFadeFoldWidgets(checked);
});
var secondSession = null;
bindDropdown("split", function(value) {
var sp = env.split;
if (value == "none") {
if (sp.getSplits() == 2) {
secondSession = sp.getEditor(1).session;
}
sp.setSplits(1);
} else {
var newEditor = (sp.getSplits() == 1);
if (value == "below") {
sp.setOrientation(sp.BELOW);
} else {
sp.setOrientation(sp.BESIDE);
}
sp.setSplits(2);
if (newEditor) {
var session = secondSession || sp.getEditor(0).session;
var newSession = sp.setSession(session, 1);
newSession.name = session.name;
}
}
});
function bindCheckbox(id, callback) {
var el = document.getElementById(id);
if (localStorage && localStorage.getItem(id))
el.checked = localStorage.getItem(id) == "1";
var onCheck = function() {
callback(!!el.checked);
saveOption(el);
};
el.onclick = onCheck;
onCheck();
}
function bindDropdown(id, callback) {
var el = document.getElementById(id);
if (localStorage && localStorage.getItem(id))
el.value = localStorage.getItem(id);
var onChange = function() {
callback(el.value);
saveOption(el);
};
el.onchange = onChange;
onChange();
}
function fillDropdown(list, el) {
list.forEach(function(item) {
var option = document.createElement("option");
option.setAttribute("value", item.name);
option.innerHTML = item.desc;
el.appendChild(option);
});
}
/************** dragover ***************************/
event.addListener(container, "dragover", function(e) {
return event.preventDefault(e);
});
event.addListener(container, "drop", function(e) {
var file;
try {
file = e.dataTransfer.files[0];
if (window.FileReader) {
var reader = new FileReader();
reader.onload = function() {
var mode = getModeFromPath(file.name);
env.editor.session.doc.setValue(reader.result);
modeEl.value = mode.name;
env.editor.session.setMode(mode.mode);
env.editor.session.modeName = mode.name;
};
reader.readAsText(file);
}
return event.preventDefault(e);
} catch(err) {
return event.stopEvent(e);
}
});
// add multiple cursor support to editor
require("ace/multi_select").MultiSelect(env.editor);
function singleLineEditor(el) {
var renderer = new Renderer(el);
renderer.scrollBar.element.style.display = "none";
renderer.scrollBar.width = 0;
renderer.content.style.height = "auto";
renderer.screenToTextCoordinates = function(x, y) {
var pos = this.pixelToScreenCoordinates(x, y);
return this.session.screenToDocumentPosition(
Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)),
Math.max(pos.column, 0)
);
};
// todo size change event
renderer.$computeLayerConfig = function() {
var longestLine = this.$getLongestLine();
var firstRow = 0;
var lastRow = this.session.getLength();
var height = this.session.getScreenLength() * this.lineHeight;
this.scrollTop = 0;
var config = this.layerConfig;
config.width = longestLine;
config.padding = this.$padding;
config.firstRow = 0;
config.firstRowScreen = 0;
config.lastRow = lastRow;
config.lineHeight = this.lineHeight;
config.characterWidth = this.characterWidth;
config.minHeight = height;
config.maxHeight = height;
config.offset = 0;
config.height = height;
this.$gutterLayer.element.style.marginTop = 0 + "px";
this.content.style.marginTop = 0 + "px";
this.content.style.width = longestLine + 2 * this.$padding + "px";
this.content.style.height = height + "px";
this.scroller.style.height = height + "px";
this.container.style.height = height + "px";
};
renderer.isScrollableBy=function(){return false};
var editor = new Editor(renderer);
new MultiSelect(editor);
editor.session.setUndoManager(new UndoManager());
editor.setHighlightActiveLine(false);
editor.setShowPrintMargin(false);
editor.renderer.setShowGutter(false);
editor.renderer.setHighlightGutterLine(false);
return editor;
};
/** simple statusbar **/
var editor = env.editor;
var statusBarEl = dom.createElement("div");
statusBarEl.style.cssText = "color:gray;position:absolute;right:0;border-left:1px solid";
cmdLine.container.appendChild(statusBarEl);
var statusUpdate = lang.deferredCall(function() {
var status = [];
function add(s, sep) {s && status.push(s, sep || "|")}
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();
statusBarEl.textContent = status.join("");
});
env.editor.on("changeStatus", function() {
statusUpdate.schedule(50);
});
env.editor.on("changeSelection", function() {
statusUpdate.schedule(50);
});
});