liquid_cms 0.3.0.1 → 0.3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +5 -1
- data/Gemfile.lock +1 -1
- data/README.rdoc +5 -1
- data/app/helpers/cms/common_helper.rb +1 -0
- data/app/views/cms/pages/_page.html.erb +2 -1
- data/app/views/layouts/cms.html.erb +2 -1
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/LICENSE +2 -2
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/csscolors.css +12 -8
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/docs.css +123 -29
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/csstest.html +1 -1
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/htmltest.html +1 -1
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/index.html +232 -179
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/codemirror.js +211 -65
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/editor.js +360 -194
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/mirrorframe.js +1 -1
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsecss.js +11 -7
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsejavascript.js +14 -5
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsesparql.js +1 -1
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/select.js +140 -87
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/stringstream.js +5 -0
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/tokenizejavascript.js +1 -1
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/undo.js +7 -7
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/manual.html +148 -52
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/story.html +631 -614
- data/lib/generators/liquid_cms/templates/public/cms/stylesheets/styles.css +7 -7
- data/lib/liquid_cms/version.rb +1 -1
- metadata +4 -26
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/lua/LICENSE +0 -32
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/lua/css/luacolors.css +0 -63
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/lua/index.html +0 -68
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/lua/js/parselua.js +0 -253
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/php/LICENSE +0 -37
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/php/css/phpcolors.css +0 -114
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/php/index.html +0 -292
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/php/js/parsephp.js +0 -371
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/php/js/parsephphtmlmixed.js +0 -90
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/php/js/tokenizephp.js +0 -1006
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/plsql/LICENSE +0 -22
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/plsql/css/plsqlcolors.css +0 -57
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/plsql/index.html +0 -67
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/plsql/js/parseplsql.js +0 -233
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/python/LICENSE +0 -32
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/python/css/pythoncolors.css +0 -58
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/python/index.html +0 -141
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/python/js/parsepython.js +0 -542
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/sql/LICENSE +0 -22
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/sql/css/sqlcolors.css +0 -57
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/sql/index.html +0 -56
- data/lib/generators/liquid_cms/templates/public/cms/codemirror/contrib/sql/js/parsesql.js +0 -211
@@ -112,16 +112,18 @@ var CSSParser = Editor.Parser = (function() {
|
|
112
112
|
function parseCSS(source, basecolumn) {
|
113
113
|
basecolumn = basecolumn || 0;
|
114
114
|
var tokens = tokenizeCSS(source);
|
115
|
-
var inBraces = false, inRule = false
|
115
|
+
var inBraces = false, inRule = false, inDecl = false;;
|
116
116
|
|
117
117
|
var iter = {
|
118
118
|
next: function() {
|
119
119
|
var token = tokens.next(), style = token.style, content = token.content;
|
120
120
|
|
121
|
-
if (style == "css-identifier" && inRule)
|
122
|
-
token.style = "css-value";
|
123
121
|
if (style == "css-hash")
|
124
|
-
token.style = inRule ? "css-colorcode" : "css-identifier";
|
122
|
+
style = token.style = inRule ? "css-colorcode" : "css-identifier";
|
123
|
+
if (style == "css-identifier") {
|
124
|
+
if (inRule) token.style = "css-value";
|
125
|
+
else if (!inBraces && !inDecl) token.style = "css-selector";
|
126
|
+
}
|
125
127
|
|
126
128
|
if (content == "\n")
|
127
129
|
token.indentation = indentCSS(inBraces, inRule, basecolumn);
|
@@ -129,11 +131,13 @@ var CSSParser = Editor.Parser = (function() {
|
|
129
131
|
if (content == "{")
|
130
132
|
inBraces = true;
|
131
133
|
else if (content == "}")
|
132
|
-
inBraces = inRule = false;
|
133
|
-
else if (
|
134
|
-
inRule = false;
|
134
|
+
inBraces = inRule = inDecl = false;
|
135
|
+
else if (content == ";")
|
136
|
+
inRule = inDecl = false;
|
135
137
|
else if (inBraces && style != "css-comment" && style != "whitespace")
|
136
138
|
inRule = true;
|
139
|
+
else if (!inBraces && style == "css-at" && content != "@media")
|
140
|
+
inDecl = true;
|
137
141
|
|
138
142
|
return token;
|
139
143
|
},
|
@@ -60,7 +60,7 @@ var JSParser = Editor.Parser = (function() {
|
|
60
60
|
// semicolon. Actions at the end of the stack go first. It is
|
61
61
|
// initialized with an infinitely looping action that consumes
|
62
62
|
// whole statements.
|
63
|
-
var cc = [statements];
|
63
|
+
var cc = [json ? expressions : statements];
|
64
64
|
// Context contains information about the current local scope, the
|
65
65
|
// variables defined in that, and the scopes above it.
|
66
66
|
var context = null;
|
@@ -206,6 +206,8 @@ var JSParser = Editor.Parser = (function() {
|
|
206
206
|
}
|
207
207
|
// Pop off the current lexical context.
|
208
208
|
function poplex(){
|
209
|
+
if (lexical.type == ")")
|
210
|
+
indented = lexical.indented;
|
209
211
|
lexical = lexical.prev;
|
210
212
|
}
|
211
213
|
poplex.lex = true;
|
@@ -218,6 +220,7 @@ var JSParser = Editor.Parser = (function() {
|
|
218
220
|
function expect(wanted){
|
219
221
|
return function expecting(type){
|
220
222
|
if (type == wanted) cont();
|
223
|
+
else if (wanted == ";") pass();
|
221
224
|
else cont(arguments.callee);
|
222
225
|
};
|
223
226
|
}
|
@@ -226,14 +229,17 @@ var JSParser = Editor.Parser = (function() {
|
|
226
229
|
function statements(type){
|
227
230
|
return pass(statement, statements);
|
228
231
|
}
|
232
|
+
function expressions(type){
|
233
|
+
return pass(expression, expressions);
|
234
|
+
}
|
229
235
|
// Dispatches various types of statements based on the type of the
|
230
236
|
// current token.
|
231
237
|
function statement(type){
|
232
238
|
if (type == "var") cont(pushlex("vardef"), vardef1, expect(";"), poplex);
|
233
239
|
else if (type == "keyword a") cont(pushlex("form"), expression, statement, poplex);
|
234
240
|
else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
|
235
|
-
else if (type == "{" && json) cont(pushlex("}"), commasep(objprop, "}"), poplex);
|
236
241
|
else if (type == "{") cont(pushlex("}"), block, poplex);
|
242
|
+
else if (type == ";") cont();
|
237
243
|
else if (type == "function") cont(functiondef);
|
238
244
|
else if (type == "for") cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex);
|
239
245
|
else if (type == "variable") cont(pushlex("stat"), maybelabel);
|
@@ -252,13 +258,16 @@ var JSParser = Editor.Parser = (function() {
|
|
252
258
|
else if (type == "operator") cont(expression);
|
253
259
|
else if (type == "[") cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
|
254
260
|
else if (type == "{") cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
|
261
|
+
else cont();
|
255
262
|
}
|
256
263
|
// Called for places where operators, function calls, or
|
257
264
|
// subscripts are valid. Will skip on to the next action if none
|
258
265
|
// is found.
|
259
|
-
function maybeoperator(type){
|
260
|
-
if (type == "operator") cont(
|
261
|
-
else if (type == "
|
266
|
+
function maybeoperator(type, value){
|
267
|
+
if (type == "operator" && /\+\+|--/.test(value)) cont(maybeoperator);
|
268
|
+
else if (type == "operator") cont(expression);
|
269
|
+
else if (type == ";") pass();
|
270
|
+
else if (type == "(") cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
|
262
271
|
else if (type == ".") cont(property, maybeoperator);
|
263
272
|
else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
|
264
273
|
}
|
@@ -6,7 +6,7 @@ var SparqlParser = Editor.Parser = (function() {
|
|
6
6
|
"isblank", "isliteral", "union", "a"]);
|
7
7
|
var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
|
8
8
|
"ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
|
9
|
-
"graph", "by", "asc", "desc"
|
9
|
+
"graph", "by", "asc", "desc"]);
|
10
10
|
var operatorChars = /[*+\-<>=&|]/;
|
11
11
|
|
12
12
|
var tokenizeSparql = (function() {
|
@@ -29,11 +29,10 @@ var select = {};
|
|
29
29
|
|
30
30
|
var fourSpaces = "\u00a0\u00a0\u00a0\u00a0";
|
31
31
|
|
32
|
-
select.scrollToNode = function(
|
33
|
-
if (!
|
34
|
-
var
|
35
|
-
|
36
|
-
html = doc.documentElement,
|
32
|
+
select.scrollToNode = function(node, cursor) {
|
33
|
+
if (!node) return;
|
34
|
+
var element = node, body = document.body,
|
35
|
+
html = document.documentElement,
|
37
36
|
atEnd = !element.nextSibling || !element.nextSibling.nextSibling
|
38
37
|
|| !element.nextSibling.nextSibling.nextSibling;
|
39
38
|
// In Opera (and recent Webkit versions), BR elements *always*
|
@@ -48,7 +47,14 @@ var select = {};
|
|
48
47
|
// offset, just scroll to the end.
|
49
48
|
if (compensateHack == 0) atEnd = false;
|
50
49
|
|
51
|
-
|
50
|
+
// WebKit has a bad habit of (sometimes) happily returning bogus
|
51
|
+
// offsets when the document has just been changed. This seems to
|
52
|
+
// always be 5/5, so we don't use those.
|
53
|
+
if (webkit && element && element.offsetTop == 5 && element.offsetLeft == 5)
|
54
|
+
return;
|
55
|
+
|
56
|
+
var y = compensateHack * (element ? element.offsetHeight : 0), x = 0,
|
57
|
+
width = (node ? node.offsetWidth : 0), pos = element;
|
52
58
|
while (pos && pos.offsetParent) {
|
53
59
|
y += pos.offsetTop;
|
54
60
|
// Don't count X offset for <br> nodes
|
@@ -59,21 +65,29 @@ var select = {};
|
|
59
65
|
|
60
66
|
var scroll_x = body.scrollLeft || html.scrollLeft || 0,
|
61
67
|
scroll_y = body.scrollTop || html.scrollTop || 0,
|
62
|
-
|
68
|
+
scroll = false, screen_width = window.innerWidth || html.clientWidth || 0;
|
63
69
|
|
64
|
-
if (
|
65
|
-
|
66
|
-
|
70
|
+
if (cursor || width < screen_width) {
|
71
|
+
if (cursor) {
|
72
|
+
var off = select.offsetInNode(node), size = nodeText(node).length;
|
73
|
+
if (size) x += width * (off / size);
|
74
|
+
}
|
75
|
+
var screen_x = x - scroll_x;
|
76
|
+
if (screen_x < 0 || screen_x > screen_width) {
|
77
|
+
scroll_x = x;
|
78
|
+
scroll = true;
|
79
|
+
}
|
67
80
|
}
|
68
|
-
|
81
|
+
var screen_y = y - scroll_y;
|
82
|
+
if (screen_y < 0 || atEnd || screen_y > (window.innerHeight || html.clientHeight || 0) - 50) {
|
69
83
|
scroll_y = atEnd ? 1e6 : y;
|
70
84
|
scroll = true;
|
71
85
|
}
|
72
|
-
if (scroll)
|
86
|
+
if (scroll) window.scrollTo(scroll_x, scroll_y);
|
73
87
|
};
|
74
88
|
|
75
89
|
select.scrollToCursor = function(container) {
|
76
|
-
select.scrollToNode(select.selectionTopNode(container, true) || container.firstChild);
|
90
|
+
select.scrollToNode(select.selectionTopNode(container, true) || container.firstChild, true);
|
77
91
|
};
|
78
92
|
|
79
93
|
// Used to prevent restoring a selection when we do not need to.
|
@@ -130,8 +144,8 @@ var select = {};
|
|
130
144
|
// Most functions are defined in two ways, one for the IE selection
|
131
145
|
// model, one for the W3C one.
|
132
146
|
if (select.ie_selection) {
|
133
|
-
function selectionNode(
|
134
|
-
var range =
|
147
|
+
function selectionNode(start) {
|
148
|
+
var range = document.selection.createRange();
|
135
149
|
range.collapse(start);
|
136
150
|
|
137
151
|
function nodeAfter(node) {
|
@@ -149,7 +163,7 @@ var select = {};
|
|
149
163
|
}
|
150
164
|
|
151
165
|
var containing = range.parentElement();
|
152
|
-
if (!isAncestor(
|
166
|
+
if (!isAncestor(document.body, containing)) return null;
|
153
167
|
if (!containing.firstChild) return nodeAtStartOf(containing);
|
154
168
|
|
155
169
|
var working = range.duplicate();
|
@@ -176,25 +190,24 @@ var select = {};
|
|
176
190
|
return nodeAfter(containing);
|
177
191
|
}
|
178
192
|
|
179
|
-
select.markSelection = function(
|
193
|
+
select.markSelection = function() {
|
180
194
|
currentSelection = null;
|
181
|
-
var sel =
|
195
|
+
var sel = document.selection;
|
182
196
|
if (!sel) return;
|
183
|
-
var start = selectionNode(
|
184
|
-
end = selectionNode(
|
197
|
+
var start = selectionNode(true),
|
198
|
+
end = selectionNode(false);
|
185
199
|
if (!start || !end) return;
|
186
|
-
currentSelection = {start: start, end: end,
|
200
|
+
currentSelection = {start: start, end: end, changed: false};
|
187
201
|
};
|
188
202
|
|
189
203
|
select.selectMarked = function() {
|
190
204
|
if (!currentSelection || !currentSelection.changed) return;
|
191
|
-
var win = currentSelection.window, doc = win.document;
|
192
205
|
|
193
206
|
function makeRange(point) {
|
194
|
-
var range =
|
207
|
+
var range = document.body.createTextRange(),
|
195
208
|
node = point.node;
|
196
209
|
if (!node) {
|
197
|
-
range.moveToElementText(
|
210
|
+
range.moveToElementText(document.body);
|
198
211
|
range.collapse(false);
|
199
212
|
}
|
200
213
|
else if (node.nodeType == 3) {
|
@@ -218,11 +231,20 @@ var select = {};
|
|
218
231
|
start.select();
|
219
232
|
};
|
220
233
|
|
234
|
+
select.offsetInNode = function(node) {
|
235
|
+
var sel = document.selection;
|
236
|
+
if (!sel) return 0;
|
237
|
+
var range = sel.createRange(), range2 = range.duplicate();
|
238
|
+
try {range2.moveToElementText(node);} catch(e){return 0;}
|
239
|
+
range.setEndPoint("StartToStart", range2);
|
240
|
+
return range.text.length;
|
241
|
+
};
|
242
|
+
|
221
243
|
// Get the top-level node that one end of the cursor is inside or
|
222
244
|
// after. Note that this returns false for 'no cursor', and null
|
223
245
|
// for 'start of document'.
|
224
246
|
select.selectionTopNode = function(container, start) {
|
225
|
-
var selection =
|
247
|
+
var selection = document.selection;
|
226
248
|
if (!selection) return false;
|
227
249
|
|
228
250
|
var range = selection.createRange(), range2 = range.duplicate();
|
@@ -272,6 +294,13 @@ var select = {};
|
|
272
294
|
else
|
273
295
|
end = middle - 1;
|
274
296
|
}
|
297
|
+
|
298
|
+
if (start == 0) {
|
299
|
+
var test1 = selection.createRange(), test2 = test1.duplicate();
|
300
|
+
test2.moveToElementText(container);
|
301
|
+
if (test1.compareEndPoints("StartToStart", test2) == 0)
|
302
|
+
return null;
|
303
|
+
}
|
275
304
|
return container.childNodes[start] || null;
|
276
305
|
};
|
277
306
|
|
@@ -279,19 +308,19 @@ var select = {};
|
|
279
308
|
// manually moving the cursor instead of restoring it to its old
|
280
309
|
// position.
|
281
310
|
select.focusAfterNode = function(node, container) {
|
282
|
-
var range =
|
311
|
+
var range = document.body.createTextRange();
|
283
312
|
range.moveToElementText(node || container);
|
284
313
|
range.collapse(!node);
|
285
314
|
range.select();
|
286
315
|
};
|
287
316
|
|
288
|
-
select.somethingSelected = function(
|
289
|
-
var sel =
|
317
|
+
select.somethingSelected = function() {
|
318
|
+
var sel = document.selection;
|
290
319
|
return sel && (sel.createRange().text != "");
|
291
320
|
};
|
292
321
|
|
293
|
-
function insertAtCursor(
|
294
|
-
var selection =
|
322
|
+
function insertAtCursor(html) {
|
323
|
+
var selection = document.selection;
|
295
324
|
if (selection) {
|
296
325
|
var range = selection.createRange();
|
297
326
|
range.pasteHTML(html);
|
@@ -302,19 +331,19 @@ var select = {};
|
|
302
331
|
|
303
332
|
// Used to normalize the effect of the enter key, since browsers
|
304
333
|
// do widely different things when pressing enter in designMode.
|
305
|
-
select.insertNewlineAtCursor = function(
|
306
|
-
insertAtCursor(
|
334
|
+
select.insertNewlineAtCursor = function() {
|
335
|
+
insertAtCursor("<br>");
|
307
336
|
};
|
308
337
|
|
309
|
-
select.insertTabAtCursor = function(
|
310
|
-
insertAtCursor(
|
338
|
+
select.insertTabAtCursor = function() {
|
339
|
+
insertAtCursor(fourSpaces);
|
311
340
|
};
|
312
341
|
|
313
342
|
// Get the BR node at the start of the line on which the cursor
|
314
343
|
// currently is, and the offset into the line. Returns null as
|
315
344
|
// node if cursor is on first line.
|
316
345
|
select.cursorPos = function(container, start) {
|
317
|
-
var selection =
|
346
|
+
var selection = document.selection;
|
318
347
|
if (!selection) return null;
|
319
348
|
|
320
349
|
var topNode = select.selectionTopNode(container, start);
|
@@ -340,7 +369,7 @@ var select = {};
|
|
340
369
|
|
341
370
|
select.setCursorPos = function(container, from, to) {
|
342
371
|
function rangeAt(pos) {
|
343
|
-
var range =
|
372
|
+
var range = document.body.createTextRange();
|
344
373
|
if (!pos.node) {
|
345
374
|
range.moveToElementText(container);
|
346
375
|
range.collapse(true);
|
@@ -373,42 +402,38 @@ var select = {};
|
|
373
402
|
}
|
374
403
|
// W3C model
|
375
404
|
else {
|
405
|
+
// Find the node right at the cursor, not one of its
|
406
|
+
// ancestors with a suitable offset. This goes down the DOM tree
|
407
|
+
// until a 'leaf' is reached (or is it *up* the DOM tree?).
|
408
|
+
function innerNode(node, offset) {
|
409
|
+
while (node.nodeType != 3 && !isBR(node)) {
|
410
|
+
var newNode = node.childNodes[offset] || node.nextSibling;
|
411
|
+
offset = 0;
|
412
|
+
while (!newNode && node.parentNode) {
|
413
|
+
node = node.parentNode;
|
414
|
+
newNode = node.nextSibling;
|
415
|
+
}
|
416
|
+
node = newNode;
|
417
|
+
if (!newNode) break;
|
418
|
+
}
|
419
|
+
return {node: node, offset: offset};
|
420
|
+
}
|
421
|
+
|
376
422
|
// Store start and end nodes, and offsets within these, and refer
|
377
423
|
// back to the selection object from those nodes, so that this
|
378
424
|
// object can be updated when the nodes are replaced before the
|
379
425
|
// selection is restored.
|
380
|
-
select.markSelection = function (
|
381
|
-
var selection =
|
426
|
+
select.markSelection = function () {
|
427
|
+
var selection = window.getSelection();
|
382
428
|
if (!selection || selection.rangeCount == 0)
|
383
429
|
return (currentSelection = null);
|
384
430
|
var range = selection.getRangeAt(0);
|
385
431
|
|
386
432
|
currentSelection = {
|
387
|
-
start:
|
388
|
-
end:
|
389
|
-
window: win,
|
433
|
+
start: innerNode(range.startContainer, range.startOffset),
|
434
|
+
end: innerNode(range.endContainer, range.endOffset),
|
390
435
|
changed: false
|
391
436
|
};
|
392
|
-
|
393
|
-
// We want the nodes right at the cursor, not one of their
|
394
|
-
// ancestors with a suitable offset. This goes down the DOM tree
|
395
|
-
// until a 'leaf' is reached (or is it *up* the DOM tree?).
|
396
|
-
function normalize(point){
|
397
|
-
while (point.node.nodeType != 3 && !isBR(point.node)) {
|
398
|
-
var newNode = point.node.childNodes[point.offset] || point.node.nextSibling;
|
399
|
-
point.offset = 0;
|
400
|
-
while (!newNode && point.node.parentNode) {
|
401
|
-
point.node = point.node.parentNode;
|
402
|
-
newNode = point.node.nextSibling;
|
403
|
-
}
|
404
|
-
point.node = newNode;
|
405
|
-
if (!newNode)
|
406
|
-
break;
|
407
|
-
}
|
408
|
-
}
|
409
|
-
|
410
|
-
normalize(currentSelection.start);
|
411
|
-
normalize(currentSelection.end);
|
412
437
|
};
|
413
438
|
|
414
439
|
select.selectMarked = function () {
|
@@ -419,10 +444,15 @@ var select = {};
|
|
419
444
|
// this occurs is when a selection is deleted or overwitten. we
|
420
445
|
// check for that here.
|
421
446
|
function focusIssue() {
|
422
|
-
|
447
|
+
if (cs.start.node == cs.end.node && cs.start.offset == cs.end.offset) {
|
448
|
+
var selection = window.getSelection();
|
449
|
+
if (!selection || selection.rangeCount == 0) return true;
|
450
|
+
var range = selection.getRangeAt(0), point = innerNode(range.startContainer, range.startOffset);
|
451
|
+
return cs.start.node != point.node || cs.start.offset != point.offset;
|
452
|
+
}
|
423
453
|
}
|
424
454
|
if (!cs || !(cs.changed || (webkit && focusIssue()))) return;
|
425
|
-
var
|
455
|
+
var range = document.createRange();
|
426
456
|
|
427
457
|
function setPoint(point, which) {
|
428
458
|
if (point.node) {
|
@@ -434,22 +464,23 @@ var select = {};
|
|
434
464
|
range["set" + which](point.node, point.offset);
|
435
465
|
}
|
436
466
|
else {
|
437
|
-
range.setStartAfter(
|
467
|
+
range.setStartAfter(document.body.lastChild || document.body);
|
438
468
|
}
|
439
469
|
}
|
440
470
|
|
441
471
|
setPoint(cs.end, "End");
|
442
472
|
setPoint(cs.start, "Start");
|
443
|
-
selectRange(range
|
473
|
+
selectRange(range);
|
444
474
|
};
|
445
475
|
|
446
476
|
// Helper for selecting a range object.
|
447
|
-
function selectRange(range
|
477
|
+
function selectRange(range) {
|
448
478
|
var selection = window.getSelection();
|
479
|
+
if (!selection) return;
|
449
480
|
selection.removeAllRanges();
|
450
481
|
selection.addRange(range);
|
451
482
|
}
|
452
|
-
function selectionRange(
|
483
|
+
function selectionRange() {
|
453
484
|
var selection = window.getSelection();
|
454
485
|
if (!selection || selection.rangeCount == 0)
|
455
486
|
return false;
|
@@ -460,7 +491,7 @@ var select = {};
|
|
460
491
|
// Finding the top-level node at the cursor in the W3C is, as you
|
461
492
|
// can see, quite an involved process.
|
462
493
|
select.selectionTopNode = function(container, start) {
|
463
|
-
var range = selectionRange(
|
494
|
+
var range = selectionRange();
|
464
495
|
if (!range) return false;
|
465
496
|
|
466
497
|
var node = start ? range.startContainer : range.endContainer;
|
@@ -505,8 +536,7 @@ var select = {};
|
|
505
536
|
};
|
506
537
|
|
507
538
|
select.focusAfterNode = function(node, container) {
|
508
|
-
var
|
509
|
-
range = win.document.createRange();
|
539
|
+
var range = document.createRange();
|
510
540
|
range.setStartBefore(container.firstChild || container);
|
511
541
|
// In Opera, setting the end of a range at the end of a line
|
512
542
|
// (before a BR) will cause the cursor to appear on the next
|
@@ -519,37 +549,59 @@ var select = {};
|
|
519
549
|
else
|
520
550
|
range.setEndBefore(container.firstChild || container);
|
521
551
|
range.collapse(false);
|
522
|
-
selectRange(range
|
552
|
+
selectRange(range);
|
523
553
|
};
|
524
554
|
|
525
|
-
select.somethingSelected = function(
|
526
|
-
var range = selectionRange(
|
555
|
+
select.somethingSelected = function() {
|
556
|
+
var range = selectionRange();
|
527
557
|
return range && !range.collapsed;
|
528
558
|
};
|
529
559
|
|
530
|
-
function
|
531
|
-
var range = selectionRange(
|
560
|
+
select.offsetInNode = function(node) {
|
561
|
+
var range = selectionRange();
|
562
|
+
if (!range) return 0;
|
563
|
+
range = range.cloneRange();
|
564
|
+
range.setStartBefore(node);
|
565
|
+
return range.toString().length;
|
566
|
+
};
|
567
|
+
|
568
|
+
function insertNodeAtCursor(node) {
|
569
|
+
var range = selectionRange();
|
532
570
|
if (!range) return;
|
533
571
|
|
534
572
|
range.deleteContents();
|
535
573
|
range.insertNode(node);
|
536
|
-
webkitLastLineHack(
|
537
|
-
|
574
|
+
webkitLastLineHack(document.body);
|
575
|
+
|
576
|
+
// work around weirdness where Opera will magically insert a new
|
577
|
+
// BR node when a BR node inside a span is moved around. makes
|
578
|
+
// sure the BR ends up outside of spans.
|
579
|
+
if (window.opera && isBR(node) && isSpan(node.parentNode)) {
|
580
|
+
var next = node.nextSibling, p = node.parentNode, outer = p.parentNode;
|
581
|
+
outer.insertBefore(node, p.nextSibling);
|
582
|
+
var textAfter = "";
|
583
|
+
for (; next && next.nodeType == 3; next = next.nextSibling) {
|
584
|
+
textAfter += next.nodeValue;
|
585
|
+
removeElement(next);
|
586
|
+
}
|
587
|
+
outer.insertBefore(makePartSpan(textAfter, document), node.nextSibling);
|
588
|
+
}
|
589
|
+
range = document.createRange();
|
538
590
|
range.selectNode(node);
|
539
591
|
range.collapse(false);
|
540
|
-
selectRange(range
|
592
|
+
selectRange(range);
|
541
593
|
}
|
542
594
|
|
543
|
-
select.insertNewlineAtCursor = function(
|
544
|
-
insertNodeAtCursor(
|
595
|
+
select.insertNewlineAtCursor = function() {
|
596
|
+
insertNodeAtCursor(document.createElement("BR"));
|
545
597
|
};
|
546
598
|
|
547
|
-
select.insertTabAtCursor = function(
|
548
|
-
insertNodeAtCursor(
|
599
|
+
select.insertTabAtCursor = function() {
|
600
|
+
insertNodeAtCursor(document.createTextNode(fourSpaces));
|
549
601
|
};
|
550
602
|
|
551
603
|
select.cursorPos = function(container, start) {
|
552
|
-
var range = selectionRange(
|
604
|
+
var range = selectionRange();
|
553
605
|
if (!range) return;
|
554
606
|
|
555
607
|
var topNode = select.selectionTopNode(container, start);
|
@@ -562,12 +614,13 @@ var select = {};
|
|
562
614
|
range.setStartAfter(topNode);
|
563
615
|
else
|
564
616
|
range.setStartBefore(container);
|
565
|
-
|
617
|
+
|
618
|
+
var text = range.toString();
|
619
|
+
return {node: topNode, offset: text.length};
|
566
620
|
};
|
567
621
|
|
568
622
|
select.setCursorPos = function(container, from, to) {
|
569
|
-
var
|
570
|
-
range = win.document.createRange();
|
623
|
+
var range = document.createRange();
|
571
624
|
|
572
625
|
function setPoint(node, offset, side) {
|
573
626
|
if (offset == 0 && node && !node.nextSibling) {
|
@@ -613,7 +666,7 @@ var select = {};
|
|
613
666
|
|
614
667
|
to = to || from;
|
615
668
|
if (setPoint(to.node, to.offset, "End") && setPoint(from.node, from.offset, "Start"))
|
616
|
-
selectRange(range
|
669
|
+
selectRange(range);
|
617
670
|
};
|
618
671
|
}
|
619
672
|
})();
|
@@ -39,11 +39,13 @@ var stringStream = function(source){
|
|
39
39
|
}
|
40
40
|
|
41
41
|
return {
|
42
|
+
// peek: -> character
|
42
43
|
// Return the next character in the stream.
|
43
44
|
peek: function() {
|
44
45
|
if (!ensureChars()) return null;
|
45
46
|
return current.charAt(pos);
|
46
47
|
},
|
48
|
+
// next: -> character
|
47
49
|
// Get the next character, throw StopIteration if at end, check
|
48
50
|
// for unused content.
|
49
51
|
next: function() {
|
@@ -55,6 +57,7 @@ var stringStream = function(source){
|
|
55
57
|
}
|
56
58
|
return current.charAt(pos++);
|
57
59
|
},
|
60
|
+
// get(): -> string
|
58
61
|
// Return the characters iterated over since the last call to
|
59
62
|
// .get().
|
60
63
|
get: function() {
|
@@ -108,6 +111,8 @@ var stringStream = function(source){
|
|
108
111
|
},
|
109
112
|
|
110
113
|
// Utils built on top of the above
|
114
|
+
// more: -> boolean
|
115
|
+
// Produce true if the stream isn't empty.
|
111
116
|
more: function() {
|
112
117
|
return this.peek() !== null;
|
113
118
|
},
|
@@ -65,7 +65,7 @@ var tokenizeJavaScript = (function() {
|
|
65
65
|
};
|
66
66
|
}
|
67
67
|
|
68
|
-
// The token reader,
|
68
|
+
// The token reader, intended to be used by the tokenizer from
|
69
69
|
// tokenize.js (through jsTokenState). Advances the source stream
|
70
70
|
// over a token, and returns an object containing the type and style
|
71
71
|
// of that token.
|
@@ -9,7 +9,7 @@
|
|
9
9
|
* complexity and hackery.
|
10
10
|
*
|
11
11
|
* In short, the editor 'touches' BR elements as it parses them, and
|
12
|
-
* the
|
12
|
+
* the UndoHistory stores these. When nothing is touched in commitDelay
|
13
13
|
* milliseconds, the changes are committed: It goes over all touched
|
14
14
|
* nodes, throws out the ones that did not change since last commit or
|
15
15
|
* are no longer in the document, and assembles the rest into zero or
|
@@ -26,7 +26,7 @@
|
|
26
26
|
// delay (of no input) after which it commits a set of changes, and,
|
27
27
|
// unfortunately, the 'parent' window -- a window that is not in
|
28
28
|
// designMode, and on which setTimeout works in every browser.
|
29
|
-
function
|
29
|
+
function UndoHistory(container, maxDepth, commitDelay, editor) {
|
30
30
|
this.container = container;
|
31
31
|
this.maxDepth = maxDepth; this.commitDelay = commitDelay;
|
32
32
|
this.editor = editor; this.parent = editor.parent;
|
@@ -47,7 +47,7 @@ function History(container, maxDepth, commitDelay, editor) {
|
|
47
47
|
this.history = []; this.redoHistory = []; this.touched = [];
|
48
48
|
}
|
49
49
|
|
50
|
-
|
50
|
+
UndoHistory.prototype = {
|
51
51
|
// Schedule a commit (if no other touches come in for commitDelay
|
52
52
|
// milliseconds).
|
53
53
|
scheduleCommit: function() {
|
@@ -145,7 +145,7 @@ History.prototype = {
|
|
145
145
|
|
146
146
|
// Commit unless there are pending dirty nodes.
|
147
147
|
tryCommit: function() {
|
148
|
-
if (!window.
|
148
|
+
if (!window.parent || !window.UndoHistory) return; // Stop when frame has been unloaded
|
149
149
|
if (this.editor.highlightDirty()) this.commit(true);
|
150
150
|
else this.scheduleCommit();
|
151
151
|
},
|
@@ -192,10 +192,10 @@ History.prototype = {
|
|
192
192
|
},
|
193
193
|
|
194
194
|
notifyEnvironment: function() {
|
195
|
+
if (this.onChange) this.onChange();
|
195
196
|
// Used by the line-wrapping line-numbering code.
|
196
197
|
if (window.frameElement && window.frameElement.CodeMirror.updateNumbers)
|
197
198
|
window.frameElement.CodeMirror.updateNumbers();
|
198
|
-
if (this.onChange) this.onChange();
|
199
199
|
},
|
200
200
|
|
201
201
|
// Link a chain into the DOM nodes (or the first/last links for null
|
@@ -380,7 +380,7 @@ History.prototype = {
|
|
380
380
|
self.container.insertBefore(line.from, end);
|
381
381
|
|
382
382
|
// Add the text.
|
383
|
-
var node = makePartSpan(fixSpaces(line.text)
|
383
|
+
var node = makePartSpan(fixSpaces(line.text));
|
384
384
|
self.container.insertBefore(node, end);
|
385
385
|
// See if the cursor was on this line. Put it back, adjusting
|
386
386
|
// for changed line length, if it was.
|
@@ -391,7 +391,7 @@ History.prototype = {
|
|
391
391
|
// Only adjust if the cursor is after the unchanged part of
|
392
392
|
// the line.
|
393
393
|
for (var match = 0; match < cursor.offset &&
|
394
|
-
line.text.charAt(match) == prev.text.charAt(match); match++)
|
394
|
+
line.text.charAt(match) == prev.text.charAt(match); match++){}
|
395
395
|
if (cursor.offset > match)
|
396
396
|
cursordiff = line.text.length - prev.text.length;
|
397
397
|
}
|