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.
|
+}); |
+ |