Chromium Code Reviews| 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..bc4996bebd448487c0ffc4b4e2c2d761dc230c19 |
| --- /dev/null |
| +++ b/chrome/browser/resources/options/inline_editable_list.js |
| @@ -0,0 +1,237 @@ |
| +// 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); |
| + |
| + var listItem = this; |
| + |
| + this.addEventListener('selectedChange', function(event) { |
|
arv (Not doing code reviews)
2011/01/11 21:52:45
You should be able to override the selected setter
stuartmorgan
2011/01/11 23:18:41
Actually, I discovered that there's already a sele
|
| + if (listItem.editable) |
| + listItem.editing = listItem.selected; |
| + }); |
| + |
| + this.addEventListener('keydown', this.handleKeyDown_.bind(this)); |
| + }, |
| + |
| + /** |
| + * 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'); |
| + |
| + |
|
Evan Stade
2011/01/11 21:06:01
remove extra line
stuartmorgan
2011/01/11 23:18:41
Done.
|
| + if (editing) { |
| + this.editCancelled_ = false; |
| + |
| + this.onEditStarted(); |
|
arv (Not doing code reviews)
2011/01/11 21:52:45
cr.dispatchEvent
stuartmorgan
2011/01/11 23:18:41
Done, for all three onEdit* calls.
|
| + |
| + 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()) |
|
Evan Stade
2011/01/11 21:06:01
curlies for multi-line conditional
stuartmorgan
2011/01/11 23:18:41
Done.
|
| + this.onEditCommitted(); |
| + else |
| + this.onEditCancelled(); |
| + } |
| + }, |
| + |
| + /** |
| + * Whether the item is editable. |
| + * @type {boolean} |
| + */ |
| + get editable() { |
| + return this.editable_; |
| + }, |
| + set editable(editable) { |
| + this.editable_ = editable; |
| + if (!editable) |
| + this.editing = false; |
| + }, |
| + |
| + /** |
| + * Returns the HTML element that should have focus initially when editing |
| + * starts. |
| + * Should be overriden by subclasses. |
| + * @return {HTMLElement} The element to focus when editing starts |
| + */ |
| + initialFocusElement: function() { |
|
arv (Not doing code reviews)
2011/01/11 21:52:45
Use getter?
stuartmorgan
2011/01/11 23:18:41
Done.
|
| + return null; |
| + }, |
| + |
| + /** |
| + * Returns true if 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. |
| + */ |
| + currentInputIsValid: function() { |
|
arv (Not doing code reviews)
2011/01/11 21:52:45
use getter?
stuartmorgan
2011/01/11 23:18:41
Done.
|
| + 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 when editing mode starts. |
| + * Can be overridden by subclasses to do any pre-edit tasks. |
| + */ |
| + onEditStarted: function() { |
| + }, |
| + |
| + /** |
| + * Called when editing mode ends without cancelling. |
| + * Should be overridden by subclasses to do any post-edit tasks, such as |
| + * commiting the change. |
| + */ |
| + onEditCommitted: function() { |
| + }, |
| + |
| + /** |
| + * Called when editing mode is cancelled. |
| + * Should be overridden by subclasses to do any post-cancellation tasks, |
| + * such as undoing changes to the editable controls. |
| + */ |
| + onEditCancelled: function() { |
| + }, |
| + |
| + /** |
| + * 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, |
| + }; |
| + |
|
Evan Stade
2011/01/11 21:06:01
extra line here and at eof
stuartmorgan
2011/01/11 23:18:41
Done.
|
| +}); |
| + |