text: /*
   * 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.
   */
  
  WI.GeneralTreeElement = class GeneralTreeElement extends WI.TreeElement
  {
      constructor(classNames, title, subtitle, representedObject, options)
      {
          super("", representedObject, options);
  
          this.classNames = classNames;
  
          this._tooltipHandledSeparately = false;
          this._mainTitle = title || "";
          this._subtitle = subtitle || "";
          this._status = "";
      }
  
      // Public
  
      get element()
      {
          return this._listItemNode;
      }
  
      get iconElement()
      {
          this._createElementsIfNeeded();
          return this._iconElement;
      }
  
      get statusElement()
      {
          return this._statusElement;
      }
  
      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)
      {
          x = x || [];
  
          if (typeof x === "string")
              x = [x];
  
          if (Array.shallowEqual(this._classNames, x))
              return;
  
          if (this._listItemNode && this._classNames)
              this._listItemNode.classList.remove(...this._classNames);
  
          this._classNames = x;
  
          if (this._listItemNode)
              this._listItemNode.classList.add(...this._classNames);
      }
  
      addClassName(className)
      {
          if (this._classNames.includes(className))
              return;
  
          this._classNames.push(className);
  
          if (this._listItemNode)
              this._listItemNode.classList.add(className);
      }
  
      removeClassName(className)
      {
          if (!this._classNames.includes(className))
              return;
  
          this._classNames.remove(className);
  
          if (this._listItemNode)
              this._listItemNode.classList.remove(className);
      }
  
      get mainTitle()
      {
          return this._mainTitle;
      }
  
      set mainTitle(x)
      {
          x = x || "";
  
          if (this._mainTitle === x)
              return;
  
          this._mainTitle = x;
          this._updateTitleElements();
          this.didChange();
          this.dispatchEventToListeners(WI.GeneralTreeElement.Event.MainTitleDidChange);
      }
  
      get subtitle()
      {
          return this._subtitle;
      }
  
      set subtitle(x)
      {
          x = x || "";
  
          if (this._subtitle === x)
              return;
  
          this._subtitle = x;
          this._updateTitleElements();
          this.didChange();
      }
  
      get status()
      {
          return this._status;
      }
  
      set status(x)
      {
          x = x || "";
  
          if (this._status === x)
              return;
  
          if (!this._statusElement) {
              this._statusElement = document.createElement("div");
              this._statusElement.className = WI.GeneralTreeElement.StatusElementStyleClassName;
          }
  
          this._status = x;
          this._updateStatusElement();
      }
  
      get filterableData()
      {
          return {text: [this.mainTitle, this.subtitle]};
      }
  
      get tooltipHandledSeparately()
      {
          return this._tooltipHandledSeparately;
      }
  
      set tooltipHandledSeparately(x)
      {
          this._tooltipHandledSeparately = !!x;
      }
  
      createFoldersAsNeededForSubpath(subpath)
      {
          if (!subpath)
              return this;
  
          let components = subpath.split("/");
          if (components.length === 1)
              return this;
  
          if (!this._subpathFolderTreeElementMap)
              this._subpathFolderTreeElementMap = new Map;
  
          let currentPath = "";
          let currentFolderTreeElement = this;
  
          for (let component of components) {
              if (component === components.lastValue)
                  break;
  
              if (currentPath)
                  currentPath += "/";
              currentPath += component;
  
              let cachedFolder = this._subpathFolderTreeElementMap.get(currentPath);
              if (cachedFolder) {
                  currentFolderTreeElement = cachedFolder;
                  continue;
              }
  
              let newFolder = new WI.FolderTreeElement(component);
              this._subpathFolderTreeElementMap.set(currentPath, newFolder);
  
              let index = insertionIndexForObjectInListSortedByFunction(newFolder, currentFolderTreeElement.children, WI.ResourceTreeElement.compareFolderAndResourceTreeElements);
              currentFolderTreeElement.insertChild(newFolder, index);
              currentFolderTreeElement = newFolder;
          }
  
          return currentFolderTreeElement;
      }
  
      // Overrides from TreeElement (Private)
  
      isEventWithinDisclosureTriangle(event)
      {
          return event.target === this._disclosureButton;
      }
  
      onattach()
      {
          this._createElementsIfNeeded();
          this._updateTitleElements();
  
          this._listItemNode.classList.add("item");
  
          if (this._classNames)
              this._listItemNode.classList.add(...this._classNames);
  
          this._listItemNode.appendChild(this._disclosureButton);
          this._listItemNode.appendChild(this._iconElement);
          if (this._statusElement)
              this._listItemNode.appendChild(this._statusElement);
          this._listItemNode.appendChild(this._titlesElement);
      }
  
      ondetach()
      {
          // Overridden by subclasses.
      }
  
      onreveal()
      {
          if (this._listItemNode)
              this._listItemNode.scrollIntoViewIfNeeded(false);
      }
  
      // Protected
  
      callFirstAncestorFunction(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;
          }
      }
  
      customTitleTooltip()
      {
          // Implemented by subclasses.
      }
  
      // Private
  
      _createElementsIfNeeded()
      {
          if (this._createdElements)
              return;
  
          this._disclosureButton = document.createElement("button");
          this._disclosureButton.className = WI.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 = WI.GeneralTreeElement.IconElementStyleClassName;
  
          this._titlesElement = document.createElement("div");
          this._titlesElement.className = WI.GeneralTreeElement.TitlesElementStyleClassName;
  
          this._mainTitleElement = document.createElement("span");
          this._mainTitleElement.className = WI.GeneralTreeElement.MainTitleElementStyleClassName;
          this._titlesElement.appendChild(this._mainTitleElement);
  
          this._createdElements = true;
      }
  
      _createSubtitleElementIfNeeded()
      {
          if (this._subtitleElement)
              return;
  
          this._subtitleElement = document.createElement("span");
          this._subtitleElement.className = WI.GeneralTreeElement.SubtitleElementStyleClassName;
          this._titlesElement.appendChild(this._subtitleElement);
      }
  
      _updateTitleElements()
      {
          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(WI.GeneralTreeElement.NoSubtitleStyleClassName);
          } else if (this._subtitle instanceof Node) {
              this._createSubtitleElementIfNeeded();
              this._subtitleElement.removeChildren();
              this._subtitleElement.appendChild(this._subtitle);
              this._titlesElement.classList.remove(WI.GeneralTreeElement.NoSubtitleStyleClassName);
          } else {
              if (this._subtitleElement)
                  this._subtitleElement.textContent = "";
              this._titlesElement.classList.add(WI.GeneralTreeElement.NoSubtitleStyleClassName);
          }
  
          // Set a default tooltip if there isn't a custom one already assigned.
          if (!this.tooltip && !this._tooltipHandledSeparately)
              this._updateTitleTooltip();
      }
  
      _updateTitleTooltip()
      {
          console.assert(this._listItemNode);
          if (!this._listItemNode)
              return;
  
          let tooltip = this.customTitleTooltip();
          if (!tooltip) {
              // Get the textContent for the elements since they can contain other nodes,
              // and the tool tip only cares about the text.
              let mainTitleText = this._mainTitleElement.textContent;
              let subtitleText = this._subtitleElement ? this._subtitleElement.textContent : "";
              let large = this.treeOutline && this.treeOutline.large;
              if (mainTitleText && subtitleText)
                  tooltip = mainTitleText + (large ? "\n" : " \u2014 ") + subtitleText;
              else if (mainTitleText)
                  tooltip = mainTitleText;
              else
                  tooltip = subtitleText;
          }
  
          this._listItemNode.title = tooltip;
      }
  
      _updateStatusElement()
      {
          if (!this._statusElement)
              return;
  
          if (!this._statusElement.parentNode && this._listItemNode)
              this._listItemNode.insertBefore(this._statusElement, this._titlesElement);
  
          if (this._status instanceof Node) {
              this._statusElement.removeChildren();
              this._statusElement.appendChild(this._status);
          } else
              this._statusElement.textContent = this._status;
      }
  };
  
  WI.GeneralTreeElement.DisclosureButtonStyleClassName = "disclosure-button";
  WI.GeneralTreeElement.IconElementStyleClassName = "icon";
  WI.GeneralTreeElement.StatusElementStyleClassName = "status";
  WI.GeneralTreeElement.TitlesElementStyleClassName = "titles";
  WI.GeneralTreeElement.MainTitleElementStyleClassName = "title";
  WI.GeneralTreeElement.SubtitleElementStyleClassName = "subtitle";
  WI.GeneralTreeElement.NoSubtitleStyleClassName = "no-subtitle";
  
  WI.GeneralTreeElement.Event = {
      MainTitleDidChange: "general-tree-element-main-title-did-change"
  };
  