From 671d2b94996ac71d56b2d05d5fe694ed7d84fa59 Mon Sep 17 00:00:00 2001 From: Ananya Sen Date: Wed, 4 Apr 2012 12:27:35 -0700 Subject: upgrading to CodeMirror 2.23, since it has an important fix to Not close Ninja, if backspace is pressed while autocomplete dropdown is open. Signed-off-by: Ananya Sen --- imports/codemirror/lib/util/closetag.js | 174 +++++++++++++++++++++++++ imports/codemirror/lib/util/foldcode.js | 2 +- imports/codemirror/lib/util/formatting.js | 2 +- imports/codemirror/lib/util/javascript-hint.js | 6 +- imports/codemirror/lib/util/simple-hint.js | 6 + 5 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 imports/codemirror/lib/util/closetag.js (limited to 'imports/codemirror/lib/util') diff --git a/imports/codemirror/lib/util/closetag.js b/imports/codemirror/lib/util/closetag.js new file mode 100644 index 00000000..44c2b435 --- /dev/null +++ b/imports/codemirror/lib/util/closetag.js @@ -0,0 +1,174 @@ +/** + * Tag-closer extension for CodeMirror. + * + * This extension adds a "closeTag" utility function that can be used with key bindings to + * insert a matching end tag after the ">" character of a start tag has been typed. It can + * also complete " + * Contributed under the same license terms as CodeMirror. + */ +(function() { + /** Option that allows tag closing behavior to be toggled. Default is true. */ + CodeMirror.defaults['closeTagEnabled'] = true; + + /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */ + CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul']; + + /** + * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass. + * - cm: The editor instance. + * - ch: The character being processed. + * - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option. + * Pass false to disable indentation. Pass an array to override the default list of tag names. + */ + CodeMirror.defineExtension("closeTag", function(cm, ch, indent) { + if (!cm.getOption('closeTagEnabled')) { + throw CodeMirror.Pass; + } + + var mode = cm.getOption('mode'); + + if (mode == 'text/html') { + + /* + * Relevant structure of token: + * + * htmlmixed + * className + * state + * htmlState + * type + * context + * tagName + * mode + * + * xml + * className + * state + * tagName + * type + */ + + var pos = cm.getCursor(); + var tok = cm.getTokenAt(pos); + var state = tok.state; + + if (state.mode && state.mode != 'html') { + throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode. + } + + if (ch == '>') { + var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml + + if (tok.className == 'tag' && type == 'closeTag') { + throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag. + } + + cm.replaceSelection('>'); // Mode state won't update until we finish the tag. + pos = {line: pos.line, ch: pos.ch + 1}; + cm.setCursor(pos); + + tok = cm.getTokenAt(cm.getCursor()); + state = tok.state; + type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml + + if (tok.className == 'tag' && type != 'selfcloseTag') { + var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml + if (tagName.length > 0) { + insertEndTag(cm, indent, pos, tagName); + } + return; + } + + // Undo the '>' insert and allow cm to handle the key instead. + cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos); + cm.replaceSelection(""); + + } else if (ch == '/') { + if (tok.className == 'tag' && tok.string == '<') { + var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for ' 0) { + completeEndTag(cm, pos, tagName); + return; + } + } + } + + } else if (mode == 'xmlpure') { + + var pos = cm.getCursor(); + var tok = cm.getTokenAt(pos); + var tagName = tok.state.context.tagName; + + if (ch == '>') { + // tagName=foo, string=foo + // tagName=foo, string=/ # ignore + // tagName=foo, string=/foo # ignore + if (tok.string == tagName) { + cm.replaceSelection('>'); // parity w/html modes + pos = {line: pos.line, ch: pos.ch + 1}; + cm.setCursor(pos); + + insertEndTag(cm, indent, pos, tagName); + return; + } + + } else if (ch == '/') { + // ', 'end'); + cm.indentLine(pos.line + 1); + cm.indentLine(pos.line + 2); + cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length}); + } else { + cm.replaceSelection(''); + cm.setCursor(pos); + } + } + + function shouldIndent(cm, indent, tagName) { + if (typeof indent == 'undefined' || indent == null || indent == true) { + indent = cm.getOption('closeTagIndent'); + } + if (!indent) { + indent = []; + } + return indexOf(indent, tagName.toLowerCase()) != -1; + } + + // C&P from codemirror.js...would be nice if this were visible to utilities. + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + function completeEndTag(cm, pos, tagName) { + cm.replaceSelection('/' + tagName + '>'); + cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 }); + } + +})(); diff --git a/imports/codemirror/lib/util/foldcode.js b/imports/codemirror/lib/util/foldcode.js index 50268a8b..b700d860 100644 --- a/imports/codemirror/lib/util/foldcode.js +++ b/imports/codemirror/lib/util/foldcode.js @@ -80,7 +80,7 @@ CodeMirror.tagRangeFinder = function(cm, line) { } if (found) { - var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\s)|(\\<" + tag + "$)"; + var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)"; var startTagRegExp = new RegExp(startTag, "g"); var endTag = ""; var depth = 1; diff --git a/imports/codemirror/lib/util/formatting.js b/imports/codemirror/lib/util/formatting.js index 15de0355..e1891191 100644 --- a/imports/codemirror/lib/util/formatting.js +++ b/imports/codemirror/lib/util/formatting.js @@ -1,4 +1,4 @@ -// ============== Formatting extensions ============================ +// ============== Formatting extensions ============================ // A common storage for all mode-specific formatting features if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {}; diff --git a/imports/codemirror/lib/util/javascript-hint.js b/imports/codemirror/lib/util/javascript-hint.js index 2b904a51..2117e5af 100644 --- a/imports/codemirror/lib/util/javascript-hint.js +++ b/imports/codemirror/lib/util/javascript-hint.js @@ -113,8 +113,10 @@ base = 1; else if (obj.className == "function") { if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && - (typeof jQuery == 'function')) base = jQuery(); - else if (window._ != null && (obj.string == '_') && (typeof _ == 'function')) base = _(); + (typeof window.jQuery == 'function')) + base = window.jQuery(); + else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function')) + base = window._(); } while (base != null && context.length) base = base[context.pop().string]; diff --git a/imports/codemirror/lib/util/simple-hint.js b/imports/codemirror/lib/util/simple-hint.js index b38f3892..7decd587 100644 --- a/imports/codemirror/lib/util/simple-hint.js +++ b/imports/codemirror/lib/util/simple-hint.js @@ -29,6 +29,10 @@ complete.style.left = pos.x + "px"; complete.style.top = pos.yBot + "px"; document.body.appendChild(complete); + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + if(winW - pos.x < sel.clientWidth) + complete.style.left = (pos.x - sel.clientWidth) + "px"; // Hack to hide the scrollbar. if (completions.length <= 10) complete.style.width = (sel.clientWidth - 1) + "px"; @@ -53,6 +57,8 @@ else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();} else if (code != 38 && code != 40) { close(); editor.focus(); + // Pass the event to the CodeMirror instance so that it can handle things like backspace properly. + editor.triggerOnKeyDown(event); setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50); } }); -- cgit v1.2.3