43 changes: 42 additions & 1 deletion addon/dialog/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,22 @@
} else {
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
}
dialog.innerHTML = template;
if (typeof template == "string") {
dialog.innerHTML = template;
} else { // Assuming it's a detached DOM element.
dialog.appendChild(template);
}
return dialog;
}

function closeNotification(cm, newVal) {
if (cm.state.currentNotificationClose)
cm.state.currentNotificationClose();
cm.state.currentNotificationClose = newVal;
}

CodeMirror.defineExtension("openDialog", function(template, callback, options) {
closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom);
var closed = false, me = this;
function close() {
Expand Down Expand Up @@ -51,6 +62,7 @@
});

CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom);
var buttons = dialog.getElementsByTagName("button");
var closed = false, me = this, blurring = 1;
Expand All @@ -77,4 +89,33 @@
CodeMirror.on(b, "focus", function() { ++blurring; });
}
});

/*
* openNotification
* Opens a notification, that can be closed with an optional timer
* (default 5000ms timer) and always closes on click.
*
* If a notification is opened while another is opened, it will close the
* currently opened one and open the new one immediately.
*/
CodeMirror.defineExtension("openNotification", function(template, options) {
closeNotification(this, close);
var dialog = dialogDiv(this, template, options && options.bottom);
var duration = options && (options.duration === undefined ? 5000 : options.duration);
var closed = false, doneTimer;

function close() {
if (closed) return;
closed = true;
clearTimeout(doneTimer);
dialog.parentNode.removeChild(dialog);
}

CodeMirror.on(dialog, 'click', function(e) {
CodeMirror.e_preventDefault(e);
close();
});
if (duration)
doneTimer = setTimeout(close, options.duration);
});
})();
3 changes: 2 additions & 1 deletion addon/display/fullscreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
var wrap = cm.getWrapperElement();
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
width: wrap.style.width, height: wrap.style.height};
wrap.style.width = wrap.style.height = "";
wrap.style.width = "";
wrap.style.height = "auto";
wrap.className += " CodeMirror-fullscreen";
document.documentElement.style.overflow = "hidden";
cm.refresh();
Expand Down
6 changes: 0 additions & 6 deletions addon/display/placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
cm.on("focus", onFocus);
cm.on("blur", onBlur);
cm.on("change", onChange);
onChange(cm);
} else if (!val && prev) {
cm.off("focus", onFocus);
cm.off("blur", onBlur);
cm.off("change", onChange);
clearPlaceholder(cm);
Expand All @@ -33,17 +31,13 @@
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
}

function onFocus(cm) {
clearPlaceholder(cm);
}
function onBlur(cm) {
if (isEmpty(cm)) setPlaceholder(cm);
}
function onChange(cm) {
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");

if (cm.hasFocus()) return;
if (empty) setPlaceholder(cm);
else clearPlaceholder(cm);
}
Expand Down
24 changes: 13 additions & 11 deletions addon/edit/closetag.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@

(function() {
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
if (val && (old == CodeMirror.Init || !old)) {
var map = {name: "autoCloseTags"};
if (typeof val != "object" || val.whenClosing)
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
if (typeof val != "object" || val.whenOpening)
map["'>'"] = function(cm) { return autoCloseGT(cm); };
cm.addKeyMap(map);
} else if (!val && (old != CodeMirror.Init && old)) {
if (old != CodeMirror.Init && old)
cm.removeKeyMap("autoCloseTags");
}
if (!val) return;
var map = {name: "autoCloseTags"};
if (typeof val != "object" || val.whenClosing)
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
if (typeof val != "object" || val.whenOpening)
map["'>'"] = function(cm) { return autoCloseGT(cm); };
cm.addKeyMap(map);
});

