| Index: chrome/browser/resources/options/inline_editable_list.js
|
| diff --git a/chrome/browser/resources/options/inline_editable_list.js b/chrome/browser/resources/options/inline_editable_list.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ec0f4a472628a9ddb6bce505b682313f4a722479
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/options/inline_editable_list.js
|
| @@ -0,0 +1,210 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +cr.define('options', function() {
|
| + const DeletableItem = options.DeletableItem;
|
| + const DeletableItemList = options.DeletableItemList;
|
| +
|
| + /**
|
| + * Creates a new list item with support for inline editing.
|
| + * @constructor
|
| + * @extends {options.DeletableListItem}
|
| + */
|
| + function InlineEditableItem() {
|
| + var el = cr.doc.createElement('div');
|
| + InlineEditableItem.decorate(el);
|
| + return el;
|
| + }
|
| +
|
| + /**
|
| + * Decorates an element as a inline-editable list item. Note that this is
|
| + * a subclass of DeletableItem.
|
| + * @param {!HTMLElement} el The element to decorate.
|
| + */
|
| + InlineEditableItem.decorate = function(el) {
|
| + el.__proto__ = InlineEditableItem.prototype;
|
| + el.decorate();
|
| + };
|
| +
|
| + InlineEditableItem.prototype = {
|
| + __proto__: DeletableItem.prototype,
|
| +
|
| + /**
|
| + * Whether or not this item can be edited.
|
| + * @type {boolean}
|
| + * @private
|
| + */
|
| + editable_: true,
|
| +
|
| + /**
|
| + * Whether or not the current edit should be considered cancelled, rather
|
| + * than committed, when editing ends.
|
| + * @type {boolean}
|
| + * @private
|
| + */
|
| + editCancelled_: true,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + DeletableItem.prototype.decorate.call(this);
|
| +
|
| + this.addEventListener('keydown', this.handleKeyDown_.bind(this));
|
| + },
|
| +
|
| + /** @inheritDoc */
|
| + selectionChanged: function() {
|
| + if (this.editable)
|
| + this.editing = this.selected;
|
| + },
|
| +
|
| + /**
|
| + * Whether the user is currently editing the list item.
|
| + * @type {boolean}
|
| + */
|
| + get editing() {
|
| + return this.hasAttribute('editing');
|
| + },
|
| + set editing(editing) {
|
| + if (this.editing == editing)
|
| + return;
|
| +
|
| + if (editing)
|
| + this.setAttribute('editing', '');
|
| + else
|
| + this.removeAttribute('editing');
|
| +
|
| + if (editing) {
|
| + this.editCancelled_ = false;
|
| +
|
| + cr.dispatchSimpleEvent(this, 'edit', true);
|
| +
|
| + var focusElement = this.initialFocusElement;
|
| + // When this is called in response to the selectedChange event,
|
| + // the list grabs focus immediately afterwards. Thus we must delay
|
| + // our focus grab.
|
| + if (focusElement) {
|
| + window.setTimeout(function() {
|
| + focusElement.focus();
|
| + focusElement.select();
|
| + }, 50);
|
| + }
|
| + } else {
|
| + if (!this.editCancelled_ && this.hasBeenEdited() &&
|
| + this.currentInputIsValid) {
|
| + cr.dispatchSimpleEvent(this, 'commitedit', true);
|
| + } else {
|
| + cr.dispatchSimpleEvent(this, 'canceledit', true);
|
| + }
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Whether the item is editable.
|
| + * @type {boolean}
|
| + */
|
| + get editable() {
|
| + return this.editable_;
|
| + },
|
| + set editable(editable) {
|
| + this.editable_ = editable;
|
| + if (!editable)
|
| + this.editing = false;
|
| + },
|
| +
|
| + /**
|
| + * The HTML element that should have focus initially when editing starts.
|
| + * Should be overriden by subclasses.
|
| + * @type {HTMLElement}
|
| + */
|
| + get initialFocusElement() {
|
| + return null;
|
| + },
|
| +
|
| + /**
|
| + * Whether the input in currently valid to submit. If this returns false
|
| + * when editing would be submitted, either editing will not be ended,
|
| + * or it will be cancelled, depending on the context.
|
| + * Can be overrided by subclasses to perform input validation.
|
| + */
|
| + get currentInputIsValid() {
|
| + return true;
|
| + },
|
| +
|
| + /**
|
| + * Returns true if the item has been changed by an edit.
|
| + * Can be overrided by subclasses to return false when nothing has changed
|
| + * to avoid unnecessary commits.
|
| + */
|
| + hasBeenEdited: function() {
|
| + return true;
|
| + },
|
| +
|
| + /**
|
| + * Called a key is pressed. Handles committing and cancelling edits.
|
| + * @param {Event} e The key down event.
|
| + * @private
|
| + */
|
| + handleKeyDown_: function(e) {
|
| + if (!this.editing)
|
| + return;
|
| +
|
| + var endEdit = false;
|
| + switch (e.keyIdentifier) {
|
| + case 'U+001B': // Esc
|
| + this.editCancelled_ = true;
|
| + endEdit = true;
|
| + break;
|
| + case 'Enter':
|
| + if (this.currentInputIsValid)
|
| + endEdit = true;
|
| + break;
|
| + }
|
| +
|
| + if (endEdit) {
|
| + // Blurring will trigger the edit to end; see InlineEditableItemList.
|
| + this.ownerDocument.activeElement.blur();
|
| + // Make sure that handled keys aren't passed on and double-handled.
|
| + // (e.g., esc shouldn't both cancel an edit and close a subpage)
|
| + e.stopPropagation();
|
| + }
|
| + },
|
| + };
|
| +
|
| + var InlineEditableItemList = cr.ui.define('list');
|
| +
|
| + InlineEditableItemList.prototype = {
|
| + __proto__: DeletableItemList.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + DeletableItemList.prototype.decorate.call(this);
|
| + this.addEventListener('blur', this.handleBlur_.bind(this), true);
|
| + },
|
| +
|
| + /**
|
| + * Called when an element in the list is blurred. Removes selection (thus
|
| + * ending edit) if focus moves outside the list.
|
| + * @param {Event} e The blur event.
|
| + * @private
|
| + */
|
| + handleBlur_: function(e) {
|
| + // When the blur event happens we do not know who is getting focus so we
|
| + // delay this a bit until we know if the new focus node is outside the
|
| + // list.
|
| + var list = this;
|
| + var doc = e.target.ownerDocument;
|
| + window.setTimeout(function() {
|
| + var activeElement = doc.activeElement;
|
| + if (!list.contains(activeElement))
|
| + list.selectionModel.unselectAll();
|
| + }, 50);
|
| + },
|
| + };
|
| +
|
| + // Export
|
| + return {
|
| + InlineEditableItem: InlineEditableItem,
|
| + InlineEditableItemList: InlineEditableItemList,
|
| + };
|
| +});
|
|
|