liquid_cms 0.2.0.11 → 0.2.0.12
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 +7 -0
- data/TODO.rdoc +1 -1
- data/app/controllers/cms/main_controller.rb +3 -2
- data/app/helpers/cms/common_helper.rb +9 -2
- data/app/helpers/cms/components_helper.rb +10 -4
- data/app/models/cms/component.rb +4 -0
- data/app/views/cms/assets/_list.html.erb +4 -4
- data/app/views/cms/components/_list.html.erb +5 -1
- data/app/views/cms/pages/_list.html.erb +4 -4
- data/app/views/cms/shared/_sidebar.html.erb +32 -8
- data/app/views/layouts/cms.html.erb +5 -2
- data/generators/liquid_cms/templates/config/locales/cms/en.yml +3 -2
- data/generators/liquid_cms/templates/public/cms/codemirror/LICENSE +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/css/csscolors.css +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/css/docs.css +17 -3
- data/generators/liquid_cms/templates/public/cms/codemirror/css/font.js +15 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/css/jscolors.css +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/css/sparqlcolors.css +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/css/xmlcolors.css +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/js/codemirror.js +59 -26
- data/generators/liquid_cms/templates/public/cms/codemirror/js/editor.js +149 -71
- data/generators/liquid_cms/templates/public/cms/codemirror/js/highlight.js +2 -2
- data/generators/liquid_cms/templates/public/cms/codemirror/js/mirrorframe.js +2 -2
- data/generators/liquid_cms/templates/public/cms/codemirror/js/parsecss.js +5 -3
- data/generators/liquid_cms/templates/public/cms/codemirror/js/parsedummy.js +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/js/parsehtmlmixed.js +28 -9
- data/generators/liquid_cms/templates/public/cms/codemirror/js/parsejavascript.js +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/js/parsesparql.js +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/js/parsexml.js +6 -1
- data/generators/liquid_cms/templates/public/cms/codemirror/js/select.js +48 -21
- data/generators/liquid_cms/templates/public/cms/codemirror/js/stringstream.js +15 -1
- data/generators/liquid_cms/templates/public/cms/codemirror/js/tokenize.js +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/js/tokenizejavascript.js +1 -1
- data/generators/liquid_cms/templates/public/cms/codemirror/js/undo.js +17 -14
- data/generators/liquid_cms/templates/public/cms/codemirror/js/unittests.js +44 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/js/util.js +6 -3
- data/generators/liquid_cms/templates/public/cms/javascripts/cms.js +15 -1
- data/generators/liquid_cms/templates/public/cms/javascripts/livepipe.js +181 -0
- data/generators/liquid_cms/templates/public/cms/javascripts/tabs.js +149 -0
- data/generators/liquid_cms/templates/public/cms/stylesheets/ie9.css +4 -0
- data/generators/liquid_cms/templates/public/cms/stylesheets/sidebar.css +132 -0
- data/generators/liquid_cms/templates/public/cms/stylesheets/styles.css +1 -74
- data/generators/liquid_cms/templates/public/cms/stylesheets/themes/dark.css +2 -1
- data/lib/liquid_cms/context.rb +4 -0
- data/lib/liquid_cms/version.rb +1 -1
- data/liquid_cms.gemspec +1 -1
- data/test/functional/assets_controller_test.rb +3 -3
- data/test/rails_app/config/locales/cms/en.yml +8 -0
- metadata +11 -16
- data/generators/liquid_cms/templates/public/cms/codemirror/bigtest.html +0 -1296
- data/generators/liquid_cms/templates/public/cms/codemirror/css/people.jpg +0 -0
- data/generators/liquid_cms/templates/public/cms/codemirror/csstest.html +0 -60
- data/generators/liquid_cms/templates/public/cms/codemirror/highlight.html +0 -82
- data/generators/liquid_cms/templates/public/cms/codemirror/htmltest.html +0 -52
- data/generators/liquid_cms/templates/public/cms/codemirror/index.html +0 -245
- data/generators/liquid_cms/templates/public/cms/codemirror/jstest.html +0 -56
- data/generators/liquid_cms/templates/public/cms/codemirror/manual.html +0 -759
- data/generators/liquid_cms/templates/public/cms/codemirror/mixedtest.html +0 -52
- data/generators/liquid_cms/templates/public/cms/codemirror/sparqltest.html +0 -41
- data/generators/liquid_cms/templates/public/cms/codemirror/story.html +0 -671
@@ -6,8 +6,9 @@
|
|
6
6
|
|
7
7
|
var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
|
8
8
|
var webkit = /AppleWebKit/.test(navigator.userAgent);
|
9
|
-
var safari = /Apple
|
10
|
-
var gecko = /gecko\/(\d{8})/i
|
9
|
+
var safari = /Apple Computer, Inc/.test(navigator.vendor);
|
10
|
+
var gecko = navigator.userAgent.match(/gecko\/(\d{8})/i);
|
11
|
+
if (gecko) gecko = Number(gecko[1]);
|
11
12
|
var mac = /Mac/.test(navigator.platform);
|
12
13
|
|
13
14
|
// TODO this is related to the backspace-at-end-of-line bug. Remove
|
@@ -37,7 +38,7 @@ function fixSpaces(string) {
|
|
37
38
|
}
|
38
39
|
|
39
40
|
function cleanText(text) {
|
40
|
-
return text.replace(/\u00a0/g, " ");
|
41
|
+
return text.replace(/\u00a0/g, " ").replace(/\u200b/g, "");
|
41
42
|
}
|
42
43
|
|
43
44
|
// Create a SPAN node with the expected properties for document part
|
@@ -47,13 +48,15 @@ function makePartSpan(value) {
|
|
47
48
|
if (value.nodeType == 3) text = value.nodeValue;
|
48
49
|
else value = document.createTextNode(text);
|
49
50
|
|
50
|
-
var span = document.createElement("
|
51
|
+
var span = document.createElement("span");
|
51
52
|
span.isPart = true;
|
52
53
|
span.appendChild(value);
|
53
54
|
span.currentText = text;
|
54
55
|
return span;
|
55
56
|
}
|
56
57
|
|
58
|
+
function alwaysZero() {return 0;}
|
59
|
+
|
57
60
|
// On webkit, when the last BR of the document does not have text
|
58
61
|
// behind it, the cursor can not be put on the line after it. This
|
59
62
|
// makes pressing enter at the end of the document occasionally do
|
@@ -67,22 +70,22 @@ var webkitLastLineHack = webkit ?
|
|
67
70
|
function(container) {
|
68
71
|
var last = container.lastChild;
|
69
72
|
if (!last || !last.hackBR) {
|
70
|
-
var br = document.createElement("
|
73
|
+
var br = document.createElement("br");
|
71
74
|
br.hackBR = true;
|
72
75
|
container.appendChild(br);
|
73
76
|
}
|
74
77
|
} : function() {};
|
75
78
|
|
79
|
+
function asEditorLines(string) {
|
80
|
+
var tab = makeWhiteSpace(indentUnit);
|
81
|
+
return map(string.replace(/\t/g, tab).replace(/\u00a0/g, " ").replace(/\r\n?/g, "\n").split("\n"), fixSpaces);
|
82
|
+
}
|
83
|
+
|
76
84
|
var Editor = (function(){
|
77
85
|
// The HTML elements whose content should be suffixed by a newline
|
78
86
|
// when converting them to flat text.
|
79
87
|
var newlineElements = {"P": true, "DIV": true, "LI": true};
|
80
88
|
|
81
|
-
function asEditorLines(string) {
|
82
|
-
var tab = makeWhiteSpace(indentUnit);
|
83
|
-
return map(string.replace(/\t/g, tab).replace(/\u00a0/g, " ").replace(/\r\n?/g, "\n").split("\n"), fixSpaces);
|
84
|
-
}
|
85
|
-
|
86
89
|
// Helper function for traverseDOM. Flattens an arbitrary DOM node
|
87
90
|
// into an array of textnodes and <br> tags.
|
88
91
|
function simplifyDOM(root, atEnd) {
|
@@ -91,7 +94,7 @@ var Editor = (function(){
|
|
91
94
|
|
92
95
|
function simplifyNode(node, top) {
|
93
96
|
if (node.nodeType == 3) {
|
94
|
-
var text = node.nodeValue = fixSpaces(node.nodeValue.replace(
|
97
|
+
var text = node.nodeValue = fixSpaces(node.nodeValue.replace(/[\r\u200b]/g, "").replace(/\n/g, " "));
|
95
98
|
if (text.length) leaving = false;
|
96
99
|
result.push(node);
|
97
100
|
}
|
@@ -104,7 +107,7 @@ var Editor = (function(){
|
|
104
107
|
if (!leaving && newlineElements.hasOwnProperty(node.nodeName.toUpperCase())) {
|
105
108
|
leaving = true;
|
106
109
|
if (!atEnd || !top)
|
107
|
-
result.push(document.createElement("
|
110
|
+
result.push(document.createElement("br"));
|
108
111
|
}
|
109
112
|
}
|
110
113
|
}
|
@@ -175,7 +178,9 @@ var Editor = (function(){
|
|
175
178
|
// Check whether a node is a normalized <span> element.
|
176
179
|
function partNode(node){
|
177
180
|
if (node.isPart && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
|
178
|
-
|
181
|
+
var text = node.firstChild.nodeValue;
|
182
|
+
node.dirty = node.dirty || text != node.currentText;
|
183
|
+
node.currentText = text;
|
179
184
|
return !/[\n\t\r]/.test(node.currentText);
|
180
185
|
}
|
181
186
|
return false;
|
@@ -240,20 +245,20 @@ var Editor = (function(){
|
|
240
245
|
// indicating whether anything was found, and can be called again to
|
241
246
|
// skip to the next find. Use the select and replace methods to
|
242
247
|
// actually do something with the found locations.
|
243
|
-
function SearchCursor(editor,
|
248
|
+
function SearchCursor(editor, pattern, from, caseFold) {
|
244
249
|
this.editor = editor;
|
245
250
|
this.history = editor.history;
|
246
251
|
this.history.commit();
|
247
|
-
this.valid = !!
|
252
|
+
this.valid = !!pattern;
|
248
253
|
this.atOccurrence = false;
|
249
|
-
if (caseFold == undefined) caseFold = string ==
|
254
|
+
if (caseFold == undefined) caseFold = typeof pattern == "string" && pattern == pattern.toLowerCase();
|
250
255
|
|
251
256
|
function getText(node){
|
252
257
|
var line = cleanText(editor.history.textAfter(node));
|
253
258
|
return (caseFold ? line.toLowerCase() : line);
|
254
259
|
}
|
255
260
|
|
256
|
-
var topPos = {node: null, offset: 0};
|
261
|
+
var topPos = {node: null, offset: 0}, self = this;
|
257
262
|
if (from && typeof from == "object" && typeof from.character == "number") {
|
258
263
|
editor.checkLine(from.line);
|
259
264
|
var pos = {node: from.line, offset: from.character};
|
@@ -267,16 +272,42 @@ var Editor = (function(){
|
|
267
272
|
this.pos = {from: topPos, to: topPos};
|
268
273
|
}
|
269
274
|
|
270
|
-
if (
|
275
|
+
if (typeof pattern != "string") { // Regexp match
|
276
|
+
this.matches = function(reverse, node, offset) {
|
277
|
+
if (reverse) {
|
278
|
+
var line = getText(node).slice(0, offset), match = line.match(pattern), start = 0;
|
279
|
+
while (match) {
|
280
|
+
var ind = line.indexOf(match[0]);
|
281
|
+
start += ind;
|
282
|
+
line = line.slice(ind + 1);
|
283
|
+
var newmatch = line.match(pattern);
|
284
|
+
if (newmatch) match = newmatch;
|
285
|
+
else break;
|
286
|
+
}
|
287
|
+
}
|
288
|
+
else {
|
289
|
+
var line = getText(node).slice(offset), match = line.match(pattern),
|
290
|
+
start = match && offset + line.indexOf(match[0]);
|
291
|
+
}
|
292
|
+
if (match) {
|
293
|
+
self.currentMatch = match;
|
294
|
+
return {from: {node: node, offset: start},
|
295
|
+
to: {node: node, offset: start + match[0].length}};
|
296
|
+
}
|
297
|
+
};
|
298
|
+
return;
|
299
|
+
}
|
300
|
+
|
301
|
+
if (caseFold) pattern = pattern.toLowerCase();
|
271
302
|
// Create a matcher function based on the kind of string we have.
|
272
|
-
var target =
|
303
|
+
var target = pattern.split("\n");
|
273
304
|
this.matches = (target.length == 1) ?
|
274
305
|
// For one-line strings, searching can be done simply by calling
|
275
306
|
// indexOf or lastIndexOf on the current line.
|
276
307
|
function(reverse, node, offset) {
|
277
|
-
var line = getText(node), len =
|
278
|
-
if (reverse ? (offset >= len && (match = line.lastIndexOf(
|
279
|
-
: (match = line.indexOf(
|
308
|
+
var line = getText(node), len = pattern.length, match;
|
309
|
+
if (reverse ? (offset >= len && (match = line.lastIndexOf(pattern, offset - len)) != -1)
|
310
|
+
: (match = line.indexOf(pattern, offset)) != -1)
|
280
311
|
return {from: {node: node, offset: match},
|
281
312
|
to: {node: node, offset: match + len}};
|
282
313
|
} :
|
@@ -364,6 +395,9 @@ var Editor = (function(){
|
|
364
395
|
|
365
396
|
replace: function(string) {
|
366
397
|
if (this.atOccurrence) {
|
398
|
+
var fragments = this.currentMatch;
|
399
|
+
if (fragments)
|
400
|
+
string = string.replace(/\\(\d)/, function(m, i){return fragments[i];});
|
367
401
|
var end = this.editor.replaceRange(this.pos.from, this.pos.to, string);
|
368
402
|
this.pos.to = end;
|
369
403
|
this.atOccurrence = false;
|
@@ -380,7 +414,6 @@ var Editor = (function(){
|
|
380
414
|
function Editor(options) {
|
381
415
|
this.options = options;
|
382
416
|
window.indentUnit = options.indentUnit;
|
383
|
-
this.parent = parent;
|
384
417
|
var container = this.container = document.body;
|
385
418
|
this.history = new UndoHistory(container, options.undoDepth, options.undoDelay, this);
|
386
419
|
var self = this;
|
@@ -390,7 +423,7 @@ var Editor = (function(){
|
|
390
423
|
if (options.parserConfig && Editor.Parser.configure)
|
391
424
|
Editor.Parser.configure(options.parserConfig);
|
392
425
|
|
393
|
-
if (!options.readOnly)
|
426
|
+
if (!options.readOnly && !internetExplorer)
|
394
427
|
select.setCursorPos(container, {node: null, offset: 0});
|
395
428
|
|
396
429
|
this.dirty = [];
|
@@ -417,7 +450,8 @@ var Editor = (function(){
|
|
417
450
|
// body of the document to focus it in IE, making focusing
|
418
451
|
// hard when the document is small.
|
419
452
|
if (internetExplorer && options.height != "dynamic")
|
420
|
-
document.body.style.minHeight = (
|
453
|
+
document.body.style.minHeight = (
|
454
|
+
window.frameElement.clientHeight - 2 * document.body.offsetTop - 5) + "px";
|
421
455
|
|
422
456
|
document.documentElement.style.borderWidth = "0";
|
423
457
|
if (!options.textWrapping)
|
@@ -442,7 +476,7 @@ var Editor = (function(){
|
|
442
476
|
addEventHandler(document, "keyup", method(this, "keyUp"));
|
443
477
|
|
444
478
|
function cursorActivity() {self.cursorActivity(false);}
|
445
|
-
addEventHandler(document.body, "mouseup", cursorActivity);
|
479
|
+
addEventHandler(internetExplorer ? document.body : window, "mouseup", cursorActivity);
|
446
480
|
addEventHandler(document.body, "cut", cursorActivity);
|
447
481
|
|
448
482
|
// workaround for a gecko bug [?] where going forward and then
|
@@ -481,8 +515,24 @@ var Editor = (function(){
|
|
481
515
|
Editor.prototype = {
|
482
516
|
// Import a piece of code into the editor.
|
483
517
|
importCode: function(code) {
|
484
|
-
|
485
|
-
this.
|
518
|
+
var lines = asEditorLines(code), chunk = 1000;
|
519
|
+
if (!this.options.incrementalLoading || lines.length < chunk) {
|
520
|
+
this.history.push(null, null, lines);
|
521
|
+
this.history.reset();
|
522
|
+
}
|
523
|
+
else {
|
524
|
+
var cur = 0, self = this;
|
525
|
+
function addChunk() {
|
526
|
+
var chunklines = lines.slice(cur, cur + chunk);
|
527
|
+
chunklines.push("");
|
528
|
+
self.history.push(self.history.nodeBefore(null), null, chunklines);
|
529
|
+
self.history.reset();
|
530
|
+
cur += chunk;
|
531
|
+
if (cur < lines.length)
|
532
|
+
parent.setTimeout(addChunk, 1000);
|
533
|
+
}
|
534
|
+
addChunk();
|
535
|
+
}
|
486
536
|
},
|
487
537
|
|
488
538
|
// Extract the code from the editor.
|
@@ -493,16 +543,16 @@ var Editor = (function(){
|
|
493
543
|
var accum = [];
|
494
544
|
select.markSelection();
|
495
545
|
forEach(traverseDOM(this.container.firstChild), method(accum, "push"));
|
496
|
-
webkitLastLineHack(this.container);
|
497
546
|
select.selectMarked();
|
498
547
|
// On webkit, don't count last (empty) line if the webkitLastLineHack BR is present
|
499
548
|
if (webkit && this.container.lastChild.hackBR)
|
500
549
|
accum.pop();
|
550
|
+
webkitLastLineHack(this.container);
|
501
551
|
return cleanText(accum.join(""));
|
502
552
|
},
|
503
553
|
|
504
554
|
checkLine: function(node) {
|
505
|
-
if (node === false || !(node == null || node.parentNode == this.container))
|
555
|
+
if (node === false || !(node == null || node.parentNode == this.container || node.hackBR))
|
506
556
|
throw parent.CodeMirror.InvalidLineHandle;
|
507
557
|
},
|
508
558
|
|
@@ -518,14 +568,17 @@ var Editor = (function(){
|
|
518
568
|
},
|
519
569
|
|
520
570
|
lastLine: function() {
|
521
|
-
|
522
|
-
|
571
|
+
var last = this.container.lastChild;
|
572
|
+
if (last) last = startOfLine(last);
|
573
|
+
if (last && last.hackBR) last = startOfLine(last.previousSibling);
|
574
|
+
return last;
|
523
575
|
},
|
524
576
|
|
525
577
|
nextLine: function(line) {
|
526
578
|
this.checkLine(line);
|
527
579
|
var end = endOfLine(line, this.container);
|
528
|
-
|
580
|
+
if (!end || end.hackBR) return false;
|
581
|
+
else return end;
|
529
582
|
},
|
530
583
|
|
531
584
|
prevLine: function(line) {
|
@@ -647,14 +700,14 @@ var Editor = (function(){
|
|
647
700
|
webkitLastLineHack(this.container);
|
648
701
|
},
|
649
702
|
|
650
|
-
cursorCoords: function(start) {
|
703
|
+
cursorCoords: function(start, internal) {
|
651
704
|
var sel = select.cursorPos(this.container, start);
|
652
705
|
if (!sel) return null;
|
653
706
|
var off = sel.offset, node = sel.node, self = this;
|
654
707
|
function measureFromNode(node, xOffset) {
|
655
708
|
var y = -(document.body.scrollTop || document.documentElement.scrollTop || 0),
|
656
709
|
x = -(document.body.scrollLeft || document.documentElement.scrollLeft || 0) + xOffset;
|
657
|
-
forEach([node, window.frameElement], function(n) {
|
710
|
+
forEach([node, internal ? null : window.frameElement], function(n) {
|
658
711
|
while (n) {x += n.offsetLeft; y += n.offsetTop;n = n.offsetParent;}
|
659
712
|
});
|
660
713
|
return {x: x, y: y, yBot: y + node.offsetHeight};
|
@@ -691,15 +744,21 @@ var Editor = (function(){
|
|
691
744
|
},
|
692
745
|
|
693
746
|
reroutePasteEvent: function() {
|
694
|
-
if (this.capturingPaste || window.opera) return;
|
747
|
+
if (this.capturingPaste || window.opera || (gecko && gecko >= 20101026)) return;
|
695
748
|
this.capturingPaste = true;
|
696
749
|
var te = window.frameElement.CodeMirror.textareaHack;
|
750
|
+
var coords = this.cursorCoords(true, true);
|
751
|
+
te.style.top = coords.y + "px";
|
752
|
+
if (internetExplorer) {
|
753
|
+
var snapshot = select.getBookmark(this.container);
|
754
|
+
if (snapshot) this.selectionSnapshot = snapshot;
|
755
|
+
}
|
697
756
|
parent.focus();
|
698
757
|
te.value = "";
|
699
758
|
te.focus();
|
700
759
|
|
701
760
|
var self = this;
|
702
|
-
|
761
|
+
parent.setTimeout(function() {
|
703
762
|
self.capturingPaste = false;
|
704
763
|
window.focus();
|
705
764
|
if (self.selectionSnapshot) // IE hack
|
@@ -741,7 +800,7 @@ var Editor = (function(){
|
|
741
800
|
var start = select.selectionTopNode(this.container, true),
|
742
801
|
end = select.selectionTopNode(this.container, false);
|
743
802
|
if (start === false || end === false) return;
|
744
|
-
this.indentRegion(start, end, direction);
|
803
|
+
this.indentRegion(start, end, direction, true);
|
745
804
|
}
|
746
805
|
},
|
747
806
|
|
@@ -870,7 +929,7 @@ var Editor = (function(){
|
|
870
929
|
this.reroutePasteEvent();
|
871
930
|
}
|
872
931
|
else if (electric && electric.indexOf(event.character) != -1)
|
873
|
-
|
932
|
+
parent.setTimeout(function(){self.indentAtCursor(null);}, 0);
|
874
933
|
// Work around a bug where pressing backspace at the end of a
|
875
934
|
// line, or delete at the start, often causes the cursor to jump
|
876
935
|
// to the start of the line in Opera 10.60.
|
@@ -879,7 +938,7 @@ var Editor = (function(){
|
|
879
938
|
var sel = select.selectionTopNode(this.container), self = this,
|
880
939
|
next = sel ? sel.nextSibling : this.container.firstChild;
|
881
940
|
if (sel !== false && next && isBR(next))
|
882
|
-
|
941
|
+
parent.setTimeout(function(){
|
883
942
|
if (select.selectionTopNode(self.container) == next)
|
884
943
|
select.focusAfterNode(next.previousSibling, self.container);
|
885
944
|
}, 20);
|
@@ -887,7 +946,7 @@ var Editor = (function(){
|
|
887
946
|
else if (event.code == 46) { // delete
|
888
947
|
var sel = select.selectionTopNode(this.container), self = this;
|
889
948
|
if (sel && isBR(sel)) {
|
890
|
-
|
949
|
+
parent.setTimeout(function(){
|
891
950
|
if (select.selectionTopNode(self.container) != sel)
|
892
951
|
select.focusAfterNode(sel, self.container);
|
893
952
|
}, 20);
|
@@ -908,12 +967,23 @@ var Editor = (function(){
|
|
908
967
|
if (sel && next && isBR(next) && !isBR(sel)) {
|
909
968
|
var cheat = document.createTextNode("\u200b");
|
910
969
|
this.container.insertBefore(cheat, next);
|
911
|
-
|
970
|
+
parent.setTimeout(function() {
|
912
971
|
if (cheat.nodeValue == "\u200b") removeElement(cheat);
|
913
972
|
else cheat.nodeValue = cheat.nodeValue.replace("\u200b", "");
|
914
973
|
}, 20);
|
915
974
|
}
|
916
975
|
}
|
976
|
+
|
977
|
+
// Magic incantation that works abound a webkit bug when you
|
978
|
+
// can't type on a blank line following a line that's wider than
|
979
|
+
// the window.
|
980
|
+
if (webkit && !this.options.textWrapping)
|
981
|
+
setTimeout(function () {
|
982
|
+
var node = select.selectionTopNode(self.container, true);
|
983
|
+
if (node && node.nodeType == 3 && node.previousSibling && isBR(node.previousSibling)
|
984
|
+
&& node.nextSibling && isBR(node.nextSibling))
|
985
|
+
node.parentNode.replaceChild(document.createElement("BR"), node.previousSibling);
|
986
|
+
}, 50);
|
917
987
|
},
|
918
988
|
|
919
989
|
// Mark the node at the cursor dirty when a non-safe key is
|
@@ -938,6 +1008,7 @@ var Editor = (function(){
|
|
938
1008
|
var self = this, whiteSpace = whiteSpaceAfter(start);
|
939
1009
|
var newIndent = 0, curIndent = whiteSpace ? whiteSpace.currentText.length : 0;
|
940
1010
|
|
1011
|
+
var firstText = whiteSpace ? whiteSpace.nextSibling : (start ? start.nextSibling : this.container.firstChild);
|
941
1012
|
if (direction == "keep") {
|
942
1013
|
if (start) {
|
943
1014
|
var prevWS = whiteSpaceAfter(startOfLine(start.previousSibling))
|
@@ -947,17 +1018,16 @@ var Editor = (function(){
|
|
947
1018
|
else {
|
948
1019
|
// Sometimes the start of the line can influence the correct
|
949
1020
|
// indentation, so we retrieve it.
|
950
|
-
var firstText = whiteSpace ? whiteSpace.nextSibling : (start ? start.nextSibling : this.container.firstChild);
|
951
1021
|
var nextChars = (start && firstText && firstText.currentText) ? firstText.currentText : "";
|
952
1022
|
|
953
1023
|
// Ask the lexical context for the correct indentation, and
|
954
1024
|
// compute how much this differs from the current indentation.
|
955
|
-
if (direction != null && this.options.tabMode
|
1025
|
+
if (direction != null && this.options.tabMode != "indent")
|
956
1026
|
newIndent = direction ? curIndent + indentUnit : Math.max(0, curIndent - indentUnit)
|
957
1027
|
else if (start)
|
958
|
-
newIndent = start.indentation(nextChars, curIndent, direction);
|
1028
|
+
newIndent = start.indentation(nextChars, curIndent, direction, firstText);
|
959
1029
|
else if (Editor.Parser.firstIndentation)
|
960
|
-
newIndent = Editor.Parser.firstIndentation(nextChars, curIndent, direction);
|
1030
|
+
newIndent = Editor.Parser.firstIndentation(nextChars, curIndent, direction, firstText);
|
961
1031
|
}
|
962
1032
|
|
963
1033
|
var indentDiff = newIndent - curIndent;
|
@@ -1017,7 +1087,7 @@ var Editor = (function(){
|
|
1017
1087
|
// re-indented, when nothing is selected, the line with the cursor
|
1018
1088
|
// is re-indented.
|
1019
1089
|
handleTab: function(direction) {
|
1020
|
-
if (this.options.tabMode == "spaces")
|
1090
|
+
if (this.options.tabMode == "spaces" && !select.somethingSelected())
|
1021
1091
|
select.insertTabAtCursor();
|
1022
1092
|
else
|
1023
1093
|
this.reindentSelection(direction);
|
@@ -1086,9 +1156,9 @@ var Editor = (function(){
|
|
1086
1156
|
|
1087
1157
|
// Delay (or initiate) the next paren highlight event.
|
1088
1158
|
scheduleParenHighlight: function() {
|
1089
|
-
if (this.parenEvent)
|
1159
|
+
if (this.parenEvent) parent.clearTimeout(this.parenEvent);
|
1090
1160
|
var self = this;
|
1091
|
-
this.parenEvent =
|
1161
|
+
this.parenEvent = parent.setTimeout(function(){self.highlightParens();}, 300);
|
1092
1162
|
},
|
1093
1163
|
|
1094
1164
|
// Take the token before the cursor. If it contains a character in
|
@@ -1096,23 +1166,24 @@ var Editor = (function(){
|
|
1096
1166
|
// highlight them in green for a moment, or red if no proper match
|
1097
1167
|
// was found.
|
1098
1168
|
highlightParens: function(jump, fromKey) {
|
1099
|
-
var self = this;
|
1169
|
+
var self = this, mark = this.options.markParen;
|
1170
|
+
if (typeof mark == "string") mark = [mark, mark];
|
1100
1171
|
// give the relevant nodes a colour.
|
1101
1172
|
function highlight(node, ok) {
|
1102
1173
|
if (!node) return;
|
1103
|
-
if (
|
1104
|
-
self.options.markParen(node, ok);
|
1105
|
-
}
|
1106
|
-
else {
|
1174
|
+
if (!mark) {
|
1107
1175
|
node.style.fontWeight = "bold";
|
1108
1176
|
node.style.color = ok ? "#8F8" : "#F88";
|
1109
1177
|
}
|
1178
|
+
else if (mark.call) mark(node, ok);
|
1179
|
+
else node.className += " " + mark[ok ? 0 : 1];
|
1110
1180
|
}
|
1111
1181
|
function unhighlight(node) {
|
1112
1182
|
if (!node) return;
|
1113
|
-
if (
|
1183
|
+
if (mark && !mark.call)
|
1184
|
+
removeClass(removeClass(node, mark[0]), mark[1]);
|
1185
|
+
else if (self.options.unmarkParen)
|
1114
1186
|
self.options.unmarkParen(node);
|
1115
|
-
}
|
1116
1187
|
else {
|
1117
1188
|
node.style.fontWeight = "";
|
1118
1189
|
node.style.color = "";
|
@@ -1123,9 +1194,9 @@ var Editor = (function(){
|
|
1123
1194
|
unhighlight(self.highlighted[1]);
|
1124
1195
|
}
|
1125
1196
|
|
1126
|
-
if (!window.parent || !window.select) return;
|
1197
|
+
if (!window || !window.parent || !window.select) return;
|
1127
1198
|
// Clear the event property.
|
1128
|
-
if (this.parenEvent)
|
1199
|
+
if (this.parenEvent) parent.clearTimeout(this.parenEvent);
|
1129
1200
|
this.parenEvent = null;
|
1130
1201
|
|
1131
1202
|
// Extract a 'paren' from a piece of text.
|
@@ -1184,7 +1255,7 @@ var Editor = (function(){
|
|
1184
1255
|
highlight(cursor, found.status);
|
1185
1256
|
highlight(found.node, found.status);
|
1186
1257
|
if (fromKey)
|
1187
|
-
|
1258
|
+
parent.setTimeout(function() {unhighlight(cursor); unhighlight(found.node);}, 500);
|
1188
1259
|
else
|
1189
1260
|
self.highlighted = [cursor, found.node];
|
1190
1261
|
if (jump && found.node)
|
@@ -1213,7 +1284,7 @@ var Editor = (function(){
|
|
1213
1284
|
|
1214
1285
|
// Indent all lines whose start falls inside of the current
|
1215
1286
|
// selection.
|
1216
|
-
indentRegion: function(start, end, direction) {
|
1287
|
+
indentRegion: function(start, end, direction, selectAfter) {
|
1217
1288
|
var current = (start = startOfLine(start)), before = start && startOfLine(start.previousSibling);
|
1218
1289
|
if (!isBR(end)) end = endOfLine(end, this.container);
|
1219
1290
|
this.addDirtyNode(start);
|
@@ -1225,7 +1296,8 @@ var Editor = (function(){
|
|
1225
1296
|
before = current;
|
1226
1297
|
current = next;
|
1227
1298
|
} while (current != end);
|
1228
|
-
|
1299
|
+
if (selectAfter)
|
1300
|
+
select.setCursorPos(this.container, {node: start, offset: 0}, {node: end, offset: 0});
|
1229
1301
|
},
|
1230
1302
|
|
1231
1303
|
// Find the node that the cursor is in, mark it as dirty, and make
|
@@ -1240,10 +1312,15 @@ var Editor = (function(){
|
|
1240
1312
|
|
1241
1313
|
if (internetExplorer) {
|
1242
1314
|
this.container.createTextRange().execCommand("unlink");
|
1243
|
-
|
1315
|
+
clearTimeout(this.saveSelectionSnapshot);
|
1316
|
+
var self = this;
|
1317
|
+
this.saveSelectionSnapshot = setTimeout(function() {
|
1318
|
+
var snapshot = select.getBookmark(self.container);
|
1319
|
+
if (snapshot) self.selectionSnapshot = snapshot;
|
1320
|
+
}, 200);
|
1244
1321
|
}
|
1245
1322
|
|
1246
|
-
var activity = this.options.
|
1323
|
+
var activity = this.options.onCursorActivity;
|
1247
1324
|
if (!safe || activity) {
|
1248
1325
|
var cursor = select.selectionTopNode(this.container, false);
|
1249
1326
|
if (cursor === false || !this.container.firstChild) return;
|
@@ -1288,8 +1365,8 @@ var Editor = (function(){
|
|
1288
1365
|
// Timeouts are routed through the parent window, because on
|
1289
1366
|
// some browsers designMode windows do not fire timeouts.
|
1290
1367
|
var self = this;
|
1291
|
-
|
1292
|
-
this.highlightTimeout =
|
1368
|
+
parent.clearTimeout(this.highlightTimeout);
|
1369
|
+
this.highlightTimeout = parent.setTimeout(function(){self.highlightDirty();}, this.options.passDelay);
|
1293
1370
|
},
|
1294
1371
|
|
1295
1372
|
// Fetch one dirty node, and remove it from the dirty set.
|
@@ -1319,7 +1396,7 @@ var Editor = (function(){
|
|
1319
1396
|
highlightDirty: function(force) {
|
1320
1397
|
// Prevent FF from raising an error when it is firing timeouts
|
1321
1398
|
// on a page that's no longer loaded.
|
1322
|
-
if (!window.parent || !window.select) return false;
|
1399
|
+
if (!window || !window.parent || !window.select) return false;
|
1323
1400
|
|
1324
1401
|
if (!this.options.readOnly) select.markSelection();
|
1325
1402
|
var start, endTime = force ? null : time() + this.options.passTime;
|
@@ -1339,7 +1416,7 @@ var Editor = (function(){
|
|
1339
1416
|
var self = this, pos = null;
|
1340
1417
|
return function() {
|
1341
1418
|
// FF timeout weirdness workaround.
|
1342
|
-
if (!window.parent || !window.select) return;
|
1419
|
+
if (!window || !window.parent || !window.select) return;
|
1343
1420
|
// If the current node is no longer in the document... oh
|
1344
1421
|
// well, we start over.
|
1345
1422
|
if (pos && pos.parentNode != self.container)
|
@@ -1357,8 +1434,8 @@ var Editor = (function(){
|
|
1357
1434
|
// a given interval.
|
1358
1435
|
delayScanning: function() {
|
1359
1436
|
if (this.scanner) {
|
1360
|
-
|
1361
|
-
this.documentScan =
|
1437
|
+
parent.clearTimeout(this.documentScan);
|
1438
|
+
this.documentScan = parent.setTimeout(this.scanner, this.options.continuousScanning);
|
1362
1439
|
}
|
1363
1440
|
},
|
1364
1441
|
|
@@ -1516,7 +1593,7 @@ var Editor = (function(){
|
|
1516
1593
|
// later resume parsing from this point, the second is used
|
1517
1594
|
// for indentation.
|
1518
1595
|
part.parserFromHere = parsed.copy();
|
1519
|
-
part.indentation = token.indentation;
|
1596
|
+
part.indentation = token.indentation || alwaysZero;
|
1520
1597
|
part.dirty = false;
|
1521
1598
|
|
1522
1599
|
// If the target argument wasn't an integer, go at least
|
@@ -1540,6 +1617,7 @@ var Editor = (function(){
|
|
1540
1617
|
|
1541
1618
|
// If the part matches the token, we can leave it alone.
|
1542
1619
|
if (correctPart(token, part)){
|
1620
|
+
if (active && part.dirty) active(part, token, self);
|
1543
1621
|
part.dirty = false;
|
1544
1622
|
parts.next();
|
1545
1623
|
}
|
@@ -1589,5 +1667,5 @@ var Editor = (function(){
|
|
1589
1667
|
addEventHandler(window, "load", function() {
|
1590
1668
|
var CodeMirror = window.frameElement.CodeMirror;
|
1591
1669
|
var e = CodeMirror.editor = new Editor(CodeMirror.options);
|
1592
|
-
|
1670
|
+
parent.setTimeout(method(CodeMirror, "init"), 0);
|
1593
1671
|
});
|