var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
Expand All @@ -54,7 +53,8 @@
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
var lowerTagName = tagName.toLowerCase();
// Don't process the '>' at the end of an end-tag or self-closing tag
if (tok.type == "tag" && state.type == "closeTag" ||
if (tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
tok.type == "tag" && state.type == "closeTag" ||
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1)
return CodeMirror.Pass;
Expand All @@ -72,7 +72,9 @@
function autoCloseSlash(cm) {
var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
if (tok.string.charAt(0) != "<" || tok.start != pos.ch - 1 || inner.mode.name != "xml") return CodeMirror.Pass;
if (tok.type == "string" || tok.string.charAt(0) != "<" ||
tok.start != pos.ch - 1 || inner.mode.name != "xml")
return CodeMirror.Pass;

var tagName = state.context && state.context.tagName;
if (tagName) cm.replaceSelection("/" + tagName + ">", "end");
Expand Down
3 changes: 2 additions & 1 deletion addon/edit/matchbrackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
function findMatchingBracket(cm, where, strict) {
var state = cm.state.matchBrackets;
var maxScanLen = (state && state.maxScanLineLength) || 10000;
var maxScanLines = (state && state.maxScanLines) || 100;

var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
Expand All @@ -32,7 +33,7 @@
}
}
}
for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) {
for (var i = cur.line, found, e = forward ? Math.min(i + maxScanLines, cm.lineCount()) : Math.max(-1, i - maxScanLines); i != e; i+=d) {
if (i == cur.line) found = scan(line, i, pos);
else found = scan(cm.getLineHandle(i), i);
if (found) break;
Expand Down
8 changes: 4 additions & 4 deletions addon/fold/foldgutter.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@
}

function onChange(cm) {
var state = cm.state.foldGutter;
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
state.from = state.to = 0;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, 600);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
}

function onViewportChange(cm) {
var state = cm.state.foldGutter;
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() {
var vp = cm.getViewport();
Expand All @@ -113,7 +113,7 @@
}
});
}
}, 400);
}, opts.updateViewportTimeSpan || 400);
}

function onFold(cm, from) {
Expand Down
46 changes: 25 additions & 21 deletions addon/fold/indent-fold.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var lastLine = cm.lastLine(),
tabSize = cm.getOption("tabSize"),
firstLine = cm.getLine(start.line),
myIndent = CodeMirror.countColumn(firstLine, null, tabSize);

function foldEnded(curColumn, prevColumn) {
return curColumn < myIndent ||
(curColumn == myIndent && prevColumn >= myIndent) ||
(curColumn > myIndent && i == lastLine);
}

for (var i = start.line + 1; i <= lastLine; i++) {
var curColumn = CodeMirror.countColumn(cm.getLine(i), null, tabSize);
var prevColumn = CodeMirror.countColumn(cm.getLine(i-1), null, tabSize);

if (foldEnded(curColumn, prevColumn)) {
var lastFoldLineNumber = curColumn > myIndent && i == lastLine ? i : i-1;
var lastFoldLine = cm.getLine(lastFoldLineNumber);
return {from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(lastFoldLineNumber, lastFoldLine.length)};
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
if (!/\S/.test(firstLine)) return;
var getIndent = function(lineNum) {
return CodeMirror.countColumn(lineNum, null, tabSize);
};
var myIndent = getIndent(firstLine);
var lastLineInFold = null;
// Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end.
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var curLine = cm.getLine(i);
var curIndent = getIndent(curLine);
if (curIndent > myIndent) {
// Lines with a greater indent are considered part of the block.
lastLineInFold = i;
} else if (!/\S/.test(curLine)) {
// Empty lines might be breaks within the block we're trying to fold.
} else {
// A non-empty line at an indent equal to or less than ours marks the
// start of another block.
break;
}
}
if (lastLineInFold) return {
from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
};
});

