diff --git a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 index b8110dd3dca..b34bbc7e909 100644 --- a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 +++ b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 @@ -6,44 +6,26 @@ export var CANCELLED_STATUS = "__CANCELLED"; -var shiftMap = []; -shiftMap[192] = "~"; -shiftMap[49] = "!"; -shiftMap[50] = "@"; -shiftMap[51] = "#"; -shiftMap[52] = "$"; -shiftMap[53] = "%"; -shiftMap[54] = "^"; -shiftMap[55] = "&"; -shiftMap[56] = "*"; -shiftMap[57] = "("; -shiftMap[48] = ")"; -shiftMap[109] = "_"; -shiftMap[107] = "+"; -shiftMap[219] = "{"; -shiftMap[221] = "}"; -shiftMap[220] = "|"; -shiftMap[59] = ":"; -shiftMap[222] = "\""; -shiftMap[188] = "<"; -shiftMap[190] = ">"; -shiftMap[191] = "?"; -shiftMap[32] = " "; - -function mapKeyPressToActualCharacter(isShiftKey, characterCode) { - if ( characterCode === 27 || characterCode === 8 || characterCode === 9 || characterCode === 20 || characterCode === 16 || characterCode === 17 || characterCode === 91 || characterCode === 13 || characterCode === 92 || characterCode === 18 ) { return false; } - - // Lookup non-letter keypress while holding shift - if (isShiftKey && ( characterCode < 65 || characterCode > 90 )) { - return shiftMap[characterCode]; - } - - var stringValue = String.fromCharCode(characterCode); - if ( !isShiftKey ) { - stringValue = stringValue.toLowerCase(); - } - return stringValue; -} +var Keys = { + BackSpace: 8, + Tab: 9, + Enter: 13, + Shift: 16, + Ctrl: 17, + Alt: 18, + Esc: 27, + Space: 32, + LeftWindows: 91, + RightWindows: 92, + PageUp: 33, + PageDown: 34, + End: 35, + Home: 36, + LeftArrow: 37, + UpArrow: 38, + RightArrow: 39, + DownArrow: 40, +}; export default function(options) { var autocompletePlugin = this; @@ -78,9 +60,14 @@ export default function(options) { } div = null; completeStart = null; + completeEnd = null; autocompleteOptions = null; }; + var autoCompleting = function () { + return completeStart !== null; + }; + var addInputSelectedItem = function(item) { var transformed, transformedItem = item; @@ -131,7 +118,7 @@ export default function(options) { term = options.transformComplete(term); } var text = me.val(); - text = text.substring(0, completeStart) + (options.key || "") + term + ' ' + text.substring(completeEnd + 1, text.length); + text = text.substring(0, completeStart) + term + ' ' + text.substring(completeEnd, text.length); me.val(text); Discourse.Utilities.setCaretPosition(me[0], completeStart + 1 + term.length); } @@ -264,24 +251,37 @@ export default function(options) { closeAutocomplete(); }); + var getTerm = function() { + return me.val().slice(completeStart, completeEnd); + }; $(this).keypress(function(e) { + var term, key = (e.char || String.fromCharCode(e.charCode)); - if (!options.key) return; + // if we just started with an options.key, set start and end. + if (key === options.key && !autoCompleting()) { + completeStart = completeEnd = Discourse.Utilities.caretPosition(me[0]) + 1; + } - // keep hunting backwards till you hit a - if (e.which === options.key.charCodeAt(0)) { - var caretPosition = Discourse.Utilities.caretPosition(me[0]); - var prevChar = me.val().charAt(caretPosition - 1); - if (!prevChar || /\s/.test(prevChar)) { - completeStart = completeEnd = caretPosition; + if (!options.key) { + completeStart = 0; + completeEnd = Discourse.Utilities.caretPosition(me[0]); + } + + if (autoCompleting()) { + if ((completeStart === completeEnd) && key === options.key) { updateAutoComplete(options.dataSource("")); + } else { + term = getTerm() + key; + completeEnd += 1; + updateAutoComplete(options.dataSource(term)); } + return true; } }); $(this).keydown(function(e) { - var c, caretPosition, i, initial, next, prev, prevIsGood, stopFound, term, total, userToComplete; + var caretPosition, i, term, total, userToComplete; if(options.allowAny){ // saves us wiring up a change event as well, keypress is while its pressed @@ -301,57 +301,38 @@ export default function(options) { },50); } - if (!options.key) { - completeStart = 0; - } - if (e.which === 16) return; - if ((completeStart === null) && e.which === 8 && options.key) { - c = Discourse.Utilities.caretPosition(me[0]); - next = me[0].value[c]; - c -= 1; - initial = c; - prevIsGood = true; - while (prevIsGood && c >= 0) { - c -= 1; - prev = me[0].value[c]; - stopFound = prev === options.key; - if (stopFound) { - prev = me[0].value[c - 1]; - if (!prev || /\s/.test(prev)) { - completeStart = c; - caretPosition = completeEnd = initial; - term = me[0].value.substring(c + 1, initial); - updateAutoComplete(options.dataSource(term)); - return true; - } + // Handle Backspacing into stuff + if ((!autoCompleting()) && e.which === Keys.BackSpace && options.key) { + var c = Discourse.Utilities.caretPosition(me[0]), + last, first, + text = me[0].value; + // search backwards until you find the last letter of the word + while (/[\s]/.test(text[c]) && c >= 0) { c--; } + last = c; + // search further until you find the first letter of the word + while (/[\S]/.test(text[c]) && c >= 0) { c--; } + first = c + 1; + + if (text[first] === options.key) { + completeStart = first + 1; + completeEnd = (options.key === ":" ? last - 1 : last); + + if (completeEnd >= completeStart) { + updateAutoComplete(options.dataSource(getTerm())); } - prevIsGood = /[a-zA-Z\.]/.test(prev); + return true; } } - // ESC - if (e.which === 27) { - if (completeStart !== null) { - closeAutocomplete(); - return false; - } - return true; - } - - if (completeStart !== null) { - caretPosition = Discourse.Utilities.caretPosition(me[0]); - - // If we've backspaced past the beginning, cancel unless no key - if (caretPosition <= completeStart && options.key) { - closeAutocomplete(); - return false; - } - + if (autoCompleting()) { // Keyboard codes! So 80's. switch (e.which) { - case 13: - case 39: - case 9: + case Keys.Esc: + closeAutocomplete(); + return false; + case Keys.Enter: + case Keys.RightArrow: + case Keys.Tab: if (!autocompleteOptions) return true; if (selectedOption >= 0 && (userToComplete = autocompleteOptions[selectedOption])) { completeTerm(userToComplete); @@ -361,14 +342,14 @@ export default function(options) { } e.stopImmediatePropagation(); return false; - case 38: + case Keys.UpArrow: selectedOption = selectedOption - 1; if (selectedOption < 0) { selectedOption = 0; } markSelected(); return false; - case 40: + case Keys.DownArrow: total = autocompleteOptions.length; selectedOption = selectedOption + 1; if (selectedOption >= total) { @@ -379,12 +360,11 @@ export default function(options) { } markSelected(); return false; - default: - // otherwise they're typing - let's search for it! + case Keys.BackSpace: + caretPosition = Discourse.Utilities.caretPosition(me[0]) - 1; completeEnd = caretPosition; - if (e.which === 8) { - caretPosition--; - } + + if (caretPosition < 0) { closeAutocomplete(); if (isInput) { @@ -395,23 +375,17 @@ export default function(options) { } return false; } - term = me.val().substring(completeStart + (options.key ? 1 : 0), caretPosition); - if (e.which >= 48 && e.which <= 90) { - term += mapKeyPressToActualCharacter(e.shiftKey, e.which); - } else if (e.which === 187) { - term += "+"; - } else if (e.which === 189) { - term += (e.shiftKey) ? "_" : "-"; - } else if (e.which === 220) { - term += (e.shiftKey) ? "|" : "]"; - } else if (e.which === 222) { - term += (e.shiftKey) ? "\"" : "'"; - } else if (e.which !== 8) { - term += ","; + + if (completeEnd < completeStart) { + closeAutocomplete(); + return true; } + term = getTerm(); updateAutoComplete(options.dataSource(term)); return true; + default: + return true; } } });