X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/1fbf854ce423d2d56723ff10608267403f4916b0..1024e7820ecb22cde464da17ae22b161adf75c3b:/redakcja/static/js/lib/codemirror/codemirror.js?ds=sidebyside
diff --git a/redakcja/static/js/lib/codemirror/codemirror.js b/redakcja/static/js/lib/codemirror/codemirror.js
index 8475989c..57e44be7 100644
--- a/redakcja/static/js/lib/codemirror/codemirror.js
+++ b/redakcja/static/js/lib/codemirror/codemirror.js
@@ -26,13 +26,15 @@ var CodeMirror = (function(){
// options to a specific CodeMirror constructor. See manual.html for
// their meaning.
setDefaults(CodeMirrorConfig, {
- stylesheet: "",
+ stylesheet: [],
path: "",
parserfile: [],
basefiles: ["util.js", "stringstream.js", "select.js", "undo.js", "editor.js", "tokenize.js"],
iframeClass: null,
passDelay: 200,
passTime: 50,
+ lineNumberDelay: 200,
+ lineNumberTime: 50,
continuousScanning: false,
saveFunction: null,
onChange: null,
@@ -41,8 +43,9 @@ var CodeMirror = (function(){
disableSpellcheck: true,
textWrapping: true,
readOnly: false,
- width: "100%",
+ width: "",
height: "300px",
+ minHeight: 100,
autoMatchParens: false,
parserConfig: null,
tabMode: "indent", // or "spaces", "default", "shift"
@@ -50,124 +53,131 @@ var CodeMirror = (function(){
activeTokens: null,
cursorActivity: null,
lineNumbers: false,
- indentUnit: 2
+ indentUnit: 2,
+ domain: null
});
- function wrapLineNumberDiv(place) {
- return function(node) {
- var container = document.createElement("div"),
- nums = document.createElement("div"),
- scroller = document.createElement("div");
- container.style.position = "relative";
- nums.style.position = "absolute";
- nums.style.height = "100%";
- if (nums.style.setExpression) {
- try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");}
- catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions
- }
- nums.style.top = "0px";
- nums.style.overflow = "hidden";
- place(container);
- container.appendChild(node);
- container.appendChild(nums);
- scroller.className = "CodeMirror-line-numbers";
- nums.appendChild(scroller);
+ function addLineNumberDiv(container) {
+ var nums = document.createElement("DIV"),
+ scroller = document.createElement("DIV");
+ nums.style.position = "absolute";
+ nums.style.height = "100%";
+ if (nums.style.setExpression) {
+ try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");}
+ catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions
}
+ nums.style.top = "0px";
+ nums.style.left = "0px";
+ nums.style.overflow = "hidden";
+ container.appendChild(nums);
+ scroller.className = "CodeMirror-line-numbers";
+ nums.appendChild(scroller);
+ scroller.innerHTML = "
1
";
+ return nums;
}
- function applyLineNumbers(frame) {
- var win = frame.contentWindow, doc = win.document,
- nums = frame.nextSibling, scroller = nums.firstChild;
-
- var nextNum = 1;
-
- function update() {
- var diff = 20 + Math.max(doc.body.offsetHeight, frame.offsetHeight) - scroller.offsetHeight;
- for (var n = Math.ceil(diff / 10); n > 0; n--) {
- var div = document.createElement("div");
- div.appendChild(document.createTextNode(nextNum++));
- scroller.appendChild(div);
- }
- nums.scrollTop = doc.body.scrollTop || doc.documentElement.scrollTop || 0;
- }
+ function frameHTML(options) {
+ if (typeof options.parserfile == "string")
+ options.parserfile = [options.parserfile];
+ if (typeof options.stylesheet == "string")
+ options.stylesheet = [options.stylesheet];
- update();
- win.addEventHandler(win, "scroll", update);
- win.addEventHandler(win, "resize", update);
+ var html = [""];
+ // Hack to work around a bunch of IE8-specific problems.
+ html.push("");
+ forEach(options.stylesheet, function(file) {
+ html.push("");
+ });
+ forEach(options.basefiles.concat(options.parserfile), function(file) {
+ if (!/^https?:/.test(file)) file = options.path + file;
+ html.push("");
- });
- html.push("");
-
- var doc = this.win.document;
- doc.open();
- doc.write(html.join(""));
- doc.close();
+ this.win = frame.contentWindow;
+ if (!options.domain || !internetExplorer) {
+ this.win.document.open();
+ this.win.document.write(frameHTML(options));
+ this.win.document.close();
+ }
}
CodeMirror.prototype = {
init: function() {
if (this.options.initCallback) this.options.initCallback(this);
- if (this.options.lineNumbers) applyLineNumbers(this.frame);
+ if (this.options.lineNumbers) this.activateLineNumbers();
if (this.options.reindentOnLoad) this.reindent();
+ if (this.options.height == "dynamic") this.setDynamicHeight();
},
getCode: function() {return this.editor.getCode();},
setCode: function(code) {this.editor.importCode(code);},
- selection: function() {return this.editor.selectedText();},
+ selection: function() {this.focusIfIE(); return this.editor.selectedText();},
reindent: function() {this.editor.reindent();},
- reindentSelection: function() {this.editor.reindentSelection(null);},
+ reindentSelection: function() {this.focusIfIE(); this.editor.reindentSelection(null);},
+ focusIfIE: function() {
+ // in IE, a lot of selection-related functionality only works when the frame is focused
+ if (this.win.select.ie_selection) this.focus();
+ },
focus: function() {
this.win.focus();
if (this.editor.selectionSnapshot) // IE hack
- this.win.select.selectCoords(this.win, this.editor.selectionSnapshot);
+ this.win.select.setBookmark(this.win.document.body, this.editor.selectionSnapshot);
},
replaceSelection: function(text) {
this.focus();
@@ -177,8 +187,8 @@ var CodeMirror = (function(){
replaceChars: function(text, start, end) {
this.editor.replaceChars(text, start, end);
},
- getSearchCursor: function(string, fromCursor, regexp, case_sensitive) {
- return this.editor.getSearchCursor(string, fromCursor, regexp, case_sensitive);
+ getSearchCursor: function(string, fromCursor, caseFold) {
+ return this.editor.getSearchCursor(string, fromCursor, caseFold);
},
undo: function() {this.editor.history.undo();},
@@ -189,18 +199,76 @@ var CodeMirror = (function(){
grabKeys: function(callback, filter) {this.editor.grabKeys(callback, filter);},
ungrabKeys: function() {this.editor.ungrabKeys();},
- setParser: function(name) {this.editor.setParser(name);},
-
- cursorPosition: function(start) {
- if (this.win.select.ie_selection) this.focus();
- return this.editor.cursorPosition(start);
+ setParser: function(name, parserConfig) {this.editor.setParser(name, parserConfig);},
+ setSpellcheck: function(on) {this.win.document.body.spellcheck = on;},
+ setStylesheet: function(names) {
+ if (typeof names === "string") names = [names];
+ var activeStylesheets = {};
+ var matchedNames = {};
+ var links = this.win.document.getElementsByTagName("link");
+ // Create hashes of active stylesheets and matched names.
+ // This is O(n^2) but n is expected to be very small.
+ for (var x = 0, link; link = links[x]; x++) {
+ if (link.rel.indexOf("stylesheet") !== -1) {
+ for (var y = 0; y < names.length; y++) {
+ var name = names[y];
+ if (link.href.substring(link.href.length - name.length) === name) {
+ activeStylesheets[link.href] = true;
+ matchedNames[name] = true;
+ }
+ }
+ }
+ }
+ // Activate the selected stylesheets and disable the rest.
+ for (var x = 0, link; link = links[x]; x++) {
+ if (link.rel.indexOf("stylesheet") !== -1) {
+ link.disabled = !(link.href in activeStylesheets);
+ }
+ }
+ // Create any new stylesheets.
+ for (var y = 0; y < names.length; y++) {
+ var name = names[y];
+ if (!(name in matchedNames)) {
+ var link = this.win.document.createElement("link");
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = name;
+ this.win.document.getElementsByTagName('head')[0].appendChild(link);
+ }
+ }
+ },
+ setTextWrapping: function(on) {
+ if (on == this.options.textWrapping) return;
+ this.win.document.body.style.whiteSpace = on ? "" : "nowrap";
+ this.options.textWrapping = on;
+ if (this.lineNumbers) {
+ this.setLineNumbers(false);
+ this.setLineNumbers(true);
+ }
},
+ setIndentUnit: function(unit) {this.win.indentUnit = unit;},
+ setUndoDepth: function(depth) {this.editor.history.maxDepth = depth;},
+ setTabMode: function(mode) {this.options.tabMode = mode;},
+ setLineNumbers: function(on) {
+ if (on && !this.lineNumbers) {
+ this.lineNumbers = addLineNumberDiv(this.wrapping);
+ this.activateLineNumbers();
+ }
+ else if (!on && this.lineNumbers) {
+ this.wrapping.removeChild(this.lineNumbers);
+ this.wrapping.style.marginLeft = "";
+ this.lineNumbers = null;
+ }
+ },
+
+ cursorPosition: function(start) {this.focusIfIE(); return this.editor.cursorPosition(start);},
firstLine: function() {return this.editor.firstLine();},
lastLine: function() {return this.editor.lastLine();},
nextLine: function(line) {return this.editor.nextLine(line);},
prevLine: function(line) {return this.editor.prevLine(line);},
lineContent: function(line) {return this.editor.lineContent(line);},
setLineContent: function(line, content) {this.editor.setLineContent(line, content);},
+ removeLine: function(line){this.editor.removeLine(line);},
insertIntoLine: function(line, position, content) {this.editor.insertIntoLine(line, position, content);},
selectLines: function(startLine, startOffset, endLine, endOffset) {
this.win.focus();
@@ -220,14 +288,168 @@ var CodeMirror = (function(){
}
return num;
},
-
- // Old number-based line interface
- jumpToLine: function(n) {
- this.selectLines(this.nthLine(n), 0);
+ jumpToLine: function(line) {
+ if (typeof line == "number") line = this.nthLine(line);
+ this.selectLines(line, 0);
this.win.focus();
},
- currentLine: function() {
- return this.lineNumber(this.cursorPosition().line);
+ currentLine: function() { // Deprecated, but still there for backward compatibility
+ return this.lineNumber(this.cursorLine());
+ },
+ cursorLine: function() {
+ return this.cursorPosition().line;
+ },
+ cursorCoords: function(start) {return this.editor.cursorCoords(start);},
+
+ activateLineNumbers: function() {
+ var frame = this.frame, win = frame.contentWindow, doc = win.document, body = doc.body,
+ nums = this.lineNumbers, scroller = nums.firstChild, self = this;
+ var barWidth = null;
+
+ function sizeBar() {
+ if (frame.offsetWidth == 0) return;
+ for (var root = frame; root.parentNode; root = root.parentNode);
+ if (!nums.parentNode || root != document || !win.Editor) {
+ // Clear event handlers (their nodes might already be collected, so try/catch)
+ try{clear();}catch(e){}
+ clearInterval(sizeInterval);
+ return;
+ }
+
+ /*if (nums.offsetWidth != barWidth) {
+ barWidth = nums.offsetWidth;
+ frame.parentNode.style.paddingLeft = barWidth + "px";
+ }*/
+ }
+ function doScroll() {
+ nums.scrollTop = body.scrollTop || doc.documentElement.scrollTop || 0;
+ }
+ // Cleanup function, registered by nonWrapping and wrapping.
+ var clear = function(){};
+ sizeBar();
+ var sizeInterval = setInterval(sizeBar, 500);
+
+ function ensureEnoughLineNumbers(fill) {
+ var lineHeight = scroller.firstChild.offsetHeight;
+ if (lineHeight == 0) return;
+ var targetHeight = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0)),
+ lastNumber = Math.ceil(targetHeight / lineHeight);
+ for (var i = scroller.childNodes.length; i <= lastNumber; i++) {
+ var div = document.createElement("DIV");
+ div.appendChild(document.createTextNode(fill ? String(i + 1) : "\u00a0"));
+ scroller.appendChild(div);
+ }
+ }
+
+ function nonWrapping() {
+ function update() {
+ ensureEnoughLineNumbers(true);
+ doScroll();
+ }
+ self.updateNumbers = update;
+ var onScroll = win.addEventHandler(win, "scroll", doScroll, true),
+ onResize = win.addEventHandler(win, "resize", update, true);
+ clear = function(){
+ onScroll(); onResize();
+ if (self.updateNumbers == update) self.updateNumbers = null;
+ };
+ update();
+ }
+
+ function wrapping() {
+ var node, lineNum, next, pos, changes = [], styleNums = self.options.styleNumbers;
+
+ function setNum(n, node) {
+ // Does not typically happen (but can, if you mess with the
+ // document during the numbering)
+ if (!lineNum) lineNum = scroller.appendChild(document.createElement("DIV"));
+ if (styleNums) styleNums(lineNum, node, n);
+ // Changes are accumulated, so that the document layout
+ // doesn't have to be recomputed during the pass
+ changes.push(lineNum); changes.push(n);
+ pos = lineNum.offsetHeight + lineNum.offsetTop;
+ lineNum = lineNum.nextSibling;
+ }
+ function commitChanges() {
+ for (var i = 0; i < changes.length; i += 2)
+ changes[i].innerHTML = changes[i + 1];
+ changes = [];
+ }
+ function work() {
+ if (!scroller.parentNode || scroller.parentNode != self.lineNumbers) return;
+
+ var endTime = new Date().getTime() + self.options.lineNumberTime;
+ while (node) {
+ setNum(next++, node.previousSibling);
+ for (; node && !win.isBR(node); node = node.nextSibling) {
+ var bott = node.offsetTop + node.offsetHeight;
+ while (scroller.offsetHeight && bott - 3 > pos) setNum(" ");
+ }
+ if (node) node = node.nextSibling;
+ if (new Date().getTime() > endTime) {
+ commitChanges();
+ pending = setTimeout(work, self.options.lineNumberDelay);
+ return;
+ }
+ }
+ while (lineNum) setNum(next++);
+ commitChanges();
+ doScroll();
+ }
+ function start(firstTime) {
+ doScroll();
+ ensureEnoughLineNumbers(firstTime);
+ node = body.firstChild;
+ lineNum = scroller.firstChild;
+ pos = 0;
+ next = 1;
+ work();
+ }
+
+ start(true);
+ var pending = null;
+ function update() {
+ if (pending) clearTimeout(pending);
+ if (self.editor.allClean()) start();
+ else pending = setTimeout(update, 200);
+ }
+ self.updateNumbers = update;
+ var onScroll = win.addEventHandler(win, "scroll", doScroll, true),
+ onResize = win.addEventHandler(win, "resize", update, true);
+ clear = function(){
+ if (pending) clearTimeout(pending);
+ if (self.updateNumbers == update) self.updateNumbers = null;
+ onScroll();
+ onResize();
+ };
+ }
+ (this.options.textWrapping || this.options.styleNumbers ? wrapping : nonWrapping)();
+ },
+
+ setDynamicHeight: function() {
+ var self = this, activity = self.options.cursorActivity, win = self.win, body = win.document.body,
+ lineHeight = null, timeout = null, vmargin = 2 * self.frame.offsetTop;
+ body.style.overflowY = "hidden";
+ win.document.documentElement.style.overflowY = "hidden";
+ this.frame.scrolling = "no";
+
+ function updateHeight() {
+ for (var span = body.firstChild, sawBR = false; span; span = span.nextSibling)
+ if (win.isSpan(span) && span.offsetHeight) {
+ lineHeight = span.offsetHeight;
+ if (!sawBR) vmargin = 2 * (self.frame.offsetTop + span.offsetTop + body.offsetTop + (internetExplorer ? 10 : 0));
+ break;
+ }
+ if (lineHeight)
+ self.wrapping.style.height = Math.max(vmargin + lineHeight * (body.getElementsByTagName("BR").length + 1),
+ self.options.minHeight) + "px";
+ }
+ setTimeout(updateHeight, 100);
+ self.options.cursorActivity = function(x) {
+ if (activity) activity(x);
+ clearTimeout(timeout);
+ timeout = setTimeout(updateHeight, 200);
+ };
}
};
@@ -260,6 +482,15 @@ var CodeMirror = (function(){
area.form.addEventListener("submit", updateField, false);
else
area.form.attachEvent("onsubmit", updateField);
+ var realSubmit = area.form.submit;
+ function wrapSubmit() {
+ updateField();
+ // Can't use realSubmit.apply because IE6 is too stupid
+ area.form.submit = realSubmit;
+ area.form.submit();
+ area.form.submit = wrapSubmit;
+ }
+ area.form.submit = wrapSubmit;
}
function insert(frame) {
@@ -271,6 +502,18 @@ var CodeMirror = (function(){
area.style.display = "none";
var mirror = new CodeMirror(insert, options);
+ mirror.toTextArea = function() {
+ area.parentNode.removeChild(mirror.wrapping);
+ area.style.display = "";
+ if (area.form) {
+ area.form.submit = realSubmit;
+ if (typeof area.form.removeEventListener == "function")
+ area.form.removeEventListener("submit", updateField, false);
+ else
+ area.form.detachEvent("onsubmit", updateField);
+ }
+ };
+
return mirror;
};