mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1199579 - Eslint cleanup of inplace-editor r=pbro
This commit is contained in:
parent
ef22cd7bde
commit
5c1c2ca017
@ -1,11 +1,12 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* globals focusManager, CSSPropertyList, domUtils */
|
||||
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Basic use:
|
||||
* let spanToEdit = document.getElementById("somespan");
|
||||
*
|
||||
@ -48,28 +49,28 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
* Changes will be committed when the InlineEditor's input is blurred
|
||||
* or dropped when the user presses escape.
|
||||
*
|
||||
* @param {object} aOptions
|
||||
* @param {Object} options
|
||||
* Options for the editable field, including:
|
||||
* {Element} element:
|
||||
* (required) The span to be edited on focus.
|
||||
* {function} canEdit:
|
||||
* {Function} canEdit:
|
||||
* Will be called before creating the inplace editor. Editor
|
||||
* won't be created if canEdit returns false.
|
||||
* {function} start:
|
||||
* {Function} start:
|
||||
* Will be called when the inplace editor is initialized.
|
||||
* {function} change:
|
||||
* {Function} change:
|
||||
* Will be called when the text input changes. Will be called
|
||||
* with the current value of the text input.
|
||||
* {function} done:
|
||||
* {Function} done:
|
||||
* Called when input is committed or blurred. Called with
|
||||
* current value, a boolean telling the caller whether to
|
||||
* commit the change, and the direction of the next element to be
|
||||
* selected. Direction may be one of nsIFocusManager.MOVEFOCUS_FORWARD,
|
||||
* nsIFocusManager.MOVEFOCUS_BACKWARD, or null (no movement).
|
||||
* This function is called before the editor has been torn down.
|
||||
* {function} destroy:
|
||||
* {Function} destroy:
|
||||
* Called when the editor is destroyed and has been torn down.
|
||||
* {object} advanceChars:
|
||||
* {Object} advanceChars:
|
||||
* This can be either a string or a function.
|
||||
* If it is a string, then if any characters in it are typed,
|
||||
* focus will advance to the next element.
|
||||
@ -78,27 +79,26 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
* and the insertion point. If the function returns true,
|
||||
* then the focus advance takes place. If it returns false,
|
||||
* then the character is inserted instead.
|
||||
* {boolean} stopOnReturn:
|
||||
* {Boolean} stopOnReturn:
|
||||
* If true, the return key will not advance the editor to the next
|
||||
* focusable element.
|
||||
* {boolean} stopOnTab:
|
||||
* {Boolean} stopOnTab:
|
||||
* If true, the tab key will not advance the editor to the next
|
||||
* focusable element.
|
||||
* {boolean} stopOnShiftTab:
|
||||
* {Boolean} stopOnShiftTab:
|
||||
* If true, shift tab will not advance the editor to the previous
|
||||
* focusable element.
|
||||
* {string} trigger: The DOM event that should trigger editing,
|
||||
* {String} trigger: The DOM event that should trigger editing,
|
||||
* defaults to "click"
|
||||
* {boolean} multiline: Should the editor be a multiline textarea?
|
||||
* {Boolean} multiline: Should the editor be a multiline textarea?
|
||||
* defaults to false
|
||||
* {boolean} trimOutput: Should the returned string be trimmed?
|
||||
* {Boolean} trimOutput: Should the returned string be trimmed?
|
||||
* defaults to true
|
||||
*/
|
||||
function editableField(aOptions)
|
||||
{
|
||||
return editableItem(aOptions, function(aElement, aEvent) {
|
||||
if (!aOptions.element.inplaceEditor) {
|
||||
new InplaceEditor(aOptions, aEvent);
|
||||
function editableField(options) {
|
||||
return editableItem(options, function(element, event) {
|
||||
if (!options.element.inplaceEditor) {
|
||||
new InplaceEditor(options, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -110,25 +110,24 @@ exports.editableField = editableField;
|
||||
* clicks and sit in the editing tab order, and call
|
||||
* a callback when it is activated.
|
||||
*
|
||||
* @param {object} aOptions
|
||||
* @param {Object} options
|
||||
* The options for this editor, including:
|
||||
* {Element} element: The DOM element.
|
||||
* {string} trigger: The DOM event that should trigger editing,
|
||||
* {String} trigger: The DOM event that should trigger editing,
|
||||
* defaults to "click"
|
||||
* @param {function} aCallback
|
||||
* @param {Function} callback
|
||||
* Called when the editor is activated.
|
||||
* @return {function} function which calls aCallback
|
||||
* @return {Function} function which calls callback
|
||||
*/
|
||||
function editableItem(aOptions, aCallback)
|
||||
{
|
||||
let trigger = aOptions.trigger || "click"
|
||||
let element = aOptions.element;
|
||||
function editableItem(options, callback) {
|
||||
let trigger = options.trigger || "click";
|
||||
let element = options.element;
|
||||
element.addEventListener(trigger, function(evt) {
|
||||
if (evt.target.nodeName !== "a") {
|
||||
let win = this.ownerDocument.defaultView;
|
||||
let selection = win.getSelection();
|
||||
if (trigger != "click" || selection.isCollapsed) {
|
||||
aCallback(element, evt);
|
||||
callback(element, evt);
|
||||
}
|
||||
evt.stopPropagation();
|
||||
}
|
||||
@ -139,7 +138,7 @@ function editableItem(aOptions, aCallback)
|
||||
element.addEventListener("keypress", function(evt) {
|
||||
if (evt.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN ||
|
||||
evt.charCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
|
||||
aCallback(element);
|
||||
callback(element);
|
||||
}
|
||||
}, true);
|
||||
|
||||
@ -168,8 +167,8 @@ function editableItem(aOptions, aCallback)
|
||||
element._trigger = trigger;
|
||||
|
||||
return function turnOnEditMode() {
|
||||
aCallback(element);
|
||||
}
|
||||
callback(element);
|
||||
};
|
||||
}
|
||||
|
||||
exports.editableItem = this.editableItem;
|
||||
@ -181,31 +180,32 @@ exports.editableItem = this.editableItem;
|
||||
* within this JSM. So we provide a little workaround here.
|
||||
*/
|
||||
|
||||
function getInplaceEditorForSpan(aSpan)
|
||||
{
|
||||
return aSpan.inplaceEditor;
|
||||
};
|
||||
function getInplaceEditorForSpan(span) {
|
||||
return span.inplaceEditor;
|
||||
}
|
||||
|
||||
exports.getInplaceEditorForSpan = getInplaceEditorForSpan;
|
||||
|
||||
function InplaceEditor(aOptions, aEvent)
|
||||
{
|
||||
this.elt = aOptions.element;
|
||||
function InplaceEditor(options, event) {
|
||||
this.elt = options.element;
|
||||
let doc = this.elt.ownerDocument;
|
||||
this.doc = doc;
|
||||
this.elt.inplaceEditor = this;
|
||||
|
||||
this.change = aOptions.change;
|
||||
this.done = aOptions.done;
|
||||
this.destroy = aOptions.destroy;
|
||||
this.initial = aOptions.initial ? aOptions.initial : this.elt.textContent;
|
||||
this.multiline = aOptions.multiline || false;
|
||||
this.trimOutput = aOptions.trimOutput === undefined ? true : !!aOptions.trimOutput;
|
||||
this.stopOnShiftTab = !!aOptions.stopOnShiftTab;
|
||||
this.stopOnTab = !!aOptions.stopOnTab;
|
||||
this.stopOnReturn = !!aOptions.stopOnReturn;
|
||||
this.contentType = aOptions.contentType || CONTENT_TYPES.PLAIN_TEXT;
|
||||
this.property = aOptions.property;
|
||||
this.popup = aOptions.popup;
|
||||
this.change = options.change;
|
||||
this.done = options.done;
|
||||
this.destroy = options.destroy;
|
||||
this.initial = options.initial ? options.initial : this.elt.textContent;
|
||||
this.multiline = options.multiline || false;
|
||||
this.trimOutput = options.trimOutput === undefined
|
||||
? true
|
||||
: !!options.trimOutput;
|
||||
this.stopOnShiftTab = !!options.stopOnShiftTab;
|
||||
this.stopOnTab = !!options.stopOnTab;
|
||||
this.stopOnReturn = !!options.stopOnReturn;
|
||||
this.contentType = options.contentType || CONTENT_TYPES.PLAIN_TEXT;
|
||||
this.property = options.property;
|
||||
this.popup = options.popup;
|
||||
|
||||
this._onBlur = this._onBlur.bind(this);
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
@ -218,11 +218,11 @@ function InplaceEditor(aOptions, aEvent)
|
||||
|
||||
// Pull out character codes for advanceChars, listing the
|
||||
// characters that should trigger a blur.
|
||||
if (typeof(aOptions.advanceChars) === "function") {
|
||||
this._advanceChars = aOptions.advanceChars;
|
||||
if (typeof options.advanceChars === "function") {
|
||||
this._advanceChars = options.advanceChars;
|
||||
} else {
|
||||
let advanceCharcodes = {};
|
||||
let advanceChars = aOptions.advanceChars || '';
|
||||
let advanceChars = options.advanceChars || "";
|
||||
for (let i = 0; i < advanceChars.length; i++) {
|
||||
advanceCharcodes[advanceChars.charCodeAt(i)] = true;
|
||||
}
|
||||
@ -236,7 +236,7 @@ function InplaceEditor(aOptions, aEvent)
|
||||
|
||||
this.input.focus();
|
||||
|
||||
if (typeof(aOptions.selectAll) == "undefined" || aOptions.selectAll) {
|
||||
if (typeof options.selectAll == "undefined" || options.selectAll) {
|
||||
this.input.select();
|
||||
}
|
||||
|
||||
@ -253,7 +253,7 @@ function InplaceEditor(aOptions, aEvent)
|
||||
this.input.addEventListener("mousedown",
|
||||
(e) => { e.stopPropagation(); }, false);
|
||||
|
||||
this.validate = aOptions.validate;
|
||||
this.validate = options.validate;
|
||||
|
||||
if (this.validate) {
|
||||
this.input.addEventListener("keyup", this._onKeyup, false);
|
||||
@ -261,8 +261,8 @@ function InplaceEditor(aOptions, aEvent)
|
||||
|
||||
this._updateSize();
|
||||
|
||||
if (aOptions.start) {
|
||||
aOptions.start(this, aEvent);
|
||||
if (options.start) {
|
||||
options.start(this, event);
|
||||
}
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
@ -279,8 +279,7 @@ InplaceEditor.prototype = {
|
||||
return val;
|
||||
},
|
||||
|
||||
_createInput: function InplaceEditor_createEditor()
|
||||
{
|
||||
_createInput: function() {
|
||||
this.input =
|
||||
this.doc.createElementNS(HTML_NS, this.multiline ? "textarea" : "input");
|
||||
this.input.inplaceEditor = this;
|
||||
@ -293,8 +292,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Get rid of the editor.
|
||||
*/
|
||||
_clear: function InplaceEditor_clear()
|
||||
{
|
||||
_clear: function() {
|
||||
if (!this.input) {
|
||||
// Already cleared.
|
||||
return;
|
||||
@ -327,8 +325,7 @@ InplaceEditor.prototype = {
|
||||
* Keeps the editor close to the size of its input string. This is pretty
|
||||
* crappy, suggestions for improvement welcome.
|
||||
*/
|
||||
_autosize: function InplaceEditor_autosize()
|
||||
{
|
||||
_autosize: function() {
|
||||
// Create a hidden, absolutely-positioned span to measure the text
|
||||
// in the input. Boo.
|
||||
|
||||
@ -352,8 +349,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Clean up the mess created by _autosize().
|
||||
*/
|
||||
_stopAutosize: function InplaceEditor_stopAutosize()
|
||||
{
|
||||
_stopAutosize: function() {
|
||||
if (!this._measurement) {
|
||||
return;
|
||||
}
|
||||
@ -364,12 +360,11 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Size the editor to fit its current contents.
|
||||
*/
|
||||
_updateSize: function InplaceEditor_updateSize()
|
||||
{
|
||||
_updateSize: function() {
|
||||
// Replace spaces with non-breaking spaces. Otherwise setting
|
||||
// the span's textContent will collapse spaces and the measurement
|
||||
// will be wrong.
|
||||
this._measurement.textContent = this.input.value.replace(/ /g, '\u00a0');
|
||||
this._measurement.textContent = this.input.value.replace(/ /g, "\u00a0");
|
||||
|
||||
// We add a bit of padding to the end. Should be enough to fit
|
||||
// any letter that could be typed, otherwise we'll scroll before
|
||||
@ -391,8 +386,7 @@ InplaceEditor.prototype = {
|
||||
* Get the width of a single character in the input to properly position the
|
||||
* autocompletion popup.
|
||||
*/
|
||||
_getInputCharWidth: function InplaceEditor_getInputCharWidth()
|
||||
{
|
||||
_getInputCharWidth: function() {
|
||||
// Just make the text content to be 'x' to get the width of any character in
|
||||
// a monospace font.
|
||||
this._measurement.textContent = "x";
|
||||
@ -402,12 +396,11 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment property values in rule view.
|
||||
*
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* The amount to increase/decrease the property value.
|
||||
* @return {bool} true if value has been incremented.
|
||||
* @return {Boolean} true if value has been incremented.
|
||||
*/
|
||||
_incrementValue: function InplaceEditor_incrementValue(increment)
|
||||
{
|
||||
_incrementValue: function(increment) {
|
||||
let value = this.input.value;
|
||||
let selectionStart = this.input.selectionStart;
|
||||
let selectionEnd = this.input.selectionEnd;
|
||||
@ -434,19 +427,17 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment the property value based on the property type.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increase/decrease the property value.
|
||||
* @param {number} selStart
|
||||
* @param {Number} selStart
|
||||
* Starting index of the value.
|
||||
* @param {number} selEnd
|
||||
* @param {Number} selEnd
|
||||
* Ending index of the value.
|
||||
* @return {object} object with properties 'value', 'start', and 'end'.
|
||||
* @return {Object} object with properties 'value', 'start', and 'end'.
|
||||
*/
|
||||
_incrementCSSValue: function InplaceEditor_incrementCSSValue(value, increment,
|
||||
selStart, selEnd)
|
||||
{
|
||||
_incrementCSSValue: function(value, increment, selStart, selEnd) {
|
||||
let range = this._parseCSSValue(value, selStart);
|
||||
let type = (range && range.type) || "";
|
||||
let rawValue = (range ? value.substring(range.start, range.end) : "");
|
||||
@ -489,11 +480,12 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._incrementGenericValue(value, increment, selStart, selEnd, info);
|
||||
return this._incrementGenericValue(value, increment, selStart, selEnd,
|
||||
info);
|
||||
}
|
||||
|
||||
if (incrementedValue === null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let preRawValue = value.substr(0, range.start);
|
||||
@ -509,14 +501,14 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Parses the property value and type.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} offset
|
||||
* @param {Number} offset
|
||||
* Starting index of value.
|
||||
* @return {object} object with properties 'value', 'start', 'end', and 'type'.
|
||||
* @return {Object} object with properties 'value', 'start', 'end', and
|
||||
* 'type'.
|
||||
*/
|
||||
_parseCSSValue: function InplaceEditor_parseCSSValue(value, offset)
|
||||
{
|
||||
_parseCSSValue: function(value, offset) {
|
||||
const reSplitCSS = /(url\("?[^"\)]+"?\)?)|(rgba?\([^)]*\)?)|(hsla?\([^)]*\)?)|(#[\dA-Fa-f]+)|(-?\d*\.?\d+(%|[a-z]{1,4})?)|"([^"]*)"?|'([^']*)'?|([^,\s\/!\(\)]+)|(!(.*)?)/;
|
||||
let start = 0;
|
||||
let m;
|
||||
@ -530,7 +522,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let type;
|
||||
@ -558,22 +550,19 @@ InplaceEditor.prototype = {
|
||||
* Increment the property value for types other than
|
||||
* number or hex, such as rgb, hsl, and file names.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increment/decrement.
|
||||
* @param {number} offset
|
||||
* @param {Number} offset
|
||||
* Starting index of the property value.
|
||||
* @param {number} offsetEnd
|
||||
* @param {Number} offsetEnd
|
||||
* Ending index of the property value.
|
||||
* @param {object} info
|
||||
* @param {Object} info
|
||||
* Object with details about the property value.
|
||||
* @return {object} object with properties 'value', 'start', and 'end'.
|
||||
* @return {Object} object with properties 'value', 'start', and 'end'.
|
||||
*/
|
||||
_incrementGenericValue:
|
||||
function InplaceEditor_incrementGenericValue(value, increment, offset,
|
||||
offsetEnd, info)
|
||||
{
|
||||
_incrementGenericValue: function(value, increment, offset, offsetEnd, info) {
|
||||
// Try to find a number around the cursor to increment.
|
||||
let start, end;
|
||||
// Check if we are incrementing in a non-number context (such as a URL)
|
||||
@ -585,8 +574,8 @@ InplaceEditor.prototype = {
|
||||
start = offset;
|
||||
end = offsetEnd;
|
||||
} else {
|
||||
// Parse periods as belonging to the number only if we are in a known number
|
||||
// context. (This makes incrementing the 1 in 'image1.gif' work.)
|
||||
// Parse periods as belonging to the number only if we are in a known
|
||||
// number context. (This makes incrementing the 1 in 'image1.gif' work.)
|
||||
let pattern = "[" + (info ? "0-9." : "0-9") + "]*";
|
||||
let before = new RegExp(pattern + "$").exec(value.substr(0, offset))[0].length;
|
||||
let after = new RegExp("^" + pattern).exec(value.substr(offset))[0].length;
|
||||
@ -602,8 +591,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (start !== end)
|
||||
{
|
||||
if (start !== end) {
|
||||
// Include percentages as part of the incremented number (they are
|
||||
// common enough).
|
||||
if (value.charAt(end) === "%") {
|
||||
@ -629,17 +617,15 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment the property value for numbers.
|
||||
*
|
||||
* @param {string} rawValue
|
||||
* @param {String} rawValue
|
||||
* Raw value to increment.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increase/decrease the raw value.
|
||||
* @param {object} info
|
||||
* @param {Object} info
|
||||
* Object with info about the property value.
|
||||
* @return {string} the incremented value.
|
||||
* @return {String} the incremented value.
|
||||
*/
|
||||
_incrementRawValue:
|
||||
function InplaceEditor_incrementRawValue(rawValue, increment, info)
|
||||
{
|
||||
_incrementRawValue: function(rawValue, increment, info) {
|
||||
let num = parseFloat(rawValue);
|
||||
|
||||
if (isNaN(num)) {
|
||||
@ -667,25 +653,23 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Increment the property value for hex.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {String} value
|
||||
* Property value.
|
||||
* @param {number} increment
|
||||
* @param {Number} increment
|
||||
* Amount to increase/decrease the property value.
|
||||
* @param {number} offset
|
||||
* @param {Number} offset
|
||||
* Starting index of the property value.
|
||||
* @param {number} offsetEnd
|
||||
* @param {Number} offsetEnd
|
||||
* Ending index of the property value.
|
||||
* @return {object} object with properties 'value' and 'selection'.
|
||||
* @return {Object} object with properties 'value' and 'selection'.
|
||||
*/
|
||||
_incHexColor:
|
||||
function InplaceEditor_incHexColor(rawValue, increment, offset, offsetEnd)
|
||||
{
|
||||
_incHexColor: function(rawValue, increment, offset, offsetEnd) {
|
||||
// Return early if no part of the rawValue is selected.
|
||||
if (offsetEnd > rawValue.length && offset >= rawValue.length) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (offset < 1 && offsetEnd <= 1) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// Ignore the leading #.
|
||||
rawValue = rawValue.substr(1);
|
||||
@ -707,7 +691,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
if (rawValue.length !== 6) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// If no selection, increment an adjacent color, preferably one to the left.
|
||||
@ -724,7 +708,7 @@ InplaceEditor.prototype = {
|
||||
offsetEnd += offsetEnd % 2;
|
||||
|
||||
// Remap the increments from [0.1, 1, 10] to [1, 1, 16].
|
||||
if (-1 < increment && increment < 1) {
|
||||
if (increment > -1 && increment < 1) {
|
||||
increment = (increment < 0 ? -1 : 1);
|
||||
}
|
||||
if (Math.abs(increment) === 10) {
|
||||
@ -739,7 +723,7 @@ InplaceEditor.prototype = {
|
||||
let value = parseInt(mid, 16);
|
||||
|
||||
if (isNaN(value)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
mid = Math.min(Math.max(value + increment, 0), 255).toString(16);
|
||||
@ -763,43 +747,45 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Cycle through the autocompletion suggestions in the popup.
|
||||
*
|
||||
* @param {boolean} aReverse
|
||||
* @param {Boolean} reverse
|
||||
* true to select previous item from the popup.
|
||||
* @param {boolean} aNoSelect
|
||||
* @param {Boolean} noSelect
|
||||
* true to not select the text after selecting the newly selectedItem
|
||||
* from the popup.
|
||||
*/
|
||||
_cycleCSSSuggestion:
|
||||
function InplaceEditor_cycleCSSSuggestion(aReverse, aNoSelect)
|
||||
{
|
||||
_cycleCSSSuggestion: function(reverse, noSelect) {
|
||||
// selectedItem can be null when nothing is selected in an empty editor.
|
||||
let {label, preLabel} = this.popup.selectedItem || {label: "", preLabel: ""};
|
||||
if (aReverse) {
|
||||
let {label, preLabel} = this.popup.selectedItem ||
|
||||
{label: "", preLabel: ""};
|
||||
if (reverse) {
|
||||
this.popup.selectPreviousItem();
|
||||
} else {
|
||||
this.popup.selectNextItem();
|
||||
}
|
||||
|
||||
this._selectedIndex = this.popup.selectedIndex;
|
||||
let input = this.input;
|
||||
let pre = "";
|
||||
|
||||
if (input.selectionStart < input.selectionEnd) {
|
||||
pre = input.value.slice(0, input.selectionStart);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pre = input.value.slice(0, input.selectionStart - label.length +
|
||||
preLabel.length);
|
||||
preLabel.length);
|
||||
}
|
||||
|
||||
let post = input.value.slice(input.selectionEnd, input.value.length);
|
||||
let item = this.popup.selectedItem;
|
||||
let toComplete = item.label.slice(item.preLabel.length);
|
||||
input.value = pre + toComplete + post;
|
||||
if (!aNoSelect) {
|
||||
|
||||
if (!noSelect) {
|
||||
input.setSelectionRange(pre.length, pre.length + toComplete.length);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
input.setSelectionRange(pre.length + toComplete.length,
|
||||
pre.length + toComplete.length);
|
||||
}
|
||||
|
||||
this._updateSize();
|
||||
// This emit is mainly for the purpose of making the test flow simpler.
|
||||
this.emit("after-suggest");
|
||||
@ -808,10 +794,9 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Call the client's done handler and clear out.
|
||||
*/
|
||||
_apply: function InplaceEditor_apply(aEvent, direction)
|
||||
{
|
||||
_apply: function(event, direction) {
|
||||
if (this._applied) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
this._applied = true;
|
||||
@ -827,25 +812,26 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Handle loss of focus by calling done if it hasn't been called yet.
|
||||
*/
|
||||
_onBlur: function InplaceEditor_onBlur(aEvent, aDoNotClear)
|
||||
{
|
||||
if (aEvent && this.popup && this.popup.isOpen &&
|
||||
_onBlur: function(event, doNotClear) {
|
||||
if (event && this.popup && this.popup.isOpen &&
|
||||
this.popup.selectedIndex >= 0) {
|
||||
let label, preLabel;
|
||||
|
||||
if (this._selectedIndex === undefined) {
|
||||
({label, preLabel} = this.popup.getItemAtIndex(this.popup.selectedIndex));
|
||||
}
|
||||
else {
|
||||
({label, preLabel} =
|
||||
this.popup.getItemAtIndex(this.popup.selectedIndex));
|
||||
} else {
|
||||
({label, preLabel} = this.popup.getItemAtIndex(this._selectedIndex));
|
||||
}
|
||||
|
||||
let input = this.input;
|
||||
let pre = "";
|
||||
|
||||
if (input.selectionStart < input.selectionEnd) {
|
||||
pre = input.value.slice(0, input.selectionStart);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pre = input.value.slice(0, input.selectionStart - label.length +
|
||||
preLabel.length);
|
||||
preLabel.length);
|
||||
}
|
||||
let post = input.value.slice(input.selectionEnd, input.value.length);
|
||||
let item = this.popup.selectedItem;
|
||||
@ -873,8 +859,10 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._apply();
|
||||
if (!aDoNotClear) {
|
||||
|
||||
if (!doNotClear) {
|
||||
this._clear();
|
||||
}
|
||||
},
|
||||
@ -882,8 +870,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Handle the input field's keypress event.
|
||||
*/
|
||||
_onKeyPress: function InplaceEditor_onKeyPress(aEvent)
|
||||
{
|
||||
_onKeyPress: function(event) {
|
||||
let prevent = false;
|
||||
|
||||
const largeIncrement = 100;
|
||||
@ -892,35 +879,35 @@ InplaceEditor.prototype = {
|
||||
|
||||
let increment = 0;
|
||||
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
|
||||
increment = 1;
|
||||
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
increment = -1;
|
||||
}
|
||||
|
||||
if (aEvent.shiftKey && !aEvent.altKey) {
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
if (event.shiftKey && !event.altKey) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
increment *= largeIncrement;
|
||||
} else {
|
||||
increment *= mediumIncrement;
|
||||
}
|
||||
} else if (aEvent.altKey && !aEvent.shiftKey) {
|
||||
} else if (event.altKey && !event.shiftKey) {
|
||||
increment *= smallIncrement;
|
||||
}
|
||||
|
||||
// Use default cursor movement rather than providing auto-suggestions.
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
|
||||
this._preventSuggestions = true;
|
||||
}
|
||||
|
||||
let cycling = false;
|
||||
if (increment && this._incrementValue(increment) ) {
|
||||
if (increment && this._incrementValue(increment)) {
|
||||
this._updateSize();
|
||||
prevent = true;
|
||||
cycling = true;
|
||||
@ -931,30 +918,30 @@ InplaceEditor.prototype = {
|
||||
this._doValidation();
|
||||
}
|
||||
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE ||
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DELETE ||
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_LEFT ||
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DELETE ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_LEFT ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
|
||||
if (this.popup && this.popup.isOpen) {
|
||||
this.popup.hidePopup();
|
||||
}
|
||||
} else if (!cycling && !aEvent.metaKey && !aEvent.altKey && !aEvent.ctrlKey) {
|
||||
} else if (!cycling && !event.metaKey && !event.altKey && !event.ctrlKey) {
|
||||
this._maybeSuggestCompletion();
|
||||
}
|
||||
|
||||
if (this.multiline &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN &&
|
||||
aEvent.shiftKey) {
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN &&
|
||||
event.shiftKey) {
|
||||
prevent = false;
|
||||
} else if (this._advanceChars(aEvent.charCode, this.input.value,
|
||||
this.input.selectionStart)
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN
|
||||
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB) {
|
||||
} else if (this._advanceChars(event.charCode, this.input.value,
|
||||
this.input.selectionStart) ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN ||
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB) {
|
||||
prevent = true;
|
||||
|
||||
let direction = FOCUS_FORWARD;
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
aEvent.shiftKey) {
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
event.shiftKey) {
|
||||
if (this.stopOnShiftTab) {
|
||||
direction = null;
|
||||
} else {
|
||||
@ -962,9 +949,9 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
if ((this.stopOnReturn &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
|
||||
(this.stopOnTab && aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
!aEvent.shiftKey)) {
|
||||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
|
||||
(this.stopOnTab && event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
!event.shiftKey)) {
|
||||
direction = null;
|
||||
}
|
||||
|
||||
@ -979,22 +966,21 @@ InplaceEditor.prototype = {
|
||||
|
||||
let input = this.input;
|
||||
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
this.contentType == CONTENT_TYPES.CSS_MIXED) {
|
||||
if (this.popup && input.selectionStart < input.selectionEnd) {
|
||||
aEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
input.setSelectionRange(input.selectionEnd, input.selectionEnd);
|
||||
this.emit("after-suggest");
|
||||
return;
|
||||
}
|
||||
else if (this.popup && this.popup.isOpen) {
|
||||
aEvent.preventDefault();
|
||||
this._cycleCSSSuggestion(aEvent.shiftKey, true);
|
||||
} else if (this.popup && this.popup.isOpen) {
|
||||
event.preventDefault();
|
||||
this._cycleCSSSuggestion(event.shiftKey, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._apply(aEvent, direction);
|
||||
this._apply(event, direction);
|
||||
|
||||
// Close the popup if open
|
||||
if (this.popup && this.popup.isOpen) {
|
||||
@ -1009,14 +995,14 @@ InplaceEditor.prototype = {
|
||||
// If the next node to be focused has been tagged as an editable
|
||||
// node, trigger editing using the configured event
|
||||
if (next && next.ownerDocument === this.doc && next._editable) {
|
||||
let e = this.doc.createEvent('Event');
|
||||
let e = this.doc.createEvent("Event");
|
||||
e.initEvent(next._trigger, true, true);
|
||||
next.dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
this._clear();
|
||||
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
|
||||
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
|
||||
// Cancel and blur ourselves.
|
||||
// Now we don't want to suggest anything as we are moving out.
|
||||
this._preventSuggestions = true;
|
||||
@ -1028,8 +1014,8 @@ InplaceEditor.prototype = {
|
||||
this.cancelled = true;
|
||||
this._apply();
|
||||
this._clear();
|
||||
aEvent.stopPropagation();
|
||||
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
|
||||
event.stopPropagation();
|
||||
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
|
||||
// No need for leading spaces here. This is particularly
|
||||
// noticable when adding a property: it's very natural to type
|
||||
// <name>: (which advances to the next property) then spacebar.
|
||||
@ -1037,22 +1023,21 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
if (prevent) {
|
||||
aEvent.preventDefault();
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the input field's keyup event.
|
||||
*/
|
||||
_onKeyup: function(aEvent) {
|
||||
_onKeyup: function() {
|
||||
this._applied = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle changes to the input text.
|
||||
*/
|
||||
_onInput: function InplaceEditor_onInput(aEvent)
|
||||
{
|
||||
_onInput: function() {
|
||||
// Validate the entered value.
|
||||
this._doValidation();
|
||||
|
||||
@ -1070,8 +1055,7 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Fire validation callback with current input
|
||||
*/
|
||||
_doValidation: function()
|
||||
{
|
||||
_doValidation: function() {
|
||||
if (this.validate && this.input) {
|
||||
this.validate(this.input.value);
|
||||
}
|
||||
@ -1080,10 +1064,10 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Handles displaying suggestions based on the current input.
|
||||
*
|
||||
* @param {boolean} aNoAutoInsert
|
||||
* @param {Boolean} noAutoInsert
|
||||
* true if you don't want to automatically insert the first suggestion
|
||||
*/
|
||||
_maybeSuggestCompletion: function(aNoAutoInsert) {
|
||||
_maybeSuggestCompletion: function(noAutoInsert) {
|
||||
// Input can be null in cases when you intantaneously switch out of it.
|
||||
if (!this.input) {
|
||||
return;
|
||||
@ -1135,7 +1119,8 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
|
||||
list =
|
||||
["!important", ...domUtils.getCSSValuesForProperty(this.property.name)];
|
||||
["!important",
|
||||
...domUtils.getCSSValuesForProperty(this.property.name)];
|
||||
|
||||
if (query == "") {
|
||||
// Do not suggest '!important' without any manually typed character.
|
||||
@ -1150,7 +1135,8 @@ InplaceEditor.prototype = {
|
||||
let propertyName =
|
||||
query.match(/[;"'=]\s*([^"';:= ]+)\s*:\s*[^"';:=]*$/)[1];
|
||||
list =
|
||||
["!important;", ...domUtils.getCSSValuesForProperty(propertyName)];
|
||||
["!important;",
|
||||
...domUtils.getCSSValuesForProperty(propertyName)];
|
||||
let matchLastQuery = /([^\s,.\/]+$)/.exec(match[2] || "");
|
||||
if (matchLastQuery) {
|
||||
startCheckQuery = matchLastQuery[0];
|
||||
@ -1172,7 +1158,7 @@ InplaceEditor.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!aNoAutoInsert) {
|
||||
if (!noAutoInsert) {
|
||||
list.some(item => {
|
||||
if (startCheckQuery != null && item.startsWith(startCheckQuery)) {
|
||||
input.value = query + item.slice(startCheckQuery.length) +
|
||||
@ -1199,13 +1185,11 @@ InplaceEditor.prototype = {
|
||||
preLabel: startCheckQuery,
|
||||
label: list[i]
|
||||
});
|
||||
}
|
||||
else if (count > 0) {
|
||||
} else if (count > 0) {
|
||||
// Since count was incremented, we had already crossed the entries
|
||||
// which would have started with query, assuming that list is sorted.
|
||||
break;
|
||||
}
|
||||
else if (startCheckQuery != null && list[i][0] > startCheckQuery[0]) {
|
||||
} else if (startCheckQuery != null && list[i][0] > startCheckQuery[0]) {
|
||||
// We have crossed all possible matches alphabetically.
|
||||
break;
|
||||
}
|
||||
@ -1217,7 +1201,7 @@ InplaceEditor.prototype = {
|
||||
this.inputCharWidth;
|
||||
this.popup.setItems(finalList);
|
||||
this.popup.openPopup(this.input, x);
|
||||
if (aNoAutoInsert) {
|
||||
if (noAutoInsert) {
|
||||
this.popup.selectedIndex = -1;
|
||||
}
|
||||
} else {
|
||||
@ -1233,25 +1217,22 @@ InplaceEditor.prototype = {
|
||||
/**
|
||||
* Copy text-related styles from one element to another.
|
||||
*/
|
||||
function copyTextStyles(aFrom, aTo)
|
||||
{
|
||||
let win = aFrom.ownerDocument.defaultView;
|
||||
let style = win.getComputedStyle(aFrom);
|
||||
aTo.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
|
||||
aTo.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
|
||||
aTo.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
|
||||
aTo.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
|
||||
function copyTextStyles(from, to) {
|
||||
let win = from.ownerDocument.defaultView;
|
||||
let style = win.getComputedStyle(from);
|
||||
to.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
|
||||
to.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
|
||||
to.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
|
||||
to.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a focus change similar to pressing tab/shift-tab.
|
||||
*/
|
||||
function moveFocus(aWin, aDirection)
|
||||
{
|
||||
return focusManager.moveFocus(aWin, null, aDirection, 0);
|
||||
function moveFocus(win, direction) {
|
||||
return focusManager.moveFocus(win, null, direction, 0);
|
||||
}
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "focusManager", function() {
|
||||
return Services.focus;
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user