CodeMirror.indentRangeFinder = CodeMirror.fold.indent; // deprecated
1 change: 1 addition & 0 deletions addon/hint/javascript-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
function scriptHint(editor, keywords, getToken, options) {
// Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
if (/\b(?:string|comment)\b/.test(token.type)) return;
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;

// If it's not a 'word-style' token, ignore the token.
Expand Down
28 changes: 20 additions & 8 deletions addon/hint/show-hint.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
(function() {
"use strict";

var HINT_ELEMENT_CLASS = "CodeMirror-hint";
var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";

CodeMirror.showHint = function(cm, getHints, options) {
// We want a single cursor position.
if (cm.somethingSelected()) return;
Expand Down Expand Up @@ -140,19 +143,26 @@
return ourMap;
}

function getHintElement(stopAt, el) {
while (el && el != stopAt) {
if (el.nodeName.toUpperCase() === "LI") return el;
el = el.parentNode;
}
}

function Widget(completion, data) {
this.completion = completion;
this.data = data;
var widget = this, cm = completion.cm, options = completion.options;

var hints = this.hints = document.createElement("ul");
hints.className = "CodeMirror-hints";
this.selectedHint = 0;
this.selectedHint = options.getDefaultSelection ? options.getDefaultSelection(cm,options,data) : 0;

var completions = data.list;
for (var i = 0; i < completions.length; ++i) {
var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
var className = "CodeMirror-hint" + (i ? "" : " CodeMirror-hint-active");
var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
if (cur.className != null) className = cur.className + " " + className;
elt.className = className;
if (cur.render) cur.render(elt, data, cur);
Expand Down Expand Up @@ -216,13 +226,15 @@
});

CodeMirror.on(hints, "dblclick", function(e) {
var t = e.target || e.srcElement;
if (t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
var t = getHintElement(hints, e.target || e.srcElement);
if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
});

CodeMirror.on(hints, "click", function(e) {
var t = e.target || e.srcElement;
if (t.hintId != null) widget.changeActive(t.hintId);
var t = getHintElement(hints, e.target || e.srcElement);
if (t && t.hintId != null) widget.changeActive(t.hintId);
});

CodeMirror.on(hints, "mousedown", function() {
setTimeout(function(){cm.focus();}, 20);
});
Expand Down Expand Up @@ -257,9 +269,9 @@
i = avoidWrap ? 0 : this.data.list.length - 1;
if (this.selectedHint == i) return;
var node = this.hints.childNodes[this.selectedHint];
node.className = node.className.replace(" CodeMirror-hint-active", "");
node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
node = this.hints.childNodes[this.selectedHint = i];
node.className += " CodeMirror-hint-active";
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
if (node.offsetTop < this.hints.scrollTop)
this.hints.scrollTop = node.offsetTop - 3;
else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
Expand Down
14 changes: 7 additions & 7 deletions addon/tern/tern.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@

getHint: function(cm, c) { return hint(this, cm, c); },

showType: function(cm) { showType(this, cm); },
showType: function(cm, pos) { showType(this, cm, pos); },

updateArgHints: function(cm) { updateArgHints(this, cm); },

Expand All @@ -106,10 +106,10 @@

rename: function(cm) { rename(this, cm); },

request: function (cm, query, c) {
request: function (cm, query, c, pos) {
var self = this;
var doc = findDoc(this, cm.getDoc());
var request = buildRequest(this, doc, query);
var request = buildRequest(this, doc, query, pos);

this.server.request(request, function (error, data) {
if (!error && self.options.responseFilter)
Expand Down Expand Up @@ -221,7 +221,7 @@

// Type queries

function showType(ts, cm) {
function showType(ts, cm, pos) {
ts.request(cm, "type", function(error, data) {
if (error) return showError(ts, cm, error);
if (ts.options.typeTip) {
Expand All @@ -236,7 +236,7 @@
}
}
tempTooltip(cm, tip);
});
}, pos);
}

// Maintaining argument hints
Expand Down Expand Up @@ -450,13 +450,13 @@

// Generic request-building helper

function buildRequest(ts, doc, query) {
function buildRequest(ts, doc, query, pos) {
var files = [], offsetLines = 0, allowFragments = !query.fullDocs;
if (!allowFragments) delete query.fullDocs;
if (typeof query == "string") query = {type: query};
query.lineCharPositions = true;
if (query.end == null) {
query.end = doc.doc.getCursor("end");
query.end = pos || doc.doc.getCursor("end");
if (doc.doc.somethingSelected())
query.start = doc.doc.getCursor("start");
}
Expand Down
1 change: 1 addition & 0 deletions demo/tern.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<script src="http://marijnhaverbeke.nl/acorn/acorn.js"></script>
<script src="http://marijnhaverbeke.nl/acorn/acorn_loose.js"></script>
<script src="http://marijnhaverbeke.nl/acorn/util/walk.js"></script>
<script src="http://ternjs.net/doc/demo/polyfill.js"></script>
<script src="http://ternjs.net/lib/signal.js"></script>
<script src="http://ternjs.net/lib/tern.js"></script>
<script src="http://ternjs.net/lib/def.js"></script>
Expand Down
Loading