liquid_cms 0.2.0.11 → 0.2.0.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
});
|