git add stuff
This commit is contained in:
19
simpla/design/js/codemirror/LICENSE
Normal file
19
simpla/design/js/codemirror/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2011 by Marijn Haverbeke <marijnh@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
6
simpla/design/js/codemirror/README.md
Normal file
6
simpla/design/js/codemirror/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# CodeMirror 2
|
||||
|
||||
CodeMirror 2 is a rewrite of [CodeMirror
|
||||
1](http://github.com/marijnh/CodeMirror). The docs live
|
||||
[here](http://codemirror.net/2/manual.html), and the project page is
|
||||
[http://codemirror.net/2/](http://codemirror.net/2/).
|
||||
77
simpla/design/js/codemirror/compress.html
Normal file
77
simpla/design/js/codemirror/compress.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: Compression Helper</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
|
||||
|
||||
<pre class="grey">
|
||||
<img src="css/baboon.png" class="logo" alt="logo"/>/* Script compression
|
||||
helper */
|
||||
</pre>
|
||||
|
||||
<p>To optimize loading CodeMirror, especially when including a
|
||||
bunch of different modes, it is recommended that you combine and
|
||||
minify (and preferably also gzip) the scrips. This page makes
|
||||
those first two steps very easy. Simply select the version and
|
||||
scripts you need in the form below, and
|
||||
click <strong>Compress</strong> to download the minified script
|
||||
file.</p>
|
||||
|
||||
<form id="form" action="http://marijnhaverbeke.nl/uglifyjs" method="post">
|
||||
<input type="hidden" id="download" name="download" value="codemirror-compressed.js"/>
|
||||
<p>Version: <select id="version" onchange="setVersion(this);" style="padding: 1px">
|
||||
<option value="http://codemirror.net/2/">HEAD</option>
|
||||
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=v2.0;f=">2.0</option>
|
||||
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=beta2;f=">beta2</option>
|
||||
<option value="http://marijnhaverbeke.nl/git/codemirror2?a=blob_plain;hb=beta1;f=">beta1</option>
|
||||
</select></p>
|
||||
|
||||
<select multiple="multiple" name="code_url" style="width: 40em;" class="field" id="files">
|
||||
<optgroup label="CodeMirror Library">
|
||||
<option value="http://codemirror.net/2/lib/codemirror.js" selected>codemirror.js</option>
|
||||
<option value="http://codemirror.net/2/lib/overlay.js">overlay.js</option>
|
||||
</optgroup>
|
||||
<optgroup label="Modes">
|
||||
<option value="http://codemirror.net/2/mode/javascript/javascript.js">javascript.js</option>
|
||||
<option value="http://codemirror.net/2/mode/xml/xml.js">xml.js</option>
|
||||
<option value="http://codemirror.net/2/mode/css/css.js">css.js</option>
|
||||
<option value="http://codemirror.net/2/mode/htmlmixed/htmlmixed.js">htmlmixed.js</option>
|
||||
<option value="http://codemirror.net/2/mode/clike/clike.js">clike.js</option>
|
||||
<option value="http://codemirror.net/2/mode/php/php.js">php.js</option>
|
||||
<option value="http://codemirror.net/2/mode/haskell/haskell.js">haskell.js</option>
|
||||
<option value="http://codemirror.net/2/mode/diff/diff.js">diff.js</option>
|
||||
<option value="http://codemirror.net/2/mode/stex/stex.js">stex.js</option>
|
||||
</optgroup>
|
||||
</select></p>
|
||||
|
||||
<p>
|
||||
<button type="submit">Compress</button> with <a href="http://github.com/mishoo/UglifyJS/">UglifyJS</a>
|
||||
</p>
|
||||
|
||||
<p>Custom code to add to the compressed file:<textarea name="js_code" style="width: 100%; height: 15em;" class="field"></textarea></p>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
function setVersion(ver) {
|
||||
var urlprefix = ver.options[ver.selectedIndex].value;
|
||||
var select = document.getElementById("files"), m;
|
||||
for (var optgr = select.firstChild; optgr; optgr = optgr.nextSibling)
|
||||
for (var opt = optgr.firstChild; opt; opt = opt.nextSibling) {
|
||||
if (opt.nodeName != "OPTION")
|
||||
continue;
|
||||
else if (m = opt.value.match(/^http:\/\/codemirror.net\/2\/(.*)$/))
|
||||
opt.value = urlprefix + m[1];
|
||||
else if (m = opt.value.match(/http:\/\/marijnhaverbeke.nl\/git\/codemirror\?a=blob_plain;hb=[^;]+;f=(.*)$/))
|
||||
opt.value = urlprefix + m[1];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="css/font.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
simpla/design/js/codemirror/css/baboon.png
Normal file
BIN
simpla/design/js/codemirror/css/baboon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
153
simpla/design/js/codemirror/css/baboon_vector.svg
Normal file
153
simpla/design/js/codemirror/css/baboon_vector.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 17 KiB |
158
simpla/design/js/codemirror/css/docs.css
Normal file
158
simpla/design/js/codemirror/css/docs.css
Normal file
@@ -0,0 +1,158 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
max-width: 64.3em;
|
||||
margin: 3em auto;
|
||||
padding: 0 1em;
|
||||
}
|
||||
body.droid {
|
||||
font-family: Droid Sans, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
letter-spacing: -3px;
|
||||
font-size: 3.23em;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.23em;
|
||||
font-weight: bold;
|
||||
margin: .5em 0;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
margin: .4em 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: Courier New, monospaced;
|
||||
background-color: #eee;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
pre.code {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
.grey {
|
||||
font-size: 2em;
|
||||
padding: .5em 1em;
|
||||
line-height: 1.2em;
|
||||
margin-top: .5em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
position: absolute;
|
||||
right: -25px;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
a:link, a:visited, .quasilink {
|
||||
color: #df0019;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover, .quasilink:hover {
|
||||
color: #800004;
|
||||
}
|
||||
|
||||
h1 a:link, h1 a:visited, h1 a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 1.2em;
|
||||
}
|
||||
|
||||
a.download {
|
||||
color: white;
|
||||
background-color: #df0019;
|
||||
width: 100%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 1.23em;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
padding: .5em 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
a.download:hover {
|
||||
background-color: #bb0010;
|
||||
}
|
||||
|
||||
.rel {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.rel-note {
|
||||
color: #777;
|
||||
font-size: .9em;
|
||||
margin-top: .1em;
|
||||
}
|
||||
|
||||
.logo-braces {
|
||||
color: #df0019;
|
||||
position: relative;
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
.blk {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 37em;
|
||||
padding-right: 6.53em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.left1 {
|
||||
width: 15.24em;
|
||||
padding-right: 6.45em;
|
||||
}
|
||||
|
||||
.left2 {
|
||||
width: 15.24em;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 20.68em;
|
||||
}
|
||||
|
||||
.leftbig {
|
||||
width: 42.44em;
|
||||
padding-right: 6.53em;
|
||||
}
|
||||
|
||||
.rightsmall {
|
||||
width: 15.24em;
|
||||
}
|
||||
|
||||
.clear:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
.clear { display: inline-block; }
|
||||
/* start commented backslash hack \*/
|
||||
* html .clear { height: 1%; }
|
||||
.clear { display: block; }
|
||||
/* close commented backslash hack */
|
||||
15
simpla/design/js/codemirror/css/font.js
Normal file
15
simpla/design/js/codemirror/css/font.js
Normal file
@@ -0,0 +1,15 @@
|
||||
function waitForStyles() {
|
||||
for (var i = 0; i < document.styleSheets.length; i++)
|
||||
if (/googleapis/.test(document.styleSheets[i].href))
|
||||
return document.body.className += " droid";
|
||||
setTimeout(waitForStyles, 100);
|
||||
}
|
||||
setTimeout(function() {
|
||||
if (/AppleWebKit/.test(navigator.userAgent) && /iP[oa]d|iPhone/.test(navigator.userAgent)) return;
|
||||
var link = document.createElement("LINK");
|
||||
link.type = "text/css";
|
||||
link.rel = "stylesheet";
|
||||
link.href = "http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold";
|
||||
document.documentElement.getElementsByTagName("HEAD")[0].appendChild(link);
|
||||
waitForStyles();
|
||||
}, 10);
|
||||
71
simpla/design/js/codemirror/demo/activeline.html
vendored
Normal file
71
simpla/design/js/codemirror/demo/activeline.html
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Active Line Demo</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="../mode/xml/xml.css">
|
||||
<script src="../mode/xml/xml.js"></script>
|
||||
<link rel="stylesheet" href="../css/docs.css">
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
|
||||
.activeline {background: #f0fcff !important;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Active Line Demo</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
|
||||
xmlns:georss="http://www.georss.org/georss"
|
||||
xmlns:twitter="http://api.twitter.com">
|
||||
<channel>
|
||||
<title>Twitter / codemirror</title>
|
||||
<link>http://twitter.com/codemirror</link>
|
||||
<atom:link type="application/rss+xml"
|
||||
href="http://twitter.com/statuses/user_timeline/242283288.rss" rel="self"/>
|
||||
<description>Twitter updates from CodeMirror / codemirror.</description>
|
||||
<language>en-us</language>
|
||||
<ttl>40</ttl>
|
||||
<item>
|
||||
<title>codemirror: http://cloud-ide.com — they're springing up like mushrooms. This one
|
||||
uses CodeMirror as its editor.</title>
|
||||
<description>codemirror: http://cloud-ide.com — they're springing up like mushrooms. This
|
||||
one uses CodeMirror as its editor.</description>
|
||||
<pubDate>Thu, 17 Mar 2011 23:34:47 +0000</pubDate>
|
||||
<guid>http://twitter.com/codemirror/statuses/48527733722058752</guid>
|
||||
<link>http://twitter.com/codemirror/statuses/48527733722058752</link>
|
||||
<twitter:source>web</twitter:source>
|
||||
<twitter:place/>
|
||||
</item>
|
||||
<item>
|
||||
<title>codemirror: Posted a description of the CodeMirror 2 internals at
|
||||
http://codemirror.net/2/internals.html</title>
|
||||
<description>codemirror: Posted a description of the CodeMirror 2 internals at
|
||||
http://codemirror.net/2/internals.html</description>
|
||||
<pubDate>Wed, 02 Mar 2011 12:15:09 +0000</pubDate>
|
||||
<guid>http://twitter.com/codemirror/statuses/42920879788789760</guid>
|
||||
<link>http://twitter.com/codemirror/statuses/42920879788789760</link>
|
||||
<twitter:source>web</twitter:source>
|
||||
<twitter:place/>
|
||||
</item>
|
||||
</feed></textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
mode: "application/xml",
|
||||
lineNumbers: true,
|
||||
onCursorActivity: function() {
|
||||
editor.setLineClass(hlLine, null);
|
||||
hlLine = editor.setLineClass(editor.getCursor().line, "activeline");
|
||||
}
|
||||
});
|
||||
var hlLine = editor.setLineClass(0, "activeline");
|
||||
</script>
|
||||
|
||||
<p>Styling the current cursor line.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
79
simpla/design/js/codemirror/demo/complete.html
vendored
Normal file
79
simpla/design/js/codemirror/demo/complete.html
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Autocomplete Demo</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="../mode/javascript/javascript.css">
|
||||
<script src="../mode/javascript/javascript.js"></script>
|
||||
<link rel="stylesheet" href="../css/docs.css">
|
||||
|
||||
<style type="text/css">
|
||||
.completions {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
}
|
||||
.completions select {
|
||||
background: #fafafa;
|
||||
outline: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: monospace;
|
||||
}
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Autocomplete demo</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
function getCompletions(token, context) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
for (var name in obj) maybeAdd(name);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.className == "js-variable")
|
||||
base = window[obj.string];
|
||||
else if (obj.className == "js-string")
|
||||
base = "";
|
||||
else if (obj.className == "js-atom")
|
||||
base = 1;
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
else {
|
||||
// If not, just look in the window object and any local scope
|
||||
// (reading into JS mode internals to get at the local variables)
|
||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||
gatherCompletions(window);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
</textarea></form>
|
||||
|
||||
<p>Press <strong>ctrl-space</strong> to activate autocompletion. See
|
||||
the <a href="complete.js">code</a> to figure out how it works.</p>
|
||||
|
||||
<script src="complete.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
150
simpla/design/js/codemirror/demo/complete.js
vendored
Normal file
150
simpla/design/js/codemirror/demo/complete.js
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
(function () {
|
||||
// Minimal event-handling wrapper.
|
||||
function stopEvent() {
|
||||
if (this.preventDefault) {this.preventDefault(); this.stopPropagation();}
|
||||
else {this.returnValue = false; this.cancelBubble = true;}
|
||||
}
|
||||
function addStop(event) {
|
||||
if (!event.stop) event.stop = stopEvent;
|
||||
return event;
|
||||
}
|
||||
function connect(node, type, handler) {
|
||||
function wrapHandler(event) {handler(addStop(event || window.event));}
|
||||
if (typeof node.addEventListener == "function")
|
||||
node.addEventListener(type, wrapHandler, false);
|
||||
else
|
||||
node.attachEvent("on" + type, wrapHandler);
|
||||
}
|
||||
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
onKeyEvent: function(i, e) {
|
||||
// Hook into ctrl-space
|
||||
if (e.keyCode == 32 && (e.ctrlKey || e.metaKey) && !e.altKey) {
|
||||
e.stop();
|
||||
return startComplete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function startComplete() {
|
||||
// We want a single cursor position.
|
||||
if (editor.somethingSelected()) return;
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(false), token = editor.getTokenAt(cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == "." ? "js-property" : null};
|
||||
}
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.className == "js-property") {
|
||||
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
|
||||
if (tprop.string != ".") return;
|
||||
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
var completions = getCompletions(token, context);
|
||||
if (!completions.length) return;
|
||||
function insert(str) {
|
||||
editor.replaceRange(str, {line: cur.line, ch: token.start}, {line: cur.line, ch: token.end});
|
||||
}
|
||||
// When there is only one completion, use it directly.
|
||||
if (completions.length == 1) {insert(completions[0]); return true;}
|
||||
|
||||
// Build the select widget
|
||||
var complete = document.createElement("div");
|
||||
complete.className = "completions";
|
||||
var sel = complete.appendChild(document.createElement("select"));
|
||||
sel.multiple = true;
|
||||
for (var i = 0; i < completions.length; ++i) {
|
||||
var opt = sel.appendChild(document.createElement("option"));
|
||||
opt.appendChild(document.createTextNode(completions[i]));
|
||||
}
|
||||
sel.firstChild.selected = true;
|
||||
sel.size = Math.min(10, completions.length);
|
||||
var pos = editor.cursorCoords();
|
||||
complete.style.left = pos.x + "px";
|
||||
complete.style.top = pos.yBot + "px";
|
||||
document.body.appendChild(complete);
|
||||
// Hack to hide the scrollbar.
|
||||
if (completions.length <= 10)
|
||||
complete.style.width = (sel.clientWidth - 1) + "px";
|
||||
|
||||
var done = false;
|
||||
function close() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
complete.parentNode.removeChild(complete);
|
||||
}
|
||||
function pick() {
|
||||
insert(sel.options[sel.selectedIndex].value);
|
||||
close();
|
||||
setTimeout(function(){editor.focus();}, 50);
|
||||
}
|
||||
connect(sel, "blur", close);
|
||||
connect(sel, "keydown", function(event) {
|
||||
var code = event.keyCode;
|
||||
// Enter and space
|
||||
if (code == 13 || code == 32) {event.stop(); pick();}
|
||||
// Escape
|
||||
else if (code == 27) {event.stop(); close(); editor.focus();}
|
||||
else if (code != 38 && code != 40) {close(); editor.focus(); setTimeout(startComplete, 50);}
|
||||
});
|
||||
connect(sel, "dblclick", pick);
|
||||
|
||||
sel.focus();
|
||||
// Opera sometimes ignores focusing a freshly created node
|
||||
if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||
var funcProps = "prototype apply call bind".split(" ");
|
||||
var keywords = ("break case catch continue debugger default delete do else false finally for function " +
|
||||
"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
|
||||
|
||||
function getCompletions(token, context) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
for (var name in obj) maybeAdd(name);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.className == "js-variable")
|
||||
base = window[obj.string];
|
||||
else if (obj.className == "js-string")
|
||||
base = "";
|
||||
else if (obj.className == "js-atom")
|
||||
base = 1;
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
else {
|
||||
// If not, just look in the window object and any local scope
|
||||
// (reading into JS mode internals to get at the local variables)
|
||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||
gatherCompletions(window);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
})();
|
||||
53
simpla/design/js/codemirror/demo/marker.html
vendored
Normal file
53
simpla/design/js/codemirror/demo/marker.html
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Breakpoint Demo</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="../mode/javascript/javascript.css">
|
||||
<script src="../mode/javascript/javascript.js"></script>
|
||||
<link rel="stylesheet" href="../css/docs.css">
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror-gutter {
|
||||
width: 3em;
|
||||
background: white;
|
||||
}
|
||||
.CodeMirror {
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Breakpoint demo</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
onGutterClick: function(cm, n) {
|
||||
var info = cm.lineInfo(n);
|
||||
if (info.markerText)
|
||||
cm.clearMarker(n);
|
||||
else
|
||||
cm.setMarker(n, "<span style=\"color: #900\">●</span> %N%");
|
||||
}
|
||||
});
|
||||
</textarea></form>
|
||||
|
||||
<p>Click the line-number gutter to add or remove 'breakpoints'.</p>
|
||||
|
||||
<script>
|
||||
CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
onGutterClick: function(cm, n) {
|
||||
var info = cm.lineInfo(n);
|
||||
if (info.markerText)
|
||||
cm.clearMarker(n);
|
||||
else
|
||||
cm.setMarker(n, "<span style=\"color: #900\">●</span> %N%");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
57
simpla/design/js/codemirror/demo/mustache.html
vendored
Normal file
57
simpla/design/js/codemirror/demo/mustache.html
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Overlay Parser Demo</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<script src="../lib/overlay.js"></script>
|
||||
<link rel="stylesheet" href="../mode/xml/xml.css">
|
||||
<script src="../mode/xml/xml.js"></script>
|
||||
<link rel="stylesheet" href="../css/docs.css">
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror {border: 1px solid black;}
|
||||
.mustache {color: #0ca;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Overlay Parser Demo</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
<html>
|
||||
<body>
|
||||
<h1>{{title}}</h1>
|
||||
<p>These are links to {{things}}:</p>
|
||||
<ul>{{#links}}
|
||||
<li><a href="{{url}}">{{text}}</a></li>
|
||||
{{/links}}</ul>
|
||||
</body>
|
||||
</html>
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
CodeMirror.defineMode("mustache", function(config, parserConfig) {
|
||||
var mustacheOverlay = {
|
||||
token: function(stream, state) {
|
||||
if (stream.match("{{")) {
|
||||
while ((ch = stream.next()) != null)
|
||||
if (ch == "}" && stream.next() == "}") break;
|
||||
return "mustache";
|
||||
}
|
||||
while (stream.next() != null && !stream.match("{{", false)) {}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return CodeMirror.overlayParser(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay);
|
||||
});
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "mustache"});
|
||||
</script>
|
||||
|
||||
<p>Demonstration of a mode that parses HTML, highlighting
|
||||
the <a href="http://mustache.github.com/">Mustache</a> templating
|
||||
directives inside of it by using the code
|
||||
in <a href="../lib/overlay.js"><code>overlay.js</code></a>. View
|
||||
source to see the 15 lines of code needed to accomplish this.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
38
simpla/design/js/codemirror/demo/resize.html
vendored
Normal file
38
simpla/design/js/codemirror/demo/resize.html
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Autoresize Demo</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="../mode/css/css.css">
|
||||
<script src="../mode/css/css.js"></script>
|
||||
<link rel="stylesheet" href="../css/docs.css">
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Autoresize demo</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
.CodeMirror {
|
||||
height: auto;
|
||||
}</textarea></form>
|
||||
|
||||
<p>By setting a single CSS property, CodeMirror can be made to
|
||||
automatically resize to fit the content. Use <code>max-height</code>
|
||||
to prevent it from growing past a given point (on halfway modern
|
||||
browsers).</p>
|
||||
|
||||
<script>
|
||||
CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
106
simpla/design/js/codemirror/demo/search.html
vendored
Normal file
106
simpla/design/js/codemirror/demo/search.html
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Search/Replace Demo</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="../mode/xml/xml.css">
|
||||
<script src="../mode/xml/xml.js"></script>
|
||||
<link rel="stylesheet" href="../css/docs.css">
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
|
||||
.searched {background: yellow;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Search/Replace Demo</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
<dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
|
||||
<dd>Whether, when indenting, the first N*8 spaces should be
|
||||
replaced by N tabs. Default is false.</dd>
|
||||
|
||||
<dt id="option_tabMode"><code>tabMode (string)</code></dt>
|
||||
<dd>Determines what happens when the user presses the tab key.
|
||||
Must be one of the following:
|
||||
<dl>
|
||||
<dt><code>"classic" (the default)</code></dt>
|
||||
<dd>When nothing is selected, insert a tab. Otherwise,
|
||||
behave like the <code>"shift"</code> mode. (When shift is
|
||||
held, this behaves like the <code>"indent"</code> mode.)</dd>
|
||||
<dt><code>"shift"</code></dt>
|
||||
<dd>Indent all selected lines by
|
||||
one <a href="#option_indentUnit"><code>indentUnit</code></a>.
|
||||
If shift was held while pressing tab, un-indent all selected
|
||||
lines one unit.</dd>
|
||||
<dt><code>"indent"</code></dt>
|
||||
<dd>Indent the line the 'correctly', based on its syntactic
|
||||
context. Only works if the
|
||||
mode <a href="#indent">supports</a> it.</dd>
|
||||
<dt><code>"default"</code></dt>
|
||||
<dd>Do not capture tab presses, let the browser apply its
|
||||
default behaviour (which usually means it skips to the next
|
||||
control).</dd>
|
||||
</dl></dd>
|
||||
|
||||
<dt id="option_enterMode"><code>enterMode (string)</code></dt>
|
||||
<dd>Determines whether and how new lines are indented when the
|
||||
enter key is pressed. The following modes are supported:
|
||||
<dl>
|
||||
<dt><code>"indent" (the default)</code></dt>
|
||||
<dd>Use the mode's indentation rules to give the new line
|
||||
the correct indentation.</dd>
|
||||
<dt><code>"keep"</code></dt>
|
||||
<dd>Indent the line the same as the previous line.</dd>
|
||||
<dt><code>"flat"</code></dt>
|
||||
<dd>Do not indent the new line.</dd>
|
||||
</dl></dd>
|
||||
</textarea></form>
|
||||
<button type=button onclick="search()">Search</button>
|
||||
<input type=text style="width: 5em" id=query value=indent> or
|
||||
<button type=button onclick="replace()">replace</button> it by
|
||||
<input type=text style="width: 5em" id=replace>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", lineNumbers: true});
|
||||
|
||||
var lastPos = null, lastQuery = null, marked = [];
|
||||
|
||||
function unmark() {
|
||||
for (var i = 0; i < marked.length; ++i) marked[i]();
|
||||
marked.length = 0;
|
||||
}
|
||||
|
||||
function search() {
|
||||
unmark();
|
||||
var text = document.getElementById("query").value;
|
||||
if (!text) return;
|
||||
for (var cursor = editor.getSearchCursor(text); cursor.findNext();)
|
||||
marked.push(editor.markText(cursor.from(), cursor.to(), "searched"));
|
||||
|
||||
if (lastQuery != text) lastPos = null;
|
||||
var cursor = editor.getSearchCursor(text, lastPos || editor.getCursor());
|
||||
if (!cursor.findNext()) {
|
||||
cursor = editor.getSearchCursor(text);
|
||||
if (!cursor.findNext()) return;
|
||||
}
|
||||
editor.setSelection(cursor.from(), cursor.to());
|
||||
lastQuery = text; lastPos = cursor.to();
|
||||
}
|
||||
|
||||
function replace() {
|
||||
unmark();
|
||||
var text = document.getElementById("query").value,
|
||||
replace = document.getElementById("replace").value;
|
||||
if (!text) return;
|
||||
for (var cursor = editor.getSearchCursor(text); cursor.findNext();)
|
||||
editor.replaceRange(replace, cursor.from(), cursor.to());
|
||||
}
|
||||
</script>
|
||||
|
||||
<p>Demonstration of search/replace functionality and marking
|
||||
text.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
225
simpla/design/js/codemirror/index.html
Normal file
225
simpla/design/js/codemirror/index.html
Normal file
@@ -0,0 +1,225 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
|
||||
|
||||
<pre class="grey">
|
||||
<img src="css/baboon.png" class="logo" alt="logo"/>/* In-browser code editing
|
||||
made bearable */
|
||||
</pre>
|
||||
|
||||
<div class="clear"><div class="left blk">
|
||||
|
||||
<p style="margin-top: 0">CodeMirror is a JavaScript library that can
|
||||
be used to create a relatively pleasant editor interface for
|
||||
code-like content ― computer programs, HTML markup, and
|
||||
similar. If a mode has been written for the language you are
|
||||
editing, the code will be coloured, and the editor will optionally
|
||||
help you with indentation.</p>
|
||||
|
||||
<p>This is the project page for CodeMirror 2, the currently more
|
||||
actively developed, and recommended
|
||||
version. <a href="1/index.html">CodeMirror 1</a> is still available
|
||||
from here.</p>
|
||||
|
||||
<div class="clear"><div class="left1 blk">
|
||||
|
||||
<h2 style="margin-top: 0">Supported modes:</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="mode/javascript/index.html">JavaScript</a></li>
|
||||
<li><a href="mode/xml/index.html">XML/HTML</a></li>
|
||||
<li><a href="mode/css/index.html">CSS</a></li>
|
||||
<li><a href="mode/htmlmixed/index.html">HTML mixed-mode</a></li>
|
||||
<li><a href="mode/php/index.html">PHP</a></li>
|
||||
<li><a href="mode/diff/index.html">diff</a></li>
|
||||
<li><a href="mode/clike/index.html">C, Java, and similar</a></li>
|
||||
<li><a href="mode/stex/index.html">sTeX, LaTeX</a></li>
|
||||
<li><a href="mode/haskell/index.html">Haskell</a></li>
|
||||
</ul>
|
||||
|
||||
</div><div class="left2 blk">
|
||||
|
||||
<h2 style="margin-top: 0">Usage demos:</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="demo/complete.html">Autocompletion</a></li>
|
||||
<li><a href="demo/mustache.html">Mode overlays</a></li>
|
||||
<li><a href="demo/search.html">Search/replace</a></li>
|
||||
<li><a href="demo/resize.html">Auto-resizing editor</a></li>
|
||||
<li><a href="demo/marker.html">Setting breakpoints</a></li>
|
||||
<li><a href="demo/activeline.html">Highlighting the current line</a></li>
|
||||
</ul>
|
||||
|
||||
</div></div>
|
||||
|
||||
<h2 id="code">Getting the code</h2>
|
||||
|
||||
<p>All of CodeMirror is released under a <a
|
||||
href="LICENSE">MIT-style</a> license. To get it, you can download
|
||||
the <a href="http://codemirror.net/codemirror.zip">latest
|
||||
release</a> or the current <a
|
||||
href="http://codemirror.net/codemirror-latest.zip">development
|
||||
snapshot</a> as zip files. To create a custom minified script file,
|
||||
you can use the <a href="compress.html">compression API</a>.</p>
|
||||
|
||||
<p>We use <a href="http://git-scm.com/">git</a> for version control.
|
||||
The main repository can be fetched in this way:</p>
|
||||
|
||||
<pre class="code">git clone http://marijnhaverbeke.nl/git/codemirror2</pre>
|
||||
|
||||
<p>CodeMirror can also be found on GitHub at <a
|
||||
href="http://github.com/marijnh/CodeMirror2">marijnh/CodeMirror2</a>.
|
||||
If you plan to hack on the code and contribute patches, the best way
|
||||
to do it is to create a GitHub fork, and send pull requests.</p>
|
||||
|
||||
<h2 id="documention">Documentation</h2>
|
||||
|
||||
<p>The <a href="manual.html">manual</a> is your first stop for
|
||||
learning how to use this library. It starts with a quick explanation
|
||||
of how to use the editor, and then describes all of the (many)
|
||||
options and methods that CodeMirror exposes.</p>
|
||||
|
||||
<p>For those who want to learn more about the code, there is
|
||||
an <a href="internals.html">overview of the internals</a> available.
|
||||
The <a href="http://github.com/marijnh/CodeMirror2">source code</a>
|
||||
itself is, for the most part, also well commented.</p>
|
||||
|
||||
<h2 id="support">Support and bug reports</h2>
|
||||
|
||||
<p>There is
|
||||
a <a href="http://groups.google.com/group/codemirror">Google
|
||||
group</a> (a sort of mailing list/newsgroup thing) for discussion
|
||||
and news related to CodeMirror. Reporting bugs is best done
|
||||
on <a href="http://github.com/marijnh/CodeMirror2/issues">github</a>.
|
||||
You can also e-mail me
|
||||
directly: <a href="mailto:marijnh@gmail.com">Marijn
|
||||
Haverbeke</a>.</p>
|
||||
|
||||
<h2 id="supported">Supported browsers</h2>
|
||||
|
||||
<p>The following browsers are able to run CodeMirror:</p>
|
||||
|
||||
<ul>
|
||||
<li>Firefox 2 or higher</li>
|
||||
<li>Chrome, any version</li>
|
||||
<li>Safari 3 or higher</li>
|
||||
<li>Internet Explorer 6 or higher</li>
|
||||
<li>Opera 9 or higher (with some key-handling problems on OS X)</li>
|
||||
</ul>
|
||||
|
||||
<p>I am not actively testing against every new browser release, and
|
||||
vendors have a habit of introducing bugs all the time, so I am
|
||||
relying on the community to tell me when something breaks.
|
||||
See <a href="#support">below</a> for information on how to contact
|
||||
me.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="right blk">
|
||||
|
||||
<a href="http://codemirror.net/codemirror.zip" class="download">Download the latest release</a>
|
||||
|
||||
<h2>Make a donation</h2>
|
||||
|
||||
<ul>
|
||||
<li><span onclick="document.getElementById('paypal').submit();" class="quasilink">Paypal</span></li>
|
||||
<li><span onclick="document.getElementById('bankinfo').style.display = 'block';" class="quasilink">Bank</span></li>
|
||||
</ul>
|
||||
|
||||
<p id="bankinfo" style="display: none;">
|
||||
Bank: <i>Rabobank</i><br/>
|
||||
Country: <i>Netherlands</i><br/>
|
||||
SWIFT: <i>RABONL2U</i><br/>
|
||||
Account: <i>147850770</i><br/>
|
||||
Name: <i>Marijn Haverbeke</i><br/>
|
||||
IBAN: <i>NL26 RABO 0147 8507 70</i>
|
||||
</p>
|
||||
|
||||
<h2>Releases:</h2>
|
||||
|
||||
<p class="rel">28-03-2011: <a href="http://codemirror.net/codemirror-2.0.zip">Version 2.0</a>:</p>
|
||||
<p class="rel-note">CodeMirror 2 is a complete rewrite that's
|
||||
faster, smaller, simpler to use, and less dependent on browser
|
||||
quirks. See <a href="internals.html">this</a>
|
||||
and <a href="http://groups.google.com/group/codemirror/browse_thread/thread/5a8e894024a9f580">this</a>
|
||||
for more information.</a>
|
||||
|
||||
<p class="rel">28-03-2011: <a href="http://codemirror.net/codemirror-1.0.zip">Version 1.0</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li>Fix error when debug history overflows.</li>
|
||||
<li>Refine handling of C# verbatim strings.</li>
|
||||
<li>Fix some issues with JavaScript indentation.</li>
|
||||
</ul>
|
||||
|
||||
<p class="rel">22-02-2011: <a href="https://github.com/marijnh/codemirror2/tree/beta2">Version 2.0 beta 2</a>:</p>
|
||||
<p class="rel-note">Somewhate more mature API, lots of bugs shaken out.</a>
|
||||
|
||||
<p class="rel">17-02-2011: <a href="http://codemirror.net/codemirror-0.94.zip">Version 0.94</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li><code>tabMode: "spaces"</code> was modified slightly (now indents when something is selected).</li>
|
||||
<li>Fixes a bug that would cause the selection code to break on some IE versions.</li>
|
||||
<li>Disabling spell-check on WebKit browsers now works.</li>
|
||||
</ul>
|
||||
|
||||
<p class="rel">08-02-2011: <a href="http://codemirror.net/2/">Version 2.0 beta 1</a>:</p>
|
||||
<p class="rel-note">CodeMirror 2 is a complete rewrite of
|
||||
CodeMirror, no longer depending on an editable frame.</p>
|
||||
|
||||
<p class="rel">19-01-2011: <a href="http://codemirror.net/codemirror-0.93.zip">Version 0.93</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li>Added a <a href="contrib/regex/index.html">Regular Expression</a> parser.</li>
|
||||
<li>Fixes to the PHP parser.</li>
|
||||
<li>Support for regular expression in search/replace.</li>
|
||||
<li>Add <code>save</code> method to instances created with <code>fromTextArea</code>.</li>
|
||||
<li>Add support for MS T-SQL in the SQL parser.</li>
|
||||
<li>Support use of CSS classes for highlighting brackets.</li>
|
||||
<li>Fix yet another hang with line-numbering in hidden editors.</li>
|
||||
</ul>
|
||||
|
||||
<p class="rel">17-12-2010: <a href="http://codemirror.net/codemirror-0.92.zip">Version 0.92</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li>Make CodeMirror work in XHTML documents.</li>
|
||||
<li>Fix bug in handling of backslashes in Python strings.</li>
|
||||
<li>The <code>styleNumbers</code> option is now officially
|
||||
supported and documented.</li>
|
||||
<li><code>onLineNumberClick</code> option added.</li>
|
||||
<li>More consistent names <code>onLoad</code> and
|
||||
<code>onCursorActivity</code> callbacks. Old names still work, but
|
||||
are deprecated.</li>
|
||||
<li>Add a <a href="contrib/freemarker/index.html">Freemarker</a> mode.</li>
|
||||
</ul>
|
||||
|
||||
<p class="rel">11-11-2010: <a
|
||||
href="http://codemirror.net/codemirror-0.91.zip">Version 0.91</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li>Adds support for <a href="contrib/java">Java</a>.</li>
|
||||
<li>Small additions to the <a href="contrib/php">PHP</a> and <a href="contrib/sql">SQL</a> parsers.</li>
|
||||
<li>Work around various <a href="https://bugs.webkit.org/show_bug.cgi?id=47806">Webkit</a> <a href="https://bugs.webkit.org/show_bug.cgi?id=23474">issues</a>.</li>
|
||||
<li>Fix <code>toTextArea</code> to update the code in the textarea.</li>
|
||||
<li>Add a <code>noScriptCaching</code> option (hack to ease development).</li>
|
||||
<li>Make sub-modes of <a href="mixedtest.html">HTML mixed</a> mode configurable.</li>
|
||||
</ul>
|
||||
|
||||
<p><a href="oldrelease.html">Older releases...</a></p>
|
||||
|
||||
</div></div>
|
||||
|
||||
<div style="height: 2em"> </div>
|
||||
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" id="paypal">
|
||||
<input type="hidden" name="cmd" value="_s-xclick"/>
|
||||
<input type="hidden" name="hosted_button_id" value="3FVHS5FGUY7CC"/>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript" src="css/font.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
352
simpla/design/js/codemirror/internals.html
Normal file
352
simpla/design/js/codemirror/internals.html
Normal file
@@ -0,0 +1,352 @@
|
||||
<!doctype html>
|
||||
<html><head>
|
||||
<title>CodeMirror 2: (Re-) Implementing A Syntax-Highlighting Editor in JavaScript</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="stylesheet" href="docs.css">
|
||||
</head><body>
|
||||
|
||||
<h1>(Re-) Implementing A Syntax-Highlighting Editor in JavaScript</h1>
|
||||
|
||||
<p style="font-size: 85%">
|
||||
<strong>Topic:</strong> JavaScript, code editor implementation<br>
|
||||
<strong>Author:</strong> Marijn Haverbeke<br>
|
||||
<strong>Date:</strong> March 2nd 2011
|
||||
</p>
|
||||
|
||||
<p>This is a followup to
|
||||
my <a href="http://codemirror.net/story.html">Brutal Odyssey to the
|
||||
Dark Side of the DOM Tree</a> story. That one describes the
|
||||
mind-bending process of implementing (what would become) CodeMirror 1.
|
||||
This one describes the internals of CodeMirror 2, a complete rewrite
|
||||
and rethink of the old code base. I wanted to give this piece another
|
||||
Hunter Thompson copycat subtitle, but somehow that would be out of
|
||||
place—the process this time around was one of straightforward
|
||||
engineering, requiring no serious mind-bending whatsoever.</p>
|
||||
|
||||
<p>So, what is wrong with CodeMirror 1? I'd estimate, by mailing list
|
||||
activity and general search-engine presence, that it has been
|
||||
integrated into about a thousand systems by now. The most prominent
|
||||
one, since a few weeks,
|
||||
being <a href="http://googlecode.blogspot.com/2011/01/make-quick-fixes-quicker-on-google.html">Google
|
||||
code's project hosting</a>. It works, and it's being used widely.</a>
|
||||
|
||||
<p>Still, I did not start replacing it because I was bored. CodeMirror
|
||||
1 was heavily reliant on <code>designMode</code>
|
||||
or <code>contentEditable</code> (depending on the browser). Neither of
|
||||
these are well specified (HTML5 tries
|
||||
to <a href="http://www.w3.org/TR/html5/editing.html#contenteditable">specify</a>
|
||||
their basics), and, more importantly, they tend to be one of the more
|
||||
obscure and buggy areas of browser functionality—CodeMirror, by using
|
||||
this functionality in a non-typical way, was constantly running up
|
||||
against browser bugs. WebKit wouldn't show an empty line at the end of
|
||||
the document, and in some releases would suddenly get unbearably slow.
|
||||
Firefox would show the cursor in the wrong place. Internet Explorer
|
||||
would insist on linkifying everything that looked like a URL or email
|
||||
address, a behaviour that can't be turned off. Some bugs I managed to
|
||||
work around (which was often a frustrating, painful process), others,
|
||||
such as the Firefox cursor placement, I gave up on, and had to tell
|
||||
user after user that they were known problems, but not something I
|
||||
could help.</p>
|
||||
|
||||
<p>Also, there is the fact that <code>designMode</code> (which seemed
|
||||
to be less buggy than <code>contentEditable</code> in Webkit and
|
||||
Firefox, and was thus used by CodeMirror 1 in those browsers) requires
|
||||
a frame. Frames are another tricky area. It takes some effort to
|
||||
prevent getting tripped up by domain restrictions, they don't
|
||||
initialize synchronously, behave strangely in response to the back
|
||||
button, and, on several browsers, can't be moved around the DOM
|
||||
without having them re-initialize. They did provide a very nice way to
|
||||
namespace the library, though—CodeMirror 1 could freely pollute the
|
||||
namespace inside the frame.</p>
|
||||
|
||||
<p>Finally, working with an editable document means working with
|
||||
selection in arbitrary DOM structures. Internet Explorer (8 and
|
||||
before) has an utterly different (and awkward) selection API than all
|
||||
of the other browsers, and even among the different implementations of
|
||||
<code>document.selection</code>, details about how exactly a selection
|
||||
is represented vary quite a bit. Add to that the fact that Opera's
|
||||
selection support tended to be very buggy until recently, and you can
|
||||
imagine why CodeMirror 1 contains 700 lines of selection-handling
|
||||
code.</p>
|
||||
|
||||
<p>And that brings us to the main issue with the CodeMirror 1
|
||||
code base: The proportion of browser-bug-workarounds to real
|
||||
application code was getting dangerously high. By building on top of a
|
||||
few dodgy features, I put the system in a vulnerable position—any
|
||||
incompatibility and bugginess in these features, I had to paper over
|
||||
with my own code. Not only did I have to do some serious stunt-work to
|
||||
get it to work on older browsers (as detailed in the
|
||||
previous <a href="http://codemirror.net/story.html">story</a>), things
|
||||
also kept breaking in newly released versions, requiring me to come up
|
||||
with <em>new</em> scary hacks in order to keep up. This was starting
|
||||
to lose its appeal.</p>
|
||||
|
||||
<h2>General Approach</h2>
|
||||
|
||||
<p>What CodeMirror 2 does is try to sidestep most of the hairy hacks
|
||||
that came up in version 1. I owe a lot to the
|
||||
<a href="http://ace.ajax.org">ACE</a> editor for inspiration on how to
|
||||
approach this.</p>
|
||||
|
||||
<p>I absolutely did not want to be completely reliant on key events to
|
||||
generate my input. Every JavaScript programmer knows that key event
|
||||
information is horrible and incomplete. Some people (most awesomely
|
||||
Mihai Bazon with <a href="http://ymacs.org">Ymacs</a>) have been able
|
||||
to build more or less functioning editors by directly reading key
|
||||
events, but it takes a lot of work (the kind of never-ending, fragile
|
||||
work I described earlier), and will never be able to properly support
|
||||
things like multi-keystoke international character input.</p>
|
||||
|
||||
<p>So what I do is focus a hidden textarea, and let the browser
|
||||
believe that the user is typing into that. What we show to the user is
|
||||
a DOM structure we built to represent his document. If this is updated
|
||||
quickly enough, and shows some kind of believable cursor, it feels
|
||||
like a real text-input control.</p>
|
||||
|
||||
<p>Another big win is that this DOM representation does not have to
|
||||
span the whole document. Some CodeMirror 1 users insisted that they
|
||||
needed to put a 30 thousand line XML document into CodeMirror. Putting
|
||||
all that into the DOM takes a while, especially since, for some
|
||||
reason, an editable DOM tree is slower than a normal one on most
|
||||
browsers. If we have full control over what we show, we must only
|
||||
ensure that the visible part of the document has been added, and can
|
||||
do the rest only when needed. (Fortunately, the <code>onscroll</code>
|
||||
event works almost the same on all browsers, and lends itself well to
|
||||
displaying things only as they are scrolled into view.)</p>
|
||||
|
||||
<h2>Input</h2>
|
||||
|
||||
<p>ACE uses its hidden textarea only as a text input shim, and does
|
||||
all cursor movement and things like text deletion itself by directly
|
||||
handling key events. CodeMirror's way is to let the browser do its
|
||||
thing as much as possible, and not, for example, define its own set of
|
||||
key bindings. One way to do this would have been to have the whole
|
||||
document inside the hidden textarea, and after each key event update
|
||||
the display DOM to reflect what's in that textarea.</p>
|
||||
|
||||
<p>That'd be simple, but it is not realistic. For even medium-sized
|
||||
document the editor would be constantly munging huge strings, and get
|
||||
terribly slow. What CodeMirror 2 does is put the current selection,
|
||||
along with an extra line on the top and on the bottom, into the
|
||||
textarea.</p>
|
||||
|
||||
<p>This means that the arrow keys (and their ctrl-variations), home,
|
||||
end, etcetera, do not have to be handled specially. We just read the
|
||||
cursor position in the textarea, and update our cursor to match it.
|
||||
Also, copy and paste work pretty much for free, and people get their
|
||||
native key bindings, without any special work on my part. For example,
|
||||
I have emacs key bindings configured for Chrome and Firefox. There is
|
||||
no way for a script to detect this.</p>
|
||||
|
||||
<p>Of course, since only a small part of the document sits in the
|
||||
textarea, keys like page up and ctrl-end won't do the right thing.
|
||||
CodeMirror is catching those events and handling them itself.</p>
|
||||
|
||||
<h2>Selection</h2>
|
||||
|
||||
<p>Getting and setting the selection range of a textarea in modern
|
||||
browsers is trivial—you just use the <code>selectionStart</code>
|
||||
and <code>selectionEnd</code> properties. On IE you have to do some
|
||||
insane stuff with temporary ranges and compensating for the fact that
|
||||
moving the selection by a 'character' will treat \r\n as a single
|
||||
character, but even there it is possible to build functions that
|
||||
reliably set and get the selection range.</p>
|
||||
|
||||
<p>But consider this typical case: When I'm somewhere in my document,
|
||||
press shift, and press the up arrow, something gets selected. Then, if
|
||||
I, still holding shift, press the up arrow again, the top of my
|
||||
selection is adjusted. The selection remembers where its <em>head</em>
|
||||
and its <em>anchor</em> are, and moves the head when we shift-move.
|
||||
This is a generally accepted property of selections, and done right by
|
||||
every editing component built in the past twenty years.</p>
|
||||
|
||||
<p>But not something that the browser selection APIs expose.</p>
|
||||
|
||||
<p>Great. So when someone creates an 'upside-down' selection, the next
|
||||
time CodeMirror has to update the textarea, it'll re-create the
|
||||
selection as an 'upside-up' selection, with the anchor at the top, and
|
||||
the next cursor motion will behave in an unexpected way—our second
|
||||
up-arrow press in the example above will not do anything, since it is
|
||||
interpreted in exactly the same way as the first.</p>
|
||||
|
||||
<p>No problem. We'll just, ehm, detect that the selection is
|
||||
upside-down (you can tell by the way it was created), and then, when
|
||||
an upside-down selection is present, and a cursor-moving key is
|
||||
pressed in combination with shift, we quickly collapse the selection
|
||||
in the textarea to its start, allow the key to take effect, and then
|
||||
combine its new head with its old anchor to get the <em>real</em>
|
||||
selection.</p>
|
||||
|
||||
<p>In short, scary hacks could not be avoided entirely in CodeMirror
|
||||
2.</p>
|
||||
|
||||
<p>And, the observant reader might ask, how do you even know that a
|
||||
key combo is a cursor-moving combo, if you claim you support any
|
||||
native key bindings? Well, we don't, but we can learn. The editor
|
||||
keeps a set known cursor-movement combos (initialized to the
|
||||
predictable defaults), and updates this set when it observes that
|
||||
pressing a certain key had (only) the effect of moving the cursor.
|
||||
This, of course, doesn't work if the first time the key is used was
|
||||
for extending an inverted selection, but it works most of the
|
||||
time.</p>
|
||||
|
||||
<h2>Intelligent Updating</h2>
|
||||
|
||||
<p>One thing that always comes up when you have a complicated internal
|
||||
state that's reflected in some user-visible external representation
|
||||
(in this case, the displayed code and the textarea's content) is
|
||||
keeping the two in sync. The naive way is to just update the display
|
||||
every time you change your state, but this is not only error prone
|
||||
(you'll forget), it also easily leads to duplicate work on big,
|
||||
composite operations. Then you start passing around flags indicating
|
||||
whether the display should be updated in an attempt to be efficient
|
||||
again and, well, at that point you might as well give up completely.</p>
|
||||
|
||||
<p>I did go down that road, but then switched to a much simpler model:
|
||||
simply keep track of all the things that have been changed during an
|
||||
action, and then, only at the end, use this information to update the
|
||||
user-visible display.</p>
|
||||
|
||||
<p>CodeMirror uses a concept of <em>operations</em>, which start by
|
||||
calling a specific set-up function that clears the state and end by
|
||||
calling another function that reads this state and does the required
|
||||
updating. Most event handlers, and all the user-visible methods that
|
||||
change state are wrapped like this. There's a method
|
||||
called <code>operation</code> that accepts a function, and returns
|
||||
another function that wraps the given function as an operation.</p>
|
||||
|
||||
<p>It's trivial to extend this (as CodeMirror does) to detect nesting,
|
||||
and, when an operation is started inside an operation, simply
|
||||
increment the nesting count, and only do the updating when this count
|
||||
reaches zero again.</p>
|
||||
|
||||
<p>If we have a set of changed ranges and know the currently shown
|
||||
range, we can (with some awkward code to deal with the fact that
|
||||
changes can add and remove lines, so we're dealing with a changing
|
||||
coordinate system) construct a map of the ranges that were left
|
||||
intact. We can then compare this map with the part of the document
|
||||
that's currently visible (based on scroll offset and editor height) to
|
||||
determine whether something needs to be updated.</p>
|
||||
|
||||
<p>CodeMirror uses two update algorithms—a full refresh, where it just
|
||||
discards the whole part of the DOM that contains the edited text and
|
||||
rebuilds it, and a patch algorithm, where it uses the information
|
||||
about changed and intact ranges to update only the out-of-date parts
|
||||
of the DOM. When more than 30 percent (which is the current heuristic,
|
||||
might change) of the lines need to be updated, the full refresh is
|
||||
chosen (since it's faster to do than painstakingly finding and
|
||||
updating all the changed lines), in the other case it does the
|
||||
patching (so that, if you scroll a line or select another character,
|
||||
the whole screen doesn't have to be re-rendered).</p>
|
||||
|
||||
<p>All updating uses <code>innerHTML</code> rather than direct DOM
|
||||
manipulation, since that still seems to be by far the fastest way to
|
||||
build documents. There's a per-line function that combines the
|
||||
highlighting, <a href="manual.html#markText">marking</a>, and
|
||||
selection info for that line into a snippet of HTML. The patch updater
|
||||
uses this to reset individual lines, the refresh updater builds an
|
||||
HTML chunk for the whole visible document at once, and then uses a
|
||||
single <code>innerHTML</code> update to do the refresh.</p>
|
||||
|
||||
<h2>Parsers can be Simple</h2>
|
||||
|
||||
<p>When I wrote CodeMirror 1, I
|
||||
thought <a href="http://codemirror.net/story.html#parser">interruptable
|
||||
parsers</a> were a hugely scary and complicated thing, and I used a
|
||||
bunch of heavyweight abstractions to keep this supposed complexity
|
||||
under control: parsers
|
||||
were <a href="http://bob.pythonmac.org/archives/2005/07/06/iteration-in-javascript/">iterators</a>
|
||||
that consumed input from another iterator, and used funny
|
||||
closure-resetting tricks to copy and resume themselves.</p>
|
||||
|
||||
<p>This made for a rather nice system, in that parsers formed strictly
|
||||
separate modules, and could be composed in predictable ways.
|
||||
Unfortunately, it was quite slow (stacking three or four iterators on
|
||||
top of each other), and extremely intimidating to people not used to a
|
||||
functional programming style.</p>
|
||||
|
||||
<p>With a few small changes, however, we can keep all those
|
||||
advantages, but simplify the API and make the whole thing less
|
||||
indirect and inefficient. CodeMirror
|
||||
2's <a href="manual.html#modeapi">mode API</a> uses explicit state
|
||||
objects, and makes the parser/tokenizer a function that simply takes a
|
||||
state and a character stream abstraction, advances the stream one
|
||||
token, and returns the way the token should be styled. This state may
|
||||
be copied, optionally in a mode-defined way, in order to be able to
|
||||
continue a parse at a given point. Even someone who's never touched a
|
||||
lambda in his life can understand this approach. Additionally, far
|
||||
fewer objects are allocated in the course of parsing now.</p>
|
||||
|
||||
<p>The biggest speedup comes from the fact that the parsing no longer
|
||||
has to touch the DOM though. In CodeMirror 1, on an older browser, you
|
||||
could <em>see</em> the parser work its way through the document,
|
||||
managing some twenty lines in each 50-millisecond time slice it got. It
|
||||
was reading its input from the DOM, and updating the DOM as it went
|
||||
along, which any experienced JavaScript programmer will immediately
|
||||
spot as a recipe for slowness. In CodeMirror 2, the parser usually
|
||||
finishes the whole document in a single 100-millisecond time slice—it
|
||||
manages some 1500 lines during that time on Chrome. All it has to do
|
||||
is munge strings, so there is no real reason for it to be slow
|
||||
anymore.</p>
|
||||
|
||||
<h2>What Gives?</h2>
|
||||
|
||||
<p>Given all this, what can you expect from CodeMirror 2? First, the
|
||||
good:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><strong>Small.</strong> the base library is some 32k when minified
|
||||
now, 12k when gzipped. It's smaller than its own logo.</li>
|
||||
|
||||
<li><strong>Lightweight.</strong> CodeMirror 2 initializes very
|
||||
quickly, and does almost no work when it is not focused. This means
|
||||
you can treat it almost like a textarea, have multiple instances on a
|
||||
page without trouble.</li>
|
||||
|
||||
<li><strong>Huge document support.</strong> Since highlighting is
|
||||
really fast, and no DOM structure is being built for non-visible
|
||||
content, you don't have to worry about locking up your browser when a
|
||||
user enters a megabyte-sized document.</li>
|
||||
|
||||
<li><strong>Extended API.</strong> Some things kept coming up in the
|
||||
mailing list, such as marking pieces of text or lines, which were
|
||||
extremely hard to do with CodeMirror 1. The new version has proper
|
||||
support for these built in.</li>
|
||||
|
||||
<li><strong>Tab support.</strong> Tabs inside editable documents were,
|
||||
for some reason, a no-go. At least six different people announced they
|
||||
were going to add tab support to CodeMirror 1, none survived (I mean,
|
||||
none delivered a working version). CodeMirror 2 no longer removes tabs
|
||||
from your document.</li>
|
||||
|
||||
<li><strong>Sane styling.</strong> <code>iframe</code> nodes aren't
|
||||
really known for respecting document flow. Now that an editor instance
|
||||
is a plain <code>div</code> element, it is much easier to size it to
|
||||
fit the surrounding elements. You don't even have to make it scroll if
|
||||
you do not <a href="demo/resize.html">want to</a>.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>Then, the bad:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><strong>No line-wrapping.</strong> I'd have liked to get
|
||||
line-wrapping to work, but it doesn't match the model I'm using very
|
||||
well. It is important that cursor movement in the textarea matches
|
||||
what you see on the screen, and it seems to be impossible to have the
|
||||
lines wrapped the same in the textarea and the normal DOM.</li>
|
||||
|
||||
<li><strong>Some cursor flakiness.</strong> The textarea hack does not
|
||||
really do justice to the complexity of cursor handling—a selection is
|
||||
typically more than just an offset into a string. For example, if you
|
||||
use the up and down arrow keys to move to a shorter line and then
|
||||
back, you'll end up in your old position in most editor controls, but
|
||||
CodeMirror 2 currently doesn't remember the 'real' cursor column in
|
||||
this case. These can be worked around on a case-by-case basis, but
|
||||
I haven't put much energy into that yet.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</body></html>
|
||||
53
simpla/design/js/codemirror/lib/codemirror.css
vendored
Normal file
53
simpla/design/js/codemirror/lib/codemirror.css
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
.CodeMirror {
|
||||
overflow: auto;
|
||||
height: 300px;
|
||||
line-height: 1em;
|
||||
font-family: monospace;
|
||||
_position: relative; /* IE6 hack */
|
||||
}
|
||||
|
||||
.CodeMirror-gutter {
|
||||
position: absolute; left: 0; top: 0;
|
||||
background-color: #f7f7f7;
|
||||
border-right: 1px solid #eee;
|
||||
min-width: 2em;
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-gutter-text {
|
||||
color: #aaa;
|
||||
text-align: right;
|
||||
padding: .4em .2em .4em .4em;
|
||||
}
|
||||
.CodeMirror-lines {
|
||||
padding: .4em;
|
||||
}
|
||||
|
||||
.CodeMirror pre {
|
||||
-moz-border-radius: 0;
|
||||
-webkit-border-radius: 0;
|
||||
-o-border-radius: 0;
|
||||
border-radius: 0;
|
||||
border-width: 0; margin: 0; padding: 0; background: transparent;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
border-left: 1px solid black !important;
|
||||
}
|
||||
.CodeMirror-focused .CodeMirror-cursor {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
span.CodeMirror-selected {
|
||||
background: #ccc !important;
|
||||
color: HighlightText !important;
|
||||
}
|
||||
.CodeMirror-focused span.CodeMirror-selected {
|
||||
background: Highlight !important;
|
||||
}
|
||||
|
||||
.CodeMirror-matchingbracket {color: #0f0 !important;}
|
||||
.CodeMirror-nonmatchingbracket {color: #f22 !important;}
|
||||
1915
simpla/design/js/codemirror/lib/codemirror.js
vendored
Normal file
1915
simpla/design/js/codemirror/lib/codemirror.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
51
simpla/design/js/codemirror/lib/overlay.js
vendored
Normal file
51
simpla/design/js/codemirror/lib/overlay.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Utility function that allows modes to be combined. The mode given
|
||||
// as the base argument takes care of most of the normal mode
|
||||
// functionality, but a second (typically simple) mode is used, which
|
||||
// can override the style of text. Both modes get to parse all of the
|
||||
// text, but when both assign a non-null style to a piece of code, the
|
||||
// overlay wins, unless the combine argument was true, in which case
|
||||
// the styles are combined.
|
||||
|
||||
CodeMirror.overlayParser = function(base, overlay, combine) {
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
base: CodeMirror.startState(base),
|
||||
overlay: CodeMirror.startState(overlay),
|
||||
basePos: 0, baseCur: null,
|
||||
overlayPos: 0, overlayCur: null
|
||||
};
|
||||
},
|
||||
copyState: function(state) {
|
||||
return {
|
||||
base: CodeMirror.copyState(base, state.base),
|
||||
overlay: CodeMirror.copyState(overlay, state.overlay),
|
||||
basePos: state.basePos, baseCur: null,
|
||||
overlayPos: state.overlayPos, overlayCur: null
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.start == state.basePos) {
|
||||
state.baseCur = base.token(stream, state.base);
|
||||
state.basePos = stream.pos;
|
||||
}
|
||||
if (stream.start == state.overlayPos) {
|
||||
stream.pos = stream.start;
|
||||
state.overlayCur = overlay.token(stream, state.overlay);
|
||||
state.overlayPos = stream.pos;
|
||||
}
|
||||
stream.pos = Math.min(state.basePos, state.overlayPos);
|
||||
if (stream.eol()) state.basePos = state.overlayPos = 0;
|
||||
|
||||
if (state.overlayCur == null) return state.baseCur;
|
||||
if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
|
||||
else return state.overlayCur;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
return base.indent(state.base, textAfter);
|
||||
},
|
||||
electricChars: base.electricChars
|
||||
};
|
||||
};
|
||||
771
simpla/design/js/codemirror/manual.html
Normal file
771
simpla/design/js/codemirror/manual.html
Normal file
@@ -0,0 +1,771 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: User Manual</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<style>dl dl {margin: 0;}</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
|
||||
|
||||
<pre class="grey">
|
||||
<img src="css/baboon.png" class="logo" alt="logo"/>/* User manual and
|
||||
reference guide */
|
||||
</pre>
|
||||
|
||||
<div class="clear"><div class="leftbig blk">
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
|
||||
<p>CodeMirror is a code-editor component that can be embedded in
|
||||
Web pages. It provides <em>only</em> the editor component, no
|
||||
accompanying buttons, auto-completion, or other IDE functionality.
|
||||
It does provide a rich API on top of which such functionality can
|
||||
be straightforwardly implemented.</p>
|
||||
|
||||
<p>CodeMirror works with language-specific modes. Modes are
|
||||
JavaScript programs that help color (and optionally indent) text
|
||||
written in a given language. The distribution comes with a few
|
||||
modes (see the <code>mode/</code> directory), and it isn't hard
|
||||
to <a href="#modeapi">write new ones</a> for other languages.</p>
|
||||
|
||||
<h2 id="usage">Basic Usage</h2>
|
||||
|
||||
<p>The easiest way to use CodeMirror is to simply load the script
|
||||
and style sheet found under <code>lib/</code> in the distribution,
|
||||
plus the script and style sheet for the mode(s) you want to use.
|
||||
(See also <a href="compress.html">the compresion helper</a>.) For
|
||||
example:</p>
|
||||
|
||||
<pre><script src="lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="lib/codemirror.css">
|
||||
<script src="mode/javascript/javascript.js"></script>
|
||||
<link rel="stylesheet" href="mode/javascript/javascript.css"></pre>
|
||||
|
||||
<p>Having done this, an editor instance can be created like
|
||||
this:</p>
|
||||
|
||||
<pre>var myCodeMirror = CodeMirror(document.body);</pre>
|
||||
|
||||
<p>The editor will be appended to the document body, will start
|
||||
empty, and will use the mode that we loaded. To have more control
|
||||
over the new editor, a configuration object can be passed
|
||||
to <code>CodeMirror</code> as a second argument:</p>
|
||||
|
||||
<pre>var myCodeMirror = CodeMirror(document.body, {
|
||||
value: "function myScript(){return 100;}\n",
|
||||
mode: "javascript"
|
||||
});</pre>
|
||||
|
||||
<p>This will initialize the editor with a piece of code already in
|
||||
it, and explicitly tell it to use the JavaScript mode (which is
|
||||
useful when multiple modes are loaded).
|
||||
See <a href="#config">below</a> for a full discussion of the
|
||||
configuration options that CodeMirror accepts.</p>
|
||||
|
||||
<p>In cases where you don't want to append the editor to an
|
||||
element, and need more control over the way it is inserted, the
|
||||
first argument to the <code>CodeMirror</code> function can also
|
||||
be a function that, when given a DOM element, inserts it into the
|
||||
document somewhere. This could be used to, for example, replace a
|
||||
textarea with a real editor:</p>
|
||||
|
||||
<pre>var myCodeMirror = CodeMirror(function(elt) {
|
||||
myTextArea.parentNode.replaceChild(myTextArea, elt);
|
||||
}, {value: myTextArea.value});</pre>
|
||||
|
||||
<p>However, for this use case, which is a common way to use
|
||||
CodeMirror, the library provides a much more powerful
|
||||
shortcut:</p>
|
||||
|
||||
<pre>var myCodeMirror = CodeMirror.fromTextArea(myTextArea);</pre>
|
||||
|
||||
<p>This will, among other things, ensure that the textarea's value
|
||||
is updated when the form (if it is part of a form) is submitted.
|
||||
See the <a href="#fromTextArea">API reference</a> for a full
|
||||
description of this method.</p>
|
||||
|
||||
<h2 id="config">Configuration</h2>
|
||||
|
||||
<p>Both the <code>CodeMirror</code> function and
|
||||
its <code>fromTextArea</code> method take as second (optional)
|
||||
argument an object containing configuration options. Any option
|
||||
not supplied like this will be taken
|
||||
from <code>CodeMirror.defaults</code>, an object containing the
|
||||
default options. You can update this object to change the defaults
|
||||
on your page.</p>
|
||||
|
||||
<p>Options are not checked in any way, so setting bogus options is
|
||||
bound to lead to odd errors.</p>
|
||||
|
||||
<p>These are the supported options:</p>
|
||||
|
||||
<dl>
|
||||
<dt id="option_value"><code>value (string)</code></dt>
|
||||
<dd>The starting value of the editor.</dd>
|
||||
|
||||
<dt id="option_mode"><code>mode (string or object)</code></dt>
|
||||
<dd>The mode to use. When not given, this will default to the
|
||||
first mode that was loaded. It may be a string, which either
|
||||
simply names the mode or is
|
||||
a <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> type
|
||||
associated with the mode. Alternatively, it may be an object
|
||||
containing configuration options for the mode, with
|
||||
a <code>name</code> property that names the mode (for
|
||||
example <code>{name: "javascript", json: true}</code>). The demo
|
||||
pages for each mode contain information about what configuration
|
||||
parameters the mode supports. You can ask CodeMirror which modes
|
||||
and MIME types are loaded with
|
||||
the <code>CodeMirror.listModes</code>
|
||||
and <code>CodeMirror.listMIMEs</code> functions.</dd>
|
||||
|
||||
<dt id="option_indentUnit"><code>indentUnit (integer)</code></dt>
|
||||
<dd>How many spaces a block (whatever that means in the edited
|
||||
language) should be indented. The default is 2.</dd>
|
||||
|
||||
<dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
|
||||
<dd>Whether, when indenting, the first N*8 spaces should be
|
||||
replaced by N tabs. Default is false.</dd>
|
||||
|
||||
<dt id="option_tabMode"><code>tabMode (string)</code></dt>
|
||||
<dd>Determines what happens when the user presses the tab key.
|
||||
Must be one of the following:
|
||||
<dl>
|
||||
<dt><code>"classic" (the default)</code></dt>
|
||||
<dd>When nothing is selected, insert a tab. Otherwise,
|
||||
behave like the <code>"shift"</code> mode. (When shift is
|
||||
held, this behaves like the <code>"indent"</code> mode.)</dd>
|
||||
<dt><code>"shift"</code></dt>
|
||||
<dd>Indent all selected lines by
|
||||
one <a href="#option_indentUnit"><code>indentUnit</code></a>.
|
||||
If shift was held while pressing tab, un-indent all selected
|
||||
lines one unit.</dd>
|
||||
<dt><code>"indent"</code></dt>
|
||||
<dd>Indent the line the 'correctly', based on its syntactic
|
||||
context. Only works if the
|
||||
mode <a href="#indent">supports</a> it.</dd>
|
||||
<dt><code>"default"</code></dt>
|
||||
<dd>Do not capture tab presses, let the browser apply its
|
||||
default behaviour (which usually means it skips to the next
|
||||
control).</dd>
|
||||
</dl></dd>
|
||||
|
||||
<dt id="option_enterMode"><code>enterMode (string)</code></dt>
|
||||
<dd>Determines whether and how new lines are indented when the
|
||||
enter key is pressed. The following modes are supported:
|
||||
<dl>
|
||||
<dt><code>"indent" (the default)</code></dt>
|
||||
<dd>Use the mode's indentation rules to give the new line
|
||||
the correct indentation.</dd>
|
||||
<dt><code>"keep"</code></dt>
|
||||
<dd>Indent the line the same as the previous line.</dd>
|
||||
<dt><code>"flat"</code></dt>
|
||||
<dd>Do not indent the new line.</dd>
|
||||
</dl></dd>
|
||||
|
||||
<dt id="option_electricChars"><code>electricChars (boolean)</code></dt>
|
||||
<dd>Configures whether the editor should re-indent the current
|
||||
line when a character is typed that might change its proper
|
||||
indentation (only works if the mode supports indentation).
|
||||
Default is true.</dd>
|
||||
|
||||
<dt id="option_lineNumbers"><code>lineNumbers (boolean)</code></dt>
|
||||
<dd>Whether to show line numbers to the left of the editor.</dd>
|
||||
|
||||
<dt id="option_firstLineNumber"><code>firstLineNumber (integer)</code></dt>
|
||||
<dd>At which number to start counting lines. Default is 1.</dd>
|
||||
|
||||
<dt id="option_gutter"><code>gutter (boolean)</code></dt>
|
||||
<dd>Can be used to force a 'gutter' (empty space on the left of
|
||||
the editor) to be shown even when no line numbers are active.
|
||||
This is useful for setting <a href="#setMarker">markers</a>.</dd>
|
||||
|
||||
<dt id="option_readOnly"><code>readOnly (boolean)</code></dt>
|
||||
<dd>This disables editing of the editor content by the user.
|
||||
(Changes through API functions will still be possible.)</dd>
|
||||
|
||||
<dt id="option_onChange"><code>onChange (function)</code></dt>
|
||||
<dd>When given, this function will be called every time the
|
||||
content of the editor is changed. It will be given the editor
|
||||
instance as only argument.</dd>
|
||||
|
||||
<dt id="option_onCursorActivity"><code>onCursorActivity (function)</code></dt>
|
||||
<dd>Like <code>onChange</code>, but will also be called when the
|
||||
cursor moves without any changes being made.</dd>
|
||||
|
||||
<dt id="option_onGutterClick"><code>onGutterClick (function)</code></dt>
|
||||
<dd>When given, will be called whenever the editor gutter (the
|
||||
line-number area) is clicked. Will be given the editor instance
|
||||
as first argument, and the (zero-based) number of the line that
|
||||
was clicked as second argument.</dd>
|
||||
|
||||
<dt id="option_onFocus"><code>onFocus, onBlur (function)</code></dt>
|
||||
<dd>The given functions will be called whenever the editor is
|
||||
focused or unfocused.</dd>
|
||||
|
||||
<dt id="option_onScroll"><code>onScroll (function)</code></dt>
|
||||
<dd>When given, will be called whenever the editor is
|
||||
scrolled.</dd>
|
||||
|
||||
<dt id="option_matchBrackets"><code>matchBrackets (boolean)</code></dt>
|
||||
<dd>Determines whether brackets are matched whenever the cursor
|
||||
is moved next to a bracket.</dd>
|
||||
|
||||
<dt id="option_workTime"><code>workTime, workDelay (number)</code></dt>
|
||||
<dd>Highlighting is done by a pseudo background-thread that will
|
||||
work for <code>workTime</code> milliseconds, and then use
|
||||
timeout to sleep for <code>workDelay</code> milliseconds. The
|
||||
defaults are 200 and 300, you can change these options to make
|
||||
the highlighting more or less aggressive.</dd>
|
||||
|
||||
<dt id="option_undoDepth"><code>undoDepth (integer)</code></dt>
|
||||
<dd>The maximum number of undo levels that the editor stores.
|
||||
Defaults to 40.</dd>
|
||||
|
||||
<dt id="option_tabindex"><code>tabindex (integer)</code></dt>
|
||||
<dd>The <a href="http://www.w3.org/TR/html401/interact/forms.html#adef-tabindex">tab
|
||||
index</a> to assign to the editor. If not given, no tab index
|
||||
will be assigned.</dd>
|
||||
|
||||
<dt id="option_onKeyEvent"><code>onKeyEvent (function)</code></dt>
|
||||
<dd>This provides a rather low-level hook into CodeMirror's key
|
||||
handling. If provided, this function will be called on
|
||||
every <code>keydown</code> and <code>keypress</code> event that
|
||||
CodeMirror captures. It will be passed two arguments, the editor
|
||||
instance and the key event. This key event is pretty much the
|
||||
raw key event, except that a <code>stop()</code> method is
|
||||
always added to it. You could feed it to, for
|
||||
example, <code>jQuery.Event</code> to further normalize
|
||||
it.<br>This function can inspect the key event, and handle it if
|
||||
it wants to. It may return true to tell CodeMirror to ignore the
|
||||
event. Be wary that, on some browsers, stopping
|
||||
a <code>keydown</code> does not stop the <code>keypress</code>
|
||||
from firing, whereas on others it does. If you respond to an
|
||||
event, you should probably inspect its <code>type</code>
|
||||
property and only do something when it is <code>keydown</code>
|
||||
(or <code>keypress</code> for actions that need character
|
||||
data).</dd>
|
||||
</dl>
|
||||
|
||||
<h2 id="styling">Customized Styling</h2>
|
||||
|
||||
<p>Up to a certain extent, CodeMirror's look can be changed by
|
||||
modifying style sheet files. The style sheets supplied by modes
|
||||
simply provide the colors for that mode, and can be adapted in a
|
||||
very straightforward way. To style the editor itself, it is
|
||||
possible to alter or override the styles defined
|
||||
in <a href="lib/codemirror.css"><code>codemirror.css</code></a>.</p>
|
||||
|
||||
<p>Some care must be taken there, since a lot of the rules in this
|
||||
file are necessary to have CodeMirror function properly. Adjusting
|
||||
colors should be safe, of course, and with some care a lot of
|
||||
other things can be changed as well. The CSS classes defined in
|
||||
this file serve the following roles:</p>
|
||||
|
||||
<dl>
|
||||
<dt id="class_CodeMirror"><code>CodeMirror</code></dt>
|
||||
<dd>The outer element of the editor. This determines whether the
|
||||
editor scrolls (<code>overflow: auto</code> + fixed height). Can
|
||||
also be used to set styles that should hold for everything
|
||||
inside the editor, or to set a background.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_focused"><code>CodeMirror-focused</code></dt>
|
||||
<dd>Whenever the editor is focused, the top element gets this
|
||||
class. This is used to hide the cursor and give the selection a
|
||||
different color when the editor is not focused.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_gutter"><code>CodeMirror-gutter</code></dt>
|
||||
<dd>Use this for giving a background or a border to the editor
|
||||
gutter. Don't set any padding here,
|
||||
use <code>CodeMirror-gutter-text</code> for that. By default,
|
||||
the gutter is 'fluid', meaning it will adjust its width to the
|
||||
maximum line number or line marker width. You can also set a
|
||||
fixed width if you want.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_gutter_text"><code>CodeMirror-gutter-text</code></dt>
|
||||
<dd>Used to style the actual line numbers. For the numbers to
|
||||
line up, you'll want this style to use exactly the same font and
|
||||
vertical padding as normal edited text, as per
|
||||
the <code>CodeMirror-lines</code> class.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_lines"><code>CodeMirror-lines</code></dt>
|
||||
<dd>The visible lines. If this has vertical
|
||||
padding, <code>CodeMirror-gutter</code> should have the same
|
||||
padding.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_cursor"><code>CodeMirror-cursor</code></dt>
|
||||
<dd>The cursor is a block element that is absolutely positioned.
|
||||
You can make it look whichever way you want.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_selected"><code>CodeMirror-selected</code></dt>
|
||||
<dd>The selection is represented by <code>span</code> elements
|
||||
with this class.</dd>
|
||||
|
||||
<dt id="class_CodeMirror_matchingbracket"><code>CodeMirror-matchingbracket</code>,
|
||||
<code>CodeMirror-matchingbracket</code></dt>
|
||||
<dd>These are used to style matched (or unmatched) brackets.</dd>
|
||||
</dl>
|
||||
|
||||
<p>The actual lines, as well as the cursor, are represented
|
||||
by <code>pre</code> elements. By default no text styling (such as
|
||||
bold) that might change line height is applied. If you do want
|
||||
such effects, you'll have to give <code>CodeMirror pre</code> a
|
||||
fixed height. Also, you must still take care that character width
|
||||
is constant.</p>
|
||||
|
||||
<p>If your page's style sheets do funky things to
|
||||
all <code>div</code> or <code>pre</code> elements (you probably
|
||||
shouldn't do that), you'll have to define rules to cancel these
|
||||
effects out again for elements under the <code>CodeMirror</code>
|
||||
class.</p>
|
||||
|
||||
<h2 id="api">Programming API</h2>
|
||||
|
||||
<p>A lot of CodeMirror features are only available through its API.
|
||||
This has the disadvantage that you need to do work to enable them,
|
||||
and the advantage that CodeMirror will fit seamlessly into your
|
||||
application.</p>
|
||||
|
||||
<p>Whenever points in the document are represented, the API uses
|
||||
objects with <code>line</code> and <code>ch</code> properties.
|
||||
Both are zero-based. CodeMirror makes sure to 'clip' any positions
|
||||
passed by client code so that they fit inside the document, so you
|
||||
shouldn't worry too much about sanitizing your coordinates. If you
|
||||
give <code>ch</code> a value of <code>null</code>, or don't
|
||||
specify it, it will be replaced with the length of the specified
|
||||
line.</p>
|
||||
|
||||
<dl>
|
||||
<dt id="getValue"><code>getValue() → string</code></dt>
|
||||
<dd>Get the current editor content.</dd>
|
||||
<dt id="setValue"><code>setValue(string)</code></dt>
|
||||
<dd>Set the editor content.</dd>
|
||||
|
||||
<dt id="getSelection"><code>getSelection() → string</code></dt>
|
||||
<dd>Get the currently selected code.</dd>
|
||||
<dt id="replaceSelection"><code>replaceSelection(string)</code></dt>
|
||||
<dd>Replace the selection with the given string.</dd>
|
||||
|
||||
<dt id="focus"><code>focus()</code></dt>
|
||||
<dd>Give the editor focus.</dd>
|
||||
|
||||
<dt id="setOption"><code>setOption(option, value)</code></dt>
|
||||
<dd>Change the configuration of the editor. <code>option</code>
|
||||
should the name of an <a href="#config">option</a>,
|
||||
and <code>value</code> should be a valid value for that
|
||||
option.</dd>
|
||||
<dt id="getOption"><code>getOption(option) → value</code></dt>
|
||||
<dd>Retrieves the current value of the given option for this
|
||||
editor instance.</dd>
|
||||
|
||||
<dt id="cursorCoords"><code>cursorCoords(start) → object</code></dt>
|
||||
<dd>Returns an <code>{x, y, yBot}</code> object containing the
|
||||
coordinates of the cursor relative to the top-left corner of the
|
||||
page. <code>yBot</code> is the coordinate of the bottom of the
|
||||
cursor. <code>start</code> is a boolean indicating whether you
|
||||
want the start or the end of the selection.</dd>
|
||||
<dt id="charCoords"><code>charCoords(pos) → object</code></dt>
|
||||
<dd>Like <code>cursorCoords</code>, but returns the position of
|
||||
an arbitrary characters. <code>pos</code> should be
|
||||
a <code>{line, ch}</code> object.</dd>
|
||||
<dt id="coordsChar"><code>coordsChar(object) → pos</code></dt>
|
||||
<dd>Given an <code>{x, y}</code> object (in page coordinates),
|
||||
returns the <code>{line, ch}</code> position that corresponds to
|
||||
it.</dd>
|
||||
|
||||
<dt id="undo"><code>undo()</code></dt>
|
||||
<dd>Undo one edit (if any undo events are stored).</dd>
|
||||
<dt id="redo"><code>redo()</code></dt>
|
||||
<dd>Redo one undone edit.</dd>
|
||||
<dt id="historySize"><code>historySize() → object</code></dt>
|
||||
<dd>Returns an object with <code>{undo, redo}</code> properties,
|
||||
both of which hold integers, indicating the amount of stored
|
||||
undo and redo operations.</dd>
|
||||
|
||||
<dt id="indentLine"><code>indentLine(line)</code></dt>
|
||||
<dd>Reset the given line's indentation to the indentation
|
||||
prescribed by the mode.</dd>
|
||||
|
||||
<dt id="getSearchCursor"><code>getSearchCursor(query, start, caseFold) → cursor</code></dt>
|
||||
<dd>Used to implement search/replace
|
||||
functionality. <code>query</code> can be a regular expression or
|
||||
a string (only strings will match across lines—if they contain
|
||||
newlines). <code>start</code> provides the starting position of
|
||||
the search. It can be a <code>{line, ch}</code> object, or can
|
||||
be left off to default to the start of the
|
||||
document. <code>caseFold</code> is only relevant when matching a
|
||||
string. It will cause the search to be case-insensitive. A
|
||||
search cursor has the following methods:
|
||||
<dl>
|
||||
<dt><code>findNext(), findPrevious() → boolean</code></dt>
|
||||
<dd>Search forward or backward from the current position.
|
||||
The return value indicates whether a match was found. If
|
||||
matching a regular expression, the return value will be the
|
||||
array returned by the <code>match</code> method, in case you
|
||||
want to extract matched groups.</dd>
|
||||
<dt><code>from(), to() → object</code></dt>
|
||||
<dd>These are only valid when the last call
|
||||
to <code>findNext</code> or <code>findPrevious</code> did
|
||||
not return false. They will return <code>{line, ch}</code>
|
||||
objects pointing at the start and end of the match.</dd>
|
||||
</dl></dd>
|
||||
|
||||
<dt id="getTokenAt"><code>getTokenAt(pos) → object</code></dt>
|
||||
<dd>Retrieves information about the token the current mode found
|
||||
at the given position (a <code>{line, ch}</code> object). The
|
||||
returned object has the following properties:
|
||||
<dl>
|
||||
<dt><code>start</code></dt><dd>The character (on the given line) at which the token starts.</dd>
|
||||
<dt><code>end</code></dt><dd>The character at which the token ends.</dd>
|
||||
<dt><code>string</code></dt><dd>The token's string.</dd>
|
||||
<dt><code>className</code></dt><dd>The class the mode assigned
|
||||
to the token. (Can be null when no class was assigned.)</dd>
|
||||
</dl></dd>
|
||||
|
||||
<dt id="markText"><code>markText(from, to, className) → function</code></dt>
|
||||
<dd>Can be used to mark a range of text with a specific CSS
|
||||
class name. <code>from</code> and <code>to</code> should
|
||||
be <code>{line, ch}</code> objects. The method will return a
|
||||
function that can be called to remove the marking.</dd>
|
||||
|
||||
<dt id="setMarker"><code>setMarker(line, text, className) → lineHandle</code></dt>
|
||||
<dd>Add a gutter marker for the given line. Gutter markers are
|
||||
shown in the line-number area (instead of the number for this
|
||||
line). Both <code>text</code> and <code>className</code> are
|
||||
optional. Setting <code>text</code> to a Unicode character like
|
||||
● tends to give a nice effect. To put a picture in the gutter,
|
||||
set <code>text</code> to a space and <code>className</code> to
|
||||
something that sets a background image. If you
|
||||
specify <code>text</code>, the given text (which may contain
|
||||
HTML) will, by default, replace the line number for that line.
|
||||
If this is not what you want, you can include the
|
||||
string <code>%N%</code> in the text, which will be replaced by
|
||||
the line number.</dd>
|
||||
<dt id="clearMarker"><code>clearMarker(line)</code></dt>
|
||||
<dd>Clears a marker created
|
||||
with <code>setMarker</code>. <code>line</code> can be either a
|
||||
number or a handle returned by <code>setMarker</code> (since a
|
||||
number may now refer to a different line if something was added
|
||||
or deleted).</dd>
|
||||
<dt id="setLineClass"><code>setLineClass(line, className) → lineHandle</code></dt>
|
||||
<dd>Set a CSS class name for the given line. <code>line</code>
|
||||
can be a number or a line handle (as returned
|
||||
by <code>setMarker</code> or this function).
|
||||
Pass <code>null</code> to clear the class for a line.</dd>
|
||||
|
||||
<dt id="lineInfo"><code>lineInfo(line) → object</code></dt>
|
||||
<dd>Returns the line number, text content, and marker status of
|
||||
the given line, which can be either a number or a handle
|
||||
returned by <code>setMarker</code>. The returned object has the
|
||||
structure <code>{line, text, markerText, markerClass}</code>.</dd>
|
||||
|
||||
<dt id="addWidget"><code>addWidget(pos, node, scrollIntoView)</code></dt>
|
||||
<dd>Puts <code>node</code>, which should be an absolutely
|
||||
positioned DOM node, into the editor, positioned right below the
|
||||
given <code>{line, ch}</code> position.
|
||||
When <code>scrollIntoView</code> is true, the editor will ensure
|
||||
that the entire node is visible (if possible). To remove the
|
||||
widget again, simply use DOM methods (move it somewhere else, or
|
||||
call <code>removeChild</code> on its parent).</dd>
|
||||
|
||||
<dt id="matchBrackets"><code>matchBrackets()</code></dt>
|
||||
<dd>Force matching-bracket-highlighting to happen.</dd>
|
||||
|
||||
<dt id="lineCount"><code>lineCount() → number</code></dt>
|
||||
<dd>Get the number of lines in the editor.</dd>
|
||||
|
||||
<dt id="getCursor"><code>getCursor(start) → object</code></dt>
|
||||
<dd><code>start</code> is a boolean indicating whether the start
|
||||
or the end of the selection must be retrieved. If it is not
|
||||
given, the current cursor pos, i.e. the side of the selection
|
||||
that would move if you pressed an arrow key, is chosen.
|
||||
A <code>{line, ch}</code> object will be returned.</dd>
|
||||
<dt id="somethingSelected"><code>somethingSelected() → boolean</code></dt>
|
||||
<dd>Return true if any text is selected.</dd>
|
||||
<dt id="setCursor"><code>setCursor(pos)</code></dt>
|
||||
<dd>Set the cursor position. You can either pass a
|
||||
single <code>{line, ch}</code> object, or the line and the
|
||||
character as two separate parameters.</dd>
|
||||
<dt id="setSelection"><code>setSelection(start, end)</code></dt>
|
||||
<dd>Set the selection range. <code>start</code>
|
||||
and <code>end</code> should be <code>{line, ch}</code> objects.</dd>
|
||||
|
||||
<dt id="getLine"><code>getLine(n) → string</code></dt>
|
||||
<dd>Get the content of line <code>n</code>.</dd>
|
||||
<dt id="setLine"><code>setLine(n, text)</code></dt>
|
||||
<dd>Set the content of line <code>n</code>.</dd>
|
||||
<dt id="removeLine"><code>removeLine(n)</code></dt>
|
||||
<dd>Remove the given line from the document.</dd>
|
||||
|
||||
<dt id="getRange"><code>getRange(from, to) → string</code></td>
|
||||
<dd>Get the text between the given points in the editor, which
|
||||
should be <code>{line, ch}</code> objects.</dd>
|
||||
<dt id="replaceRange"><code>replaceRange(string, from, to)</code></dt>
|
||||
<dd>Replace the part of the document between <code>from</code>
|
||||
and <code>to</code> with the given string. <code>from</code>
|
||||
and <code>to</code> must be <code>{line, ch}</code>
|
||||
objects. <code>to</code> can be left off to simply insert the
|
||||
string at position <code>from</code>.</dd>
|
||||
</dl>
|
||||
|
||||
<p>The following are more low-level methods:</p>
|
||||
|
||||
<dl>
|
||||
<dt id="operation"><code>operation(func) → result</code></dt>
|
||||
<dd>CodeMirror internally buffers changes and only updates its
|
||||
DOM structure after it has finished performing some operation.
|
||||
If you need to perform a lot of operations on a CodeMirror
|
||||
instance, you can call this method with a function argument. It
|
||||
will call the function, buffering up all changes, and only doing
|
||||
the expensive update after the function returns. This can be a
|
||||
lot faster. The return value from this method will be the return
|
||||
value of your function.</dd>
|
||||
|
||||
<dt id="refresh"><code>refresh()</code></dt>
|
||||
<dd>If your code does something to change the size of the editor
|
||||
element (window resizes are already listened for), or unhides
|
||||
it, you should probably follow up by calling this method to
|
||||
ensure CodeMirror is still looking as intended.</dd>
|
||||
|
||||
<dt id="getInputField"><code>getInputField() → textarea</code></dt>
|
||||
<dd>Returns the hiden textarea used to read input.</dd>
|
||||
<dt id="getWrapperElement"><code>getWrapperElement() → node</code></dt>
|
||||
<dd>Returns the DOM node that represents the editor. Remove this
|
||||
from your tree to delete an editor instance.</dd>
|
||||
</dl>
|
||||
|
||||
<p id="fromTextArea">Finally, the <code>CodeMirror</code> object
|
||||
itself has a method <code>fromTextArea</code>. This takes a
|
||||
textarea DOM node as first argument and an optional configuration
|
||||
object as second. It will replace the textarea with a CodeMirror
|
||||
instance, and wire up the form of that textarea (if any) to make
|
||||
sure the editor contents are put into the textarea when the form
|
||||
is submitted. A CodeMirror instance created this way has two
|
||||
additional methods:</p>
|
||||
|
||||
<dl>
|
||||
<dt id="save"><code>save()</code></dt>
|
||||
<dd>Copy the content of the editor into the textarea.</dd>
|
||||
|
||||
<dt id="toTextArea"><code>toTextArea()</code></dt>
|
||||
<dd>Remove the editor, and restore the original textarea (with
|
||||
the editor's current content).</dd>
|
||||
</dl>
|
||||
|
||||
<h2 id="modeapi">Writing CodeMirror Modes</h2>
|
||||
|
||||
<p>Modes typically consist of a JavaScript file and a CSS file.
|
||||
The CSS file (see, for
|
||||
example <a href="mode/javascript/javascript.css"><code>javascript.css</code></a>)
|
||||
defines the classes that will be used to style the syntactic
|
||||
elements of the code, and the script contains the logic to
|
||||
actually assign these classes to the right pieces of text.</p>
|
||||
|
||||
<p>You'll usually want to use some kind of prefix for your CSS
|
||||
classes, so that they are unlikely to clash with other classes,
|
||||
both those used by other modes and those defined by the page in
|
||||
which CodeMirror is embedded.</p>
|
||||
|
||||
<p id="defineMode">The mode script should
|
||||
call <code>CodeMirror.defineMode</code> to register itself with
|
||||
CodeMirror. This function takes two arguments. The first should be
|
||||
the name of the mode, for which you should use a lowercase string,
|
||||
preferably one that is also the name of the files that define the
|
||||
mode (i.e. <code>"xml"</code> is defined <code>xml.js</code>). The
|
||||
second argument should be a function that, given a CodeMirror
|
||||
configuration object (the thing passed to
|
||||
the <code>CodeMirror</code> function) and a mode configuration
|
||||
object (as in the <a href="#option_mode"><code>mode</code></a>
|
||||
option), returns a mode object.</p>
|
||||
|
||||
<p>Typically, you should use this second argument
|
||||
to <code>defineMode</code> as your module scope function (modes
|
||||
should not leak anything into the global scope!), i.e. write your
|
||||
whole mode inside this function.</p>
|
||||
|
||||
<p>The main responsibility of a mode script is <em>parsing</em>
|
||||
the content of the editor. Depending on the language and the
|
||||
amount of functionality desired, this can be done in really easy
|
||||
or extremely complicated ways. Some parsers can be stateless,
|
||||
meaning that they look at one element (<em>token</em>) of the code
|
||||
at a time, with no memory of what came before. Most, however, will
|
||||
need to remember something. This is done by using a <em>state
|
||||
object</em>, which is an object that can be mutated every time a
|
||||
new token is read.</p>
|
||||
|
||||
<p id="startState">Modes that use a state must define
|
||||
a <code>startState</code> method on their mode object. This is a
|
||||
function of no arguments that produces a state object to be used
|
||||
at the start of a document.</p>
|
||||
|
||||
<p id="token">The most important part of a mode object is
|
||||
its <code>token(stream, state)</code> method. All modes must
|
||||
define this method. It should read one token from the stream it is
|
||||
given as an argument, optionally update its state, and return a
|
||||
CSS class string, or <code>null</code> for tokens that do not have
|
||||
to be styled.<p>
|
||||
|
||||
<p id="StringStream">The stream object encapsulates a line of code
|
||||
(tokens may never span lines) and our current position in that
|
||||
line. It has the following API:</p>
|
||||
|
||||
<dl>
|
||||
<dt><code>eol() → boolean</code></dt>
|
||||
<dd>Returns true only if the stream is at the end of the
|
||||
line.</dd>
|
||||
<dt><code>sol() → boolean</code></dt>
|
||||
<dd>Returns true only if the stream is at the start of the
|
||||
line.</dd>
|
||||
|
||||
<dt><code>peek() → character</code></dt>
|
||||
<dd>Returns the next character in the stream without advancing
|
||||
it. Will return <code>undefined</code> at the end of the
|
||||
line.</dd>
|
||||
<dt><code>next() → character</code></dt>
|
||||
<dd>Returns the next character in the stream and advances it.
|
||||
Also returns <code>undefined</code> when no more characters are
|
||||
available.</dd>
|
||||
|
||||
<dt><code>eat(match) → character</code></dt>
|
||||
<dd><code>match</code> can be a character, a regular expression,
|
||||
or a function that takes a character and returns a boolean. If
|
||||
the next character in the stream 'matches' the given argument,
|
||||
it is consumed and returned. Otherwise, <code>undefined</code>
|
||||
is returned.</dd>
|
||||
<dt><code>eatWhile(match) → boolean</code></dt>
|
||||
<dd>Repeatedly calls <code>eat</code> with the given argument,
|
||||
until it fails. Returns true if any characters were eaten.</dd>
|
||||
<dt><code>eatSpace() → boolean</code></dt>
|
||||
<dd>Shortcut for <code>eatWhile</code> when matching
|
||||
white-space.</dd>
|
||||
<dt><code>skipToEnd()</code></dt>
|
||||
<dd>Moves the position to the end of the line.</dd>
|
||||
<dt><code>skipTo(ch) → boolean</code></dt>
|
||||
<dd>Skips to the next occurrence of the given character, if
|
||||
found. Returns true if the character was found.</dd>
|
||||
<dt><code>match(pattern, consume, caseFold) → boolean</code></dt>
|
||||
<dd>Act like a
|
||||
multi-character <code>eat</code>—if <code>consume</code> is true
|
||||
or not given—or a look-ahead that doesn't update the stream
|
||||
position—if it is false. <code>pattern</code> can be either a
|
||||
string or a regular expression starting with <code>^</code>.
|
||||
When it is a string, <code>caseFold</code> can be set to true to
|
||||
make the match case-insensitive. When successfully matching a
|
||||
regular expression, the returned value will be the array
|
||||
returned by <code>match</code>, in case you need to extract
|
||||
matched groups.</dd>
|
||||
|
||||
<dt><code>backUp(n)</code></dt>
|
||||
<dd>Backs up the stream <code>n</code> characters. Backing it up
|
||||
further than the start of the current token will cause things to
|
||||
break, so be careful.</dd>
|
||||
<dt><code>column() → integer</code></dt>
|
||||
<dd>Returns the column (taking into account tabs) at which the
|
||||
current token starts. Can be used to find out whether a token
|
||||
starts a new line.</dd>
|
||||
<dt><code>indentation() → integer</code></dt>
|
||||
<dd>Tells you how far the current line has been indented, in
|
||||
spaces. Corrects for tab characters.</dd>
|
||||
|
||||
<dt><code>current() → string</code></dt>
|
||||
<dd>Get the string between the start of the current token and
|
||||
the current stream position.</dd>
|
||||
</dl>
|
||||
|
||||
<p id="copyState">Because state object are mutated, and CodeMirror
|
||||
needs to keep valid versions of a state around so that it can
|
||||
restart a parse at any line, copies must be made of state objects.
|
||||
The default algorithm used is that a new state object is created,
|
||||
which gets all the properties of the old object. Any properties
|
||||
which hold arrays get a copy of these arrays (since arrays tend to
|
||||
be used as mutable stacks). When this is not correct, for example
|
||||
because a mode mutates non-array properties of its state object, a
|
||||
mode object should define a <code>copyState</code> method,
|
||||
which is given a state and should return a safe copy of that
|
||||
state.</p>
|
||||
|
||||
<p id="indent">If you want your mode to provide smart indentation
|
||||
(see <a href="#option_enterMode"><code>entermode</code></a>
|
||||
and <a href="#option_tabMode"><code>tabMode</code></a> when they
|
||||
have a value of <code>"indent"</code>), you must define
|
||||
an <code>indent(state, textAfter)</code> method on your mode
|
||||
object.</p>
|
||||
|
||||
<p>The indentation method should inspect the given state object,
|
||||
and optionally the <code>textAfter</code> string, which contains
|
||||
the text on the line that is being indented, and return an
|
||||
integer, the amount of spaces to indent. It should usually take
|
||||
the <a href="#option_indentUnit"><code>indentUnit</code></a>
|
||||
option into account.</p>
|
||||
|
||||
<p id="electricChars">Finally, a mode may define
|
||||
an <code>electricChars</code> property, which should hold a string
|
||||
containing all the characters that should trigger the behaviour
|
||||
described for
|
||||
the <a href="#option_electricChars"><code>electricChars</code></a>
|
||||
option.</p>
|
||||
|
||||
<p>So, to summarize, a mode <em>must</em> provide
|
||||
a <code>token</code> method, and it <em>may</em>
|
||||
provide <code>startState</code>, <code>copyState</code>,
|
||||
and <code>indent</code> methods. For an example of a trivial mode,
|
||||
see the <a href="mode/diff/diff.js">diff mode</a>, for a more
|
||||
involved example, see
|
||||
the <a href="mode/javascript/javascript.js">JavaScript
|
||||
mode</a>.</p>
|
||||
|
||||
<p>Sometimes, it is useful for modes to <em>nest</em>—to have one
|
||||
mode delegate work to another mode. An example of this kind of
|
||||
mode is the <a href="mode/htmlmixed/htmlmixed.js">mixed-mode HTML
|
||||
mode</a>. To implement such nesting, it is usually necessary to
|
||||
create mode objects and copy states yourself. To create a mode
|
||||
object, there are <code>CodeMirror.getMode(options,
|
||||
parserConfig)</code>, where the first argument is a configuration
|
||||
object as passed to the mode constructor function, and the second
|
||||
argument is a mode specification as in
|
||||
the <a href="#option_mode"><code>mode</code></a> option. To copy a
|
||||
state object, call <code>CodeMirror.copyState(mode, state)</code>,
|
||||
where <code>mode</code> is the mode that created the given
|
||||
state.</p>
|
||||
|
||||
<p>To make indentation work properly in a nested parser, it is
|
||||
advisable to give the <code>startState</code> method of modes that
|
||||
are intended to be nested an optional argument that provides the
|
||||
base indentation for the block of code. The JavaScript and CSS
|
||||
parser do this, for example, to allow JavaScript and CSS code
|
||||
inside the mixed-mode HTML mode to be properly indented.</p>
|
||||
|
||||
<p>Finally, it is possible to associate your mode, or a certain
|
||||
configuration of your mode, with
|
||||
a <a href="http://en.wikipedia.org/wiki/MIME">MIME</a> type. For
|
||||
example, the JavaScript mode associates itself
|
||||
with <code>text/javascript</code>, and its JSON variant
|
||||
with <code>application/json</code>. To do this,
|
||||
call <code>CodeMirror.defineMIME(mime, modeSpec)</code>,
|
||||
where <code>modeSpec</code> can be a string or object specifying a
|
||||
mode, as in the <a href="#option_mode"><code>mode</code></a>
|
||||
option.</p>
|
||||
|
||||
</div><div class="rightsmall blk">
|
||||
|
||||
<h2>Contents</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#overview">Overview</a></li>
|
||||
<li><a href="#usage">Basic Usage</a></li>
|
||||
<li><a href="#config">Configuration</a></li>
|
||||
<li><a href="#styling">Customized Styling</a></li>
|
||||
<li><a href="#api">Programming API</a></li>
|
||||
<li><a href="#modeapi">Writing CodeMirror Modes</a></li>
|
||||
</ul>
|
||||
|
||||
</div></div>
|
||||
|
||||
<div style="height: 2em"> </div>
|
||||
|
||||
<script type="text/javascript" src="css/font.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
6
simpla/design/js/codemirror/mode/clike/clike.css
vendored
Normal file
6
simpla/design/js/codemirror/mode/clike/clike.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
span.c-like-keyword {color: #90b;}
|
||||
span.c-like-number {color: #291;}
|
||||
span.c-like-comment {color: #a70;}
|
||||
span.c-like-string {color: #a22;}
|
||||
span.c-like-preprocessor {color: #049;}
|
||||
span.c-like-var {color: #22b;}
|
||||
181
simpla/design/js/codemirror/mode/clike/clike.js
vendored
Normal file
181
simpla/design/js/codemirror/mode/clike/clike.js
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
CodeMirror.defineMode("clike", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit, keywords = parserConfig.keywords,
|
||||
cpp = parserConfig.useCPP, multiLineStrings = parserConfig.multiLineStrings, $vars = parserConfig.$vars;
|
||||
var isOperatorChar = /[+\-*&%=<>!?|]/;
|
||||
|
||||
function chain(stream, state, f) {
|
||||
state.tokenize = f;
|
||||
return f(stream, state);
|
||||
}
|
||||
|
||||
var type;
|
||||
function ret(tp, style) {
|
||||
type = tp;
|
||||
return style;
|
||||
}
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'")
|
||||
return chain(stream, state, tokenString(ch));
|
||||
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
|
||||
return ret(ch);
|
||||
else if (ch == "#" && cpp && state.startOfLine) {
|
||||
stream.skipToEnd();
|
||||
return ret("directive", "c-like-preprocessor");
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w\.]/)
|
||||
return ret("number", "c-like-number");
|
||||
}
|
||||
else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
return chain(stream, state, tokenComment);
|
||||
}
|
||||
else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "c-like-comment");
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator");
|
||||
}
|
||||
}
|
||||
else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator");
|
||||
}
|
||||
else if ($vars && ch == "$") {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return ret("word", "c-like-var");
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
if (keywords && keywords.propertyIsEnumerable(stream.current())) return ret("keyword", "c-like-keyword");
|
||||
return ret("word", "c-like-word");
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) {end = true; break;}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (end || !(escaped || multiLineStrings))
|
||||
state.tokenize = tokenBase;
|
||||
return ret("string", "c-like-string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "c-like-comment");
|
||||
}
|
||||
|
||||
function Context(indented, column, type, align, prev) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.align = align;
|
||||
this.prev = prev;
|
||||
}
|
||||
|
||||
function pushContext(state, col, type) {
|
||||
return state.context = new Context(state.indented, col, type, null, state.context);
|
||||
}
|
||||
function popContext(state) {
|
||||
return state.context = state.context.prev;
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: tokenBase,
|
||||
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
|
||||
indented: 0,
|
||||
startOfLine: true
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var ctx = state.context;
|
||||
if (stream.sol()) {
|
||||
if (ctx.align == null) ctx.align = false;
|
||||
state.indented = stream.indentation();
|
||||
state.startOfLine = true;
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
if (ctx.align == null) ctx.align = true;
|
||||
|
||||
if ((type == ";" || type == ":") && ctx.type == "statement") popContext(state);
|
||||
else if (type == "{") pushContext(state, stream.column(), "}");
|
||||
else if (type == "[") pushContext(state, stream.column(), "]");
|
||||
else if (type == "(") pushContext(state, stream.column(), ")");
|
||||
else if (type == "}") {
|
||||
if (ctx.type == "statement") ctx = popContext(state);
|
||||
if (ctx.type == "}") ctx = popContext(state);
|
||||
if (ctx.type == "statement") ctx = popContext(state);
|
||||
}
|
||||
else if (type == ctx.type) popContext(state);
|
||||
else if (ctx.type == "}") pushContext(state, stream.column(), "statement");
|
||||
state.startOfLine = false;
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
|
||||
if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
|
||||
else if (ctx.align) return ctx.column + (closing ? 0 : 1);
|
||||
else return ctx.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricChars: "{}"
|
||||
};
|
||||
});
|
||||
|
||||
(function() {
|
||||
function keywords(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
|
||||
"double static else struct entry switch extern typedef float union for unsigned " +
|
||||
"goto while enum void const signed volatile";
|
||||
|
||||
CodeMirror.defineMIME("text/x-csrc", {
|
||||
name: "clike",
|
||||
useCPP: true,
|
||||
keywords: keywords(cKeywords)
|
||||
});
|
||||
CodeMirror.defineMIME("text/x-c++src", {
|
||||
name: "clike",
|
||||
useCPP: true,
|
||||
keywords: keywords(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
|
||||
"static_cast typeid catch false operator template typename class friend private " +
|
||||
"this using const_cast inline public throw virtual delete mutable protected true " +
|
||||
"wchar_t")
|
||||
});
|
||||
CodeMirror.defineMIME("text/x-java", {
|
||||
name: "clike",
|
||||
keywords: keywords("abstract assert boolean break byte case catch char class const continue default " +
|
||||
"do double else enum extends false final finally float for goto if implements import " +
|
||||
"instanceof int interface long native new null package private protected public " +
|
||||
"return short static strictfp super switch synchronized this throw throws transient " +
|
||||
"true try void volatile while")
|
||||
});
|
||||
}());
|
||||
101
simpla/design/js/codemirror/mode/clike/index.html
vendored
Normal file
101
simpla/design/js/codemirror/mode/clike/index.html
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: C-like mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="clike.js"></script>
|
||||
<link rel="stylesheet" href="clike.css">
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
<style>.CodeMirror {border: 2px inset #dee;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: C-like mode</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
/* C demo code */
|
||||
|
||||
#include <zmq.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
|
||||
typedef struct {
|
||||
void* arg_socket;
|
||||
zmq_msg_t* arg_msg;
|
||||
char* arg_string;
|
||||
unsigned long arg_len;
|
||||
int arg_int, arg_command;
|
||||
|
||||
int signal_fd;
|
||||
int pad;
|
||||
void* context;
|
||||
sem_t sem;
|
||||
} acl_zmq_context;
|
||||
|
||||
#define p(X) (context->arg_##X)
|
||||
|
||||
void* zmq_thread(void* context_pointer) {
|
||||
acl_zmq_context* context = (acl_zmq_context*)context_pointer;
|
||||
char ok = 'K', err = 'X';
|
||||
int res;
|
||||
|
||||
while (1) {
|
||||
while ((res = sem_wait(&context->sem)) == EINTR);
|
||||
if (res) {write(context->signal_fd, &err, 1); goto cleanup;}
|
||||
switch(p(command)) {
|
||||
case 0: goto cleanup;
|
||||
case 1: p(socket) = zmq_socket(context->context, p(int)); break;
|
||||
case 2: p(int) = zmq_close(p(socket)); break;
|
||||
case 3: p(int) = zmq_bind(p(socket), p(string)); break;
|
||||
case 4: p(int) = zmq_connect(p(socket), p(string)); break;
|
||||
case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &p(len)); break;
|
||||
case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;
|
||||
case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;
|
||||
case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;
|
||||
case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;
|
||||
}
|
||||
p(command) = errno;
|
||||
write(context->signal_fd, &ok, 1);
|
||||
}
|
||||
cleanup:
|
||||
close(context->signal_fd);
|
||||
free(context_pointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* zmq_thread_init(void* zmq_context, int signal_fd) {
|
||||
acl_zmq_context* context = malloc(sizeof(acl_zmq_context));
|
||||
pthread_t thread;
|
||||
|
||||
context->context = zmq_context;
|
||||
context->signal_fd = signal_fd;
|
||||
sem_init(&context->sem, 1, 0);
|
||||
pthread_create(&thread, 0, &zmq_thread, context);
|
||||
pthread_detach(thread);
|
||||
return context;
|
||||
}
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "text/x-csrc"
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>Simple mode that tries to handle C-like languages as well as it
|
||||
can. Takes two configuration parameters: <code>keywords</code>, an
|
||||
object whose property names are the keywords in the language,
|
||||
and <code>useCPP</code>, which determines whether C preprocessor
|
||||
directives are recognized.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
|
||||
(C code), <code>text/x-c++src</code> (C++
|
||||
code), <code>text/x-java</code> (Java code).</p>
|
||||
</body>
|
||||
</html>
|
||||
9
simpla/design/js/codemirror/mode/css/css.css
vendored
Normal file
9
simpla/design/js/codemirror/mode/css/css.css
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
span.css-at {color: #708;}
|
||||
span.css-unit {color: #281;}
|
||||
span.css-value {color: #708;}
|
||||
span.css-identifier {color: black;}
|
||||
span.css-selector {color: #11B;}
|
||||
span.css-important {color: #00F;}
|
||||
span.css-colorcode {color: #299;}
|
||||
span.css-comment {color: #A70;}
|
||||
span.css-string {color: #A22;}
|
||||
124
simpla/design/js/codemirror/mode/css/css.js
vendored
Normal file
124
simpla/design/js/codemirror/mode/css/css.js
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
CodeMirror.defineMode("css", function(config) {
|
||||
var indentUnit = config.indentUnit, type;
|
||||
function ret(style, tp) {type = tp; return style;}
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == "@") {stream.eatWhile(/\w/); return ret("css-at", stream.current());}
|
||||
else if (ch == "/" && stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
}
|
||||
else if (ch == "<" && stream.eat("!")) {
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
}
|
||||
else if (ch == "=") ret(null, "compare");
|
||||
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
|
||||
else if (ch == "\"" || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
else if (ch == "#") {
|
||||
stream.eatWhile(/\w/);
|
||||
return ret("css-selector", "hash");
|
||||
}
|
||||
else if (ch == "!") {
|
||||
stream.match(/^\s*\w*/);
|
||||
return ret("css-important", "important");
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("css-unit", "unit");
|
||||
}
|
||||
else if (/[,.+>*\/]/.test(ch)) {
|
||||
return ret(null, "select-op");
|
||||
}
|
||||
else if (/[;{}:\[\]]/.test(ch)) {
|
||||
return ret(null, ch);
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[\w\\\-_]/);
|
||||
return ret("css-identifier", "identifier");
|
||||
}
|
||||
}
|
||||
|
||||
function tokenCComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (maybeEnd && ch == "/") {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("css-comment", "comment");
|
||||
}
|
||||
|
||||
function tokenSGMLComment(stream, state) {
|
||||
var dashes = 0, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (dashes >= 2 && ch == ">") {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
dashes = (ch == "-") ? dashes + 1 : 0;
|
||||
}
|
||||
return ret("css-comment", "comment");
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped)
|
||||
break;
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("css-string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function(base) {
|
||||
return {tokenize: tokenBase,
|
||||
baseIndent: base || 0,
|
||||
stack: []};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
|
||||
var context = state.stack[state.stack.length-1];
|
||||
if (type == "hash" && context == "rule") style = "css-colorcode";
|
||||
else if (style == "css-identifier") {
|
||||
if (context == "rule") style = "css-value";
|
||||
else if (!context || context == "@media{") style = "css-selector";
|
||||
}
|
||||
|
||||
if (context == "rule" && /^[\{\};]$/.test(type))
|
||||
state.stack.pop();
|
||||
if (type == "{") {
|
||||
if (context == "@media") state.stack[state.stack.length-1] = "@media{";
|
||||
else state.stack.push("{");
|
||||
}
|
||||
else if (type == "}") state.stack.pop();
|
||||
else if (type == "@media") state.stack.push("@media");
|
||||
else if (context != "rule" && context != "@media" && type != "comment") state.stack.push("rule");
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var n = state.stack.length;
|
||||
if (/^\}/.test(textAfter))
|
||||
n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
|
||||
return state.baseIndent + n * indentUnit;
|
||||
},
|
||||
|
||||
electricChars: "}"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/css", "css");
|
||||
56
simpla/design/js/codemirror/mode/css/index.html
vendored
Normal file
56
simpla/design/js/codemirror/mode/css/index.html
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: CSS mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="css.js"></script>
|
||||
<link rel="stylesheet" href="css.css">
|
||||
<style>.CodeMirror {background: #f8f8f8;}</style>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: CSS mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
/* Some example CSS */
|
||||
|
||||
@import url("something.css");
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 3em 6em;
|
||||
font-family: tahoma, arial, sans-serif;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#navigation a {
|
||||
font-weight: bold;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
h1:before, h2:before {
|
||||
content: "::";
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: courier, monospace;
|
||||
font-size: 80%;
|
||||
color: #418A8A;
|
||||
}
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
3
simpla/design/js/codemirror/mode/diff/diff.css
vendored
Normal file
3
simpla/design/js/codemirror/mode/diff/diff.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
span.diff-rangeinfo {color: #a0b;}
|
||||
span.diff-minus {color: #a22;}
|
||||
span.diff-plus {color: #2b2;}
|
||||
13
simpla/design/js/codemirror/mode/diff/diff.js
vendored
Normal file
13
simpla/design/js/codemirror/mode/diff/diff.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
CodeMirror.defineMode("diff", function() {
|
||||
return {
|
||||
token: function(stream) {
|
||||
var ch = stream.next();
|
||||
stream.skipToEnd();
|
||||
if (ch == "+") return "diff-plus";
|
||||
if (ch == "-") return "diff-minus";
|
||||
if (ch == "@") return "diff-rangeinfo";
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-diff", "diff");
|
||||
99
simpla/design/js/codemirror/mode/diff/index.html
vendored
Normal file
99
simpla/design/js/codemirror/mode/diff/index.html
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Diff mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="diff.js"></script>
|
||||
<link rel="stylesheet" href="diff.css">
|
||||
<style>.CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}</style>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Diff mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
diff --git a/index.html b/index.html
|
||||
index c1d9156..7764744 100644
|
||||
--- a/index.html
|
||||
+++ b/index.html
|
||||
@@ -95,7 +95,8 @@ StringStream.prototype = {
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
- autoMatchBrackets: true
|
||||
+ autoMatchBrackets: true,
|
||||
+ onGutterClick: function(x){console.log(x);}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
diff --git a/lib/codemirror.js b/lib/codemirror.js
|
||||
index 04646a9..9a39cc7 100644
|
||||
--- a/lib/codemirror.js
|
||||
+++ b/lib/codemirror.js
|
||||
@@ -399,10 +399,16 @@ var CodeMirror = (function() {
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
- var start = posFromMouse(e), last = start;
|
||||
+ var start = posFromMouse(e), last = start, target = e.target();
|
||||
if (!start) return;
|
||||
setCursor(start.line, start.ch, false);
|
||||
if (e.button() != 1) return;
|
||||
+ if (target.parentNode == gutter) {
|
||||
+ if (options.onGutterClick)
|
||||
+ options.onGutterClick(indexOf(gutter.childNodes, target) + showingFrom);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (!focused) onFocus();
|
||||
|
||||
e.stop();
|
||||
@@ -808,7 +814,7 @@ var CodeMirror = (function() {
|
||||
for (var i = showingFrom; i < showingTo; ++i) {
|
||||
var marker = lines[i].gutterMarker;
|
||||
if (marker) html.push('<div class="' + marker.style + '">' + htmlEscape(marker.text) + '</div>');
|
||||
- else html.push("<div>" + (options.lineNumbers ? i + 1 : "\u00a0") + "</div>");
|
||||
+ else html.push("<div>" + (options.lineNumbers ? i + options.firstLineNumber : "\u00a0") + "</div>");
|
||||
}
|
||||
gutter.style.display = "none"; // TODO test whether this actually helps
|
||||
gutter.innerHTML = html.join("");
|
||||
@@ -1371,10 +1377,8 @@ var CodeMirror = (function() {
|
||||
if (option == "parser") setParser(value);
|
||||
else if (option === "lineNumbers") setLineNumbers(value);
|
||||
else if (option === "gutter") setGutter(value);
|
||||
- else if (option === "readOnly") options.readOnly = value;
|
||||
- else if (option === "indentUnit") {options.indentUnit = indentUnit = value; setParser(options.parser);}
|
||||
- else if (/^(?:enterMode|tabMode|indentWithTabs|readOnly|autoMatchBrackets|undoDepth)$/.test(option)) options[option] = value;
|
||||
- else throw new Error("Can't set option " + option);
|
||||
+ else if (option === "indentUnit") {options.indentUnit = value; setParser(options.parser);}
|
||||
+ else options[option] = value;
|
||||
},
|
||||
cursorCoords: cursorCoords,
|
||||
undo: operation(undo),
|
||||
@@ -1402,7 +1406,8 @@ var CodeMirror = (function() {
|
||||
replaceRange: operation(replaceRange),
|
||||
|
||||
operation: function(f){return operation(f)();},
|
||||
- refresh: function(){updateDisplay([{from: 0, to: lines.length}]);}
|
||||
+ refresh: function(){updateDisplay([{from: 0, to: lines.length}]);},
|
||||
+ getInputField: function(){return input;}
|
||||
};
|
||||
return instance;
|
||||
}
|
||||
@@ -1420,6 +1425,7 @@ var CodeMirror = (function() {
|
||||
readOnly: false,
|
||||
onChange: null,
|
||||
onCursorActivity: null,
|
||||
+ onGutterClick: null,
|
||||
autoMatchBrackets: false,
|
||||
workTime: 200,
|
||||
workDelay: 300,
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-diff</code>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
25
simpla/design/js/codemirror/mode/haskell/haskell.css
vendored
Normal file
25
simpla/design/js/codemirror/mode/haskell/haskell.css
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
span.hs-char,
|
||||
span.hs-float,
|
||||
span.hs-integer,
|
||||
span.hs-string {color: #762;}
|
||||
|
||||
span.hs-comment {color: #262;font-style: italic;}
|
||||
span.hs-pragma {color: #555;font-style: italic;}
|
||||
|
||||
span.hs-special,
|
||||
span.hs-varid,
|
||||
span.hs-varsym {color: #000;}
|
||||
|
||||
span.hs-conid,
|
||||
span.hs-consym {color: #b11;}
|
||||
|
||||
span.hs-qualifier {color: #555;}
|
||||
|
||||
span.hs-reservedid,
|
||||
span.hs-reservedop {color: #730;}
|
||||
|
||||
span.hs-prelude-varid,
|
||||
span.hs-prelude-varsym {color: #30a;}
|
||||
span.hs-prelude-conid {color: #b11;}
|
||||
|
||||
span.hs-error {background-color: #fdd;}
|
||||
242
simpla/design/js/codemirror/mode/haskell/haskell.js
vendored
Normal file
242
simpla/design/js/codemirror/mode/haskell/haskell.js
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
CodeMirror.defineMode("haskell", function(cmCfg, modeCfg) {
|
||||
|
||||
function switchState(source, setState, f) {
|
||||
setState(f);
|
||||
return f(source, setState);
|
||||
}
|
||||
|
||||
// These should all be Unicode extended, as per the Haskell 2010 report
|
||||
var smallRE = /[a-z_]/;
|
||||
var largeRE = /[A-Z]/;
|
||||
var digitRE = /[0-9]/;
|
||||
var hexitRE = /[0-9A-Fa-f]/;
|
||||
var octitRE = /[0-7]/;
|
||||
var idRE = /[a-z_A-Z0-9']/;
|
||||
var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
|
||||
var specialRE = /[(),;[\]`{}]/;
|
||||
var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
|
||||
|
||||
function normal(source, setState) {
|
||||
if (source.eatWhile(whiteCharRE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ch = source.next();
|
||||
if (specialRE.test(ch)) {
|
||||
if (ch == '{' && source.eat('-')) {
|
||||
var t = "hs-comment";
|
||||
if (source.eat('#')) {
|
||||
t = "hs-pragma";
|
||||
}
|
||||
return switchState(source, setState, ncomment(t, 1));
|
||||
}
|
||||
return "hs-special";
|
||||
}
|
||||
|
||||
if (ch == '\'') {
|
||||
if (source.eat('\\')) {
|
||||
source.next(); // should handle other escapes here
|
||||
}
|
||||
else {
|
||||
source.next();
|
||||
}
|
||||
if (source.eat('\'')) {
|
||||
return "hs-char";
|
||||
}
|
||||
return "hs-error";
|
||||
}
|
||||
|
||||
if (ch == '"') {
|
||||
return switchState(source, setState, stringLiteral);
|
||||
}
|
||||
|
||||
if (largeRE.test(ch)) {
|
||||
source.eatWhile(idRE);
|
||||
if (source.eat('.')) {
|
||||
return "hs-qualifier";
|
||||
}
|
||||
return "hs-conid";
|
||||
}
|
||||
|
||||
if (smallRE.test(ch)) {
|
||||
source.eatWhile(idRE);
|
||||
return "hs-varid";
|
||||
}
|
||||
|
||||
if (digitRE.test(ch)) {
|
||||
if (ch == '0') {
|
||||
if (source.eat(/[xX]/)) {
|
||||
source.eatWhile(hexitRE); // should require at least 1
|
||||
return "hs-integer";
|
||||
}
|
||||
if (source.eat(/[oO]/)) {
|
||||
source.eatWhile(octitRE); // should require at least 1
|
||||
return "hs-integer";
|
||||
}
|
||||
}
|
||||
source.eatWhile(digitRE);
|
||||
var t = "hs-integer";
|
||||
if (source.eat('.')) {
|
||||
t = "hs-float";
|
||||
source.eatWhile(digitRE); // should require at least 1
|
||||
}
|
||||
if (source.eat(/[eE]/)) {
|
||||
t = "hs-float";
|
||||
source.eat(/[-+]/);
|
||||
source.eatWhile(digitRE); // should require at least 1
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
if (symbolRE.test(ch)) {
|
||||
if (ch == '-' && source.eat(/-/)) {
|
||||
source.eatWhile(/-/);
|
||||
if (!source.eat(symbolRE)) {
|
||||
source.skipToEnd();
|
||||
return "hs-comment";
|
||||
}
|
||||
}
|
||||
var t = "hs-varsym";
|
||||
if (ch == ':') {
|
||||
t = "hs-consym";
|
||||
}
|
||||
source.eatWhile(symbolRE);
|
||||
return t;
|
||||
}
|
||||
|
||||
return "hs-error";
|
||||
}
|
||||
|
||||
function ncomment(type, nest) {
|
||||
if (nest == 0) {
|
||||
return normal;
|
||||
}
|
||||
return function(source, setState) {
|
||||
var currNest = nest;
|
||||
while (!source.eol()) {
|
||||
ch = source.next();
|
||||
if (ch == '{' && source.eat('-')) {
|
||||
++currNest;
|
||||
}
|
||||
else if (ch == '-' && source.eat('}')) {
|
||||
--currNest;
|
||||
if (currNest == 0) {
|
||||
setState(normal);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
setState(ncomment(type, currNest));
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
function stringLiteral(source, setState) {
|
||||
while (!source.eol()) {
|
||||
var ch = source.next();
|
||||
if (ch == '"') {
|
||||
setState(normal);
|
||||
return "hs-string";
|
||||
}
|
||||
if (ch == '\\') {
|
||||
if (source.eol() || source.eat(whiteCharRE)) {
|
||||
setState(stringGap);
|
||||
return "hs-string";
|
||||
}
|
||||
if (source.eat('&')) {
|
||||
}
|
||||
else {
|
||||
source.next(); // should handle other escapes here
|
||||
}
|
||||
}
|
||||
}
|
||||
setState(normal);
|
||||
return "hs-error";
|
||||
}
|
||||
|
||||
function stringGap(source, setState) {
|
||||
if (source.eat('\\')) {
|
||||
return switchState(source, setState, stringLiteral);
|
||||
}
|
||||
source.next();
|
||||
setState(normal);
|
||||
return "hs-error";
|
||||
}
|
||||
|
||||
|
||||
var wellKnownWords = (function() {
|
||||
var wkw = {};
|
||||
function setType(t) {
|
||||
return function () {
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
wkw[arguments[i]] = t;
|
||||
}
|
||||
}
|
||||
|
||||
setType("hs-reservedid")(
|
||||
"case", "class", "data", "default", "deriving", "do", "else", "foreign",
|
||||
"if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
|
||||
"module", "newtype", "of", "then", "type", "where", "_");
|
||||
|
||||
setType("hs-reservedop")(
|
||||
"\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
|
||||
|
||||
setType("hs-prelude-varsym")(
|
||||
"!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
|
||||
"==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
|
||||
|
||||
setType("hs-prelude-conid")(
|
||||
"Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
|
||||
"False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
|
||||
"IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
|
||||
"Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
|
||||
"ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
|
||||
"String", "True");
|
||||
|
||||
setType("hs-prelude-varid")(
|
||||
"abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
|
||||
"asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
|
||||
"compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
|
||||
"cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
|
||||
"elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
|
||||
"enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
|
||||
"flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
|
||||
"foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
|
||||
"fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
|
||||
"getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
|
||||
"isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
|
||||
"lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
|
||||
"mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
|
||||
"minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
|
||||
"otherwise", "pi", "pred", "print", "product", "properFraction",
|
||||
"putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
|
||||
"readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
|
||||
"realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
|
||||
"round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
|
||||
"sequence", "sequence_", "show", "showChar", "showList", "showParen",
|
||||
"showString", "shows", "showsPrec", "significand", "signum", "sin",
|
||||
"sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
|
||||
"tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
|
||||
"toRational", "truncate", "uncurry", "undefined", "unlines", "until",
|
||||
"unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
|
||||
"zip3", "zipWith", "zipWith3");
|
||||
|
||||
return wkw;
|
||||
})();
|
||||
|
||||
|
||||
|
||||
return {
|
||||
startState: function () { return { f: normal }; },
|
||||
copyState: function (s) { return { f: s.f }; },
|
||||
|
||||
token: function(stream, state) {
|
||||
var t = state.f(stream, function(s) { state.f = s; });
|
||||
var w = stream.current();
|
||||
return (w in wellKnownWords) ? wellKnownWords[w] : t;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-haskell", "haskell");
|
||||
59
simpla/design/js/codemirror/mode/haskell/index.html
vendored
Normal file
59
simpla/design/js/codemirror/mode/haskell/index.html
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Haskell mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="haskell.js"></script>
|
||||
<link rel="stylesheet" href="haskell.css">
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Haskell mode</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
module UniquePerms (
|
||||
uniquePerms
|
||||
)
|
||||
where
|
||||
|
||||
-- | Find all unique permutations of a list where there might be duplicates.
|
||||
uniquePerms :: (Eq a) => [a] -> [[a]]
|
||||
uniquePerms = permBag . makeBag
|
||||
|
||||
-- | An unordered collection where duplicate values are allowed,
|
||||
-- but represented with a single value and a count.
|
||||
type Bag a = [(a, Int)]
|
||||
|
||||
makeBag :: (Eq a) => [a] -> Bag a
|
||||
makeBag [] = []
|
||||
makeBag (a:as) = mix a $ makeBag as
|
||||
where
|
||||
mix a [] = [(a,1)]
|
||||
mix a (bn@(b,n):bs) | a == b = (b,n+1):bs
|
||||
| otherwise = bn : mix a bs
|
||||
|
||||
permBag :: Bag a -> [[a]]
|
||||
permBag [] = [[]]
|
||||
permBag bs = concatMap (\(f,cs) -> map (f:) $ permBag cs) . oneOfEach $ bs
|
||||
where
|
||||
oneOfEach [] = []
|
||||
oneOfEach (an@(a,n):bs) =
|
||||
let bs' = if n == 1 then bs else (a,n-1):bs
|
||||
in (a,bs') : mapSnd (an:) (oneOfEach bs)
|
||||
|
||||
apSnd f (a,b) = (a, f b)
|
||||
mapSnd = map . apSnd
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true
|
||||
});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-haskell</code>.</p>
|
||||
</body>
|
||||
</html>
|
||||
66
simpla/design/js/codemirror/mode/htmlmixed/htmlmixed.js
vendored
Normal file
66
simpla/design/js/codemirror/mode/htmlmixed/htmlmixed.js
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
|
||||
var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
|
||||
var jsMode = CodeMirror.getMode(config, "javascript");
|
||||
var cssMode = CodeMirror.getMode(config, "css");
|
||||
|
||||
function html(stream, state) {
|
||||
var style = htmlMode.token(stream, state.htmlState);
|
||||
if (style == "xml-tag" && stream.current() == ">" && state.htmlState.context) {
|
||||
if (/^script$/i.test(state.htmlState.context.tagName)) {
|
||||
state.token = javascript;
|
||||
state.localState = jsMode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
else if (/^style$/i.test(state.htmlState.context.tagName)) {
|
||||
state.token = css;
|
||||
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
function javascript(stream, state) {
|
||||
if (stream.match(/^<\/\s*script\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.curState = null;
|
||||
return html(stream, state);
|
||||
}
|
||||
return jsMode.token(stream, state.localState);
|
||||
}
|
||||
function css(stream, state) {
|
||||
if (stream.match(/^<\/\s*style\s*>/i, false)) {
|
||||
state.token = html;
|
||||
state.localState = null;
|
||||
return html(stream, state);
|
||||
}
|
||||
return cssMode.token(stream, state.localState);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
var state = htmlMode.startState();
|
||||
return {token: html, localState: null, htmlState: state};
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
if (state.localState)
|
||||
var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState);
|
||||
return {token: state.token, localState: local, htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
return state.token(stream, state);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.token == html || /^\s*<\//.test(textAfter))
|
||||
return htmlMode.indent(state.htmlState, textAfter);
|
||||
else if (state.token == javascript)
|
||||
return jsMode.indent(state.localState, textAfter);
|
||||
else
|
||||
return cssMode.indent(state.localState, textAfter);
|
||||
},
|
||||
|
||||
electricChars: "/{}:"
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/html", "htmlmixed");
|
||||
54
simpla/design/js/codemirror/mode/htmlmixed/index.html
vendored
Normal file
54
simpla/design/js/codemirror/mode/htmlmixed/index.html
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: HTML mixed mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="../xml/xml.js"></script>
|
||||
<link rel="stylesheet" href="../xml/xml.css">
|
||||
<script src="../javascript/javascript.js"></script>
|
||||
<link rel="stylesheet" href="../javascript/javascript.css">
|
||||
<script src="../css/css.js"></script>
|
||||
<link rel="stylesheet" href="../css/css.css">
|
||||
<script src="htmlmixed.js"></script>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: HTML mixed mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
<html style="color: green">
|
||||
<!-- this is a comment -->
|
||||
<head>
|
||||
<title>Mixed HTML Example</title>
|
||||
<style type="text/css">
|
||||
h1 {font-family: comic sans; color: #f0f;}
|
||||
div {background: yellow !important;}
|
||||
body {
|
||||
max-width: 50em;
|
||||
margin: 1em 2em 1em 5em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Mixed HTML Example</h1>
|
||||
<script>
|
||||
function jsFunc(arg1, arg2) {
|
||||
if (arg1 && arg2) document.body.innerHTML = "achoo";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", tabMode: "indent"});
|
||||
</script>
|
||||
|
||||
<p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/html</code>
|
||||
(redefined, only takes effect if you load this parser after the
|
||||
XML parser).</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
78
simpla/design/js/codemirror/mode/javascript/index.html
vendored
Normal file
78
simpla/design/js/codemirror/mode/javascript/index.html
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: JavaScript mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="javascript.js"></script>
|
||||
<link rel="stylesheet" href="javascript.css">
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: JavaScript mode</h1>
|
||||
|
||||
<div><textarea id="code" name="code">
|
||||
// Demo code (the actual new parser character stream implementation)
|
||||
|
||||
function StringStream(string) {
|
||||
this.pos = 0;
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
StringStream.prototype = {
|
||||
done: function() {return this.pos >= this.string.length;},
|
||||
peek: function() {return this.string.charAt(this.pos);},
|
||||
next: function() {
|
||||
if (this.pos < this.string.length)
|
||||
return this.string.charAt(this.pos++);
|
||||
},
|
||||
eat: function(match) {
|
||||
var ch = this.string.charAt(this.pos);
|
||||
if (typeof match == "string") var ok = ch == match;
|
||||
else var ok = ch && match.test ? match.test(ch) : match(ch);
|
||||
if (ok) {this.pos++; return ch;}
|
||||
},
|
||||
eatWhile: function(match) {
|
||||
var start = this.pos;
|
||||
while (this.eat(match));
|
||||
if (this.pos > start) return this.string.slice(start, this.pos);
|
||||
},
|
||||
backUp: function(n) {this.pos -= n;},
|
||||
column: function() {return this.pos;},
|
||||
eatSpace: function() {
|
||||
var start = this.pos;
|
||||
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
|
||||
return this.pos - start;
|
||||
},
|
||||
match: function(pattern, consume, caseInsensitive) {
|
||||
if (typeof pattern == "string") {
|
||||
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
|
||||
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
|
||||
if (consume !== false) this.pos += str.length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var match = this.string.slice(this.pos).match(pattern);
|
||||
if (match && consume !== false) this.pos += match[0].length;
|
||||
return match;
|
||||
}
|
||||
}
|
||||
};
|
||||
</textarea></div>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>JavaScript mode supports a single configuration
|
||||
option, <code>json</code>, which will set the mode to expect JSON
|
||||
data rather than a JavaScript program.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>.</p>
|
||||
</body>
|
||||
</html>
|
||||
6
simpla/design/js/codemirror/mode/javascript/javascript.css
vendored
Normal file
6
simpla/design/js/codemirror/mode/javascript/javascript.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
span.js-keyword {color: #90b;}
|
||||
span.js-atom {color: #291;}
|
||||
span.js-variabledef {color: #00f;}
|
||||
span.js-localvariable {color: #049;}
|
||||
span.js-comment {color: #a70;}
|
||||
span.js-string {color: #a22;}
|
||||
348
simpla/design/js/codemirror/mode/javascript/javascript.js
vendored
Normal file
348
simpla/design/js/codemirror/mode/javascript/javascript.js
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var jsonMode = parserConfig.json;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "js-keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "js-atom"};
|
||||
return {
|
||||
"if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
|
||||
"var": kw("var"), "function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
|
||||
};
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|]/;
|
||||
|
||||
function chain(stream, state, f) {
|
||||
state.tokenize = f;
|
||||
return f(stream, state);
|
||||
}
|
||||
|
||||
function nextUntilUnescaped(stream, end) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == end && !escaped)
|
||||
return false;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
|
||||
function jsTokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'")
|
||||
return chain(stream, state, jsTokenString(ch));
|
||||
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
|
||||
return ret(ch);
|
||||
else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "js-atom");
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
|
||||
return ret("number", "js-atom");
|
||||
}
|
||||
else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
return chain(stream, state, jsTokenComment);
|
||||
}
|
||||
else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "js-comment");
|
||||
}
|
||||
else if (state.reAllowed) {
|
||||
nextUntilUnescaped(stream, "/");
|
||||
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
|
||||
return ret("regexp", "js-string");
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", null, stream.current());
|
||||
}
|
||||
}
|
||||
else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", null, stream.current());
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return known ? ret(known.type, known.style, word) :
|
||||
ret("variable", "js-variable", word);
|
||||
}
|
||||
}
|
||||
|
||||
function jsTokenString(quote) {
|
||||
return function(stream, state) {
|
||||
if (!nextUntilUnescaped(stream, quote))
|
||||
state.tokenize = jsTokenBase;
|
||||
return ret("string", "js-string");
|
||||
};
|
||||
}
|
||||
|
||||
function jsTokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = jsTokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "js-comment");
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "js-localvariable";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
var state = cx.state;
|
||||
if (state.context) {
|
||||
cx.marked = "js-variabledef";
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
if (!cx.state.context) cx.state.localVars = defaultVars;
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state;
|
||||
state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
return function expecting(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(arguments.callee);
|
||||
};
|
||||
}
|
||||
|
||||
function statement(type) {
|
||||
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
|
||||
poplex, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "keyword c") return cont(expression);
|
||||
if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
|
||||
if (type == "operator") return cont(expression);
|
||||
if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
|
||||
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
|
||||
return cont();
|
||||
}
|
||||
function maybeoperator(type, value) {
|
||||
if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
|
||||
if (type == "operator") return cont(expression);
|
||||
if (type == ";") return;
|
||||
if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
|
||||
if (type == ".") return cont(property, maybeoperator);
|
||||
if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperator, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "js-property"; return cont();}
|
||||
}
|
||||
function objprop(type) {
|
||||
if (type == "variable") cx.marked = "js-property";
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function proceed(type) {
|
||||
if (type == ",") return cont(what, proceed);
|
||||
if (type == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function commaSeparated(type) {
|
||||
if (type == end) return cont();
|
||||
else return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function vardef1(type, value) {
|
||||
if (type == "variable"){register(value); return cont(vardef2);}
|
||||
return cont();
|
||||
}
|
||||
function vardef2(type, value) {
|
||||
if (value == "=") return cont(expression, vardef2);
|
||||
if (type == ",") return cont(vardef1);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef1, forspec2);
|
||||
if (type == ";") return pass(forspec2);
|
||||
if (type == "variable") return cont(formaybein);
|
||||
return pass(forspec2);
|
||||
}
|
||||
function formaybein(type, value) {
|
||||
if (value == "in") return cont(expression);
|
||||
return cont(maybeoperator, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in") return cont(expression);
|
||||
return cont(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
|
||||
}
|
||||
function funarg(type, value) {
|
||||
if (type == "variable") {register(value); return cont();}
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: jsTokenBase,
|
||||
reAllowed: true,
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: null,
|
||||
context: null,
|
||||
indented: 0
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize != jsTokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
|
||||
type = lexical.type, closing = firstChar == type;
|
||||
if (type == "vardef") return lexical.indented + 4;
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
|
||||
else if (lexical.info == "switch" && !closing)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricChars: ":{}"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
52
simpla/design/js/codemirror/mode/php/index.html
vendored
Normal file
52
simpla/design/js/codemirror/mode/php/index.html
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: PHP mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="../xml/xml.js"></script>
|
||||
<link rel="stylesheet" href="../xml/xml.css">
|
||||
<script src="../javascript/javascript.js"></script>
|
||||
<link rel="stylesheet" href="../javascript/javascript.css">
|
||||
<script src="../css/css.js"></script>
|
||||
<link rel="stylesheet" href="../css/css.css">
|
||||
<script src="../clike/clike.js"></script>
|
||||
<link rel="stylesheet" href="../clike/clike.css">
|
||||
<script src="php.js"></script>
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: PHP mode</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
<?php
|
||||
function hello($who) {
|
||||
return "Hello " . $who;
|
||||
}
|
||||
?>
|
||||
<p>The program says <?= hello("World") ?>.</p>
|
||||
<script>
|
||||
alert("And here is some JS code"); // also colored
|
||||
</script>
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "application/x-httpd-php",
|
||||
indentUnit: 8,
|
||||
indentWithTabs: true,
|
||||
enterMode: "keep",
|
||||
tabMode: "shift"
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>Simple HTML/PHP mode based on
|
||||
the <a href="../clike/">C-like</a> mode. Depends on XML,
|
||||
JavaScript, CSS, and C-like modes.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code>.</p>
|
||||
</body>
|
||||
</html>
|
||||
83
simpla/design/js/codemirror/mode/php/php.js
vendored
Normal file
83
simpla/design/js/codemirror/mode/php/php.js
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
(function() {
|
||||
function keywords(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
var phpKeywords =
|
||||
keywords("abstract and array as break case catch cfunction class clone const continue declare " +
|
||||
"default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends " +
|
||||
"final for foreach function global goto if implements interface instanceof namespace " +
|
||||
"new or private protected public static switch throw try use var while xor");
|
||||
|
||||
CodeMirror.defineMode("php", function(config, parserConfig) {
|
||||
var htmlMode = CodeMirror.getMode(config, "text/html");
|
||||
var jsMode = CodeMirror.getMode(config, "text/javascript");
|
||||
var cssMode = CodeMirror.getMode(config, "text/css");
|
||||
var phpMode = CodeMirror.getMode(config, {name: "clike", keywords: phpKeywords, multiLineStrings: true, $vars: true});
|
||||
|
||||
function dispatch(stream, state) { // TODO open PHP inside text/css
|
||||
if (state.curMode == htmlMode) {
|
||||
var style = htmlMode.token(stream, state.curState);
|
||||
if (style == "xml-processing" && /^<\?/.test(stream.current())) {
|
||||
state.curMode = phpMode;
|
||||
state.curState = state.php;
|
||||
state.curClose = /^\?>/;
|
||||
}
|
||||
else if (style == "xml-tag" && stream.current() == ">" && state.curState.context) {
|
||||
if (/^script$/i.test(state.curState.context.tagName)) {
|
||||
state.curMode = jsMode;
|
||||
state.curState = jsMode.startState(htmlMode.indent(state.curState, ""));
|
||||
state.curClose = /^<\/\s*script\s*>/i;
|
||||
}
|
||||
else if (/^style$/i.test(state.curState.context.tagName)) {
|
||||
state.curMode = cssMode;
|
||||
state.curState = cssMode.startState(htmlMode.indent(state.curState, ""));
|
||||
state.curClose = /^<\/\s*style\s*>/i;
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
else if (stream.match(state.curClose, false)) {
|
||||
state.curMode = htmlMode;
|
||||
state.curState = state.html;
|
||||
state.curClose = null;
|
||||
return dispatch(stream, state);
|
||||
}
|
||||
else return state.curMode.token(stream, state.curState);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
var html = htmlMode.startState();
|
||||
return {html: html,
|
||||
php: phpMode.startState(),
|
||||
curMode: htmlMode,
|
||||
curState: html,
|
||||
curClose: null}
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),
|
||||
php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;
|
||||
if (state.curState == html) cur = htmlNew;
|
||||
else if (state.curState == php) cur = phpNew;
|
||||
else cur = CodeMirror.copyState(state.curMode, state.curState);
|
||||
return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, curClose: state.curClose};
|
||||
},
|
||||
|
||||
token: dispatch,
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
|
||||
(state.curMode == phpMode && /^\?>/.test(textAfter)))
|
||||
return htmlMode.indent(state.html, textAfter);
|
||||
return state.curMode.indent(state.curState, textAfter);
|
||||
},
|
||||
|
||||
electricChars: "/{}:"
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
CodeMirror.defineMIME("application/x-httpd-php", "php");
|
||||
96
simpla/design/js/codemirror/mode/stex/index.html
vendored
Normal file
96
simpla/design/js/codemirror/mode/stex/index.html
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: sTeX mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="stex.js"></script>
|
||||
<link rel="stylesheet" href="stex.css">
|
||||
<style>.CodeMirror {background: #f8f8f8;}</style>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: sTeX mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
\begin{module}[id=bbt-size]
|
||||
\importmodule[balanced-binary-trees]{balanced-binary-trees}
|
||||
\importmodule[\KWARCslides{dmath/en/cardinality}]{cardinality}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Size Lemma for Balanced Trees}
|
||||
\begin{itemize}
|
||||
\item
|
||||
\begin{assertion}[id=size-lemma,type=lemma]
|
||||
Let $G=\tup{V,E}$ be a \termref[cd=binary-trees]{balanced binary tree}
|
||||
of \termref[cd=graph-depth,name=vertex-depth]{depth}$n>i$, then the set
|
||||
$\defeq{\livar{V}i}{\setst{\inset{v}{V}}{\gdepth{v} = i}}$ of
|
||||
\termref[cd=graphs-intro,name=node]{nodes} at
|
||||
\termref[cd=graph-depth,name=vertex-depth]{depth} $i$ has
|
||||
\termref[cd=cardinality,name=cardinality]{cardinality} $\power2i$.
|
||||
\end{assertion}
|
||||
\item
|
||||
\begin{sproof}[id=size-lemma-pf,proofend=,for=size-lemma]{via induction over the depth $i$.}
|
||||
\begin{spfcases}{We have to consider two cases}
|
||||
\begin{spfcase}{$i=0$}
|
||||
\begin{spfstep}[display=flow]
|
||||
then $\livar{V}i=\set{\livar{v}r}$, where $\livar{v}r$ is the root, so
|
||||
$\eq{\card{\livar{V}0},\card{\set{\livar{v}r}},1,\power20}$.
|
||||
\end{spfstep}
|
||||
\end{spfcase}
|
||||
\begin{spfcase}{$i>0$}
|
||||
\begin{spfstep}[display=flow]
|
||||
then $\livar{V}{i-1}$ contains $\power2{i-1}$ vertexes
|
||||
\begin{justification}[method=byIH](IH)\end{justification}
|
||||
\end{spfstep}
|
||||
\begin{spfstep}
|
||||
By the \begin{justification}[method=byDef]definition of a binary
|
||||
tree\end{justification}, each $\inset{v}{\livar{V}{i-1}}$ is a leaf or has
|
||||
two children that are at depth $i$.
|
||||
\end{spfstep}
|
||||
\begin{spfstep}
|
||||
As $G$ is \termref[cd=balanced-binary-trees,name=balanced-binary-tree]{balanced} and $\gdepth{G}=n>i$, $\livar{V}{i-1}$ cannot contain
|
||||
leaves.
|
||||
\end{spfstep}
|
||||
\begin{spfstep}[type=conclusion]
|
||||
Thus $\eq{\card{\livar{V}i},{\atimes[cdot]{2,\card{\livar{V}{i-1}}}},{\atimes[cdot]{2,\power2{i-1}}},\power2i}$.
|
||||
\end{spfstep}
|
||||
\end{spfcase}
|
||||
\end{spfcases}
|
||||
\end{sproof}
|
||||
\item
|
||||
\begin{assertion}[id=fbbt,type=corollary]
|
||||
A fully balanced tree of depth $d$ has $\power2{d+1}-1$ nodes.
|
||||
\end{assertion}
|
||||
\item
|
||||
\begin{sproof}[for=fbbt,id=fbbt-pf]{}
|
||||
\begin{spfstep}
|
||||
Let $\defeq{G}{\tup{V,E}}$ be a fully balanced tree
|
||||
\end{spfstep}
|
||||
\begin{spfstep}
|
||||
Then $\card{V}=\Sumfromto{i}1d{\power2i}= \power2{d+1}-1$.
|
||||
\end{spfstep}
|
||||
\end{sproof}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
\begin{note}
|
||||
\begin{omtext}[type=conclusion,for=binary-tree]
|
||||
This shows that balanced binary trees grow in breadth very quickly, a consequence of
|
||||
this is that they are very shallow (and this compute very fast), which is the essence of
|
||||
the next result.
|
||||
\end{omtext}
|
||||
\end{note}
|
||||
\end{module}
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: LaTeX
|
||||
%%% TeX-master: "all"
|
||||
%%% End: \end{document}
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/stex</code>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
20
simpla/design/js/codemirror/mode/stex/stex.css
vendored
Normal file
20
simpla/design/js/codemirror/mode/stex/stex.css
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
span.css-at {color: #708;}
|
||||
span.css-unit {color: #281;}
|
||||
span.css-value {color: #708;}
|
||||
span.css-identifier {color: black;}
|
||||
span.css-selector {color: #11B;}
|
||||
span.css-important {color: #00F;}
|
||||
span.css-colorcode {color: #299;}
|
||||
span.css-comment {color: #A70;}
|
||||
span.css-string {color: #A22;}
|
||||
|
||||
span.stex-unit { color: #281; }
|
||||
span.stex-identifier { color: black; }
|
||||
span.stex-slash { color: #FAA; }
|
||||
span.stex-command { color: #00F; }
|
||||
span.stex-comment { color: #A70; }
|
||||
span.stex-import { color: #00F; }
|
||||
span.stex-filepath { color: #852626; }
|
||||
span.stex-module { color: #852626; }
|
||||
span.stex-error { text-decoration: underline; color: red; }
|
||||
span.stex-string { color: #A22; }
|
||||
167
simpla/design/js/codemirror/mode/stex/stex.js
vendored
Normal file
167
simpla/design/js/codemirror/mode/stex/stex.js
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
|
||||
* Licence: MIT
|
||||
*/
|
||||
|
||||
CodeMirror.defineMode("stex", function(cmCfg, modeCfg)
|
||||
{
|
||||
function pushCommand(state, command) {
|
||||
state.cmdState.push(command);
|
||||
}
|
||||
|
||||
function peekCommand(state) {
|
||||
if (state.cmdState.length>0)
|
||||
return state.cmdState[state.cmdState.length-1];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
function popCommand(state) {
|
||||
if (state.cmdState.length>0) {
|
||||
var plug = state.cmdState.pop();
|
||||
plug.closeBracket();
|
||||
}
|
||||
}
|
||||
|
||||
function applyMostPowerful(state) {
|
||||
context = state.cmdState;
|
||||
for (var i = context.length - 1; i >= 0; i--) {
|
||||
var plug = context[i];
|
||||
if (plug.name=="DEFAULT")
|
||||
continue;
|
||||
return plug.styleIdentifier();
|
||||
}
|
||||
return "stex-identifier";
|
||||
}
|
||||
|
||||
function addPluginPattern(pluginName, cmdStyle, brackets, styles) {
|
||||
return function () {
|
||||
this.name=pluginName;
|
||||
this.bracketNo = 0;
|
||||
this.style=cmdStyle;
|
||||
this.styles = styles;
|
||||
this.brackets = brackets;
|
||||
|
||||
this.styleIdentifier = function(content) {
|
||||
if (this.bracketNo<=this.styles.length)
|
||||
return this.styles[this.bracketNo-1];
|
||||
else
|
||||
return null;
|
||||
};
|
||||
this.openBracket = function(content) {
|
||||
this.bracketNo++;
|
||||
return "stex-bracket";
|
||||
};
|
||||
this.closeBracket = function(content) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var plugins = new Array();
|
||||
|
||||
plugins["importmodule"] = addPluginPattern("importmodule", "stex-command", "{[", ["stex-filepath", "stex-module"]);
|
||||
plugins["documentclass"] = addPluginPattern("documentclass", "stex-command", "{[", ["", "stex-unit"]);
|
||||
plugins["usepackage"] = addPluginPattern("documentclass", "stex-command", "[", ["stex-unit"]);
|
||||
plugins["begin"] = addPluginPattern("documentclass", "stex-command", "[", ["stex-unit"]);
|
||||
plugins["end"] = addPluginPattern("documentclass", "stex-command", "[", ["stex-unit"]);
|
||||
|
||||
plugins["DEFAULT"] = function () {
|
||||
this.name="DEFAULT";
|
||||
this.style="stex-command";
|
||||
|
||||
this.styleIdentifier = function(content) {
|
||||
};
|
||||
this.openBracket = function(content) {
|
||||
};
|
||||
this.closeBracket = function(content) {
|
||||
};
|
||||
};
|
||||
|
||||
function setState(state, f) {
|
||||
state.f = f;
|
||||
}
|
||||
|
||||
function normal(source, state) {
|
||||
if (source.match(/^\\[a-z]+/)) {
|
||||
cmdName = source.current();
|
||||
cmdName = cmdName.substr(1, cmdName.length-1);
|
||||
var plug = plugins[cmdName];
|
||||
if (typeof(plug) == 'undefined') {
|
||||
plug = plugins["DEFAULT"];
|
||||
}
|
||||
plug = new plug();
|
||||
pushCommand(state, plug);
|
||||
setState(state, beginParams);
|
||||
return plug.style;
|
||||
}
|
||||
|
||||
var ch = source.next();
|
||||
if (ch == "%") {
|
||||
setState(state, inCComment);
|
||||
return "stex-comment";
|
||||
}
|
||||
else if (ch=='}' || ch==']') {
|
||||
plug = peekCommand(state);
|
||||
if (plug) {
|
||||
plug.closeBracket(ch);
|
||||
setState(state, beginParams);
|
||||
} else
|
||||
return "stex-error";
|
||||
return "stex-bracket";
|
||||
} else if (ch=='{' || ch=='[') {
|
||||
plug = plugins["DEFAULT"];
|
||||
plug = new plug();
|
||||
pushCommand(state, plug);
|
||||
return "stex-bracket";
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
source.eatWhile(/[\w.%]/);
|
||||
return "stex-unit";
|
||||
}
|
||||
else {
|
||||
source.eatWhile(/[\w-_]/);
|
||||
return applyMostPowerful(state);
|
||||
}
|
||||
}
|
||||
|
||||
function inCComment(source, state) {
|
||||
source.skipToEnd();
|
||||
setState(state, normal);
|
||||
return "css-comment";
|
||||
}
|
||||
|
||||
function beginParams(source, state) {
|
||||
var ch = source.peek();
|
||||
if (ch == '{' || ch == '[') {
|
||||
lastPlug = peekCommand(state);
|
||||
style = lastPlug.openBracket(ch);
|
||||
source.eat(ch);
|
||||
setState(state, normal);
|
||||
return "stex-bracket";
|
||||
}
|
||||
if (/[ \t\r]/.test(ch)) {
|
||||
source.eat(ch);
|
||||
return null;
|
||||
}
|
||||
setState(state, normal);
|
||||
lastPlug = peekCommand(state);
|
||||
if (lastPlug) {
|
||||
popCommand(state);
|
||||
}
|
||||
return normal(source, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() { return { f:normal, cmdState:[] }; },
|
||||
copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; },
|
||||
|
||||
token: function(stream, state) {
|
||||
var t = state.f(stream, state);
|
||||
var w = stream.current();
|
||||
return t;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
CodeMirror.defineMIME("text/x-stex", "stex");
|
||||
42
simpla/design/js/codemirror/mode/xml/index.html
vendored
Normal file
42
simpla/design/js/codemirror/mode/xml/index.html
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: XML mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="xml.js"></script>
|
||||
<link rel="stylesheet" href="xml.css">
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
<link rel="stylesheet" href="../../css/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: XML mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
<html style="color: green">
|
||||
<!-- this is a comment -->
|
||||
<head>
|
||||
<title>HTML Example</title>
|
||||
</head>
|
||||
<body>
|
||||
The indentation tries to be <em>somewhat &quot;do what
|
||||
I mean&quot;</em>... but might not match your style.
|
||||
</body>
|
||||
</html>
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: {name: "xml", htmlMode: true}});
|
||||
</script>
|
||||
<p>The XML mode supports two configuration parameters:</p>
|
||||
<dl>
|
||||
<dt><code>htmlMode (boolean)</code></dt>
|
||||
<dd>This switches the mode to parse HTML instead of XML. This
|
||||
means attributes do not have to be quoted, and some elements
|
||||
(such as <code>br</code>) do not require a closing tag.</dd>
|
||||
<dt><code>alignCDATA (boolean)</code></dt>
|
||||
<dd>Setting this to true will force the opening tag of CDATA
|
||||
blocks to not be indented.</dd>
|
||||
</dl>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
|
||||
</body>
|
||||
</html>
|
||||
7
simpla/design/js/codemirror/mode/xml/xml.css
vendored
Normal file
7
simpla/design/js/codemirror/mode/xml/xml.css
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
span.xml-tag {color: #a0b;}
|
||||
span.xml-attribute {color: #281;}
|
||||
span.xml-attname {color: #00f;}
|
||||
span.xml-comment {color: #a70;}
|
||||
span.xml-cdata {color: #48a;}
|
||||
span.xml-processing {color: #999;}
|
||||
span.xml-entity {color: #a22;}
|
||||
206
simpla/design/js/codemirror/mode/xml/xml.js
vendored
Normal file
206
simpla/design/js/codemirror/mode/xml/xml.js
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var Kludges = parserConfig.htmlMode ? {
|
||||
autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
|
||||
"meta": true, "col": true, "frame": true, "base": true, "area": true},
|
||||
doNotIndent: {"pre": true, "!cdata": true},
|
||||
allowUnquoted: true
|
||||
} : {autoSelfClosers: {}, doNotIndent: {"!cdata": true}, allowUnquoted: false};
|
||||
var alignCDATA = parserConfig.alignCDATA;
|
||||
|
||||
// Return variables for tokenizers
|
||||
var tagName, type;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
state.tokenize = parser;
|
||||
return parser(stream, state);
|
||||
}
|
||||
|
||||
var ch = stream.next();
|
||||
if (ch == "<") {
|
||||
if (stream.eat("!")) {
|
||||
if (stream.eat("[")) {
|
||||
if (stream.match("[CDATA[")) return chain(inBlock("xml-cdata", "]]>"));
|
||||
else return null;
|
||||
}
|
||||
else if (stream.match("--")) return chain(inBlock("xml-comment", "-->"));
|
||||
else if (stream.match("DOCTYPE")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
return chain(inBlock("xml-doctype", ">"));
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
else if (stream.eat("?")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
state.tokenize = inBlock("xml-processing", "?>");
|
||||
return "xml-processing";
|
||||
}
|
||||
else {
|
||||
type = stream.eat("/") ? "closeTag" : "openTag";
|
||||
stream.eatSpace();
|
||||
tagName = "";
|
||||
var c;
|
||||
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
|
||||
state.tokenize = inTag;
|
||||
return "xml-tag";
|
||||
}
|
||||
}
|
||||
else if (ch == "&") {
|
||||
stream.eatWhile(/[^;]/);
|
||||
stream.eat(";");
|
||||
return "xml-entity";
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[^&<]/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function inTag(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
|
||||
state.tokenize = inText;
|
||||
type = ch == ">" ? "endTag" : "selfcloseTag";
|
||||
return "xml-tag";
|
||||
}
|
||||
else if (ch == "=") {
|
||||
type = "equals";
|
||||
return null;
|
||||
}
|
||||
else if (/[\'\"]/.test(ch)) {
|
||||
state.tokenize = inAttribute(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
else {
|
||||
stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
|
||||
return "xml-word";
|
||||
}
|
||||
}
|
||||
|
||||
function inAttribute(quote) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.next() == quote) {
|
||||
state.tokenize = inTag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "xml-attribute";
|
||||
};
|
||||
}
|
||||
|
||||
function inBlock(style, terminator) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.match(terminator)) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
return style;
|
||||
};
|
||||
}
|
||||
|
||||
var curState, setStyle;
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
function pushContext(tagName, startOfLine) {
|
||||
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
|
||||
curState.context = {
|
||||
prev: curState.context,
|
||||
tagName: tagName,
|
||||
indent: curState.indented,
|
||||
startOfLine: startOfLine,
|
||||
noIndent: noIndent
|
||||
};
|
||||
}
|
||||
function popContext() {
|
||||
if (curState.context) curState.context = curState.context.prev;
|
||||
}
|
||||
|
||||
function element(type) {
|
||||
if (type == "openTag") {curState.tagName = tagName; return cont(attributes, endtag(curState.startOfLine));}
|
||||
else if (type == "closeTag") {popContext(); return cont(endclosetag);}
|
||||
else if (type == "xml-cdata") {
|
||||
if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
|
||||
if (curState.tokenize == inText) popContext();
|
||||
return cont();
|
||||
}
|
||||
else return cont();
|
||||
}
|
||||
function endtag(startOfLine) {
|
||||
return function(type) {
|
||||
if (type == "selfcloseTag" ||
|
||||
(type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
|
||||
return cont();
|
||||
if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
|
||||
return cont();
|
||||
};
|
||||
}
|
||||
function endclosetag(type) {
|
||||
if (type == "endTag") return cont();
|
||||
return pass();
|
||||
}
|
||||
|
||||
function attributes(type) {
|
||||
if (type == "xml-word") {setStyle = "xml-attname"; return cont(attributes);}
|
||||
if (type == "equals") return cont(attvalue, attributes);
|
||||
return pass();
|
||||
}
|
||||
function attvalue(type) {
|
||||
if (type == "xml-word" && Kludges.allowUnquoted) {setStyle = "xml-attribute"; return cont();}
|
||||
if (type == "xml-attribute") return cont();
|
||||
return pass();
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
state.startOfLine = true;
|
||||
state.indented = stream.indentation();
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
|
||||
setStyle = type = tagName = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if ((style || type) && style != "xml-comment") {
|
||||
curState = state;
|
||||
while (true) {
|
||||
var comb = state.cc.pop() || element;
|
||||
if (comb(type || style)) break;
|
||||
}
|
||||
}
|
||||
state.startOfLine = false;
|
||||
return setStyle || style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var context = state.context;
|
||||
if (context && context.noIndent) return 0;
|
||||
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
|
||||
if (context && /^<\//.test(textAfter))
|
||||
context = context.prev;
|
||||
while (context && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return 0;
|
||||
},
|
||||
|
||||
electricChars: "/"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
||||
116
simpla/design/js/codemirror/oldrelease.html
Normal file
116
simpla/design/js/codemirror/oldrelease.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/docs.css"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
|
||||
|
||||
<pre class="grey">
|
||||
<img src="css/baboon.png" class="logo" alt="logo"/>/* Old release history */
|
||||
|
||||
</pre>
|
||||
|
||||
<p class="rel">02-10-2010: <a
|
||||
href="http://codemirror.net/codemirror-0.9.zip">Version 0.9</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li>Add support for searching backwards.</li>
|
||||
<li>There are now parsers for <a href="contrib/scheme/index.html">Scheme</a>, <a href="contrib/xquery/index.html">XQuery</a>, and <a href="contrib/ometa/index.html">OmetaJS</a>.</li>
|
||||
<li>Makes <code>height: "dynamic"</code> more robust.</li>
|
||||
<li>Fixes bug where paste did not work on OS X.</li>
|
||||
<li>Add a <code>enterMode</code> and <code>electricChars</code> options to make indentation even more customizable.</li>
|
||||
<li>Add <code>firstLineNumber</code> option.</li>
|
||||
<li>Fix bad handling of <code>@media</code> rules by the CSS parser.</li>
|
||||
<li>Take a new, more robust approach to working around the invisible-last-line bug in WebKit.</li>
|
||||
</ul>
|
||||
|
||||
<p class="rel">22-07-2010: <a
|
||||
href="http://codemirror.net/codemirror-0.8.zip">Version 0.8</a>:</p>
|
||||
<ul class="rel-note">
|
||||
<li>Add a <code>cursorCoords</code> method to find the screen
|
||||
coordinates of the cursor.</li>
|
||||
<li>A number of fixes and support for more syntax in the PHP parser.</li>
|
||||
<li>Fix indentation problem with JSON-mode JS parser in Webkit.</li>
|
||||
<li>Add a <a href="compress.html">minification</a> UI.</li>
|
||||
<li>Support a <code>height: dynamic</code> mode, where the editor's
|
||||
height will adjust to the size of its content.</li>
|
||||
<li>Better support for IME input mode.</li>
|
||||
<li>Fix JavaScript parser getting confused when seeing a no-argument
|
||||
function call.</li>
|
||||
<li>Have CSS parser see the difference between selectors and other
|
||||
identifiers.</li>
|
||||
<li>Fix scrolling bug when pasting in a horizontally-scrolled
|
||||
editor.</li>
|
||||
<li>Support <code>toTextArea</code> method in instances created with
|
||||
<code>fromTextArea</code>.</li>
|
||||
<li>Work around new Opera cursor bug that causes the cursor to jump
|
||||
when pressing backspace at the end of a line.</li>
|
||||
</ul>
|
||||
|
||||
<p class="rel">27-04-2010: <a
|
||||
href="http://codemirror.net/codemirror-0.67.zip">Version
|
||||
0.67</a>:</p>
|
||||
<p class="rel-note">More consistent page-up/page-down behaviour
|
||||
across browsers. Fix some issues with hidden editors looping forever
|
||||
when line-numbers were enabled. Make PHP parser parse
|
||||
<code>"\\"</code> correctly. Have <code>jumpToLine</code> work on
|
||||
line handles, and add <code>cursorLine</code> function to fetch the
|
||||
line handle where the cursor currently is. Add new
|
||||
<code>setStylesheet</code> function to switch style-sheets in a
|
||||
running editor.</p>
|
||||
|
||||
<p class="rel">01-03-2010: <a
|
||||
href="http://codemirror.net/codemirror-0.66.zip">Version
|
||||
0.66</a>:</p>
|
||||
<p class="rel-note">Adds <code>removeLine</code> method to API.
|
||||
Introduces the <a href="contrib/plsql/index.html">PLSQL parser</a>.
|
||||
Marks XML errors by adding (rather than replacing) a CSS class, so
|
||||
that they can be disabled by modifying their style. Fixes several
|
||||
selection bugs, and a number of small glitches.</p>
|
||||
|
||||
<p class="rel">12-11-2009: <a
|
||||
href="http://codemirror.net/codemirror-0.65.zip">Version
|
||||
0.65</a>:</p>
|
||||
<p class="rel-note">Add support for having both line-wrapping and
|
||||
line-numbers turned on, make paren-highlighting style customisable
|
||||
(<code>markParen</code> and <code>unmarkParen</code> config
|
||||
options), work around a selection bug that Opera
|
||||
<em>re</em>introduced in version 10.</p>
|
||||
|
||||
<p class="rel">23-10-2009: <a
|
||||
href="http://codemirror.net/codemirror-0.64.zip">Version
|
||||
0.64</a>:</p>
|
||||
<p class="rel-note">Solves some issues introduced by the
|
||||
paste-handling changes from the previous release. Adds
|
||||
<code>setSpellcheck</code>, <code>setTextWrapping</code>,
|
||||
<code>setIndentUnit</code>, <code>setUndoDepth</code>,
|
||||
<code>setTabMode</code>, and <code>setLineNumbers</code> to
|
||||
customise a running editor. Introduces an <a
|
||||
href="contrib/sql/index.html">SQL</a> parser. Fixes a few small
|
||||
problems in the <a href="contrib/python/index.html">Python</a>
|
||||
parser. And, as usual, add workarounds for various newly discovered
|
||||
browser incompatibilities.</p>
|
||||
|
||||
<p class="rel"><em>31-08-2009</em>: <a
|
||||
href="http://codemirror.net/codemirror-0.63.zip">Version
|
||||
0.63</a>:</p>
|
||||
<p class="rel-note"> Overhaul of paste-handling (less fragile), fixes for several
|
||||
serious IE8 issues (cursor jumping, end-of-document bugs) and a number
|
||||
of small problems.</p>
|
||||
|
||||
<p class="rel"><em>30-05-2009</em>: <a
|
||||
href="http://codemirror.net/codemirror-0.62.zip">Version
|
||||
0.62</a>:</p>
|
||||
<p class="rel-note">Introduces <a href="contrib/python/index.html">Python</a>
|
||||
and <a href="contrib/lua/index.html">Lua</a> parsers. Add
|
||||
<code>setParser</code> (on-the-fly mode changing) and
|
||||
<code>clearHistory</code> methods. Make parsing passes time-based
|
||||
instead of lines-based (see the <code>passTime</code> option).</p>
|
||||
|
||||
<script type="text/javascript" src="css/font.js"></script>
|
||||
|
||||
</body></html>
|
||||
30
simpla/design/js/codemirror/test/index.html
Normal file
30
simpla/design/js/codemirror/test/index.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror 2: Test Suite</title>
|
||||
<link rel="stylesheet" href="../lib/codemirror.css">
|
||||
<script src="../lib/codemirror.js"></script>
|
||||
<link rel="stylesheet" href="../mode/javascript/javascript.css">
|
||||
<script src="../mode/javascript/javascript.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="../docs.css">
|
||||
<style type="text/css">
|
||||
.ok {color: #0e0;}
|
||||
.failure {color: #e00;}
|
||||
.error {color: #c90;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror 2: Test Suite</h1>
|
||||
|
||||
<p>A limited set of programmatic sanity tests for CodeMirror.</p>
|
||||
|
||||
<pre id=output></pre>
|
||||
|
||||
<div style="visibility: hidden" id=testground>
|
||||
<form><textarea id="code" name="code"></textarea><input type=submit value=ok name=submit></form>
|
||||
</div>
|
||||
|
||||
<script src="test.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
234
simpla/design/js/codemirror/test/test.js
Normal file
234
simpla/design/js/codemirror/test/test.js
Normal file
@@ -0,0 +1,234 @@
|
||||
var tests = [];
|
||||
|
||||
test("fromTextArea", function() {
|
||||
var te = document.getElementById("code");
|
||||
te.value = "CONTENT";
|
||||
var cm = CodeMirror.fromTextArea(te);
|
||||
is(!te.offsetHeight);
|
||||
eq(cm.getValue(), "CONTENT");
|
||||
cm.setValue("foo\nbar");
|
||||
eq(cm.getValue(), "foo\nbar");
|
||||
cm.save();
|
||||
is(/^foo\r?\nbar$/.test(te.value));
|
||||
cm.setValue("xxx");
|
||||
cm.toTextArea();
|
||||
is(te.offsetHeight);
|
||||
eq(te.value, "xxx");
|
||||
});
|
||||
|
||||
testCM("getRange", function(cm) {
|
||||
eq(cm.getLine(0), "1234");
|
||||
eq(cm.getLine(1), "5678");
|
||||
eq(cm.getLine(2), null);
|
||||
eq(cm.getLine(-1), null);
|
||||
eq(cm.getRange({line: 0, ch: 0}, {line: 0, ch: 3}), "123");
|
||||
eq(cm.getRange({line: 0, ch: -1}, {line: 0, ch: 200}), "1234");
|
||||
eq(cm.getRange({line: 0, ch: 2}, {line: 1, ch: 2}), "34\n56");
|
||||
eq(cm.getRange({line: 1, ch: 2}, {line: 100, ch: 0}), "78");
|
||||
}, {value: "1234\n5678"});
|
||||
|
||||
testCM("replaceRange", function(cm) {
|
||||
eq(cm.getValue(), "");
|
||||
cm.replaceRange("foo\n", {line: 0, ch: 0});
|
||||
eq(cm.getValue(), "foo\n");
|
||||
cm.replaceRange("a\nb", {line: 0, ch: 1});
|
||||
eq(cm.getValue(), "fa\nboo\n");
|
||||
eq(cm.lineCount(), 3);
|
||||
cm.replaceRange("xyzzy", {line: 0, ch: 0}, {line: 1, ch: 1});
|
||||
eq(cm.getValue(), "xyzzyoo\n");
|
||||
cm.replaceRange("abc", {line: 0, ch: 0}, {line: 10, ch: 0});
|
||||
eq(cm.getValue(), "abc");
|
||||
eq(cm.lineCount(), 1);
|
||||
});
|
||||
|
||||
testCM("selection", function(cm) {
|
||||
cm.setSelection({line: 0, ch: 4}, {line: 2, ch: 2});
|
||||
is(cm.somethingSelected());
|
||||
eq(cm.getSelection(), "11\n222222\n33");
|
||||
eqPos(cm.getCursor(false), {line: 2, ch: 2});
|
||||
eqPos(cm.getCursor(true), {line: 0, ch: 4});
|
||||
cm.setSelection({line: 1, ch: 0});
|
||||
is(!cm.somethingSelected());
|
||||
eq(cm.getSelection(), "");
|
||||
eqPos(cm.getCursor(true), {line: 1, ch: 0});
|
||||
cm.replaceSelection("abc");
|
||||
eq(cm.getSelection(), "abc");
|
||||
eq(cm.getValue(), "111111\nabc222222\n333333");
|
||||
cm.replaceSelection("def", "end");
|
||||
eq(cm.getSelection(), "");
|
||||
eqPos(cm.getCursor(true), {line: 1, ch: 3});
|
||||
cm.setCursor({line: 2, ch: 1});
|
||||
eqPos(cm.getCursor(true), {line: 2, ch: 1});
|
||||
cm.setCursor(1, 2);
|
||||
eqPos(cm.getCursor(true), {line: 1, ch: 2});
|
||||
}, {value: "111111\n222222\n333333"});
|
||||
|
||||
testCM("lines", function(cm) {
|
||||
eq(cm.getLine(0), "111111");
|
||||
eq(cm.getLine(1), "222222");
|
||||
eq(cm.getLine(-1), null);
|
||||
cm.removeLine(1);
|
||||
cm.setLine(1, "abc");
|
||||
eq(cm.getValue(), "111111\nabc");
|
||||
}, {value: "111111\n222222\n333333"});
|
||||
|
||||
testCM("indent", function(cm) {
|
||||
cm.indentLine(1);
|
||||
eq(cm.getLine(1), " blah();");
|
||||
cm.setOption("indentUnit", 8);
|
||||
cm.indentLine(1);
|
||||
eq(cm.getLine(1), "\tblah();");
|
||||
}, {value: "if (x) {\nblah();\n}", indentUnit: 3, indentWithTabs: true});
|
||||
|
||||
test("defaults", function() {
|
||||
var olddefaults = CodeMirror.defaults, defs = CodeMirror.defaults = {};
|
||||
for (var opt in olddefaults) defs[opt] = olddefaults[opt];
|
||||
defs.indentUnit = 5;
|
||||
defs.value = "uu";
|
||||
defs.enterMode = "keep";
|
||||
defs.tabindex = 55;
|
||||
var place = document.getElementById("testground"), cm = CodeMirror(place);
|
||||
try {
|
||||
eq(cm.getOption("indentUnit"), 5);
|
||||
cm.setOption("indentUnit", 10);
|
||||
eq(defs.indentUnit, 5);
|
||||
eq(cm.getValue(), "uu");
|
||||
eq(cm.getOption("enterMode"), "keep");
|
||||
eq(cm.getInputField().tabindex, 55);
|
||||
}
|
||||
finally {
|
||||
CodeMirror.defaults = olddefaults;
|
||||
place.removeChild(cm.getWrapperElement());
|
||||
}
|
||||
});
|
||||
|
||||
testCM("lineInfo", function(cm) {
|
||||
eq(cm.lineInfo(-1), null);
|
||||
var lh = cm.setMarker(1, "FOO", "bar");
|
||||
var info = cm.lineInfo(1);
|
||||
eq(info.text, "222222");
|
||||
eq(info.markerText, "FOO");
|
||||
eq(info.markerClass, "bar");
|
||||
eq(info.line, 1);
|
||||
eq(cm.lineInfo(2).markerText, null);
|
||||
cm.clearMarker(lh);
|
||||
eq(cm.lineInfo(1).markerText, null);
|
||||
}, {value: "111111\n222222\n333333"});
|
||||
|
||||
testCM("coords", function(cm) {
|
||||
cm.getWrapperElement().style.height = "100px";
|
||||
var content = [];
|
||||
for (var i = 0; i < 200; ++i) content.push("------------------------------" + i);
|
||||
cm.setValue(content.join("\n"));
|
||||
var top = cm.charCoords({line: 0, ch: 0});
|
||||
var bot = cm.charCoords({line: 200, ch: 30});
|
||||
is(top.x < bot.x);
|
||||
is(top.y < bot.y);
|
||||
is(top.y < top.yBot);
|
||||
cm.getWrapperElement().scrollTop = 100;
|
||||
cm.refresh();
|
||||
var top2 = cm.charCoords({line: 0, ch: 0});
|
||||
is(top.y > top2.y);
|
||||
eq(top.x, top2.x);
|
||||
});
|
||||
|
||||
testCM("undo", function(cm) {
|
||||
cm.setLine(0, "def");
|
||||
eq(cm.historySize().undo, 1);
|
||||
cm.undo();
|
||||
eq(cm.getValue(), "abc");
|
||||
eq(cm.historySize().undo, 0);
|
||||
eq(cm.historySize().redo, 1);
|
||||
cm.redo();
|
||||
eq(cm.getValue(), "def");
|
||||
eq(cm.historySize().undo, 1);
|
||||
eq(cm.historySize().redo, 0);
|
||||
cm.setValue("1\n\n\n2");
|
||||
eq(cm.historySize().undo, 0);
|
||||
for (var i = 0; i < 20; ++i) {
|
||||
cm.replaceRange("a", {line: 0, ch: 0});
|
||||
cm.replaceRange("b", {line: 3, ch: 0});
|
||||
}
|
||||
eq(cm.historySize().undo, 40);
|
||||
for (var i = 0; i < 38; ++i) cm.undo();
|
||||
eq(cm.historySize().undo, 2);
|
||||
eq(cm.historySize().redo, 38);
|
||||
eq(cm.getValue(), "a1\n\n\nb2");
|
||||
cm.setOption("undoDepth", 10);
|
||||
for (var i = 0; i < 20; ++i) {
|
||||
cm.replaceRange("a", {line: 0, ch: 0});
|
||||
cm.replaceRange("b", {line: 3, ch: 0});
|
||||
}
|
||||
eq(cm.historySize().undo, 10);
|
||||
}, {value: "abc"});
|
||||
|
||||
testCM("undoMultiLine", function(cm) {
|
||||
cm.replaceRange("x", {line:0, ch: 0});
|
||||
cm.replaceRange("y", {line:1, ch: 0});
|
||||
cm.undo();
|
||||
eq(cm.getValue(), "abc\ndef\nghi");
|
||||
cm.replaceRange("y", {line:1, ch: 0});
|
||||
cm.replaceRange("x", {line:0, ch: 0});
|
||||
cm.undo();
|
||||
eq(cm.getValue(), "abc\ndef\nghi");
|
||||
cm.replaceRange("y", {line:2, ch: 0});
|
||||
cm.replaceRange("x", {line:1, ch: 0});
|
||||
cm.replaceRange("z", {line:2, ch: 0});
|
||||
cm.undo();
|
||||
eq(cm.getValue(), "abc\ndef\nghi");
|
||||
}, {value: "abc\ndef\nghi"});
|
||||
|
||||
// Scaffolding
|
||||
|
||||
function htmlEscape(str) {
|
||||
return str.replace(/[<&]/g, function(str) {return str == "&" ? "&" : "<";});
|
||||
}
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function Failure(why) {this.message = why;}
|
||||
|
||||
function test(name, run) {tests.push({name: name, func: run});}
|
||||
function testCM(name, run, opts) {
|
||||
test(name, function() {
|
||||
var place = document.getElementById("testground"), cm = CodeMirror(place, opts);
|
||||
try {run(cm);}
|
||||
finally {place.removeChild(cm.getWrapperElement());}
|
||||
});
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
var failures = [], run = 0;
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
var test = tests[i];
|
||||
try {test.func();}
|
||||
catch(e) {
|
||||
if (e instanceof Failure)
|
||||
failures.push({type: "failure", test: test.name, text: e.message});
|
||||
else
|
||||
failures.push({type: "error", test: test.name, text: e.toString()});
|
||||
}
|
||||
run++;
|
||||
}
|
||||
var html = [run + " tests run."];
|
||||
if (failures.length)
|
||||
forEach(failures, function(fail) {
|
||||
html.push(fail.test + ': <span class="' + fail.type + '">' + htmlEscape(fail.text) + "</span>");
|
||||
});
|
||||
else html.push('<span class="ok">All passed.</span>');
|
||||
document.getElementById("output").innerHTML = html.join("\n");
|
||||
}
|
||||
|
||||
function eq(a, b, msg) {
|
||||
if (a != b) throw new Failure(a + " != " + b + (msg ? " (" + msg + ")" : ""));
|
||||
}
|
||||
function eqPos(a, b, msg) {
|
||||
eq(a.line, b.line, msg);
|
||||
eq(a.ch, b.ch, msg);
|
||||
}
|
||||
function is(a, msg) {
|
||||
if (!a) throw new Failure("assertion failed" + (msg ? " (" + msg + ")" : ""));
|
||||
}
|
||||
|
||||
window.onload = runTests;
|
||||
Reference in New Issue
Block a user