blob: 11c1bf0b87bb7d9053abd5e980c0277965b16ac6 [file] [log] [blame]
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.GeneralTreeElement = function(classNames, title, subtitle, representedObject, hasChildren)
{
TreeElement.call(this, "", representedObject, hasChildren);
this.classNames = classNames;
this._tooltipHandledSeparately = false;
this._mainTitle = title || "";
this._subtitle = subtitle || "";
this._status = "";
}
WebInspector.GeneralTreeElement.StyleClassName = "item";
WebInspector.GeneralTreeElement.DisclosureButtonStyleClassName = "disclosure-button";
WebInspector.GeneralTreeElement.IconElementStyleClassName = "icon";
WebInspector.GeneralTreeElement.StatusElementStyleClassName = "status";
WebInspector.GeneralTreeElement.TitlesElementStyleClassName = "titles";
WebInspector.GeneralTreeElement.MainTitleElementStyleClassName = "title";
WebInspector.GeneralTreeElement.SubtitleElementStyleClassName = "subtitle";
WebInspector.GeneralTreeElement.NoSubtitleStyleClassName = "no-subtitle";
WebInspector.GeneralTreeElement.SmallStyleClassName = "small";
WebInspector.GeneralTreeElement.TwoLineStyleClassName = "two-line";
WebInspector.GeneralTreeElement.Event = {
MainTitleDidChange: "general-tree-element-main-title-did-change"
};
WebInspector.GeneralTreeElement.prototype = {
constructor: WebInspector.GeneralTreeElement,
// Public
get element()
{
return this._listItemNode;
},
get disclosureButton()
{
this._createElementsIfNeeded();
return this._disclosureButton;
},
get iconElement()
{
this._createElementsIfNeeded();
return this._iconElement;
},
get titlesElement()
{
this._createElementsIfNeeded();
return this._titlesElement;
},
get mainTitleElement()
{
this._createElementsIfNeeded();
return this._mainTitleElement;
},
get subtitleElement()
{
this._createElementsIfNeeded();
this._createSubtitleElementIfNeeded();
return this._subtitleElement;
},
get classNames()
{
return this._classNames;
},
set classNames(x)
{
if (this._listItemNode && this._classNames) {
for (var i = 0; i < this._classNames.length; ++i)
this._listItemNode.classList.remove(this._classNames[i]);
}
if (typeof x === "string")
x = [x];
this._classNames = x || [];
if (this._listItemNode) {
for (var i = 0; i < this._classNames.length; ++i)
this._listItemNode.classList.add(this._classNames[i]);
}
},
addClassName: function(className)
{
if (this._classNames.contains(className))
return;
this._classNames.push(className);
if (this._listItemNode)
this._listItemNode.classList.add(className);
},
removeClassName: function(className)
{
if (!this._classNames.contains(className))
return;
this._classNames.remove(className);
if (this._listItemNode)
this._listItemNode.classList.remove(className);
},
get small()
{
return this._small;
},
set small(x)
{
this._small = x;
if (this._listItemNode) {
if (this._small)
this._listItemNode.classList.add(WebInspector.GeneralTreeElement.SmallStyleClassName);
else
this._listItemNode.classList.remove(WebInspector.GeneralTreeElement.SmallStyleClassName);
}
},
get twoLine()
{
return this._twoLine;
},
set twoLine(x)
{
this._twoLine = x;
if (this._listItemNode) {
if (this._twoLine)
this._listItemNode.classList.add(WebInspector.GeneralTreeElement.TwoLineStyleClassName);
else
this._listItemNode.classList.remove(WebInspector.GeneralTreeElement.TwoLineStyleClassName);
}
},
get mainTitle()
{
return this._mainTitle;
},
set mainTitle(x)
{
this._mainTitle = x || "";
this._updateTitleElements();
this.didChange();
this.dispatchEventToListeners(WebInspector.GeneralTreeElement.Event.MainTitleDidChange);
},
get subtitle()
{
return this._subtitle;
},
set subtitle(x)
{
this._subtitle = x || "";
this._updateTitleElements();
this.didChange();
},
get status()
{
return this._status;
},
set status(x)
{
this._status = x || "";
this._updateStatusElement();
},
get filterableData()
{
return {text: [this.mainTitle, this.subtitle]};
},
get tooltipHandledSeparately()
{
return this._tooltipHandledSeparately;
},
set tooltipHandledSeparately(x)
{
this._tooltipHandledSeparately = x || false;
},
// Overrides from TreeElement (Private)
isEventWithinDisclosureTriangle: function(event)
{
return event.target === this._disclosureButton;
},
onattach: function()
{
this._createElementsIfNeeded();
this._updateTitleElements();
this._updateStatusElement();
this._listItemNode.classList.add(WebInspector.GeneralTreeElement.StyleClassName);
if (this._classNames) {
for (var i = 0; i < this._classNames.length; ++i)
this._listItemNode.classList.add(this._classNames[i]);
}
if (this._small)
this._listItemNode.classList.add(WebInspector.GeneralTreeElement.SmallStyleClassName);
if (this._twoLine)
this._listItemNode.classList.add(WebInspector.GeneralTreeElement.TwoLineStyleClassName);
this._listItemNode.appendChild(this._disclosureButton);
this._listItemNode.appendChild(this._iconElement);
this._listItemNode.appendChild(this._statusElement);
this._listItemNode.appendChild(this._titlesElement);
if (this.oncontextmenu && typeof this.oncontextmenu === "function") {
this._boundContextMenuEventHandler = this.oncontextmenu.bind(this);
this._listItemNode.addEventListener("contextmenu", this._boundContextMenuEventHandler, true);
}
if (!this._boundContextMenuEventHandler && this.treeOutline.oncontextmenu && typeof this.treeOutline.oncontextmenu === "function") {
this._boundContextMenuEventHandler = function(event) { this.treeOutline.oncontextmenu(event, this); }.bind(this);
this._listItemNode.addEventListener("contextmenu", this._boundContextMenuEventHandler, true);
}
},
ondetach: function()
{
if (this._boundContextMenuEventHandler) {
this._listItemNode.removeEventListener("contextmenu", this._boundContextMenuEventHandler, true);
delete this._boundContextMenuEventHandler;
}
},
onreveal: function()
{
if (this._listItemNode)
this._listItemNode.scrollIntoViewIfNeeded(false);
},
// Protected
callFirstAncestorFunction: function(functionName, args)
{
// Call the first ancestor that implements a function named functionName (if any).
var currentNode = this.parent;
while (currentNode) {
if (typeof currentNode[functionName] === "function") {
currentNode[functionName].apply(currentNode, args);
break;
}
currentNode = currentNode.parent;
}
},
// Private
_createElementsIfNeeded: function()
{
if (this._createdElements)
return;
this._disclosureButton = document.createElement("button");
this._disclosureButton.className = WebInspector.GeneralTreeElement.DisclosureButtonStyleClassName;
// Don't allow the disclosure button to be keyboard focusable. The TreeOutline is focusable and has
// its own keybindings for toggling expand and collapse.
this._disclosureButton.tabIndex = -1;
this._iconElement = document.createElement("img");
this._iconElement.className = WebInspector.GeneralTreeElement.IconElementStyleClassName;
this._statusElement = document.createElement("div");
this._statusElement.className = WebInspector.GeneralTreeElement.StatusElementStyleClassName;
this._titlesElement = document.createElement("div");
this._titlesElement.className = WebInspector.GeneralTreeElement.TitlesElementStyleClassName;
this._mainTitleElement = document.createElement("span");
this._mainTitleElement.className = WebInspector.GeneralTreeElement.MainTitleElementStyleClassName;
this._titlesElement.appendChild(this._mainTitleElement);
this._createdElements = true;
},
_createSubtitleElementIfNeeded: function()
{
if (this._subtitleElement)
return;
this._subtitleElement = document.createElement("span");
this._subtitleElement.className = WebInspector.GeneralTreeElement.SubtitleElementStyleClassName;
this._titlesElement.appendChild(this._subtitleElement);
},
_updateTitleElements: function()
{
if (!this._createdElements)
return;
if (typeof this._mainTitle === "string") {
if (this._mainTitleElement.textContent !== this._mainTitle)
this._mainTitleElement.textContent = this._mainTitle;
} else if (this._mainTitle instanceof Node) {
this._mainTitleElement.removeChildren();
this._mainTitleElement.appendChild(this._mainTitle);
}
if (typeof this._subtitle === "string" && this._subtitle) {
this._createSubtitleElementIfNeeded();
if (this._subtitleElement.textContent !== this._subtitle)
this._subtitleElement.textContent = this._subtitle;
this._titlesElement.classList.remove(WebInspector.GeneralTreeElement.NoSubtitleStyleClassName);
} else if (this._subtitle instanceof Node) {
this._createSubtitleElementIfNeeded();
this._subtitleElement.removeChildren();
this._subtitleElement.appendChild(this._subtitle);
} else {
if (this._subtitleElement)
this._subtitleElement.textContent = "";
this._titlesElement.classList.add(WebInspector.GeneralTreeElement.NoSubtitleStyleClassName);
}
// Set a default tooltip if there isn't a custom one already assigned.
if (!this.tooltip && !this._tooltipHandledSeparately) {
console.assert(this._listItemNode);
// Get the textContent for the elements since they can contain other nodes,
// and the tool tip only cares about the text.
var mainTitleText = this._mainTitleElement.textContent;
var subtitleText = this._subtitleElement ? this._subtitleElement.textContent : "";
if (mainTitleText && subtitleText)
this._listItemNode.title = mainTitleText + (this._small && !this._twoLine ? " \u2014 " : "\n") + subtitleText;
else if (mainTitleText)
this._listItemNode.title = mainTitleText;
else
this._listItemNode.title = subtitleText;
}
},
_updateStatusElement: function()
{
if (!this._createdElements)
return;
if (this._status instanceof Node) {
this._statusElement.removeChildren();
this._statusElement.appendChild(this._status);
} else
this._statusElement.textContent = this._status;
}
}
WebInspector.GeneralTreeElement.prototype.__proto__ = TreeElement.prototype;