diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/htaccess.js b/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/htaccess.js index b6c9668b..c8cd78da 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/htaccess.js +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/htaccess.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode('shell', function() { +CodeMirror.defineMode('htaccess', function() { var words = {}; function define(style, string) { @@ -121,4 +121,113 @@ CodeMirror.defineMode('shell', function() { }; }); -CodeMirror.defineMIME('text/x-sh', 'shell'); +CodeMirror.defineMIME('text/x-htaccess', 'htaccess'); +CodeMirror.defineMIME('text/x-apache-conf', 'htaccess'); + +(function() { + CodeMirror.htaccessHint = function(editor, getHints, givenOptions) { + // Determine effective options based on given values and defaults. + var options = {}, defaults = CodeMirror.htaccessHint.defaults; + for (var opt in defaults) + if (defaults.hasOwnProperty(opt)) + options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt]; + + function collectHints(previousToken) { + // We want a single cursor position. + if (editor.somethingSelected()) return; + + var tempToken = editor.getTokenAt(editor.getCursor()); + + // Don't show completions if token has changed and the option is set. + if (options.closeOnTokenChange && previousToken != null && + (tempToken.start != previousToken.start || tempToken.type != previousToken.type)) { + return; + } + + //var result = getHints(editor, givenOptions); + var result = { + list: ['RewriteRule', 'RewriteEngine'] + }; + if (!result || !result.list.length) return; + var completions = result.list; + function insert(str) { + editor.replaceRange(str, result.from, result.to); + } + // When there is only one completion, use it directly. + if (options.completeSingle && completions.length == 1) { + insert(completions[0]); + return true; + } + + // Build the select widget + var complete = document.createElement("div"); + complete.className = "CodeMirror-completions"; + var sel = complete.appendChild(document.createElement("select")); + // Opera doesn't move the selection when pressing up/down in a + // multi-select, but it does properly support the size property on + // single-selects, so no multi-select is necessary. + if (!window.opera) sel.multiple = true; + for (var i = 0; i < completions.length; ++i) { + var opt = sel.appendChild(document.createElement("option")); + opt.appendChild(document.createTextNode(completions[i])); + } + sel.firstChild.selected = true; + sel.size = Math.min(10, completions.length); + var pos = editor.cursorCoords(options.alignWithWord ? result.from : null); + complete.style.left = pos.left + "px"; + complete.style.top = pos.bottom + "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.left < sel.clientWidth) + complete.style.left = (pos.left - sel.clientWidth) + "px"; + // Hack to hide the scrollbar. + if (completions.length <= 10) + complete.style.width = (sel.clientWidth - 1) + "px"; + + var done = false; + function close() { + if (done) return; + done = true; + complete.parentNode.removeChild(complete); + } + function pick() { + insert(completions[sel.selectedIndex]); + close(); + setTimeout(function(){editor.focus();}, 50); + } + CodeMirror.on(sel, "blur", close); + CodeMirror.on(sel, "keydown", function(event) { + var code = event.keyCode; + // Enter + if (code == 13) {CodeMirror.e_stop(event); pick();} + // Escape + else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();} + else if (code != 38 && code != 40 && code != 33 && code != 34 && !CodeMirror.isModifierKey(event)) { + close(); editor.focus(); + // Pass the event to the CodeMirror instance so that it can handle things like backspace properly. + editor.triggerOnKeyDown(event); + // Don't show completions if the code is backspace and the option is set. + if (!options.closeOnBackspace || code != 8) { + setTimeout(function(){collectHints(tempToken);}, 50); + } + } + }); + CodeMirror.on(sel, "dblclick", pick); + + sel.focus(); + // Opera sometimes ignores focusing a freshly created node + if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100); + return true; + } + return collectHints(); + }; + CodeMirror.htaccessHint.defaults = { + closeOnBackspace: true, + closeOnTokenChange: false, + completeSingle: true, + alignWithWord: true + }; +})(); + + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/index.html b/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/index.html index 24a45ac7..32d1ff9d 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/index.html +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/JavaScript/codemirror/index.html @@ -45,8 +45,17 @@ Header set Server "Apache/2.2.9 (Unix)" + + + \ No newline at end of file