diff options
Diffstat (limited to 'devtools/client/shared/widgets/SimpleListWidget.jsm')
-rw-r--r-- | devtools/client/shared/widgets/SimpleListWidget.jsm | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/devtools/client/shared/widgets/SimpleListWidget.jsm b/devtools/client/shared/widgets/SimpleListWidget.jsm new file mode 100644 index 000000000..ec47ab0da --- /dev/null +++ b/devtools/client/shared/widgets/SimpleListWidget.jsm @@ -0,0 +1,255 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript 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/. */ +"use strict"; + +const Ci = Components.interfaces; +const Cu = Components.utils; + +const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); +const { ViewHelpers } = require("devtools/client/shared/widgets/view-helpers"); + +this.EXPORTED_SYMBOLS = ["SimpleListWidget"]; + +/** + * A very simple vertical list view. + * + * Note: this widget should be used in tandem with the WidgetMethods in + * view-helpers.js. + * + * @param nsIDOMNode aNode + * The element associated with the widget. + */ +function SimpleListWidget(aNode) { + this.document = aNode.ownerDocument; + this.window = this.document.defaultView; + this._parent = aNode; + + // Create an internal list container. + this._list = this.document.createElement("scrollbox"); + this._list.className = "simple-list-widget-container theme-body"; + this._list.setAttribute("flex", "1"); + this._list.setAttribute("orient", "vertical"); + this._parent.appendChild(this._list); + + // Delegate some of the associated node's methods to satisfy the interface + // required by WidgetMethods instances. + ViewHelpers.delegateWidgetAttributeMethods(this, aNode); + ViewHelpers.delegateWidgetEventMethods(this, aNode); +} +this.SimpleListWidget = SimpleListWidget; + +SimpleListWidget.prototype = { + /** + * Inserts an item in this container at the specified index. + * + * @param number aIndex + * The position in the container intended for this item. + * @param nsIDOMNode aContents + * The node displayed in the container. + * @return nsIDOMNode + * The element associated with the displayed item. + */ + insertItemAt: function (aIndex, aContents) { + aContents.classList.add("simple-list-widget-item"); + + let list = this._list; + return list.insertBefore(aContents, list.childNodes[aIndex]); + }, + + /** + * Returns the child node in this container situated at the specified index. + * + * @param number aIndex + * The position in the container intended for this item. + * @return nsIDOMNode + * The element associated with the displayed item. + */ + getItemAtIndex: function (aIndex) { + return this._list.childNodes[aIndex]; + }, + + /** + * Immediately removes the specified child node from this container. + * + * @param nsIDOMNode aChild + * The element associated with the displayed item. + */ + removeChild: function (aChild) { + this._list.removeChild(aChild); + + if (this._selectedItem == aChild) { + this._selectedItem = null; + } + }, + + /** + * Removes all of the child nodes from this container. + */ + removeAllItems: function () { + let list = this._list; + let parent = this._parent; + + while (list.hasChildNodes()) { + list.firstChild.remove(); + } + + parent.scrollTop = 0; + parent.scrollLeft = 0; + this._selectedItem = null; + }, + + /** + * Gets the currently selected child node in this container. + * @return nsIDOMNode + */ + get selectedItem() { + return this._selectedItem; + }, + + /** + * Sets the currently selected child node in this container. + * @param nsIDOMNode aChild + */ + set selectedItem(aChild) { + let childNodes = this._list.childNodes; + + if (!aChild) { + this._selectedItem = null; + } + for (let node of childNodes) { + if (node == aChild) { + node.classList.add("selected"); + this._selectedItem = node; + } else { + node.classList.remove("selected"); + } + } + }, + + /** + * Adds a new attribute or changes an existing attribute on this container. + * + * @param string aName + * The name of the attribute. + * @param string aValue + * The desired attribute value. + */ + setAttribute: function (aName, aValue) { + this._parent.setAttribute(aName, aValue); + + if (aName == "emptyText") { + this._textWhenEmpty = aValue; + } else if (aName == "headerText") { + this._textAsHeader = aValue; + } + }, + + /** + * Removes an attribute on this container. + * + * @param string aName + * The name of the attribute. + */ + removeAttribute: function (aName) { + this._parent.removeAttribute(aName); + + if (aName == "emptyText") { + this._removeEmptyText(); + } + }, + + /** + * Ensures the specified element is visible. + * + * @param nsIDOMNode aElement + * The element to make visible. + */ + ensureElementIsVisible: function (aElement) { + if (!aElement) { + return; + } + + // Ensure the element is visible but not scrolled horizontally. + let boxObject = this._list.boxObject; + boxObject.ensureElementIsVisible(aElement); + boxObject.scrollBy(-this._list.clientWidth, 0); + }, + + /** + * Sets the text displayed permanently in this container as a header. + * @param string aValue + */ + set _textAsHeader(aValue) { + if (this._headerTextNode) { + this._headerTextNode.setAttribute("value", aValue); + } + this._headerTextValue = aValue; + this._showHeaderText(); + }, + + /** + * Sets the text displayed in this container when empty. + * @param string aValue + */ + set _textWhenEmpty(aValue) { + if (this._emptyTextNode) { + this._emptyTextNode.setAttribute("value", aValue); + } + this._emptyTextValue = aValue; + this._showEmptyText(); + }, + + /** + * Creates and appends a label displayed as this container's header. + */ + _showHeaderText: function () { + if (this._headerTextNode || !this._headerTextValue) { + return; + } + let label = this.document.createElement("label"); + label.className = "plain simple-list-widget-perma-text"; + label.setAttribute("value", this._headerTextValue); + + this._parent.insertBefore(label, this._list); + this._headerTextNode = label; + }, + + /** + * Creates and appends a label signaling that this container is empty. + */ + _showEmptyText: function () { + if (this._emptyTextNode || !this._emptyTextValue) { + return; + } + let label = this.document.createElement("label"); + label.className = "plain simple-list-widget-empty-text"; + label.setAttribute("value", this._emptyTextValue); + + this._parent.appendChild(label); + this._emptyTextNode = label; + }, + + /** + * Removes the label signaling that this container is empty. + */ + _removeEmptyText: function () { + if (!this._emptyTextNode) { + return; + } + this._parent.removeChild(this._emptyTextNode); + this._emptyTextNode = null; + }, + + window: null, + document: null, + _parent: null, + _list: null, + _selectedItem: null, + _headerTextNode: null, + _headerTextValue: "", + _emptyTextNode: null, + _emptyTextValue: "" +}; |