move files one level up
This commit is contained in:
parent
112b5f76ed
commit
81df50da2d
86 changed files with 0 additions and 0 deletions
165
LICENSE
Normal file
165
LICENSE
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
298
demo/editor.html
Normal file
298
demo/editor.html
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Editor</title>
|
||||
<meta name="author" content="Fabian Jakobs">
|
||||
|
||||
<style type="text/css" media="screen">
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font: sans-serif;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-family: Arial, Helvetica, sans-serif, Tahoma, Verdana;
|
||||
font-size: 12px;
|
||||
background: rgb(14, 98, 165);
|
||||
color: white;
|
||||
}
|
||||
|
||||
#editor {
|
||||
top: 55px;
|
||||
left: 0px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
#controls {
|
||||
width: 100%;
|
||||
height: 55px;
|
||||
}
|
||||
|
||||
#jump {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border: 1px solid red;
|
||||
z-index: 10000;
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script src="require.js" type="text/javascript" charset="utf-8"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="jump"></div>
|
||||
|
||||
<table id="controls">
|
||||
<tr>
|
||||
<td>
|
||||
<label for="doc">Document:</label>
|
||||
<select id="doc" size="1">
|
||||
<option value="js">JS Document</option>
|
||||
<option value="html">HTML Document</option>
|
||||
<option value="css">CSS Document</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<label for="mode">Mode:</label>
|
||||
<select id="mode" size="1">
|
||||
<option value="text">Plain Text</option>
|
||||
<option value="javascript">JavaScript</option>
|
||||
<option value="xml">XML</option>
|
||||
<option value="html">HTML</option>
|
||||
<option value="css">CSS</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<label for="theme">Theme:</label>
|
||||
<select id="theme" size="1">
|
||||
<option value="ace/theme/TextMate">TextMate</option>
|
||||
<option value="ace/theme/Eclipse">Eclipse</option>
|
||||
<option value="ace/theme/Dawn">Dawn</option>
|
||||
<option value="ace/theme/IdleFingers">idleFingers</option>
|
||||
<option value="ace/theme/Twilight">Twilight</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<label for="select_style">Full line selections</label>
|
||||
<input type="checkbox" name="select_style" id="select_style" checked>
|
||||
</td>
|
||||
<td>
|
||||
<label for="highlight_active">Highlight active line</label>
|
||||
<input type="checkbox" name="highlight_active" id="highlight_active" checked>
|
||||
</td>
|
||||
<td align="right">
|
||||
<img src="logo.png">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="editor">
|
||||
</div>
|
||||
|
||||
<script type="text/editor" id="jstext">function foo(items) {
|
||||
for (var i=0; i<items.length; i++) {
|
||||
alert(items[i] + "juhu";
|
||||
}
|
||||
}</script>
|
||||
|
||||
<script type="text/editor" id="csstext">.text-layer {
|
||||
font-family: Monaco, "Courier New", monospace;
|
||||
font-size: 12px;
|
||||
cursor: text;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/editor" id="htmltext"><html>
|
||||
<head>
|
||||
|
||||
<style type="text/css">
|
||||
.text-layer {
|
||||
font-family: Monaco, "Courier New", monospace;
|
||||
font-size: 12px;
|
||||
cursor: text;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="color:red">Juhu Kinners</h1>
|
||||
</body>
|
||||
</html>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
require(
|
||||
{baseUrl: "../src"},
|
||||
[
|
||||
"ace/lib/event",
|
||||
"ace/Editor",
|
||||
"ace/VirtualRenderer",
|
||||
"ace/theme/TextMate",
|
||||
"ace/Document",
|
||||
"ace/mode/JavaScript",
|
||||
"ace/mode/Css",
|
||||
"ace/mode/Html",
|
||||
"ace/mode/Xml",
|
||||
"ace/mode/Text",
|
||||
"ace/UndoManager"
|
||||
], function(event, Editor, Renderer, theme, Document, JavaScriptMode, CssMode, HtmlMode, XmlMode, TextMode, UndoManager) {
|
||||
|
||||
var docs = {}
|
||||
|
||||
docs.js = new Document(document.getElementById("jstext").innerHTML);
|
||||
docs.js.setMode(new JavaScriptMode());
|
||||
docs.js.setUndoManager(new UndoManager());
|
||||
|
||||
docs.css = new Document(document.getElementById("csstext").innerHTML);
|
||||
docs.css.setMode(new CssMode());
|
||||
docs.css.setUndoManager(new UndoManager());
|
||||
|
||||
docs.html = new Document(document.getElementById("htmltext").innerHTML);
|
||||
docs.html.setMode(new HtmlMode());
|
||||
docs.html.setUndoManager(new UndoManager());
|
||||
|
||||
var docEl = document.getElementById("doc");
|
||||
|
||||
function onDocChange() {
|
||||
var doc = getDoc();
|
||||
editor.setDocument(doc);
|
||||
|
||||
var mode = doc.getMode();
|
||||
if (mode instanceof JavaScriptMode) {
|
||||
modeEl.value = "javascript"
|
||||
}
|
||||
else if (mode instanceof CssMode) {
|
||||
modeEl.value = "css"
|
||||
}
|
||||
else if (mode instanceof HtmlMode) {
|
||||
modeEl.value = "html"
|
||||
}
|
||||
else if (mode instanceof XmlMode) {
|
||||
modeEl.value = "xml"
|
||||
}
|
||||
else {
|
||||
modeEl.value = "text"
|
||||
}
|
||||
|
||||
editor.focus();
|
||||
}
|
||||
docEl.onchange = onDocChange;
|
||||
|
||||
function getDoc() {
|
||||
return docs[docEl.value];
|
||||
}
|
||||
|
||||
var modeEl = document.getElementById("mode");
|
||||
modeEl.onchange = function() {
|
||||
editor.getDocument().setMode(modes[modeEl.value] || modes.text);
|
||||
};
|
||||
|
||||
var modes = {
|
||||
text: new TextMode(),
|
||||
xml: new XmlMode(),
|
||||
html: new HtmlMode(),
|
||||
css: new CssMode(),
|
||||
javascript: new JavaScriptMode()
|
||||
};
|
||||
|
||||
function getMode() {
|
||||
return modes[modeEl.value];
|
||||
}
|
||||
|
||||
var themeEl = document.getElementById("theme");
|
||||
themeEl.onchange = function() {
|
||||
editor.setTheme(themeEl.value);
|
||||
};
|
||||
|
||||
var selectEl = document.getElementById("select_style");
|
||||
selectEl.onchange = function() {
|
||||
if (selectEl.checked) {
|
||||
editor.setSelectionStyle("line");
|
||||
} else {
|
||||
editor.setSelectionStyle("text");
|
||||
}
|
||||
};
|
||||
|
||||
var activeEl = document.getElementById("highlight_active");
|
||||
activeEl.onchange = function() {
|
||||
editor.setHighlightActiveLine(!!activeEl.checked);
|
||||
};
|
||||
|
||||
var container = document.getElementById("editor");
|
||||
var editor = new Editor(new Renderer(container, theme));
|
||||
onDocChange();
|
||||
|
||||
window.jump = function() {
|
||||
var jump = document.getElementById("jump")
|
||||
var cursor = editor.getCursorPosition()
|
||||
var pos = editor.renderer.textToScreenCoordinates(cursor.row, cursor.column);
|
||||
jump.style.left = pos.pageX + "px";
|
||||
jump.style.top = pos.pageY + "px";
|
||||
jump.style.display = "block";
|
||||
}
|
||||
|
||||
function onResize() {
|
||||
container.style.width = (document.documentElement.clientWidth - 4) + "px";
|
||||
container.style.height = (document.documentElement.clientHeight - 55 - 4) + "px";
|
||||
editor.resize();
|
||||
};
|
||||
|
||||
window.onresize = onResize;
|
||||
onResize();
|
||||
|
||||
event.addListener(container, "dragover", function(e) {
|
||||
return event.preventDefault(e);
|
||||
});
|
||||
|
||||
event.addListener(container, "drop", function(e) {
|
||||
try {
|
||||
var file = e.dataTransfer.files[0];
|
||||
} catch(e) {
|
||||
return event.stopEvent();
|
||||
}
|
||||
|
||||
if (window.FileReader) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
editor.getSelection().selectAll();
|
||||
|
||||
var mode = "text";
|
||||
if (/^.*\.js$/i.test(file.name)) {
|
||||
mode = "javascript";
|
||||
} else if (/^.*\.xml$/i.test(file.name)) {
|
||||
mode = "xml";
|
||||
} else if (/^.*\.html$/i.test(file.name)) {
|
||||
mode = "html";
|
||||
} else if (/^.*\.css$/i.test(file.name)) {
|
||||
mode = "css";
|
||||
}
|
||||
|
||||
editor.onTextInput(reader.result);
|
||||
|
||||
modeEl.value = mode;
|
||||
editor.getDocument().setMode(modes[mode]);
|
||||
}
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
return event.preventDefault(e);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
demo/logo.png
Normal file
BIN
demo/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
2397
demo/require.js
Normal file
2397
demo/require.js
Normal file
File diff suppressed because it is too large
Load diff
61
doc/Editor.mm
Normal file
61
doc/Editor.mm
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<map version="0.8.0">
|
||||
<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
|
||||
<node CREATED="1270106801605" ID="Freemind_Link_1615101381" MODIFIED="1270106809036" TEXT="Editor">
|
||||
<node CREATED="1270106809716" ID="_" MODIFIED="1270106896494" POSITION="right" TEXT="core features">
|
||||
<node CREATED="1270106812606" ID="Freemind_Link_941515617" MODIFIED="1270106824625" TEXT="text input"/>
|
||||
<node CREATED="1270106825885" ID="Freemind_Link_871701424" MODIFIED="1270106831385" TEXT="key navigation"/>
|
||||
<node CREATED="1270106831861" ID="Freemind_Link_497186050" MODIFIED="1270106836217" TEXT="shortcuts"/>
|
||||
<node CREATED="1270106836717" ID="Freemind_Link_53741891" MODIFIED="1270106841480" TEXT="copy&paste"/>
|
||||
<node CREATED="1270106842020" ID="Freemind_Link_985111837" MODIFIED="1270106846968" TEXT="drag&drop"/>
|
||||
<node CREATED="1270106849069" ID="Freemind_Link_81832450" MODIFIED="1270106852800" TEXT="selection"/>
|
||||
<node CREATED="1270106853508" ID="Freemind_Link_1490464696" MODIFIED="1270106861072" TEXT="syntax highlighting"/>
|
||||
<node CREATED="1270106861565" ID="Freemind_Link_1400628964" MODIFIED="1270106864776" TEXT="line numbers"/>
|
||||
<node CREATED="1270106865228" ID="Freemind_Link_1547807601" MODIFIED="1270106879192" TEXT="breakpoints (gutter)"/>
|
||||
</node>
|
||||
<node CREATED="1270106901715" ID="Freemind_Link_621059230" MODIFIED="1270106915606" POSITION="right" TEXT="additional features">
|
||||
<node CREATED="1270106916179" ID="Freemind_Link_138436821" MODIFIED="1270106921566" TEXT="column highlight"/>
|
||||
<node CREATED="1271052933294" ID="Freemind_Link_725020862" MODIFIED="1271052942879" TEXT="comment selection"/>
|
||||
<node CREATED="1270106922066" ID="Freemind_Link_1177585742" MODIFIED="1270106928030" TEXT="rectangular selection"/>
|
||||
<node CREATED="1270106928514" ID="Freemind_Link_1778337415" MODIFIED="1270106933390" TEXT="undo/redo"/>
|
||||
<node CREATED="1270106936530" ID="Freemind_Link_1313653586" MODIFIED="1270106939485" TEXT="auto indent"/>
|
||||
<node CREATED="1270106940626" ID="Freemind_Link_785606540" MODIFIED="1270106943653" TEXT="match braces"/>
|
||||
<node CREATED="1270106944617" ID="Freemind_Link_265205410" MODIFIED="1270106951045" TEXT="auto insert of code blocks"/>
|
||||
<node CREATED="1270106951682" ID="Freemind_Link_1064064918" MODIFIED="1270106955581" TEXT="autocomplete"/>
|
||||
<node CREATED="1270106957130" ID="Freemind_Link_1118872285" MODIFIED="1270106964437" TEXT="mark-highlight-variables"/>
|
||||
<node CREATED="1270106965257" ID="Freemind_Link_977412851" MODIFIED="1270106967828" TEXT="code folding"/>
|
||||
<node CREATED="1270106969353" ID="Freemind_Link_1003992965" MODIFIED="1270106972165" TEXT="refactoring"/>
|
||||
</node>
|
||||
<node CREATED="1270106975057" FOLDED="true" ID="Freemind_Link_1471854995" MODIFIED="1270106981986" POSITION="right" TEXT="supported browsers">
|
||||
<node CREATED="1270106983313" ID="Freemind_Link_594954564" MODIFIED="1270106988068" TEXT="IE 6-9"/>
|
||||
<node CREATED="1270106988584" ID="Freemind_Link_1809785833" MODIFIED="1270107014323" TEXT="FF 3 >= 3"/>
|
||||
<node CREATED="1270107000488" ID="Freemind_Link_497511816" MODIFIED="1270107008460" TEXT="Webkit >= 4"/>
|
||||
<node CREATED="1270107015287" ID="Freemind_Link_417983587" MODIFIED="1270107017819" TEXT="Chrome"/>
|
||||
<node CREATED="1270107018191" ID="Freemind_Link_393314987" MODIFIED="1270107038858" TEXT="Opera 9 or >= 10?"/>
|
||||
</node>
|
||||
<node CREATED="1271052795069" ID="Freemind_Link_674657297" MODIFIED="1271061756598" POSITION="left" TEXT="Ideas">
|
||||
<node CREATED="1271052800596" ID="Freemind_Link_1094064295" MODIFIED="1271052804602" TEXT="jsTestDriver"/>
|
||||
<node CREATED="1271052805542" FOLDED="true" ID="Freemind_Link_1473541975" MODIFIED="1271052813414" TEXT="Bindings">
|
||||
<node CREATED="1271052813802" ID="Freemind_Link_779313331" MODIFIED="1271052821938" TEXT="jquery"/>
|
||||
<node CREATED="1271052822527" ID="Freemind_Link_467300132" MODIFIED="1271052825604" TEXT="yql"/>
|
||||
<node CREATED="1271052825952" ID="Freemind_Link_622561431" MODIFIED="1271052828013" TEXT="qooxdoo"/>
|
||||
<node CREATED="1271052830859" ID="Freemind_Link_18779066" MODIFIED="1271052833496" TEXT="APF!"/>
|
||||
</node>
|
||||
<node CREATED="1271052839079" ID="Freemind_Link_439583810" MODIFIED="1271052852530" TEXT="Options">
|
||||
<node CREATED="1271052853166" ID="Freemind_Link_629899491" MODIFIED="1271052860101" TEXT="Tabs to spaces"/>
|
||||
<node CREATED="1271052862867" ID="Freemind_Link_746641062" MODIFIED="1271052866129" TEXT="Spaces to tabs"/>
|
||||
<node CREATED="1271052866517" ID="Freemind_Link_192666733" MODIFIED="1271052869210" TEXT="tab width"/>
|
||||
<node CREATED="1271052879027" ID="Freemind_Link_778966191" MODIFIED="1271052882825" TEXT="Language switch">
|
||||
<node CREATED="1271052883285" ID="Freemind_Link_436205918" MODIFIED="1271052895231" TEXT="highlighting"/>
|
||||
<node CREATED="1271052896052" ID="Freemind_Link_799407328" MODIFIED="1271052900474" TEXT="indent/outdent"/>
|
||||
<node CREATED="1271052900934" ID="Freemind_Link_62594174" MODIFIED="1271052907981" TEXT="comment block"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1271061753644" ID="Freemind_Link_1898747747" MODIFIED="1271061761714" POSITION="left" TEXT="Competition">
|
||||
<node CREATED="1271061762151" ID="Freemind_Link_248244633" MODIFIED="1271061764275" TEXT="bespin"/>
|
||||
<node CREATED="1271061764616" ID="Freemind_Link_1186004994" MODIFIED="1271061768509" TEXT="codeMirror"/>
|
||||
<node CREATED="1271061780744" ID="Freemind_Link_457888774" LINK="http://www.cdolivet.com/index.php?page=editArea" MODIFIED="1271061808808" TEXT="editarea"/>
|
||||
<node CREATED="1271061827047" ID="Freemind_Link_1466305116" LINK="http://www.amyeditor.com/" MODIFIED="1271061845504" TEXT="Amy editor"/>
|
||||
</node>
|
||||
</node>
|
||||
</map>
|
||||
17
package.json
Normal file
17
package.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "ace",
|
||||
"description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE",
|
||||
"version": "0.1",
|
||||
"homepage" : "http://github.com/ajaxorg/editor",
|
||||
"engines": {"node": ">= 0.1.102"},
|
||||
"author": "Fabian Jakobs <fabian@ajax.org>",
|
||||
"main": "src/ace/ace",
|
||||
"repository" : {
|
||||
"type" : "git",
|
||||
"url" : "http://github.com/ajaxorg/editor.git"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "LGPLv3",
|
||||
"url": "http://www.gnu.org/licenses/lgpl-3.0.txt"}
|
||||
]
|
||||
}
|
||||
132
src/ace/BackgroundTokenizer.js
Normal file
132
src/ace/BackgroundTokenizer.js
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/BackgroundTokenizer", ["ace/lib/oop", "ace/MEventEmitter"], function(oop, MEventEmitter) {
|
||||
|
||||
var BackgroundTokenizer = function(tokenizer, editor) {
|
||||
this.running = false;
|
||||
this.textLines = [];
|
||||
this.lines = [];
|
||||
this.currentLine = 0;
|
||||
this.tokenizer = tokenizer;
|
||||
|
||||
var self = this;
|
||||
|
||||
this.$worker = function() {
|
||||
if (!self.running) { return; }
|
||||
|
||||
var workerStart = new Date();
|
||||
var startLine = self.currentLine;
|
||||
var textLines = self.textLines;
|
||||
|
||||
var processedLines = 0;
|
||||
var lastVisibleRow = editor.getLastVisibleRow();
|
||||
|
||||
while (self.currentLine < textLines.length) {
|
||||
self.lines[self.currentLine] = self.$tokenizeRows(self.currentLine, self.currentLine)[0];
|
||||
self.currentLine++;
|
||||
|
||||
// only check every 5 lines
|
||||
processedLines += 1;
|
||||
if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
|
||||
self.fireUpdateEvent(startLine, self.currentLine-1);
|
||||
|
||||
var timeout = self.currentLine < lastVisibleRow ? 20 : 100;
|
||||
self.running = setTimeout(self.$worker, timeout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.running = false;
|
||||
|
||||
self.fireUpdateEvent(startLine, textLines.length - 1);
|
||||
};
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
oop.implement(this, MEventEmitter);
|
||||
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.tokenizer = tokenizer;
|
||||
this.lines = [];
|
||||
|
||||
this.start(0);
|
||||
};
|
||||
|
||||
this.setLines = function(textLines) {
|
||||
this.textLines = textLines;
|
||||
this.lines = [];
|
||||
|
||||
this.stop();
|
||||
};
|
||||
|
||||
this.fireUpdateEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
this.$dispatchEvent("update", {data: data});
|
||||
};
|
||||
|
||||
this.start = function(startRow) {
|
||||
this.currentLine = Math.min(startRow || 0, this.currentLine,
|
||||
this.textLines.length);
|
||||
|
||||
// remove all cached items below this line
|
||||
this.lines.splice(this.currentLine, this.lines.length);
|
||||
|
||||
this.stop();
|
||||
// pretty long delay to prevent the tokenizer from interfering with the user
|
||||
this.running = setTimeout(this.$worker, 700);
|
||||
};
|
||||
|
||||
this.stop = function() {
|
||||
if (this.running)
|
||||
clearTimeout(this.running);
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
this.getTokens = function(firstRow, lastRow, callback) {
|
||||
callback(this.$tokenizeRows(firstRow, lastRow));
|
||||
};
|
||||
|
||||
this.getState = function(row, callback) {
|
||||
callback(this.$tokenizeRows(row, row)[0].state);
|
||||
};
|
||||
|
||||
this.$tokenizeRows = function(firstRow, lastRow) {
|
||||
var rows = [];
|
||||
|
||||
// determine start state
|
||||
var state = "start";
|
||||
var doCache = false;
|
||||
if (firstRow > 0 && this.lines[firstRow - 1]) {
|
||||
state = this.lines[firstRow - 1].state;
|
||||
doCache = true;
|
||||
}
|
||||
|
||||
for (var row=firstRow; row<=lastRow; row++) {
|
||||
if (!this.lines[row]) {
|
||||
var tokens = this.tokenizer.getLineTokens(this.textLines[row] || "", state);
|
||||
var state = tokens.state;
|
||||
rows.push(tokens);
|
||||
|
||||
if (doCache) {
|
||||
this.lines[row] = tokens;
|
||||
}
|
||||
}
|
||||
else
|
||||
rows.push(this.lines[row]);
|
||||
}
|
||||
return rows;
|
||||
};
|
||||
|
||||
}).call(BackgroundTokenizer.prototype);
|
||||
|
||||
return BackgroundTokenizer;
|
||||
});
|
||||
687
src/ace/Document.js
Normal file
687
src/ace/Document.js
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/Document",
|
||||
[
|
||||
"ace/lib/oop",
|
||||
"ace/lib/lang",
|
||||
"ace/MEventEmitter",
|
||||
"ace/Selection",
|
||||
"ace/mode/Text",
|
||||
"ace/Range"
|
||||
], function(oop, lang, MEventEmitter, Selection, TextMode, Range) {
|
||||
|
||||
var Document = function(text, mode) {
|
||||
this.modified = true;
|
||||
this.lines = [];
|
||||
this.selection = new Selection(this);
|
||||
this.$breakpoints = [];
|
||||
|
||||
this.listeners = [];
|
||||
if (mode) {
|
||||
this.setMode(mode);
|
||||
}
|
||||
|
||||
if (lang.isArray(text)) {
|
||||
this.$insertLines(0, text);
|
||||
} else {
|
||||
this.$insert({row: 0, column: 0}, text);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, MEventEmitter);
|
||||
|
||||
this.$undoManager = null;
|
||||
|
||||
this.$split = function(text) {
|
||||
return text.split(/\r\n|\r|\n/);
|
||||
};
|
||||
|
||||
this.setValue = function(text) {
|
||||
var args = [0, this.lines.length];
|
||||
args.push.apply(args, this.$split(text));
|
||||
this.lines.splice.apply(this.lines, args);
|
||||
this.modified = true;
|
||||
this.fireChangeEvent(0);
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return this.lines.join(this.$getNewLineCharacter());
|
||||
};
|
||||
|
||||
this.getSelection = function() {
|
||||
return this.selection;
|
||||
};
|
||||
|
||||
this.fireChangeEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
firstRow: firstRow,
|
||||
lastRow: lastRow
|
||||
};
|
||||
this.$dispatchEvent("change", { data: data});
|
||||
};
|
||||
|
||||
this.setUndoManager = function(undoManager) {
|
||||
this.$undoManager = undoManager;
|
||||
this.$deltas = [];
|
||||
|
||||
if (this.$informUndoManager) {
|
||||
this.$informUndoManager.cancel();
|
||||
}
|
||||
|
||||
if (undoManager) {
|
||||
//undoManager.setDocument(this);
|
||||
var self = this;
|
||||
this.$informUndoManager = lang.deferredCall(function() {
|
||||
if (self.$deltas.length > 0)
|
||||
undoManager.execute({
|
||||
action : "aceupdate",
|
||||
args : [self.$deltas, self]
|
||||
});
|
||||
self.$deltas = [];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.$defaultUndoManager = {
|
||||
undo: function() {},
|
||||
redo: function() {}
|
||||
};
|
||||
|
||||
this.getUndoManager = function() {
|
||||
return this.$undoManager || this.$defaultUndoManager;
|
||||
},
|
||||
|
||||
this.getTabString = function() {
|
||||
if (this.getUseSoftTabs()) {
|
||||
return lang.stringRepeat(" ", this.getTabSize());
|
||||
} else {
|
||||
return "\t";
|
||||
}
|
||||
};
|
||||
|
||||
this.$useSoftTabs = true;
|
||||
this.setUseSoftTabs = function(useSoftTabs) {
|
||||
if (this.$useSoftTabs === useSoftTabs) return;
|
||||
|
||||
this.$useSoftTabs = useSoftTabs;
|
||||
};
|
||||
|
||||
this.getUseSoftTabs = function() {
|
||||
return this.$useSoftTabs;
|
||||
};
|
||||
|
||||
this.$tabSize = 4;
|
||||
this.setTabSize = function(tabSize) {
|
||||
if (isNaN(tabSize) || this.$tabSize === tabSize) return;
|
||||
|
||||
this.modified = true;
|
||||
this.$tabSize = tabSize;
|
||||
this.$dispatchEvent("changeTabSize");
|
||||
};
|
||||
|
||||
this.getTabSize = function() {
|
||||
return this.$tabSize;
|
||||
};
|
||||
|
||||
this.getBreakpoints = function() {
|
||||
return this.$breakpoints;
|
||||
};
|
||||
|
||||
this.setBreakpoints = function(rows) {
|
||||
this.$breakpoints = [];
|
||||
for (var i=0; i<rows.length; i++) {
|
||||
this.$breakpoints[rows[i]] = true;
|
||||
}
|
||||
this.$dispatchEvent("changeBreakpoint", {});
|
||||
};
|
||||
|
||||
this.clearBreakpoints = function() {
|
||||
this.$breakpoints = [];
|
||||
this.$dispatchEvent("changeBreakpoint", {});
|
||||
};
|
||||
|
||||
this.setBreakpoint = function(row) {
|
||||
this.$breakpoints[row] = true;
|
||||
this.$dispatchEvent("changeBreakpoint", {});
|
||||
};
|
||||
|
||||
this.clearBreakpoint = function(row) {
|
||||
delete this.$breakpoints[row];
|
||||
this.$dispatchEvent("changeBreakpoint", {});
|
||||
};
|
||||
|
||||
this.$detectNewLine = function(text) {
|
||||
var match = text.match(/^.*?(\r?\n)/m);
|
||||
if (match) {
|
||||
this.$autoNewLine = match[1];
|
||||
} else {
|
||||
this.$autoNewLine = "\n";
|
||||
}
|
||||
};
|
||||
|
||||
this.$getNewLineCharacter = function() {
|
||||
switch (this.$newLineMode) {
|
||||
case "windows":
|
||||
return "\r\n";
|
||||
|
||||
case "unix":
|
||||
return "\n";
|
||||
|
||||
case "auto":
|
||||
return this.$autoNewLine;
|
||||
}
|
||||
},
|
||||
|
||||
this.$autoNewLine = "\n";
|
||||
this.$newLineMode = "auto";
|
||||
this.setNewLineMode = function(newLineMode) {
|
||||
if (this.$newLineMode === newLineMode) return;
|
||||
|
||||
this.$newLineMode = newLineMode;
|
||||
};
|
||||
|
||||
this.getNewLineMode = function() {
|
||||
return this.$newLineMode;
|
||||
};
|
||||
|
||||
this.$mode = null;
|
||||
this.setMode = function(mode) {
|
||||
if (this.$mode === mode) return;
|
||||
|
||||
this.$mode = mode;
|
||||
this.$dispatchEvent("changeMode");
|
||||
};
|
||||
|
||||
this.getMode = function() {
|
||||
if (!this.$mode) {
|
||||
this.$mode = new TextMode();
|
||||
}
|
||||
return this.$mode;
|
||||
};
|
||||
|
||||
this.$scrollTop = 0;
|
||||
this.setScrollTopRow = function(scrollTopRow) {
|
||||
if (this.$scrollTop === scrollTopRow) return;
|
||||
|
||||
this.$scrollTop = scrollTopRow;
|
||||
this.$dispatchEvent("changeScrollTop");
|
||||
};
|
||||
|
||||
this.getScrollTopRow = function() {
|
||||
return this.$scrollTop;
|
||||
};
|
||||
|
||||
this.getWidth = function() {
|
||||
this.$computeWidth();
|
||||
return this.width;
|
||||
};
|
||||
|
||||
this.getScreenWidth = function() {
|
||||
this.$computeWidth();
|
||||
return this.screenWith;
|
||||
};
|
||||
|
||||
this.$computeWidth = function() {
|
||||
if (this.modified) {
|
||||
this.modified = false;
|
||||
|
||||
var lines = this.lines;
|
||||
var longestLine = 0;
|
||||
var longestScreenLine = 0;
|
||||
var tabSize = this.getTabSize();
|
||||
|
||||
for ( var i = 0; i < lines.length; i++) {
|
||||
var len = lines[i].length;
|
||||
longestLine = Math.max(longestLine, len);
|
||||
|
||||
lines[i].replace("\t", function(m) {
|
||||
len += tabSize-1;
|
||||
return m;
|
||||
});
|
||||
longestScreenLine = Math.max(longestScreenLine, len);
|
||||
}
|
||||
this.width = longestLine;
|
||||
this.screenWith = longestScreenLine;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a verbatim copy of the given line as it is in the document
|
||||
*/
|
||||
this.getLine = function(row) {
|
||||
return this.lines[row] || "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a line as it is displayed on screen. Tabs are replaced by spaces.
|
||||
*/
|
||||
this.getDisplayLine = function(row) {
|
||||
var tab = new Array(this.getTabSize()+1).join(" ");
|
||||
return this.lines[row].replace(/\t/g, tab);
|
||||
};
|
||||
|
||||
this.getLines = function(firstRow, lastRow) {
|
||||
return this.lines.slice(firstRow, lastRow+1);
|
||||
};
|
||||
|
||||
this.getLength = function() {
|
||||
return this.lines.length;
|
||||
};
|
||||
|
||||
this.getTextRange = function(range) {
|
||||
if (range.start.row == range.end.row) {
|
||||
return this.lines[range.start.row].substring(range.start.column,
|
||||
range.end.column);
|
||||
}
|
||||
else {
|
||||
var lines = [];
|
||||
lines.push(this.lines[range.start.row].substring(range.start.column));
|
||||
lines.push.apply(lines, this.getLines(range.start.row+1, range.end.row-1));
|
||||
lines.push(this.lines[range.end.row].substring(0, range.end.column));
|
||||
return lines.join(this.$getNewLineCharacter());
|
||||
}
|
||||
};
|
||||
|
||||
this.findMatchingBracket = function(position) {
|
||||
if (position.column == 0) return null;
|
||||
|
||||
var charBeforeCursor = this.getLine(position.row).charAt(position.column-1);
|
||||
if (charBeforeCursor == "") return null;
|
||||
|
||||
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (match[1]) {
|
||||
return this.$findClosingBracket(match[1], position);
|
||||
} else {
|
||||
return this.$findOpeningBracket(match[2], position);
|
||||
}
|
||||
};
|
||||
|
||||
this.$brackets = {
|
||||
")": "(",
|
||||
"(": ")",
|
||||
"]": "[",
|
||||
"[": "]",
|
||||
"{": "}",
|
||||
"}": "{"
|
||||
};
|
||||
|
||||
this.$findOpeningBracket = function(bracket, position) {
|
||||
var openBracket = this.$brackets[bracket];
|
||||
|
||||
var column = position.column - 2;
|
||||
var row = position.row;
|
||||
var depth = 1;
|
||||
|
||||
var line = this.getLine(row);
|
||||
|
||||
while (true) {
|
||||
while(column >= 0) {
|
||||
var char = line.charAt(column);
|
||||
if (char == openBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: row, column: column};
|
||||
}
|
||||
}
|
||||
else if (char == bracket) {
|
||||
depth +=1;
|
||||
}
|
||||
column -= 1;
|
||||
}
|
||||
row -=1;
|
||||
if (row < 0) break;
|
||||
|
||||
var line = this.getLine(row);
|
||||
var column = line.length-1;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.$findClosingBracket = function(bracket, position) {
|
||||
var closingBracket = this.$brackets[bracket];
|
||||
|
||||
var column = position.column;
|
||||
var row = position.row;
|
||||
var depth = 1;
|
||||
|
||||
var line = this.getLine(row);
|
||||
var lineCount = this.getLength();
|
||||
|
||||
while (true) {
|
||||
while(column < line.length) {
|
||||
var char = line.charAt(column);
|
||||
if (char == closingBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: row, column: column};
|
||||
}
|
||||
}
|
||||
else if (char == bracket) {
|
||||
depth +=1;
|
||||
}
|
||||
column += 1;
|
||||
}
|
||||
row +=1;
|
||||
if (row >= lineCount) break;
|
||||
|
||||
var line = this.getLine(row);
|
||||
var column = 0;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.insert = function(position, text, fromUndo) {
|
||||
var end = this.$insert(position, text, fromUndo);
|
||||
this.fireChangeEvent(position.row, position.row == end.row ? position.row
|
||||
: undefined);
|
||||
return end;
|
||||
};
|
||||
|
||||
this.$insertLines = function(row, lines, fromUndo) {
|
||||
if (lines.length == 0)
|
||||
return;
|
||||
|
||||
var args = [row, 0];
|
||||
args.push.apply(args, lines);
|
||||
this.lines.splice.apply(this.lines, args);
|
||||
|
||||
if (!fromUndo && this.$undoManager) {
|
||||
var nl = this.$getNewLineCharacter();
|
||||
this.$deltas.push({
|
||||
action: "insertText",
|
||||
range: new Range(row, 0, row + lines.length, 0),
|
||||
text: lines.join(nl) + nl
|
||||
});
|
||||
this.$informUndoManager.schedule();
|
||||
}
|
||||
},
|
||||
|
||||
this.$insert = function(position, text, fromUndo) {
|
||||
if (text.length == 0)
|
||||
return position;
|
||||
|
||||
this.modified = true;
|
||||
if (this.lines.length <= 1) {
|
||||
this.$detectNewLine(text);
|
||||
}
|
||||
|
||||
var newLines = this.$split(text);
|
||||
|
||||
if (this.$isNewLine(text)) {
|
||||
var line = this.lines[position.row] || "";
|
||||
this.lines[position.row] = line.substring(0, position.column);
|
||||
this.lines.splice(position.row + 1, 0, line.substring(position.column));
|
||||
|
||||
var end = {
|
||||
row : position.row + 1,
|
||||
column : 0
|
||||
};
|
||||
}
|
||||
else if (newLines.length == 1) {
|
||||
var line = this.lines[position.row] || "";
|
||||
this.lines[position.row] = line.substring(0, position.column) + text
|
||||
+ line.substring(position.column);
|
||||
|
||||
var end = {
|
||||
row : position.row,
|
||||
column : position.column + text.length
|
||||
};
|
||||
}
|
||||
else {
|
||||
var line = this.lines[position.row] || "";
|
||||
var firstLine = line.substring(0, position.column) + newLines[0];
|
||||
var lastLine = newLines[newLines.length - 1] + line.substring(position.column);
|
||||
|
||||
this.lines[position.row] = firstLine;
|
||||
this.$insertLines(position.row + 1, [lastLine], true);
|
||||
|
||||
if (newLines.length > 2) {
|
||||
this.$insertLines(position.row + 1, newLines.slice(1, -1), true);
|
||||
}
|
||||
|
||||
var end = {
|
||||
row : position.row + newLines.length - 1,
|
||||
column : newLines[newLines.length - 1].length
|
||||
};
|
||||
}
|
||||
|
||||
if (!fromUndo && this.$undoManager) {
|
||||
this.$deltas.push({
|
||||
action: "insertText",
|
||||
range: Range.fromPoints(position, end),
|
||||
text: text
|
||||
});
|
||||
this.$informUndoManager.schedule();
|
||||
}
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
this.$isNewLine = function(text) {
|
||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||
};
|
||||
|
||||
this.remove = function(range, fromUndo) {
|
||||
if (range.isEmpty())
|
||||
return range.start;
|
||||
|
||||
this.$remove(range, fromUndo);
|
||||
|
||||
this.fireChangeEvent(range.start.row,
|
||||
!range.isMultiLine() ? range.start.row
|
||||
: undefined);
|
||||
|
||||
return range.start;
|
||||
};
|
||||
|
||||
this.$remove = function(range, fromUndo) {
|
||||
if (range.isEmpty())
|
||||
return;
|
||||
|
||||
if (!fromUndo && this.$undoManager) {
|
||||
var nl = this.$getNewLineCharacter();
|
||||
this.$deltas.push({
|
||||
action: "removeText",
|
||||
range: range.clone(),
|
||||
text: this.getTextRange(range)
|
||||
});
|
||||
this.$informUndoManager.schedule();
|
||||
}
|
||||
|
||||
this.modified = true;
|
||||
|
||||
var firstRow = range.start.row;
|
||||
var lastRow = range.end.row;
|
||||
|
||||
var row = this.getLine(firstRow).substring(0, range.start.column)
|
||||
+ this.getLine(lastRow).substring(range.end.column);
|
||||
|
||||
this.lines.splice(firstRow, lastRow - firstRow + 1, row);
|
||||
|
||||
|
||||
return range.start;
|
||||
};
|
||||
|
||||
this.undoChanges = function(deltas) {
|
||||
this.selection.clearSelection();
|
||||
for (var i=deltas.length-1; i>=0; i--) {
|
||||
var delta = deltas[i];
|
||||
if (delta.action == "insertText") {
|
||||
this.remove(delta.range, true);
|
||||
this.selection.moveCursorToPosition(delta.range.start);
|
||||
} else {
|
||||
this.insert(delta.range.start, delta.text, true);
|
||||
this.selection.setSelectionRange(delta.range);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
this.redoChanges = function(deltas) {
|
||||
this.selection.clearSelection();
|
||||
for (var i=0; i<deltas.length; i++) {
|
||||
var delta = deltas[i];
|
||||
if (delta.action == "insertText") {
|
||||
this.insert(delta.range.start, delta.text, true);
|
||||
this.selection.setSelectionRange(delta.range);
|
||||
} else {
|
||||
this.remove(delta.range, true);
|
||||
this.selection.moveCursorToPosition(delta.range.start);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
this.replace = function(range, text) {
|
||||
this.$remove(range);
|
||||
if (text) {
|
||||
var end = this.$insert(range.start, text);
|
||||
}
|
||||
else {
|
||||
end = range.start;
|
||||
}
|
||||
|
||||
var lastRemoved = range.end.column == 0 ? range.end.column - 1
|
||||
: range.end.column;
|
||||
this.fireChangeEvent(range.start.row, lastRemoved == end.row ? lastRemoved
|
||||
: undefined);
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
this.indentRows = function(range, indentString) {
|
||||
indentString.replace("\t", this.getTabString());
|
||||
for (var row=range.start.row; row<=range.end.row; row++) {
|
||||
this.$insert({row: row, column:0}, indentString);
|
||||
}
|
||||
this.fireChangeEvent(range.start.row, range.end.row);
|
||||
return indentString.length;
|
||||
};
|
||||
|
||||
this.outdentRows = function (range) {
|
||||
var deleteRange = new Range(0, 0, 0, 0),
|
||||
size = this.getTabSize();
|
||||
|
||||
for (var i = range.start.row; i <= range.end.row; ++i) {
|
||||
var line = this.getLine(i);
|
||||
|
||||
deleteRange.start.row = i;
|
||||
deleteRange.end.row = i;
|
||||
for (var j = 0; j < size; ++j)
|
||||
if (line.charAt(j) != ' ')
|
||||
break;
|
||||
if (j < size && line.charAt(j) == '\t') {
|
||||
deleteRange.start.column = j;
|
||||
deleteRange.end.column = j + 1;
|
||||
} else {
|
||||
deleteRange.start.column = 0;
|
||||
deleteRange.end.column = j;
|
||||
}
|
||||
if (i == range.start.row)
|
||||
range.start.column -= deleteRange.end.column - deleteRange.start.column;
|
||||
if (i == range.end.row)
|
||||
range.end.column -= deleteRange.end.column - deleteRange.start.column;
|
||||
this.$remove(deleteRange);
|
||||
}
|
||||
this.fireChangeEvent(range.start.row, range.end.row);
|
||||
return range;
|
||||
}
|
||||
|
||||
this.moveLinesUp = function(firstRow, lastRow) {
|
||||
if (firstRow <= 0) return 0;
|
||||
|
||||
var removed = this.lines.splice(firstRow, lastRow-firstRow+1);
|
||||
this.$insertLines(firstRow-1, removed);
|
||||
|
||||
this.fireChangeEvent(firstRow-1, lastRow);
|
||||
return -1;
|
||||
};
|
||||
|
||||
this.moveLinesDown = function(firstRow, lastRow) {
|
||||
if (lastRow >= this.lines.length-1) return 0;
|
||||
|
||||
var removed = this.lines.splice(firstRow, lastRow-firstRow+1);
|
||||
this.$insertLines(firstRow+1, removed);
|
||||
|
||||
this.fireChangeEvent(firstRow, lastRow+1);
|
||||
return 1;
|
||||
};
|
||||
|
||||
this.duplicateLines = function(firstRow, lastRow) {
|
||||
var firstRow = this.$clipRowToDocument(firstRow);
|
||||
var lastRow = this.$clipRowToDocument(lastRow);
|
||||
|
||||
var lines = this.getLines(firstRow, lastRow);
|
||||
this.$insertLines(firstRow, lines);
|
||||
|
||||
var addedRows = lastRow - firstRow + 1;
|
||||
this.fireChangeEvent(firstRow);
|
||||
|
||||
return addedRows;
|
||||
};
|
||||
|
||||
this.$clipRowToDocument = function(row) {
|
||||
return Math.max(0, Math.min(row, this.lines.length-1));
|
||||
};
|
||||
|
||||
this.documentToScreenColumn = function(row, docColumn) {
|
||||
var tabSize = this.getTabSize();
|
||||
|
||||
var screenColumn = 0;
|
||||
var remaining = docColumn;
|
||||
|
||||
var line = this.getLine(row).split("\t");
|
||||
for (var i=0; i<line.length; i++) {
|
||||
var len = line[i].length;
|
||||
if (remaining > len) {
|
||||
remaining -= (len + 1);
|
||||
screenColumn += len + tabSize;
|
||||
}
|
||||
else {
|
||||
screenColumn += remaining;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return screenColumn;
|
||||
};
|
||||
|
||||
this.screenToDocumentColumn = function(row, screenColumn) {
|
||||
var tabSize = this.getTabSize();
|
||||
|
||||
var docColumn = 0;
|
||||
var remaining = screenColumn;
|
||||
|
||||
var line = this.getLine(row).split("\t");
|
||||
for (var i=0; i<line.length; i++) {
|
||||
var len = line[i].length;
|
||||
if (remaining >= len + tabSize) {
|
||||
remaining -= (len + tabSize);
|
||||
docColumn += (len + 1);
|
||||
}
|
||||
else if (remaining > len){
|
||||
docColumn += len;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
docColumn += remaining;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return docColumn;
|
||||
};
|
||||
|
||||
}).call(Document.prototype);
|
||||
|
||||
return Document;
|
||||
});
|
||||
985
src/ace/Editor.js
Normal file
985
src/ace/Editor.js
Normal file
|
|
@ -0,0 +1,985 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/Editor",
|
||||
[
|
||||
"ace/lib/oop",
|
||||
"ace/lib/event",
|
||||
"ace/lib/lang",
|
||||
"ace/TextInput",
|
||||
"ace/KeyBinding",
|
||||
"ace/Document",
|
||||
"ace/Search",
|
||||
"ace/BackgroundTokenizer",
|
||||
"ace/Range",
|
||||
"ace/MEventEmitter"
|
||||
], function(oop, event, lang, TextInput, KeyBinding, Document, Search, BackgroundTokenizer, Range, MEventEmitter) {
|
||||
|
||||
var Editor = function(renderer, doc) {
|
||||
var container = renderer.getContainerElement();
|
||||
this.container = container;
|
||||
this.renderer = renderer;
|
||||
|
||||
this.textInput = new TextInput(container, this);
|
||||
this.keyBinding = new KeyBinding(container, this);
|
||||
var self = this;
|
||||
event.addListener(container, "mousedown", function(e) {
|
||||
setTimeout(function() {self.focus();});
|
||||
return event.preventDefault(e);
|
||||
});
|
||||
event.addListener(container, "selectstart", function(e) {
|
||||
return event.preventDefault(e);
|
||||
});
|
||||
|
||||
var mouseTarget = renderer.getMouseEventTarget();
|
||||
event.addListener(mouseTarget, "mousedown", lang.bind(this.onMouseDown, this));
|
||||
event.addMultiMouseDownListener(mouseTarget, 2, 500, lang.bind(this.onMouseDoubleClick, this));
|
||||
event.addMultiMouseDownListener(mouseTarget, 3, 600, lang.bind(this.onMouseTripleClick, this));
|
||||
event.addMouseWheelListener(mouseTarget, lang.bind(this.onMouseWheel, this));
|
||||
|
||||
this.$selectionMarker = null;
|
||||
this.$highlightLineMarker = null;
|
||||
this.$blockScrolling = false;
|
||||
|
||||
this.$search = new Search().set({
|
||||
wrap: true
|
||||
});
|
||||
|
||||
this.setDocument(doc || new Document(""));
|
||||
this.focus();
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
oop.implement(this, MEventEmitter);
|
||||
|
||||
this.$forwardEvents = {
|
||||
gutterclick: 1,
|
||||
gutterdblclick: 1
|
||||
};
|
||||
|
||||
this.$originalAddEventListener = this.addEventListener;
|
||||
this.$originalRemoveEventListener = this.removeEventListener;
|
||||
|
||||
this.addEventListener = function(eventName, callback) {
|
||||
if (this.$forwardEvents[eventName]) {
|
||||
return this.renderer.addEventListener(eventName, callback);
|
||||
} else {
|
||||
return this.$originalAddEventListener(eventName, callback);
|
||||
}
|
||||
};
|
||||
|
||||
this.removeEventListener = function(eventName, callback) {
|
||||
if (this.$forwardEvents[eventName]) {
|
||||
return this.renderer.removeEventListener(eventName, callback);
|
||||
} else {
|
||||
return this.$originalRemoveEventListener(eventName, callback);
|
||||
}
|
||||
};
|
||||
|
||||
this.setDocument = function(doc) {
|
||||
if (this.doc == doc) return;
|
||||
|
||||
if (this.doc) {
|
||||
this.doc.removeEventListener("change", this.$onDocumentChange);
|
||||
this.doc.removeEventListener("changeMode", this.$onDocumentModeChange);
|
||||
this.doc.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
|
||||
this.doc.removeEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
|
||||
|
||||
var selection = this.doc.getSelection();
|
||||
selection.removeEventListener("changeCursor", this.$onCursorChange);
|
||||
selection.removeEventListener("changeSelection", this.$onSelectionChange);
|
||||
|
||||
this.doc.setScrollTopRow(this.renderer.getScrollTopRow());
|
||||
}
|
||||
|
||||
this.doc = doc;
|
||||
|
||||
this.$onDocumentChange = lang.bind(this.onDocumentChange, this);
|
||||
doc.addEventListener("change", this.$onDocumentChange);
|
||||
this.renderer.setDocument(doc);
|
||||
|
||||
this.$onDocumentModeChange = lang.bind(this.onDocumentModeChange, this);
|
||||
doc.addEventListener("changeMode", this.$onDocumentModeChange);
|
||||
|
||||
this.$onDocumentChangeTabSize = lang.bind(this.renderer.updateText, this.renderer);
|
||||
doc.addEventListener("changeTabSize", this.$onDocumentChangeTabSize);
|
||||
|
||||
this.$onDocumentChangeBreakpoint = lang.bind(this.onDocumentChangeBreakpoint, this);
|
||||
this.doc.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
|
||||
|
||||
this.selection = doc.getSelection();
|
||||
this.$desiredColumn = 0;
|
||||
|
||||
this.$onCursorChange = lang.bind(this.onCursorChange, this);
|
||||
this.selection.addEventListener("changeCursor", this.$onCursorChange);
|
||||
|
||||
this.$onSelectionChange = lang.bind(this.onSelectionChange, this);
|
||||
this.selection.addEventListener("changeSelection", this.$onSelectionChange);
|
||||
|
||||
this.onDocumentModeChange();
|
||||
this.bgTokenizer.setLines(this.doc.lines);
|
||||
this.bgTokenizer.start(0);
|
||||
|
||||
this.onCursorChange();
|
||||
this.onSelectionChange();
|
||||
this.onDocumentChangeBreakpoint();
|
||||
this.renderer.scrollToRow(doc.getScrollTopRow());
|
||||
this.renderer.updateFull();
|
||||
};
|
||||
|
||||
this.getDocument = function() {
|
||||
return this.doc;
|
||||
};
|
||||
|
||||
this.getSelection = function() {
|
||||
return this.selection;
|
||||
};
|
||||
|
||||
this.resize = function() {
|
||||
this.renderer.onResize();
|
||||
};
|
||||
|
||||
this.setTheme = function(theme) {
|
||||
this.renderer.setTheme(theme);
|
||||
};
|
||||
|
||||
this.$highlightBrackets = function() {
|
||||
if (this.$bracketHighlight) {
|
||||
this.renderer.removeMarker(this.$bracketHighlight);
|
||||
this.$bracketHighlight = null;
|
||||
}
|
||||
|
||||
if (this.$highlightPending) {
|
||||
return;
|
||||
}
|
||||
|
||||
// perform highlight async to not block the browser during navigation
|
||||
var self = this;
|
||||
this.$highlightPending = true;
|
||||
setTimeout(function() {
|
||||
self.$highlightPending = false;
|
||||
|
||||
var pos = self.doc.findMatchingBracket(self.getCursorPosition());
|
||||
if (pos) {
|
||||
var range = new Range(pos.row, pos.column, pos.row, pos.column+1);
|
||||
self.$bracketHighlight = self.renderer.addMarker(range, "ace_bracket");
|
||||
}
|
||||
}, 10);
|
||||
};
|
||||
|
||||
this.focus = function() {
|
||||
this.textInput.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
this.textInput.blur();
|
||||
};
|
||||
|
||||
this.onFocus = function() {
|
||||
this.renderer.showCursor();
|
||||
this.renderer.visualizeFocus();
|
||||
};
|
||||
|
||||
this.onBlur = function() {
|
||||
this.renderer.hideCursor();
|
||||
this.renderer.visualizeBlur();
|
||||
};
|
||||
|
||||
this.onDocumentChange = function(e) {
|
||||
var data = e.data;
|
||||
this.bgTokenizer.start(data.firstRow);
|
||||
this.renderer.updateLines(data.firstRow, data.lastRow);
|
||||
|
||||
// update cursor because tab characters can influence the cursor position
|
||||
this.renderer.updateCursor(this.getCursorPosition(), this.$overwrite);
|
||||
};
|
||||
|
||||
this.onTokenizerUpdate = function(e) {
|
||||
var rows = e.data;
|
||||
this.renderer.updateLines(rows.first, rows.last);
|
||||
};
|
||||
|
||||
this.onCursorChange = function() {
|
||||
this.$highlightBrackets();
|
||||
this.renderer.updateCursor(this.getCursorPosition(), this.$overwrite);
|
||||
|
||||
if (!this.$blockScrolling) {
|
||||
this.renderer.scrollCursorIntoView();
|
||||
}
|
||||
this.$updateHighlightActiveLine();
|
||||
};
|
||||
|
||||
this.$updateHighlightActiveLine = function() {
|
||||
if (this.$highlightLineMarker) {
|
||||
this.renderer.removeMarker(this.$highlightLineMarker);
|
||||
}
|
||||
this.$highlightLineMarker = null;
|
||||
|
||||
if (this.getHighlightActiveLine() && (this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
|
||||
var cursor = this.getCursorPosition();
|
||||
var range = new Range(cursor.row, 0, cursor.row+1, 0);
|
||||
this.$highlightLineMarker = this.renderer.addMarker(range, "ace_active_line", "line");
|
||||
}
|
||||
};
|
||||
|
||||
this.onSelectionChange = function() {
|
||||
if (this.$selectionMarker) {
|
||||
this.renderer.removeMarker(this.$selectionMarker);
|
||||
}
|
||||
this.$selectionMarker = null;
|
||||
|
||||
if (!this.selection.isEmpty()) {
|
||||
var range = this.selection.getRange();
|
||||
var style = this.getSelectionStyle();
|
||||
this.$selectionMarker = this.renderer.addMarker(range, "ace_selection", style);
|
||||
}
|
||||
|
||||
this.onCursorChange();
|
||||
};
|
||||
|
||||
this.onDocumentChangeBreakpoint = function() {
|
||||
this.renderer.setBreakpoints(this.doc.getBreakpoints());
|
||||
};
|
||||
|
||||
this.onDocumentModeChange = function() {
|
||||
var mode = this.doc.getMode();
|
||||
if (this.mode == mode)
|
||||
return;
|
||||
|
||||
this.mode = mode;
|
||||
var tokenizer = mode.getTokenizer();
|
||||
|
||||
if (!this.bgTokenizer) {
|
||||
var onUpdate = lang.bind(this.onTokenizerUpdate, this);
|
||||
this.bgTokenizer = new BackgroundTokenizer(tokenizer, this);
|
||||
this.bgTokenizer.addEventListener("update", onUpdate);
|
||||
} else {
|
||||
this.bgTokenizer.setTokenizer(tokenizer);
|
||||
}
|
||||
|
||||
this.renderer.setTokenizer(this.bgTokenizer);
|
||||
};
|
||||
|
||||
|
||||
this.onMouseDown = function(e) {
|
||||
var pageX = event.getDocumentX(e);
|
||||
var pageY = event.getDocumentY(e);
|
||||
|
||||
if (event.getButton(e) != 0)
|
||||
return;
|
||||
|
||||
var pos = this.renderer.screenToTextCoordinates(pageX, pageY);
|
||||
pos.row = Math.max(0, Math.min(pos.row, this.doc.getLength()-1));
|
||||
|
||||
if (e.shiftKey)
|
||||
this.selection.selectToPosition(pos)
|
||||
else {
|
||||
this.moveCursorToPosition(pos);
|
||||
if (!this.$clickSelection)
|
||||
this.selection.clearSelection(pos.row, pos.column);
|
||||
}
|
||||
|
||||
this.renderer.scrollCursorIntoView();
|
||||
|
||||
var self = this;
|
||||
var mousePageX, mousePageY;
|
||||
|
||||
var onMouseSelection = function(e) {
|
||||
mousePageX = event.getDocumentX(e);
|
||||
mousePageY = event.getDocumentY(e);
|
||||
};
|
||||
|
||||
var onMouseSelectionEnd = function() {
|
||||
clearInterval(timerId);
|
||||
self.$clickSelection = null;
|
||||
};
|
||||
|
||||
var onSelectionInterval = function() {
|
||||
if (mousePageX === undefined || mousePageY === undefined)
|
||||
return;
|
||||
|
||||
var cursor = self.renderer.screenToTextCoordinates(mousePageX, mousePageY);
|
||||
cursor.row = Math.max(0, Math.min(cursor.row, self.doc.getLength()-1));
|
||||
|
||||
if (self.$clickSelection) {
|
||||
if (self.$clickSelection.contains(cursor.row, cursor.column)) {
|
||||
self.selection.setSelectionRange(self.$clickSelection);
|
||||
} else {
|
||||
if (self.$clickSelection.compare(cursor.row, cursor.column) == -1) {
|
||||
var anchor = self.$clickSelection.end;
|
||||
} else {
|
||||
var anchor = self.$clickSelection.start;
|
||||
}
|
||||
self.selection.setSelectionAnchor(anchor.row, anchor.column);
|
||||
self.selection.selectToPosition(cursor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.selection.selectToPosition(cursor);
|
||||
}
|
||||
|
||||
self.renderer.scrollCursorIntoView();
|
||||
};
|
||||
|
||||
event.capture(this.container, onMouseSelection, onMouseSelectionEnd);
|
||||
var timerId = setInterval(onSelectionInterval, 20);
|
||||
|
||||
return event.preventDefault(e);
|
||||
};
|
||||
|
||||
this.onMouseDoubleClick = function(e) {
|
||||
this.selection.selectWord();
|
||||
this.$clickSelection = this.getSelectionRange();
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
this.onMouseTripleClick = function(e) {
|
||||
this.selection.selectLine();
|
||||
this.$clickSelection = this.getSelectionRange();
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
this.onMouseWheel = function(e) {
|
||||
var speed = this.$scrollSpeed * 2;
|
||||
|
||||
this.renderer.scrollBy(e.wheelX * speed, e.wheelY * speed);
|
||||
return event.preventDefault(e);
|
||||
};
|
||||
|
||||
this.getCopyText = function() {
|
||||
if (!this.selection.isEmpty()) {
|
||||
return this.doc.getTextRange(this.getSelectionRange());
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
this.onCut = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
if (!this.selection.isEmpty()) {
|
||||
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
|
||||
this.clearSelection();
|
||||
}
|
||||
};
|
||||
|
||||
this.onTextInput = function(text) {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var cursor = this.getCursorPosition();
|
||||
text = text.replace("\t", this.doc.getTabString());
|
||||
|
||||
// remove selected text
|
||||
if (!this.selection.isEmpty()) {
|
||||
var cursor = this.doc.remove(this.getSelectionRange());
|
||||
this.clearSelection();
|
||||
} else if (this.$overwrite){
|
||||
var range = new Range.fromPoints(cursor, cursor);
|
||||
range.end.column += text.length;
|
||||
this.doc.remove(range);
|
||||
}
|
||||
|
||||
this.clearSelection();
|
||||
|
||||
var _self = this;
|
||||
var row = cursor.row;
|
||||
this.bgTokenizer.getState(cursor.row-1, function (lineState) {
|
||||
var shouldOutdent = _self.mode.checkOutdent(lineState, _self.doc.getLine(row), text);
|
||||
var line = _self.doc.getLine(row);
|
||||
var end = _self.doc.insert(cursor, text);
|
||||
|
||||
/* TODO: This shortcut is somehow broken
|
||||
if (!shouldOutdent && line != _self.doc.getLine(row) && text != "\n") {
|
||||
_self.moveCursorToPosition(end);
|
||||
_self.renderer.scrollCursorIntoView();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
var line = _self.doc.getLine(row);
|
||||
_self.bgTokenizer.getState(row, function(lineState) {
|
||||
// multi line insert
|
||||
if (row !== end.row) {
|
||||
var indent = _self.mode.getNextLineIndent(lineState, line, _self.doc.getTabString());
|
||||
if (indent) {
|
||||
var indentRange = new Range(row+1, 0, end.row, end.column);
|
||||
end.column += _self.doc.indentRows(indentRange, indent);
|
||||
}
|
||||
} else {
|
||||
if (shouldOutdent) {
|
||||
end.column += _self.mode.autoOutdent(lineState, _self.doc, row);
|
||||
}
|
||||
}
|
||||
|
||||
_self.moveCursorToPosition(end);
|
||||
_self.renderer.scrollCursorIntoView();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.$overwrite = false;
|
||||
this.setOverwrite = function(overwrite) {
|
||||
if (this.$overwrite == overwrite) return;
|
||||
|
||||
this.$overwrite = overwrite;
|
||||
|
||||
this.$blockScrolling = true;
|
||||
this.onCursorChange();
|
||||
this.$blockScrolling = false;
|
||||
|
||||
this.$dispatchEvent("changeOverwrite", {data: overwrite});
|
||||
};
|
||||
|
||||
this.getOverwrite = function() {
|
||||
return this.$overwrite;
|
||||
};
|
||||
|
||||
this.toggleOverwrite = function() {
|
||||
this.setOverwrite(!this.$overwrite);
|
||||
};
|
||||
|
||||
|
||||
this.$scrollSpeed = 1;
|
||||
this.setScrollSpeed = function(speed) {
|
||||
this.$scrollSpeed = speed;
|
||||
}
|
||||
|
||||
this.getScrollSpeed = function() {
|
||||
return this.$scrollSpeed;
|
||||
}
|
||||
|
||||
this.$selectionStyle = "line";
|
||||
this.setSelectionStyle = function(style) {
|
||||
if (this.$selectionStyle == style) return;
|
||||
|
||||
this.$selectionStyle = style;
|
||||
this.onSelectionChange();
|
||||
this.$dispatchEvent("changeSelectionStyle", {data: style});
|
||||
};
|
||||
|
||||
|
||||
this.getSelectionStyle = function() {
|
||||
return this.$selectionStyle;
|
||||
};
|
||||
|
||||
this.$highlightActiveLine = true;
|
||||
this.setHighlightActiveLine = function(shouldHighlight) {
|
||||
if (this.$highlightActiveLine == shouldHighlight) return;
|
||||
|
||||
this.$highlightActiveLine = shouldHighlight;
|
||||
this.$updateHighlightActiveLine();
|
||||
};
|
||||
|
||||
this.getHighlightActiveLine = function() {
|
||||
return this.$highlightActiveLine;
|
||||
};
|
||||
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
if (this.getShowInvisibles() == showInvisibles)
|
||||
return;
|
||||
|
||||
this.renderer.setShowInvisibles(showInvisibles);
|
||||
};
|
||||
|
||||
this.getShowInvisibles = function() {
|
||||
return this.renderer.getShowInvisibles();
|
||||
};
|
||||
|
||||
this.setShowPrintMargin = function(showPrintMargin) {
|
||||
this.renderer.setShowPrintMargin(showPrintMargin);
|
||||
};
|
||||
|
||||
this.getShowPrintMargin = function() {
|
||||
return this.renderer.getShowPrintMargin();
|
||||
};
|
||||
|
||||
this.setPrintMarginColumn = function(showPrintMargin) {
|
||||
this.renderer.setPrintMarginColumn(showPrintMargin);
|
||||
};
|
||||
|
||||
this.getPrintMarginColumn = function() {
|
||||
return this.renderer.getPrintMarginColumn();
|
||||
};
|
||||
|
||||
this.$readOnly = false;
|
||||
this.setReadOnly = function(readOnly) {
|
||||
this.$readOnly = readOnly;
|
||||
};
|
||||
|
||||
this.getReadOnly = function() {
|
||||
return this.$readOnly;
|
||||
};
|
||||
|
||||
this.removeRight = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
if (this.selection.isEmpty()) {
|
||||
this.selection.selectRight();
|
||||
}
|
||||
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.removeLeft = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
if (this.selection.isEmpty()) {
|
||||
this.selection.selectLeft();
|
||||
}
|
||||
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.indent = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var range = this.getSelectionRange();
|
||||
|
||||
if (range.start.row < range.end.row ||
|
||||
range.start.column < range.end.column) {
|
||||
var count = this.doc.indentRows(this.getSelectionRange(), "\t");
|
||||
|
||||
this.selection.shiftSelection(count);
|
||||
} else {
|
||||
var indentString;
|
||||
|
||||
if (this.doc.getUseSoftTabs()) {
|
||||
var size = this.doc.getTabSize(),
|
||||
count = (size - this.getCursorPosition().column % size);
|
||||
|
||||
indentString = lang.stringRepeat(" ", count);
|
||||
} else
|
||||
indentString = "\t";
|
||||
return this.onTextInput(indentString);
|
||||
}
|
||||
};
|
||||
|
||||
this.blockOutdent = function(indentString) {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var selection = this.doc.getSelection(),
|
||||
range = this.doc.outdentRows(selection.getRange());
|
||||
|
||||
selection.setSelectionRange(range, selection.isBackwards());
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
this.toggleCommentLines = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var rows = this.$getSelectedRows();
|
||||
|
||||
var range = new Range(rows.first, 0, rows.last, 0);
|
||||
var _self = this;
|
||||
this.bgTokenizer.getState(this.getCursorPosition().row, function(state) {
|
||||
var addedColumns = _self.mode.toggleCommentLines(state, _self.doc, range);
|
||||
_self.selection.shiftSelection(addedColumns);
|
||||
});
|
||||
};
|
||||
|
||||
this.removeLines = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var rows = this.$getSelectedRows();
|
||||
this.selection.setSelectionAnchor(rows.last+1, 0);
|
||||
this.selection.selectTo(rows.first, 0);
|
||||
|
||||
this.doc.remove(this.getSelectionRange());
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.moveLinesDown = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
return this.doc.moveLinesDown(firstRow, lastRow);
|
||||
});
|
||||
};
|
||||
|
||||
this.moveLinesUp = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
return this.doc.moveLinesUp(firstRow, lastRow);
|
||||
});
|
||||
};
|
||||
|
||||
this.copyLinesUp = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
this.doc.duplicateLines(firstRow, lastRow);
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
this.copyLinesDown = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
return this.doc.duplicateLines(firstRow, lastRow);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
this.$moveLines = function(mover) {
|
||||
var rows = this.$getSelectedRows();
|
||||
|
||||
var linesMoved = mover.call(this, rows.first, rows.last);
|
||||
|
||||
var selection = this.selection;
|
||||
selection.setSelectionAnchor(rows.last+linesMoved+1, 0);
|
||||
selection.$moveSelection(function() {
|
||||
selection.moveCursorTo(rows.first+linesMoved, 0);
|
||||
});
|
||||
};
|
||||
|
||||
this.$getSelectedRows = function() {
|
||||
var range = this.getSelectionRange();
|
||||
var firstRow = range.start.row;
|
||||
var lastRow = range.end.row;
|
||||
if (range.end.column == 0 && (range.start.row !== range.end.row)) {
|
||||
lastRow -= 1;
|
||||
}
|
||||
|
||||
return {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
};
|
||||
|
||||
this.onCompositionStart = function(text) {
|
||||
this.renderer.showComposition(this.getCursorPosition());
|
||||
//this.onTextInput(text);
|
||||
};
|
||||
|
||||
this.onCompositionUpdate = function(text) {
|
||||
this.renderer.setCompositionText(text);
|
||||
};
|
||||
|
||||
this.onCompositionEnd = function() {
|
||||
this.renderer.hideComposition();
|
||||
//this.removeLeft();
|
||||
};
|
||||
|
||||
|
||||
this.getFirstVisibleRow = function() {
|
||||
return this.renderer.getFirstVisibleRow();
|
||||
};
|
||||
|
||||
this.getLastVisibleRow = function() {
|
||||
return this.renderer.getLastVisibleRow();
|
||||
};
|
||||
|
||||
this.isRowVisible = function(row) {
|
||||
return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow());
|
||||
};
|
||||
|
||||
this.getVisibleRowCount = function() {
|
||||
return this.getLastVisibleRow() - this.getFirstVisibleRow() + 1;
|
||||
};
|
||||
|
||||
this.getPageDownRow = function() {
|
||||
return this.renderer.getLastVisibleRow() - 1;
|
||||
};
|
||||
|
||||
this.getPageUpRow = function() {
|
||||
var firstRow = this.renderer.getFirstVisibleRow();
|
||||
var lastRow = this.renderer.getLastVisibleRow();
|
||||
|
||||
return firstRow - (lastRow - firstRow) + 1;
|
||||
};
|
||||
|
||||
this.selectPageDown = function() {
|
||||
var row = this.getPageDownRow() + Math.floor(this.getVisibleRowCount() / 2);
|
||||
|
||||
this.scrollPageDown();
|
||||
|
||||
var selection = this.getSelection();
|
||||
selection.$moveSelection(function() {
|
||||
selection.moveCursorTo(row, selection.getSelectionLead().column);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectPageUp = function() {
|
||||
var visibleRows = this.getLastVisibleRow() - this.getFirstVisibleRow();
|
||||
var row = this.getPageUpRow() + Math.round(visibleRows / 2);
|
||||
|
||||
this.scrollPageUp();
|
||||
|
||||
var selection = this.getSelection();
|
||||
selection.$moveSelection(function() {
|
||||
selection.moveCursorTo(row, selection.getSelectionLead().column);
|
||||
});
|
||||
};
|
||||
|
||||
this.gotoPageDown = function() {
|
||||
console.log("Goto page down");
|
||||
|
||||
var row = this.getPageDownRow(),
|
||||
column = Math.min(this.getCursorPosition().column,
|
||||
this.doc.getLine(row).length);
|
||||
|
||||
this.scrollToRow(row);
|
||||
this.getSelection().moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.gotoPageUp = function() {
|
||||
console.log("Goto page up");
|
||||
|
||||
var row = this.getPageUpRow(),
|
||||
column = Math.min(this.getCursorPosition().column,
|
||||
this.doc.getLine(row).length);
|
||||
|
||||
this.scrollToRow(row);
|
||||
this.getSelection().moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.scrollPageDown = function() {
|
||||
this.scrollToRow(this.getPageDownRow());
|
||||
};
|
||||
|
||||
this.scrollPageUp = function() {
|
||||
this.renderer.scrollToRow(this.getPageUpRow());
|
||||
};
|
||||
|
||||
this.scrollToRow = function(row) {
|
||||
this.renderer.scrollToRow(row);
|
||||
};
|
||||
|
||||
|
||||
this.getCursorPosition = function() {
|
||||
return this.selection.getCursor();
|
||||
};
|
||||
|
||||
this.getSelectionRange = function() {
|
||||
return this.selection.getRange();
|
||||
};
|
||||
|
||||
this.clearSelection = function() {
|
||||
this.selection.clearSelection();
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
this.moveCursorTo = function(row, column) {
|
||||
this.selection.moveCursorTo(row, column);
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
this.moveCursorToPosition = function(pos) {
|
||||
this.selection.moveCursorToPosition(pos);
|
||||
this.$updateDesiredColumn();
|
||||
};
|
||||
|
||||
|
||||
this.gotoLine = function(lineNumber, row) {
|
||||
this.selection.clearSelection();
|
||||
|
||||
this.$blockScrolling = true;
|
||||
this.moveCursorTo(lineNumber-1, row || 0);
|
||||
this.$blockScrolling = false;
|
||||
|
||||
if (!this.isRowVisible(this.getCursorPosition().row)) {
|
||||
this.scrollToRow(lineNumber - 1 - Math.floor(this.getVisibleRowCount() / 2));
|
||||
}
|
||||
},
|
||||
|
||||
this.navigateTo = function(row, column) {
|
||||
this.clearSelection();
|
||||
this.moveCursorTo(row, column);
|
||||
this.$updateDesiredColumn(column);
|
||||
};
|
||||
|
||||
this.navigateUp = function() {
|
||||
this.selection.clearSelection();
|
||||
this.selection.moveCursorBy(-1, 0);
|
||||
|
||||
if (this.$desiredColumn) {
|
||||
var cursor = this.getCursorPosition();
|
||||
var column = this.doc.screenToDocumentColumn(cursor.row, this.$desiredColumn);
|
||||
this.selection.moveCursorTo(cursor.row, column);
|
||||
}
|
||||
};
|
||||
|
||||
this.navigateDown = function() {
|
||||
this.selection.clearSelection();
|
||||
this.selection.moveCursorBy(1, 0);
|
||||
|
||||
if (this.$desiredColumn) {
|
||||
var cursor = this.getCursorPosition();
|
||||
var column = this.doc.screenToDocumentColumn(cursor.row, this.$desiredColumn);
|
||||
this.selection.moveCursorTo(cursor.row, column);
|
||||
}
|
||||
};
|
||||
|
||||
this.$updateDesiredColumn = function() {
|
||||
var cursor = this.getCursorPosition();
|
||||
this.$desiredColumn = this.doc.documentToScreenColumn(cursor.row, cursor.column);
|
||||
};
|
||||
|
||||
this.navigateLeft = function() {
|
||||
if (!this.selection.isEmpty()) {
|
||||
var selectionStart = this.getSelectionRange().start;
|
||||
this.moveCursorToPosition(selectionStart);
|
||||
}
|
||||
else {
|
||||
this.selection.moveCursorLeft();
|
||||
}
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateRight = function() {
|
||||
if (!this.selection.isEmpty()) {
|
||||
var selectionEnd = this.getSelectionRange().end;
|
||||
this.moveCursorToPosition(selectionEnd);
|
||||
}
|
||||
else {
|
||||
this.selection.moveCursorRight();
|
||||
}
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateLineStart = function() {
|
||||
this.selection.moveCursorLineStart();
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateLineEnd = function() {
|
||||
this.selection.moveCursorLineEnd();
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateFileEnd = function() {
|
||||
this.selection.moveCursorFileEnd();
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateFileStart = function() {
|
||||
this.selection.moveCursorFileStart();
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateWordRight = function() {
|
||||
this.selection.moveCursorWordRight();
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateWordLeft = function() {
|
||||
this.selection.moveCursorWordLeft();
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.replace = function(replacement, options) {
|
||||
if (options)
|
||||
this.$search.set(options);
|
||||
var range = this.$tryReplace(this.getSelectionRange(), replacement);
|
||||
if (range !== null)
|
||||
this.selection.setSelectionRange(range);
|
||||
this.$updateDesiredColumn();
|
||||
},
|
||||
|
||||
this.replaceAll = function(replacement, options) {
|
||||
if (options) {
|
||||
console.log("Find " + options.needle);
|
||||
this.$search.set(options);
|
||||
}
|
||||
console.log("Replace " + replacement);
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorTo(0, 0);
|
||||
|
||||
var ranges = this.$search.findAll(this.doc);
|
||||
if (!ranges.length)
|
||||
return;
|
||||
|
||||
for (var i = ranges.length - 1; i >= 0; --i)
|
||||
this.$tryReplace(ranges[i], replacement);
|
||||
this.selection.setSelectionRange(ranges[0]);
|
||||
this.$updateDesiredColumn();
|
||||
},
|
||||
|
||||
this.$tryReplace = function(range, replacement) {
|
||||
var input = this.doc.getTextRange(range);
|
||||
var replacement = this.$search.replace(input, replacement);
|
||||
if (replacement !== null) {
|
||||
range.end = this.doc.replace(range, replacement);
|
||||
return range;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this.getLastSearchOptions = function() {
|
||||
return this.$search.getOptions();
|
||||
};
|
||||
|
||||
this.find = function(needle, options) {
|
||||
this.clearSelection();
|
||||
options = options || {};
|
||||
options.needle = needle;
|
||||
this.$search.set(options);
|
||||
this.$find();
|
||||
},
|
||||
|
||||
this.findNext = function(options) {
|
||||
options = options || {};
|
||||
if (typeof options.backwards == "undefined")
|
||||
options.backwards = false;
|
||||
this.$search.set(options);
|
||||
this.$find();
|
||||
};
|
||||
|
||||
this.findPrevious = function(options) {
|
||||
options = options || {};
|
||||
if (typeof options.backwards == "undefined")
|
||||
options.backwards = true;
|
||||
this.$search.set(options);
|
||||
this.$find();
|
||||
};
|
||||
|
||||
this.$find = function(backwards) {
|
||||
if (!this.selection.isEmpty()) {
|
||||
this.$search.set({needle: this.doc.getTextRange(this.getSelectionRange())});
|
||||
}
|
||||
|
||||
if (typeof backwards != "undefined")
|
||||
this.$search.set({backwards: backwards});
|
||||
|
||||
var range = this.$search.find(this.doc);
|
||||
if (range) {
|
||||
this.gotoLine(range.end.row+1, range.end.column);
|
||||
this.$updateDesiredColumn();
|
||||
this.selection.setSelectionRange(range);
|
||||
}
|
||||
};
|
||||
|
||||
this.undo = function() {
|
||||
this.doc.getUndoManager().undo();
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
this.doc.getUndoManager().redo();
|
||||
};
|
||||
|
||||
}).call(Editor.prototype);
|
||||
|
||||
|
||||
return Editor;
|
||||
});
|
||||
123
src/ace/KeyBinding.js
Normal file
123
src/ace/KeyBinding.js
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/KeyBinding",
|
||||
["ace/lib/core",
|
||||
"ace/lib/event",
|
||||
"ace/conf/keybindings/default_mac",
|
||||
"ace/conf/keybindings/default_win",
|
||||
"ace/PluginManager",
|
||||
"ace/commands/DefaultCommands"],
|
||||
function(core, event, default_mac, default_win, PluginManager) {
|
||||
|
||||
var KeyBinding = function(element, editor, config) {
|
||||
this.setConfig(config);
|
||||
|
||||
var _self = this;
|
||||
event.addKeyListener(element, function(e) {
|
||||
var hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
|
||||
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
|
||||
var key = _self.keyNames[e.keyCode];
|
||||
|
||||
var commandName = (_self.config.reverse[hashId] || {})[(key
|
||||
|| String.fromCharCode(e.keyCode)).toLowerCase()];
|
||||
var command = PluginManager.commands[commandName];
|
||||
|
||||
if (command) {
|
||||
command(editor, editor.getSelection());
|
||||
return event.stopEvent(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.keyMods = {"ctrl": 1, "alt": 2, "option" : 2, "shift": 4, "meta": 8, "command": 8};
|
||||
|
||||
this.keyNames = {
|
||||
"8" : "Backspace",
|
||||
"9" : "Tab",
|
||||
"13" : "Enter",
|
||||
"27" : "Esc",
|
||||
"32" : "Space",
|
||||
"33" : "PageUp",
|
||||
"34" : "PageDown",
|
||||
"35" : "End",
|
||||
"36" : "Home",
|
||||
"37" : "Left",
|
||||
"38" : "Up",
|
||||
"39" : "Right",
|
||||
"40" : "Down",
|
||||
"45" : "Insert",
|
||||
"46" : "Delete",
|
||||
"107": "+",
|
||||
"112": "F1",
|
||||
"113": "F2",
|
||||
"114": "F3",
|
||||
"115": "F4",
|
||||
"116": "F5",
|
||||
"117": "F6",
|
||||
"118": "F7",
|
||||
"119": "F8",
|
||||
"120": "F9",
|
||||
"121": "F10",
|
||||
"122": "F11",
|
||||
"123": "F12"
|
||||
};
|
||||
|
||||
function splitSafe(s, separator, limit, bLowerCase) {
|
||||
return (bLowerCase && s.toLowerCase() || s)
|
||||
.replace(/(?:^\s+|\n|\s+$)/g, "")
|
||||
.split(new RegExp("[\\s ]*" + separator + "[\\s ]*", "g"), limit || 999);
|
||||
}
|
||||
|
||||
function parseKeys(keys, val, ret) {
|
||||
var key,
|
||||
hashId = 0,
|
||||
parts = splitSafe(keys, "\\-", null, true),
|
||||
i = 0,
|
||||
l = parts.length;
|
||||
|
||||
for (; i < l; ++i) {
|
||||
if (this.keyMods[parts[i]])
|
||||
hashId = hashId | this.keyMods[parts[i]];
|
||||
else
|
||||
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
|
||||
}
|
||||
|
||||
(ret[hashId] || (ret[hashId] = {}))[key] = val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function objectReverse(obj, keySplit) {
|
||||
var i, j, l, key,
|
||||
ret = {};
|
||||
for (i in obj) {
|
||||
key = obj[i];
|
||||
if (keySplit && typeof key == "string") {
|
||||
key = key.split(keySplit);
|
||||
for (j = 0, l = key.length; j < l; ++j)
|
||||
parseKeys.call(this, key[j], i, ret);
|
||||
}
|
||||
else {
|
||||
parseKeys.call(this, key, i, ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
this.setConfig = function(config) {
|
||||
this.config = config || (core.isMac
|
||||
? default_mac
|
||||
: default_win);
|
||||
if (typeof this.config.reverse == "undefined")
|
||||
this.config.reverse = objectReverse.call(this, this.config, "|");
|
||||
};
|
||||
|
||||
}).call(KeyBinding.prototype);
|
||||
|
||||
return KeyBinding;
|
||||
});
|
||||
56
src/ace/MEventEmitter.js
Normal file
56
src/ace/MEventEmitter.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
|
||||
if (!require.def) require.def = require("requireJS-node")(module);
|
||||
|
||||
require.def("ace/MEventEmitter", ["ace/lib/lang"], function(lang) {
|
||||
|
||||
var MEventEmitter = {}
|
||||
|
||||
MEventEmitter.$dispatchEvent = function(eventName, e) {
|
||||
this.$eventRegistry = this.$eventRegistry || {};
|
||||
|
||||
var listeners = this.$eventRegistry[eventName];
|
||||
if (!listeners || !listeners.length) return;
|
||||
|
||||
var e = e || {};
|
||||
e.type = eventName;
|
||||
|
||||
for (var i=0; i<listeners.length; i++) {
|
||||
listeners[i](e);
|
||||
}
|
||||
};
|
||||
|
||||
MEventEmitter.on =
|
||||
MEventEmitter.addEventListener = function(eventName, callback) {
|
||||
this.$eventRegistry = this.$eventRegistry || {};
|
||||
|
||||
var listeners = this.$eventRegistry[eventName];
|
||||
if (!listeners) {
|
||||
var listeners = this.$eventRegistry[eventName] = [];
|
||||
}
|
||||
if (lang.arrayIndexOf(listeners, callback) == -1) {
|
||||
listeners.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
MEventEmitter.removeEventListener = function(eventName, callback) {
|
||||
this.$eventRegistry = this.$eventRegistry || {};
|
||||
|
||||
var listeners = this.$eventRegistry[eventName];
|
||||
if (!listeners) {
|
||||
return;
|
||||
}
|
||||
var index = lang.arrayIndexOf(listeners, callback);
|
||||
if (index !== -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
return MEventEmitter;
|
||||
});
|
||||
19
src/ace/PluginManager.js
Normal file
19
src/ace/PluginManager.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/PluginManager", [], function() {
|
||||
|
||||
var PluginManager = {
|
||||
commands : {},
|
||||
|
||||
registerCommand : function(name, command) {
|
||||
this.commands[name] = command;
|
||||
}
|
||||
};
|
||||
|
||||
return PluginManager;
|
||||
});
|
||||
126
src/ace/Range.js
Normal file
126
src/ace/Range.js
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/Range", function() {
|
||||
|
||||
var Range = function(startRow, startColumn, endRow, endColumn) {
|
||||
this.start = {
|
||||
row: startRow,
|
||||
column: startColumn
|
||||
};
|
||||
|
||||
this.end = {
|
||||
row: endRow,
|
||||
column: endColumn
|
||||
};
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.toString = function() {
|
||||
return ("Range: [" + this.start.row + "/" + this.start.column +
|
||||
"] -> [" + this.end.row + "/" + this.end.column + "]");
|
||||
};
|
||||
|
||||
this.contains = function(row, column) {
|
||||
return this.compare(row, column) == 0;
|
||||
};
|
||||
|
||||
this.compare = function(row, column) {
|
||||
if (!this.isMultiLine()) {
|
||||
if (row === this.start.row) {
|
||||
return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
|
||||
};
|
||||
}
|
||||
|
||||
if (row < this.start.row)
|
||||
return -1;
|
||||
|
||||
if (row > this.end.row)
|
||||
return 1;
|
||||
|
||||
if (this.start.row === row)
|
||||
return column >= this.start.column ? 0 : -1;
|
||||
|
||||
if (this.end.row === row)
|
||||
return column <= this.end.column ? 0 : 1;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
this.clipRows = function(firstRow, lastRow) {
|
||||
if (this.end.row > lastRow) {
|
||||
var end = {
|
||||
row: lastRow+1,
|
||||
column: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (this.start.row > lastRow) {
|
||||
var start = {
|
||||
row: lastRow+1,
|
||||
column: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (this.start.row < firstRow) {
|
||||
var start = {
|
||||
row: firstRow,
|
||||
column: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (this.end.row < firstRow) {
|
||||
var end = {
|
||||
row: firstRow,
|
||||
column: 0
|
||||
};
|
||||
}
|
||||
return Range.fromPoints(start || this.start, end || this.end);
|
||||
};
|
||||
|
||||
this.extend = function(row, column) {
|
||||
var cmp = this.compare(row, column);
|
||||
|
||||
if (cmp == 0)
|
||||
return this;
|
||||
else if (cmp == -1)
|
||||
var start = {row: row, column: column};
|
||||
else
|
||||
var end = {row: row, column: column};
|
||||
|
||||
return Range.fromPoints(start || this.start, end || this.end);
|
||||
};
|
||||
|
||||
this.isEmpty = function() {
|
||||
return (this.start.row == this.end.row && this.start.column == this.end.column);
|
||||
};
|
||||
|
||||
this.isMultiLine = function() {
|
||||
return (this.start.row !== this.end.row);
|
||||
};
|
||||
|
||||
this.clone = function() {
|
||||
return Range.fromPoints(this.start, this.end);
|
||||
};
|
||||
|
||||
this.toScreenRange = function(doc) {
|
||||
return new Range(
|
||||
this.start.row, doc.documentToScreenColumn(this.start.row, this.start.column),
|
||||
this.end.row, doc.documentToScreenColumn(this.end.row, this.end.column)
|
||||
);
|
||||
};
|
||||
|
||||
}).call(Range.prototype);
|
||||
|
||||
|
||||
Range.fromPoints = function(start, end) {
|
||||
return new Range(start.row, start.column, end.row, end.column);
|
||||
};
|
||||
|
||||
return Range;
|
||||
})
|
||||
60
src/ace/RenderLoop.js
Normal file
60
src/ace/RenderLoop.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/RenderLoop", function() {
|
||||
|
||||
var RenderLoop = function(onRender) {
|
||||
this.onRender = onRender;
|
||||
this.pending = false;
|
||||
this.changes = 0;
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.schedule = function(change) {
|
||||
this.changes = this.changes | change;
|
||||
if (!this.pending) {
|
||||
this.pending = true;
|
||||
var _self = this;
|
||||
this.setTimeoutZero(function() {
|
||||
_self.pending = false;
|
||||
_self.onRender(_self.changes);
|
||||
_self.changes = 0;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if (window.postMessage) {
|
||||
|
||||
this.messageName = "zero-timeout-message";
|
||||
|
||||
this.setTimeoutZero = function(callback) {
|
||||
if (!this.attached) {
|
||||
var _self = this;
|
||||
window.addEventListener("message", function(e) {
|
||||
if (e.source == window && _self.callback && e.data == _self.messageName) {
|
||||
e.stopPropagation();
|
||||
_self.callback();
|
||||
}
|
||||
}, false);
|
||||
this.attached = true;
|
||||
}
|
||||
this.callback = callback;
|
||||
window.postMessage(this.messageName, "*");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.setTimeoutZero = function(callback) {
|
||||
setTimeout(callback, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}).call(RenderLoop.prototype);
|
||||
|
||||
return RenderLoop;
|
||||
});
|
||||
57
src/ace/ScrollBar.js
Normal file
57
src/ace/ScrollBar.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/ScrollBar", [
|
||||
"ace/lib/oop",
|
||||
"ace/lib/lang",
|
||||
"ace/lib/dom",
|
||||
"ace/lib/event",
|
||||
"ace/MEventEmitter"
|
||||
], function(oop, lang, dom, event, MEventEmitter) {
|
||||
|
||||
var ScrollBar = function(parent) {
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "ace_sb";
|
||||
|
||||
this.inner = document.createElement("div");
|
||||
this.element.appendChild(this.inner);
|
||||
|
||||
parent.appendChild(this.element);
|
||||
|
||||
this.width = dom.scrollbarWidth();
|
||||
this.element.style.width = this.width;
|
||||
|
||||
event.addListener(this.element, "scroll", lang.bind(this.onScroll, this));
|
||||
};
|
||||
|
||||
(function() {
|
||||
oop.implement(this, MEventEmitter);
|
||||
|
||||
this.onScroll = function() {
|
||||
this.$dispatchEvent("scroll", {data: this.element.scrollTop});
|
||||
};
|
||||
|
||||
this.getWidth = function() {
|
||||
return this.width;
|
||||
};
|
||||
|
||||
this.setHeight = function(height) {
|
||||
this.element.style.height = Math.max(0, height - this.width) + "px";
|
||||
};
|
||||
|
||||
this.setInnerHeight = function(height) {
|
||||
this.inner.style.height = height + "px";
|
||||
};
|
||||
|
||||
this.setScrollTop = function(scrollTop) {
|
||||
this.element.scrollTop = scrollTop;
|
||||
};
|
||||
|
||||
}).call(ScrollBar.prototype);
|
||||
|
||||
return ScrollBar;
|
||||
});
|
||||
291
src/ace/Search.js
Normal file
291
src/ace/Search.js
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/Search",
|
||||
["ace/lib/lang",
|
||||
"ace/lib/oop",
|
||||
"ace/Range"],
|
||||
function(lang, oop, Range) {
|
||||
|
||||
var Search = function() {
|
||||
this.$options = {
|
||||
needle: "",
|
||||
backwards: false,
|
||||
wrap: false,
|
||||
caseSensitive: false,
|
||||
wholeWord: false,
|
||||
scope: Search.ALL,
|
||||
regExp: false
|
||||
};
|
||||
};
|
||||
|
||||
Search.ALL = 1;
|
||||
Search.SELECTION = 2;
|
||||
|
||||
(function() {
|
||||
|
||||
this.set = function(options) {
|
||||
oop.mixin(this.$options, options);
|
||||
return this;
|
||||
};
|
||||
|
||||
this.getOptions = function() {
|
||||
return lang.copyObject(this.$options);
|
||||
};
|
||||
|
||||
this.find = function(doc) {
|
||||
if (!this.$options.needle)
|
||||
return null;
|
||||
|
||||
if (this.$options.backwards) {
|
||||
var iterator = this.$backwardMatchIterator(doc);
|
||||
} else {
|
||||
iterator = this.$forwardMatchIterator(doc);
|
||||
}
|
||||
|
||||
var firstRange = null;
|
||||
iterator.forEach(function(range) {
|
||||
firstRange = range;
|
||||
return true;
|
||||
});
|
||||
|
||||
return firstRange;
|
||||
};
|
||||
|
||||
this.findAll = function(doc) {
|
||||
if (!this.$options.needle)
|
||||
return [];
|
||||
|
||||
if (this.$options.backwards) {
|
||||
var iterator = this.$backwardMatchIterator(doc);
|
||||
} else {
|
||||
iterator = this.$forwardMatchIterator(doc);
|
||||
}
|
||||
|
||||
var ranges = [];
|
||||
iterator.forEach(function(range) {
|
||||
ranges.push(range);
|
||||
});
|
||||
|
||||
return ranges;
|
||||
};
|
||||
|
||||
this.replace = function(input, replacement) {
|
||||
var re = this.$assembleRegExp();
|
||||
var match = re.exec(input);
|
||||
if (match && match[0].length == input.length) {
|
||||
if (this.$options.regExp) {
|
||||
return input.replace(re, replacement);
|
||||
} else {
|
||||
return replacement;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this.$forwardMatchIterator = function(doc) {
|
||||
var re = this.$assembleRegExp();
|
||||
var self = this;
|
||||
|
||||
return {
|
||||
forEach: function(callback) {
|
||||
self.$forwardLineIterator(doc).forEach(function(line, startIndex, row) {
|
||||
if (startIndex) {
|
||||
line = line.substring(startIndex);
|
||||
}
|
||||
|
||||
var matches = [];
|
||||
|
||||
line.replace(re, function(str) {
|
||||
var offset = arguments[arguments.length-2];
|
||||
matches.push({
|
||||
str: str,
|
||||
offset: startIndex + offset
|
||||
});
|
||||
return str;
|
||||
});
|
||||
|
||||
for (var i=0; i<matches.length; i++) {
|
||||
var match = matches[i];
|
||||
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
|
||||
if (callback(range))
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.$backwardMatchIterator = function(doc) {
|
||||
var re = this.$assembleRegExp();
|
||||
var self = this;
|
||||
|
||||
return {
|
||||
forEach: function(callback) {
|
||||
self.$backwardLineIterator(doc).forEach(function(line, startIndex, row) {
|
||||
if (startIndex) {
|
||||
line = line.substring(startIndex);
|
||||
}
|
||||
|
||||
var matches = [];
|
||||
|
||||
line.replace(re, function(str, offset) {
|
||||
matches.push({
|
||||
str: str,
|
||||
offset: startIndex + offset
|
||||
});
|
||||
return str;
|
||||
});
|
||||
|
||||
for (var i=matches.length-1; i>= 0; i--) {
|
||||
var match = matches[i];
|
||||
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
|
||||
if (callback(range))
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.$rangeFromMatch = function(row, column, length) {
|
||||
return new Range(row, column, row, column+length);
|
||||
};
|
||||
|
||||
this.$assembleRegExp = function() {
|
||||
if (this.$options.regExp) {
|
||||
var needle = this.$options.needle;
|
||||
} else {
|
||||
needle = lang.escapeRegExp(this.$options.needle);
|
||||
}
|
||||
|
||||
if (this.$options.wholeWord) {
|
||||
needle = "\\b" + needle + "\\b";
|
||||
}
|
||||
|
||||
var modifier = "g";
|
||||
if (!this.$options.caseSensitive) {
|
||||
modifier += "i";
|
||||
}
|
||||
|
||||
var re = new RegExp(needle, modifier);
|
||||
return re;
|
||||
};
|
||||
|
||||
this.$forwardLineIterator = function(doc) {
|
||||
var searchSelection = this.$options.scope == Search.SELECTION;
|
||||
|
||||
var range = doc.getSelection().getRange();
|
||||
var start = doc.getSelection().getCursor();
|
||||
|
||||
var firstRow = searchSelection ? range.start.row : 0;
|
||||
var firstColumn = searchSelection ? range.start.column : 0;
|
||||
var lastRow = searchSelection ? range.end.row : doc.getLength() - 1;
|
||||
|
||||
var wrap = this.$options.wrap;
|
||||
|
||||
function getLine(row) {
|
||||
var line = doc.getLine(row);
|
||||
if (searchSelection && row == range.end.row) {
|
||||
line = line.substring(0, range.end.column);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
return {
|
||||
forEach: function(callback) {
|
||||
var row = start.row;
|
||||
|
||||
var line = getLine(row);
|
||||
var startIndex = start.column;
|
||||
|
||||
var stop = false;
|
||||
|
||||
while (!callback(line, startIndex, row)) {
|
||||
|
||||
if (stop) {
|
||||
return;
|
||||
}
|
||||
|
||||
row++;
|
||||
startIndex = 0;
|
||||
|
||||
if (row > lastRow) {
|
||||
if (wrap) {
|
||||
row = firstRow;
|
||||
startIndex = firstColumn;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (row == start.row)
|
||||
stop = true;
|
||||
|
||||
line = getLine(row);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.$backwardLineIterator = function(doc) {
|
||||
var searchSelection = this.$options.scope == Search.SELECTION;
|
||||
|
||||
var range = doc.getSelection().getRange();
|
||||
var start = searchSelection ? range.end : range.start;
|
||||
|
||||
var firstRow = searchSelection ? range.start.row : 0;
|
||||
var firstColumn = searchSelection ? range.start.column : 0;
|
||||
var lastRow = searchSelection ? range.end.row : doc.getLength() - 1;
|
||||
|
||||
var wrap = this.$options.wrap;
|
||||
|
||||
return {
|
||||
forEach : function(callback) {
|
||||
var row = start.row;
|
||||
|
||||
var line = doc.getLine(row).substring(0, start.column);
|
||||
var startIndex = 0;
|
||||
var stop = false;
|
||||
|
||||
while (!callback(line, startIndex, row)) {
|
||||
|
||||
if (stop)
|
||||
return;
|
||||
|
||||
row--;
|
||||
startIndex = 0;
|
||||
|
||||
if (row < firstRow) {
|
||||
if (wrap) {
|
||||
row = lastRow;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (row == start.row)
|
||||
stop = true;
|
||||
|
||||
line = doc.getLine(row);
|
||||
if (searchSelection) {
|
||||
if (row == firstRow)
|
||||
startIndex = firstColumn;
|
||||
else if (row == lastRow)
|
||||
line = line.substring(0, range.end.column);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}).call(Search.prototype);
|
||||
|
||||
return Search;
|
||||
});
|
||||
417
src/ace/Selection.js
Normal file
417
src/ace/Selection.js
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/Selection", [
|
||||
"ace/lib/oop",
|
||||
"ace/lib/lang",
|
||||
"ace/MEventEmitter",
|
||||
"ace/Range"
|
||||
], function(oop, lang, MEventEmitter, Range) {
|
||||
|
||||
var Selection = function(doc) {
|
||||
this.doc = doc;
|
||||
|
||||
this.clearSelection();
|
||||
this.selectionLead = {
|
||||
row: 0,
|
||||
column: 0
|
||||
};
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
oop.implement(this, MEventEmitter);
|
||||
|
||||
this.isEmpty = function() {
|
||||
return (!this.selectionAnchor ||
|
||||
(this.selectionAnchor.row == this.selectionLead.row &&
|
||||
this.selectionAnchor.column == this.selectionLead.column));
|
||||
};
|
||||
|
||||
this.isMultiLine = function() {
|
||||
if (this.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getRange().isMultiLine();
|
||||
};
|
||||
|
||||
this.getCursor = function() {
|
||||
return this.selectionLead;
|
||||
};
|
||||
|
||||
this.setSelectionAnchor = function(row, column) {
|
||||
var anchor = this.$clipPositionToDocument(row, column);
|
||||
|
||||
if (!this.selectionAnchor) {
|
||||
this.selectionAnchor = anchor;
|
||||
this.$dispatchEvent("changeSelection", {});
|
||||
}
|
||||
else if (this.selectionAnchor.row !== anchor.row || this.selectionAnchor.column !== anchor.column) {
|
||||
this.selectionAnchor = anchor;
|
||||
this.$dispatchEvent("changeSelection", {});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.getSelectionAnchor = function() {
|
||||
if (this.selectionAnchor) {
|
||||
return this.$clone(this.selectionAnchor);
|
||||
} else {
|
||||
return this.$clone(this.selectionLead);
|
||||
}
|
||||
};
|
||||
|
||||
this.getSelectionLead = function() {
|
||||
return this.$clone(this.selectionLead);
|
||||
};
|
||||
|
||||
this.shiftSelection = function(columns) {
|
||||
if (this.isEmpty()) {
|
||||
this.moveCursorTo(this.selectionLead.row, this.selectionLead.column + columns);
|
||||
return;
|
||||
};
|
||||
|
||||
var anchor = this.getSelectionAnchor();
|
||||
var lead = this.getSelectionLead();
|
||||
|
||||
var isBackwards = this.isBackwards();
|
||||
|
||||
if (!isBackwards || anchor.column !== 0)
|
||||
this.setSelectionAnchor(anchor.row, anchor.column + columns);
|
||||
|
||||
if (isBackwards || lead.column !== 0) {
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(lead.row, lead.column + columns);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.isBackwards = function() {
|
||||
var anchor = this.selectionAnchor || this.selectionLead;
|
||||
var lead = this.selectionLead;
|
||||
return (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column));
|
||||
};
|
||||
|
||||
this.getRange = function() {
|
||||
var anchor = this.selectionAnchor || this.selectionLead;
|
||||
var lead = this.selectionLead;
|
||||
|
||||
if (this.isBackwards()) {
|
||||
return Range.fromPoints(lead, anchor);
|
||||
}
|
||||
else {
|
||||
return Range.fromPoints(anchor, lead);
|
||||
}
|
||||
};
|
||||
|
||||
this.clearSelection = function() {
|
||||
if (this.selectionAnchor) {
|
||||
this.selectionAnchor = null;
|
||||
this.$dispatchEvent("changeSelection", {});
|
||||
}
|
||||
};
|
||||
|
||||
this.selectAll = function() {
|
||||
var lastRow = this.doc.getLength() - 1;
|
||||
this.setSelectionAnchor(lastRow, this.doc.getLine(lastRow).length);
|
||||
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(0, 0);
|
||||
});
|
||||
};
|
||||
|
||||
this.setSelectionRange = function(range, reverse) {
|
||||
if (reverse) {
|
||||
this.setSelectionAnchor(range.end.row, range.end.column);
|
||||
this.selectTo(range.start.row, range.start.column);
|
||||
} else {
|
||||
this.setSelectionAnchor(range.start.row, range.start.column);
|
||||
this.selectTo(range.end.row, range.end.column);
|
||||
}
|
||||
};
|
||||
|
||||
this.$moveSelection = function(mover) {
|
||||
var changed = false;
|
||||
|
||||
if (!this.selectionAnchor) {
|
||||
changed = true;
|
||||
this.selectionAnchor = this.$clone(this.selectionLead);
|
||||
}
|
||||
|
||||
var cursor = this.$clone(this.selectionLead);
|
||||
mover.call(this);
|
||||
|
||||
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.$dispatchEvent("changeSelection", {});
|
||||
};
|
||||
|
||||
this.selectTo = function(row, column) {
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(row, column);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectToPosition = function(pos) {
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorToPosition(pos);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectUp = function() {
|
||||
this.$moveSelection(this.moveCursorUp);
|
||||
};
|
||||
|
||||
this.selectDown = function() {
|
||||
this.$moveSelection(this.moveCursorDown);
|
||||
};
|
||||
|
||||
this.selectRight = function() {
|
||||
this.$moveSelection(this.moveCursorRight);
|
||||
};
|
||||
|
||||
this.selectLeft = function() {
|
||||
this.$moveSelection(this.moveCursorLeft);
|
||||
};
|
||||
|
||||
this.selectLineStart = function() {
|
||||
this.$moveSelection(this.moveCursorLineStart);
|
||||
};
|
||||
|
||||
this.selectLineEnd = function() {
|
||||
this.$moveSelection(this.moveCursorLineEnd);
|
||||
};
|
||||
|
||||
this.selectFileEnd = function() {
|
||||
this.$moveSelection(this.moveCursorFileEnd);
|
||||
};
|
||||
|
||||
this.selectFileStart = function() {
|
||||
this.$moveSelection(this.moveCursorFileStart);
|
||||
};
|
||||
|
||||
this.tokenRe = /^[\w\d]+/g;
|
||||
this.nonTokenRe = /^[^\w\d]+/g;
|
||||
|
||||
this.selectWordRight = function() {
|
||||
this.$moveSelection(this.moveCursorWordRight);
|
||||
};
|
||||
|
||||
this.selectWordLeft = function() {
|
||||
this.$moveSelection(this.moveCursorWordLeft);
|
||||
};
|
||||
|
||||
this.selectWord = function() {
|
||||
var cursor = this.selectionLead;
|
||||
|
||||
var line = this.doc.getLine(cursor.row);
|
||||
var column = cursor.column;
|
||||
|
||||
var inToken = false;
|
||||
if (column > 0) {
|
||||
inToken = !!line.charAt(column - 1).match(this.tokenRe);
|
||||
}
|
||||
|
||||
if (!inToken) {
|
||||
inToken = !!line.charAt(column).match(this.tokenRe);
|
||||
}
|
||||
|
||||
var re = inToken ? this.tokenRe : this.nonTokenRe;
|
||||
|
||||
var start = column;
|
||||
if (start > 0) {
|
||||
do {
|
||||
start--;
|
||||
}
|
||||
while (start >= 0 && line.charAt(start).match(re));
|
||||
start++;
|
||||
}
|
||||
|
||||
var end = column;
|
||||
while (end < line.length && line.charAt(end).match(re)) {
|
||||
end++;
|
||||
}
|
||||
|
||||
this.setSelectionAnchor(cursor.row, start);
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(cursor.row, end);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectLine = function() {
|
||||
this.setSelectionAnchor(this.selectionLead.row, 0);
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(this.selectionLead.row + 1, 0);
|
||||
});
|
||||
};
|
||||
|
||||
this.moveCursorUp = function() {
|
||||
this.moveCursorBy(-1, 0);
|
||||
};
|
||||
|
||||
this.moveCursorDown = function() {
|
||||
this.moveCursorBy(1, 0);
|
||||
};
|
||||
|
||||
this.moveCursorLeft = function() {
|
||||
if (this.selectionLead.column == 0) {
|
||||
if (this.selectionLead.row > 0) {
|
||||
this.moveCursorTo(this.selectionLead.row - 1, this.doc
|
||||
.getLine(this.selectionLead.row - 1).length);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moveCursorBy(0, -1);
|
||||
}
|
||||
};
|
||||
|
||||
this.moveCursorRight = function() {
|
||||
if (this.selectionLead.column == this.doc.getLine(this.selectionLead.row).length) {
|
||||
if (this.selectionLead.row < this.doc.getLength() - 1) {
|
||||
this.moveCursorTo(this.selectionLead.row + 1, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moveCursorBy(0, 1);
|
||||
}
|
||||
};
|
||||
|
||||
this.moveCursorLineStart = function() {
|
||||
var row = this.selectionLead.row;
|
||||
var column = this.selectionLead.column;
|
||||
var beforeCursor = this.doc.getLine(row).slice(0, column);
|
||||
var leadingSpace = beforeCursor.match(/^\s+/);
|
||||
if (!leadingSpace || leadingSpace[0].length >= column)
|
||||
this.moveCursorTo(this.selectionLead.row, 0);
|
||||
else
|
||||
this.moveCursorTo(this.selectionLead.row, leadingSpace[0].length);
|
||||
};
|
||||
|
||||
this.moveCursorLineEnd = function() {
|
||||
this.moveCursorTo(this.selectionLead.row,
|
||||
this.doc.getLine(this.selectionLead.row).length);
|
||||
};
|
||||
|
||||
this.moveCursorFileEnd = function() {
|
||||
var row = this.doc.getLength() - 1;
|
||||
var column = this.doc.getLine(row).length;
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorFileStart = function() {
|
||||
this.moveCursorTo(0, 0);
|
||||
};
|
||||
|
||||
this.moveCursorWordRight = function() {
|
||||
var row = this.selectionLead.row;
|
||||
var column = this.selectionLead.column;
|
||||
var line = this.doc.getLine(row);
|
||||
var rightOfCursor = line.substring(column);
|
||||
|
||||
var match;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
|
||||
if (column == line.length) {
|
||||
this.moveCursorRight();
|
||||
return;
|
||||
}
|
||||
else if (match = this.nonTokenRe.exec(rightOfCursor)) {
|
||||
column += this.nonTokenRe.lastIndex;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
}
|
||||
else if (match = this.tokenRe.exec(rightOfCursor)) {
|
||||
column += this.tokenRe.lastIndex;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
}
|
||||
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorWordLeft = function() {
|
||||
var row = this.selectionLead.row;
|
||||
var column = this.selectionLead.column;
|
||||
var line = this.doc.getLine(row);
|
||||
var leftOfCursor = lang.stringReverse(line.substring(0, column));
|
||||
|
||||
var match;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
|
||||
if (column == 0) {
|
||||
this.moveCursorLeft();
|
||||
return;
|
||||
}
|
||||
else if (match = this.nonTokenRe.exec(leftOfCursor)) {
|
||||
column -= this.nonTokenRe.lastIndex;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
}
|
||||
else if (match = this.tokenRe.exec(leftOfCursor)) {
|
||||
column -= this.tokenRe.lastIndex;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
}
|
||||
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorBy = function(rows, chars) {
|
||||
this.moveCursorTo(this.selectionLead.row + rows, this.selectionLead.column + chars);
|
||||
};
|
||||
|
||||
|
||||
this.moveCursorToPosition = function(position) {
|
||||
this.moveCursorTo(position.row, position.column);
|
||||
};
|
||||
|
||||
this.moveCursorTo = function(row, column) {
|
||||
var cursor = this.$clipPositionToDocument(row, column);
|
||||
|
||||
// only dispatch change if the cursor actually changed
|
||||
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
|
||||
this.selectionLead = cursor;
|
||||
this.$dispatchEvent("changeCursor", { data: this.getCursor() });
|
||||
}
|
||||
};
|
||||
|
||||
this.moveCursorUp = function() {
|
||||
this.moveCursorBy(-1, 0);
|
||||
};
|
||||
|
||||
this.$clipPositionToDocument = function(row, column) {
|
||||
var pos = {};
|
||||
|
||||
if (row >= this.doc.getLength()) {
|
||||
pos.row = Math.max(0, this.doc.getLength() - 1);
|
||||
pos.column = this.doc.getLine(pos.row).length;
|
||||
}
|
||||
else if (row < 0) {
|
||||
pos.row = 0;
|
||||
pos.column = 0;
|
||||
}
|
||||
else {
|
||||
pos.row = row;
|
||||
pos.column = Math.min(this.doc.getLine(pos.row).length,
|
||||
Math.max(0, column));
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
this.$clone = function(pos) {
|
||||
return {
|
||||
row: pos.row,
|
||||
column: pos.column
|
||||
};
|
||||
};
|
||||
|
||||
}).call(Selection.prototype);
|
||||
|
||||
return Selection;
|
||||
});
|
||||
118
src/ace/TextInput.js
Normal file
118
src/ace/TextInput.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/TextInput", ["ace/lib/event"], function(event) {
|
||||
|
||||
var TextInput = function(parentNode, host) {
|
||||
|
||||
var text = document.createElement("textarea");
|
||||
var style = text.style;
|
||||
style.position = "absolute";
|
||||
style.left = "-10000px";
|
||||
style.top = "-10000px";
|
||||
parentNode.appendChild(text);
|
||||
|
||||
var PLACEHOLDER = String.fromCharCode(0);
|
||||
sendText();
|
||||
|
||||
var inCompostion = false;
|
||||
var copied = false;
|
||||
|
||||
function sendText() {
|
||||
if (!copied) {
|
||||
var value = text.value;
|
||||
if (value) {
|
||||
if (value.charCodeAt(value.length-1) == PLACEHOLDER.charCodeAt(0)) {
|
||||
value = value.slice(0, -1);
|
||||
if (value)
|
||||
host.onTextInput(value);
|
||||
} else
|
||||
host.onTextInput(value);
|
||||
}
|
||||
}
|
||||
copied = false;
|
||||
|
||||
// Safari doesn't fire copy events if no text is selected
|
||||
text.value = PLACEHOLDER;
|
||||
text.select();
|
||||
}
|
||||
|
||||
var onTextInput = function(e) {
|
||||
setTimeout(function() {
|
||||
if (!inCompostion)
|
||||
sendText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onCompositionStart = function(e) {
|
||||
inCompostion = true;
|
||||
sendText();
|
||||
text.value = "";
|
||||
host.onCompositionStart();
|
||||
setTimeout(onCompositionUpdate, 0);
|
||||
};
|
||||
|
||||
var onCompositionUpdate = function() {
|
||||
host.onCompositionUpdate(text.value);
|
||||
};
|
||||
|
||||
var onCompositionEnd = function() {
|
||||
inCompostion = false;
|
||||
host.onCompositionEnd();
|
||||
onTextInput();
|
||||
};
|
||||
|
||||
var onCopy = function() {
|
||||
copied = true;
|
||||
text.value = host.getCopyText();
|
||||
text.select();
|
||||
copied = true;
|
||||
setTimeout(sendText, 0);
|
||||
};
|
||||
|
||||
var onCut = function() {
|
||||
copied = true;
|
||||
text.value = host.getCopyText();
|
||||
host.onCut();
|
||||
text.select();
|
||||
setTimeout(sendText, 0);
|
||||
};
|
||||
|
||||
event.addListener(text, "keypress", onTextInput);
|
||||
event.addListener(text, "textInput", onTextInput);
|
||||
event.addListener(text, "paste", onTextInput);
|
||||
event.addListener(text, "propertychange", onTextInput);
|
||||
|
||||
event.addListener(text, "copy", onCopy);
|
||||
event.addListener(text, "cut", onCut);
|
||||
|
||||
event.addListener(text, "compositionstart", onCompositionStart);
|
||||
event.addListener(text, "compositionupdate", onCompositionUpdate);
|
||||
event.addListener(text, "compositionend", onCompositionEnd);
|
||||
|
||||
event.addListener(text, "blur", function() {
|
||||
host.onBlur();
|
||||
});
|
||||
|
||||
event.addListener(text, "focus", function() {
|
||||
host.onFocus();
|
||||
text.select();
|
||||
});
|
||||
|
||||
this.focus = function() {
|
||||
host.onFocus();
|
||||
text.select();
|
||||
text.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
text.blur();
|
||||
};
|
||||
};
|
||||
|
||||
return TextInput;
|
||||
});
|
||||
102
src/ace/Tokenizer.js
Normal file
102
src/ace/Tokenizer.js
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/Tokenizer", [], function() {
|
||||
|
||||
var Tokenizer = function(rules) {
|
||||
this.rules = rules;
|
||||
|
||||
this.regExps = {};
|
||||
for ( var key in this.rules) {
|
||||
var state = this.rules[key];
|
||||
var ruleRegExps = [];
|
||||
|
||||
for ( var i = 0; i < state.length; i++) {
|
||||
ruleRegExps.push(state[i].regex);
|
||||
};
|
||||
|
||||
this.regExps[key] = new RegExp("(?:(" + ruleRegExps.join(")|(") + ")|(.))", "g");
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.getLineTokens = function(line, startState) {
|
||||
var currentState = startState;
|
||||
var state = this.rules[currentState];
|
||||
var re = this.regExps[currentState];
|
||||
re.lastIndex = 0;
|
||||
|
||||
var match, tokens = [];
|
||||
|
||||
var lastIndex = 0;
|
||||
|
||||
var token = {
|
||||
type: null,
|
||||
value: ""
|
||||
};
|
||||
|
||||
while (match = re.exec(line)) {
|
||||
var type = "text";
|
||||
var value = match[0];
|
||||
|
||||
if (re.lastIndex == lastIndex) { throw new Error("tokenizer error"); }
|
||||
lastIndex = re.lastIndex;
|
||||
|
||||
window.LOG && console.log(currentState, match);
|
||||
|
||||
for ( var i = 0; i < state.length; i++) {
|
||||
if (match[i + 1]) {
|
||||
if (typeof state[i].token == "function") {
|
||||
type = state[i].token(match[0]);
|
||||
}
|
||||
else {
|
||||
type = state[i].token;
|
||||
}
|
||||
|
||||
if (state[i].next && state[i].next !== currentState) {
|
||||
currentState = state[i].next;
|
||||
var state = this.rules[currentState];
|
||||
var lastIndex = re.lastIndex;
|
||||
|
||||
var re = this.regExps[currentState];
|
||||
re.lastIndex = lastIndex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (token.type !== type) {
|
||||
if (token.type) {
|
||||
tokens.push(token);
|
||||
}
|
||||
token = {
|
||||
type: type,
|
||||
value: value
|
||||
};
|
||||
} else {
|
||||
token.value += value;
|
||||
}
|
||||
};
|
||||
|
||||
if (token.type) {
|
||||
tokens.push(token);
|
||||
}
|
||||
|
||||
window.LOG && console.log(tokens, currentState);
|
||||
|
||||
return {
|
||||
tokens : tokens,
|
||||
state : currentState
|
||||
};
|
||||
};
|
||||
|
||||
}).call(Tokenizer.prototype);
|
||||
|
||||
return Tokenizer;
|
||||
});
|
||||
47
src/ace/UndoManager.js
Normal file
47
src/ace/UndoManager.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* Ajax.org Code Editor (ACE)
|
||||
*
|
||||
* @copyright 2010, Ajax.org Services B.V.
|
||||
* @license LGPLv3 <http://www.gnu.org/licenses/lgpl-3.0.txt>
|
||||
* @author Fabian Jakobs <fabian AT ajax DOT org>
|
||||
*/
|
||||
require.def("ace/UndoManager", function() {
|
||||
|
||||
var UndoManager = function() {
|
||||
this.$undoStack = [];
|
||||
this.$redoStack = [];
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
/*this.$doc = null;
|
||||
this.setDocument = function(doc) {
|
||||
this.$doc = doc;
|
||||
};*/
|
||||
|
||||
this.execute = function(options) {
|
||||
var deltas = options.args[0];
|
||||
this.$doc = options.args[1];
|
||||
this.$undoStack.push(deltas);
|
||||
};
|
||||
|
||||
this.undo = function() {
|
||||
var deltas = this.$undoStack.pop();
|
||||
if (deltas) {
|
||||
this.$doc.undoChanges(deltas);
|
||||
this.$redoStack.push(deltas);
|
||||
}
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
var deltas = this.$redoStack.pop();
|
||||
if (deltas) {
|
||||
this.$doc.redoChanges(deltas);
|
||||
this.$undoStack.push(deltas);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(UndoManager.prototype);
|
||||
|
||||
return UndoManager;
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue