home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 June / PersonalComputerWorld-June2009-CoverdiscCD.iso / Software / Freeware / Firebug 1.3.3 / firebug-1.3.3-fx.xpi / content / firebug / insideOutBox.js < prev    next >
Encoding:
JavaScript  |  2009-02-19  |  12.5 KB  |  441 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. /**
  6.  * Creates a tree based on objects provided by a separate "view" object.
  7.  *
  8.  * Construction uses an "inside-out" algorithm, meaning that the view's job is first
  9.  * to tell us the ancestry of each object, and secondarily its descendants.
  10.  */
  11. top.InsideOutBox = function(view, box)
  12. {
  13.     this.view = view;
  14.     this.box = box;
  15.  
  16.     this.rootObject = null;
  17.  
  18.     this.rootObjectBox = null;
  19.     this.selectedObjectBox = null;
  20.     this.highlightedObjectBox = null;
  21.  
  22.     this.onMouseDown = bind(this.onMouseDown, this);
  23.     box.addEventListener("mousedown", this.onMouseDown, false);
  24. };
  25.  
  26. InsideOutBox.prototype =
  27. {
  28.     destroy: function()
  29.     {
  30.         this.box.removeEventListener("mousedown", this.onMouseDown, false);
  31.     },
  32.  
  33.     highlight: function(object)
  34.     {
  35.         var objectBox = this.createObjectBox(object);
  36.         this.highlightObjectBox(objectBox);
  37.         return objectBox;
  38.     },
  39.  
  40.     openObject: function(object)
  41.     {
  42.         var firstChild = this.view.getChildObject(object, 0);
  43.         if (firstChild)
  44.             object = firstChild;
  45.  
  46.         var objectBox = this.createObjectBox(object);
  47.         this.openObjectBox(objectBox);
  48.         return objectBox;
  49.     },
  50.  
  51.     openToObject: function(object)
  52.     {
  53.         var objectBox = this.createObjectBox(object);
  54.         this.openObjectBox(objectBox);
  55.         return objectBox;
  56.     },
  57.  
  58.     select: function(object, makeBoxVisible, forceOpen, noScrollIntoView)
  59.     {
  60.         var objectBox = this.createObjectBox(object);
  61.         this.selectObjectBox(objectBox, forceOpen);
  62.         if (makeBoxVisible)
  63.         {
  64.             this.openObjectBox(objectBox);
  65.             if (!noScrollIntoView)
  66.                 scrollIntoCenterView(objectBox);
  67.         }
  68.         return objectBox;
  69.     },
  70.  
  71.     expandObject: function(object)
  72.     {
  73.         var objectBox = this.createObjectBox(object);
  74.         if (objectBox)
  75.             this.expandObjectBox(objectBox);
  76.     },
  77.  
  78.     contractObject: function(object)
  79.     {
  80.         var objectBox = this.createObjectBox(object);
  81.         if (objectBox)
  82.             this.contractObjectBox(objectBox);
  83.     },
  84.  
  85.     highlightObjectBox: function(objectBox)
  86.     {
  87.         if (this.highlightedObjectBox)
  88.         {
  89.             removeClass(this.highlightedObjectBox, "highlighted");
  90.  
  91.             var highlightedBox = this.getParentObjectBox(this.highlightedObjectBox);
  92.             for (; highlightedBox; highlightedBox = this.getParentObjectBox(highlightedBox))
  93.                 removeClass(highlightedBox, "highlightOpen");
  94.         }
  95.  
  96.         this.highlightedObjectBox = objectBox;
  97.  
  98.         if (objectBox)
  99.         {
  100.             setClass(objectBox, "highlighted");
  101.  
  102.             var highlightedBox = this.getParentObjectBox(objectBox);
  103.             for (; highlightedBox; highlightedBox = this.getParentObjectBox(highlightedBox))
  104.                 setClass(highlightedBox, "highlightOpen");
  105.  
  106.            scrollIntoCenterView(objectBox);
  107.         }
  108.     },
  109.  
  110.     selectObjectBox: function(objectBox, forceOpen)
  111.     {
  112.         var isSelected = this.selectedObjectBox && objectBox == this.selectedObjectBox;
  113.         if (!isSelected)
  114.         {
  115.             removeClass(this.selectedObjectBox, "selected");
  116.  
  117.             this.selectedObjectBox = objectBox;
  118.  
  119.             if (objectBox)
  120.             {
  121.                 setClass(objectBox, "selected");
  122.  
  123.                 // Force it open the first time it is selected
  124.                 if (forceOpen)
  125.                     this.toggleObjectBox(objectBox, true);
  126.             }
  127.         }
  128.     },
  129.  
  130.     openObjectBox: function(objectBox)
  131.     {
  132.         if (objectBox)
  133.         {
  134.             // Set all of the node's ancestors to be permanently open
  135.             var parentBox = this.getParentObjectBox(objectBox);
  136.             for (; parentBox; parentBox = this.getParentObjectBox(parentBox))
  137.                 setClass(parentBox, "open");
  138.         }
  139.     },
  140.  
  141.     expandObjectBox: function(objectBox)
  142.     {
  143.         var nodeChildBox = this.getChildObjectBox(objectBox);
  144.         if (!nodeChildBox)
  145.             return;
  146.  
  147.         if (!objectBox.populated)
  148.         {
  149.             var firstChild = this.view.getChildObject(objectBox.repObject, 0);
  150.             this.populateChildBox(firstChild, nodeChildBox);
  151.         }
  152.  
  153.         setClass(objectBox, "open");
  154.     },
  155.  
  156.     contractObjectBox: function(objectBox)
  157.     {
  158.         removeClass(objectBox, "open");
  159.     },
  160.  
  161.     toggleObjectBox: function(objectBox, forceOpen)
  162.     {
  163.         var isOpen = hasClass(objectBox, "open");
  164.         if (!forceOpen && isOpen)
  165.             this.contractObjectBox(objectBox);
  166.  
  167.         else if (!isOpen)
  168.             this.expandObjectBox(objectBox);
  169.     },
  170.  
  171.     getNextObjectBox: function(objectBox)
  172.     {
  173.         return findNext(objectBox, isVisibleTarget, false, this.box);
  174.     },
  175.  
  176.     getPreviousObjectBox: function(objectBox)
  177.     {
  178.         return findPrevious(objectBox, isVisibleTarget, true, this.box);
  179.     },
  180.  
  181.     /**
  182.      * Creates all of the boxes for an object, its ancestors, and siblings.
  183.      */
  184.     createObjectBox: function(object)
  185.     {
  186.         if (!object)
  187.             return null;
  188.  
  189.             this.rootObject = this.getRootNode(object);
  190.  
  191.         // Get or create all of the boxes for the target and its ancestors
  192.         var objectBox = this.createObjectBoxes(object, this.rootObject);
  193.  
  194.         if (!objectBox)
  195.             return null;
  196.         else if (object == this.rootObject)
  197.             return objectBox;
  198.         else
  199.             return this.populateChildBox(object, objectBox.parentNode);
  200.     },
  201.  
  202.     /**
  203.      * Creates all of the boxes for an object, its ancestors, and siblings up to a root.
  204.      */
  205.     createObjectBoxes: function(object, rootObject)
  206.     {
  207.         if (!object)
  208.             return null;
  209.  
  210.         if (object == rootObject)
  211.         {
  212.             if (!this.rootObjectBox || this.rootObjectBox.repObject != rootObject)
  213.             {
  214.                 if (this.rootObjectBox)
  215.                 {
  216.                     try {
  217.                         this.box.removeChild(this.rootObjectBox);
  218.                     } catch (exc) {
  219.                     }
  220.                 }
  221.  
  222.                 this.highlightedObjectBox = null;
  223.                 this.selectedObjectBox = null;
  224.                 this.rootObjectBox = this.view.createObjectBox(object, true);
  225.                 this.box.appendChild(this.rootObjectBox);
  226.             }
  227.             return this.rootObjectBox;
  228.         }
  229.         else
  230.         {
  231.             var parentNode = this.view.getParentObject(object);
  232.             var parentObjectBox = this.createObjectBoxes(parentNode, rootObject);
  233.             if (!parentObjectBox)
  234.                 return null;
  235.  
  236.             var parentChildBox = this.getChildObjectBox(parentObjectBox);
  237.             if (!parentChildBox)
  238.                 return null;
  239.  
  240.             var childObjectBox = this.findChildObjectBox(parentChildBox, object);
  241.             return childObjectBox
  242.                 ? childObjectBox
  243.                 : this.populateChildBox(object, parentChildBox);
  244.         }
  245.     },
  246.  
  247.     findObjectBox: function(object)
  248.     {
  249.         if (!object)
  250.             return null;
  251.  
  252.         if (object == this.rootObject)
  253.             return this.rootObjectBox;
  254.         else
  255.         {
  256.             var parentNode = this.view.getParentObject(object);
  257.             var parentObjectBox = this.findObjectBox(parentNode);
  258.             if (!parentObjectBox)
  259.                 return null;
  260.  
  261.             var parentChildBox = this.getChildObjectBox(parentObjectBox);
  262.             if (!parentChildBox)
  263.                 return null;
  264.  
  265.             return this.findChildObjectBox(parentChildBox, object);
  266.         }
  267.     },
  268.  
  269.     appendChildBox: function(parentNodeBox, repObject)
  270.     {
  271.         var childBox = this.getChildObjectBox(parentNodeBox);
  272.         var objectBox = this.findChildObjectBox(childBox, repObject);
  273.         if (objectBox)
  274.             return objectBox;
  275.  
  276.         objectBox = this.view.createObjectBox(repObject);
  277.         if (objectBox)
  278.         {
  279.             var childBox = this.getChildObjectBox(parentNodeBox);
  280.             childBox.appendChild(objectBox);
  281.         }
  282.         return objectBox;
  283.     },
  284.  
  285.     insertChildBoxBefore: function(parentNodeBox, repObject, nextSibling)
  286.     {
  287.         var childBox = this.getChildObjectBox(parentNodeBox);
  288.         var objectBox = this.findChildObjectBox(childBox, repObject);
  289.         if (objectBox)
  290.             return objectBox;
  291.  
  292.         objectBox = this.view.createObjectBox(repObject);
  293.         if (objectBox)
  294.         {
  295.             var siblingBox = this.findChildObjectBox(childBox, nextSibling);
  296.             childBox.insertBefore(objectBox, siblingBox);
  297.         }
  298.         return objectBox;
  299.     },
  300.  
  301.     removeChildBox: function(parentNodeBox, repObject)
  302.     {
  303.         var childBox = this.getChildObjectBox(parentNodeBox);
  304.         var objectBox = this.findChildObjectBox(childBox, repObject);
  305.         if (objectBox)
  306.             childBox.removeChild(objectBox);
  307.     },
  308.  
  309.     populateChildBox: function(repObject, nodeChildBox)  // We want all children of the parent of repObject.
  310.     {
  311.         if (!repObject)
  312.             return null;
  313.  
  314.         var parentObjectBox = nodeChildBox.parentNode;
  315.         if (parentObjectBox.populated)
  316.             return this.findChildObjectBox(nodeChildBox, repObject);
  317.  
  318.         var lastSiblingBox = this.getChildObjectBox(nodeChildBox);
  319.         var siblingBox = nodeChildBox.firstChild;
  320.         var targetBox = null;
  321.  
  322.         var view = this.view;
  323.  
  324.         var targetSibling = null;
  325.         var parentNode = view.getParentObject(repObject);
  326.         for (var i = 0; 1; ++i)
  327.         {
  328.             targetSibling = view.getChildObject(parentNode, i, targetSibling);
  329.             if (!targetSibling)
  330.                 break;
  331.  
  332.             // Check if we need to start appending, or continue to insert before
  333.             if (lastSiblingBox && lastSiblingBox.repObject == targetSibling)
  334.                 lastSiblingBox = null;
  335.  
  336.             if (!siblingBox || siblingBox.repObject != targetSibling)
  337.             {
  338.                 var newBox = view.createObjectBox(targetSibling);
  339.                 if (newBox)
  340.                 {
  341.                     if (lastSiblingBox)
  342.                         nodeChildBox.insertBefore(newBox, lastSiblingBox);
  343.                     else
  344.                         nodeChildBox.appendChild(newBox);
  345.                 }
  346.  
  347.                 siblingBox = newBox;
  348.             }
  349.  
  350.             if (targetSibling == repObject)
  351.                 targetBox = siblingBox;
  352.  
  353.             if (siblingBox && siblingBox.repObject == targetSibling)
  354.                 siblingBox = siblingBox.nextSibling;
  355.         }
  356.  
  357.         if (targetBox)
  358.             parentObjectBox.populated = true;
  359.         return targetBox;
  360.     },
  361.  
  362.     getParentObjectBox: function(objectBox)
  363.     {
  364.         var parent = objectBox.parentNode ? objectBox.parentNode.parentNode : null;
  365.         return parent && parent.repObject ? parent : null;
  366.     },
  367.  
  368.     getChildObjectBox: function(objectBox)
  369.     {
  370.         return getChildByClass(objectBox, "nodeChildBox");
  371.     },
  372.  
  373.     findChildObjectBox: function(parentNodeBox, repObject)
  374.     {
  375.         for (var childBox = parentNodeBox.firstChild; childBox; childBox = childBox.nextSibling)
  376.         {
  377.             if (childBox.repObject == repObject)
  378.                 return childBox;
  379.         }
  380.     },
  381.  
  382.     getRootNode: function(node)
  383.     {
  384.         while (1)
  385.         {
  386.             var parentNode = this.view.getParentObject(node);
  387.             if (!parentNode)
  388.                 return node;
  389.             else
  390.                 node = parentNode;
  391.         }
  392.         return null;
  393.     },
  394.  
  395.     // ********************************************************************************************
  396.  
  397.     onMouseDown: function(event)
  398.     {
  399.         var hitTwisty = false;
  400.         for (var child = event.target; child; child = child.parentNode)
  401.         {
  402.             if (hasClass(child, "twisty"))
  403.                 hitTwisty = true;
  404.             else if (child.repObject)
  405.             {
  406.                 if (hitTwisty)
  407.                     this.toggleObjectBox(child);
  408.                 break;
  409.             }
  410.         }
  411.     }
  412. };
  413.  
  414. // ************************************************************************************************
  415. // Local Helpers
  416.  
  417. function isVisibleTarget(node)
  418. {
  419.     if (node.repObject && node.repObject.nodeType == 1)
  420.     {
  421.         for (var parent = node.parentNode; parent; parent = parent.parentNode)
  422.         {
  423.             if (hasClass(parent, "nodeChildBox")
  424.                 && !hasClass(parent.parentNode, "open")
  425.                 && !hasClass(parent.parentNode, "highlightOpen"))
  426.                 return false;
  427.         }
  428.         return true;
  429.     }
  430. }
  431.  
  432. function formatNode(object)
  433. {
  434.     if (object)
  435.         return (object.localName ? object.localName : object);
  436.     else
  437.         return "(null object)";
  438. }
  439.  
  440. }});
  441.