diff --git a/tests/frontend/helper.js b/tests/frontend/helper.js index b49d32eb8..f1a9af84d 100644 --- a/tests/frontend/helper.js +++ b/tests/frontend/helper.js @@ -9,10 +9,13 @@ var helper = {}; // make sure we don't override existing jquery jsLibraries.jquery = `if(typeof $ === 'undefined') {\n${code}\n}`; - $.get('/tests/frontend/lib/sendkeys.js').done((code) => { - jsLibraries.sendkeys = code; + $.get('/tests/frontend/lib/bililiteRange.js').done((code) => { + jsLibraries.bililiteRange = code; - cb(); + $.get('/tests/frontend/lib/jquery.sendkeys.js').done((code) => { + jsLibraries.sendkeys = code; + cb(); + }); }); }); }; @@ -41,6 +44,7 @@ var helper = {}; win.execScript && win.execScript('null'); win.eval(jsLibraries.jquery); + win.eval(jsLibraries.bililiteRange); win.eval(jsLibraries.sendkeys); win.$.window = win; diff --git a/tests/frontend/lib/sendkeys.js b/tests/frontend/lib/bililiteRange.js similarity index 98% rename from tests/frontend/lib/sendkeys.js rename to tests/frontend/lib/bililiteRange.js index 8d65bf1c6..83424831b 100644 --- a/tests/frontend/lib/sendkeys.js +++ b/tests/frontend/lib/bililiteRange.js @@ -3,13 +3,13 @@ let bililiteRange; // create one global variable (function(){ - + const datakey = Symbol(); // use as the key to modify elements. bililiteRange = function(el){ var ret; if (el.setSelectionRange){ - // Element is an input or textarea + // Element is an input or textarea // note that some input elements do not allow selections try{ el.selectionStart = el.selectionStart; @@ -26,16 +26,16 @@ bililiteRange = function(el){ ret._doc = el.ownerDocument; ret._win = ret._doc.defaultView; ret._bounds = [0, ret.length]; - + // selection tracking. We want clicks to set the selection to the clicked location but tabbing in or element.focus() should restore // the selection to what it was. // There's no good way to do this. I just assume that a mousedown (or a drag and drop // into the element) within 100 ms of the focus event must have caused the focus, and // therefore we should not restore the selection. - if (!(el[datakey])){ // we haven't processed this element yet + if (!(el[datakey])){ // we haven't processed this element yet const data = createDataObject (el); startupHooks.forEach ( hook => hook (el, ret, data) ); - } + } return ret; } @@ -49,7 +49,7 @@ startupHooks.add (correctNewlines); function trackSelection (element, range, data){ data.selection = [0,0]; - range.listen('focusout', evt => data.selection = range._nativeSelection() ); + range.listen('focusout', evt => data.selection = range._nativeSelection() ); range.listen('mousedown', evt => data.mousetime = evt.timeStamp ); range.listen('drop', evt => data.mousetime = evt.timeStamp ); range.listen('focus', evt => { @@ -63,7 +63,7 @@ function fixInputEvents (element, range, data){ // have a data field with the text inserted, but thatisn't enough to fully describe the change; // we need to know the old text (or at least its length) // and *where* the new text was inserted. - // So we enhance input events with that information. + // So we enhance input events with that information. // the "newText" should always be the same as the 'data' field, if it is defined data.oldText = range.all(); data.liveRanges = new Set(); @@ -77,7 +77,7 @@ function fixInputEvents (element, range, data){ } } data.oldText = newText; - + // Also update live ranges on this element data.liveRanges.forEach( rng => { const start = evt.bililiteRange.start; @@ -99,7 +99,7 @@ function fixInputEvents (element, range, data){ }else{ b1 = start; } - rng.bounds([b0, b1]); + rng.bounds([b0, b1]); }) }); } @@ -181,7 +181,7 @@ function inputEventInit(type, oldText, newText, start, inputType){ // base class function Range(){} Range.prototype = { - // allow use of range[0] and range[1] for start and end of bounds + // allow use of range[0] and range[1] for start and end of bounds get 0(){ return this.bounds()[0]; }, @@ -457,7 +457,7 @@ W3CRange.prototype._nativeRange = function (bounds){ rng.collapse (true); w3cmoveBoundary (rng, bounds[1]-bounds[0], false, this._el); } - return rng; + return rng; }; W3CRange.prototype._nativeSelect = function (rng){ this._win.getSelection().removeAllRanges(); @@ -556,11 +556,11 @@ var START_TO_END = 1; var END_TO_END = 2; var END_TO_START = 3; // from the Mozilla documentation, for range.compareBoundaryPoints(how, sourceRange) -// -1, 0, or 1, indicating whether the corresponding boundary-point of range is respectively before, equal to, or after the corresponding boundary-point of sourceRange. +// -1, 0, or 1, indicating whether the corresponding boundary-point of range is respectively before, equal to, or after the corresponding boundary-point of sourceRange. // * Range.END_TO_END compares the end boundary-point of sourceRange to the end boundary-point of range. // * Range.END_TO_START compares the end boundary-point of sourceRange to the start boundary-point of range. // * Range.START_TO_END compares the start boundary-point of sourceRange to the end boundary-point of range. - // * Range.START_TO_START compares the start boundary-point of sourceRange to the start boundary-point of range. + // * Range.START_TO_START compares the start boundary-point of sourceRange to the start boundary-point of range. function w3cstart(rng, constraint){ if (rng.compareBoundaryPoints (START_TO_START, constraint) <= 0) return 0; // at or before the beginning if (rng.compareBoundaryPoints (END_TO_START, constraint) >= 0) return constraint.toString().length; @@ -610,7 +610,7 @@ function signalMonitor(prop, value, element){ const attr = `data-${prop}`; element.dispatchEvent(new CustomEvent(attr, {bubbles: true, detail: value})); try{ - element.setAttribute (attr, value); // illegal attribute names will throw. Ignore it + element.setAttribute (attr, value); // illegal attribute names will throw. Ignore it } finally { /* ignore */ } } @@ -619,7 +619,7 @@ function createDataObject (el){ set(obj, prop, value) { obj[prop] = value; if (monitored.has(prop)) signalMonitor(prop, value, obj.sourceElement); - return true; // in strict mode, 'set' returns a success flag + return true; // in strict mode, 'set' returns a success flag } }); } @@ -666,3 +666,4 @@ bililiteRange.createOption = function (name, desc = {}){ } })(); + diff --git a/tests/frontend/lib/jquery.sendkeys.js b/tests/frontend/lib/jquery.sendkeys.js new file mode 100644 index 000000000..1138f93a1 --- /dev/null +++ b/tests/frontend/lib/jquery.sendkeys.js @@ -0,0 +1,30 @@ +'use strict'; + +(function($){ + +$.fn.sendkeys = function (x){ + return this.each( function(){ + bililiteRange(this).bounds('selection').sendkeys(x).select(); + this.focus(); + }); +}; // sendkeys + +// add a default handler for keydowns so that we can send keystrokes, even though code-generated events +// are untrusted (http://www.w3.org/TR/DOM-Level-3-Events/#trusted-events) +// documentation of special event handlers is at http://learn.jquery.com/events/event-extensions/ +$.event.special.keydown = $.event.special.keydown || {}; +$.event.special.keydown._default = function (evt){ + if (evt.isTrusted) return false; + if (evt.key == null) return false; // nothing to print. Use the keymap plugin to set this + if (evt.ctrlKey || evt.altKey || evt.metaKey) return false; // only deal with printable characters. + var target = evt.target; + if (target.isContentEditable || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA') { + // only insert into editable elements + var key = evt.key; + if (key.length > 1 && key.charAt(0) != '{') key = '{'+key+'}'; // sendkeys notation + $(target).sendkeys(key); + return true; + } + return false; +} +})(jQuery)