home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / firefox-3.0.14 / chrome / browser.jar / content / browser / places / menu.xml < prev    next >
Encoding:
Extensible Markup Language  |  2008-05-06  |  33.9 KB  |  955 lines

  1. <?xml version="1.0"?>
  2.  
  3.  
  4. <bindings id="placesMenuBindings"
  5.           xmlns="http://www.mozilla.org/xbl"
  6.           xmlns:xbl="http://www.mozilla.org/xbl"
  7.           xmlns:html="http://www.w3.org/1999/xhtml"
  8.           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  9.  
  10.   <binding id="places-popup-base"
  11.            extends="chrome://global/content/bindings/popup.xml#popup">
  12.     <content>
  13.       <xul:hbox flex="1">
  14.         <xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
  15.           <xul:image class="menupopup-drop-indicator" mousethrough="always"/>
  16.         </xul:vbox>
  17.         <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical">
  18.           <children/>
  19.         </xul:arrowscrollbox>
  20.       </xul:hbox>
  21.     </content>
  22.  
  23.     <implementation>
  24.  
  25.       <field name="_indicatorBar">
  26.         document.getAnonymousElementByAttribute(this, "class",
  27.                                                 "menupopup-drop-indicator-bar");
  28.       </field>
  29.  
  30.       <field name="_scrollBox">
  31.         document.getAnonymousElementByAttribute(this, "class",
  32.                                                 "popup-internal-box");
  33.       </field>
  34.  
  35.       <!-- markers for start and end of valid places items -->
  36.       <field name="_startMarker">-1</field>
  37.       <field name="_endMarker">-1</field>
  38.  
  39.       <!-- This is the view that manage the popup -->
  40.       <field name="_rootView">PlacesUIUtils.getViewForNode(this);</field>
  41.  
  42.       <field name="_built">false</field>
  43.  
  44.       <method name="onDragOver">
  45.         <parameter name="aEvent"/>
  46.         <parameter name="aFlavour"/>
  47.         <parameter name="aDragSession"/>
  48.         <body><![CDATA[
  49.           PlacesControllerDragHelper.currentDropTarget = aEvent.target;
  50.           // check if we have a valid dropPoint
  51.           var dropPoint = this._getDropPoint(aEvent);
  52.           if (!dropPoint)
  53.             return;
  54.  
  55.           // add a dragover attribute to this popup
  56.           this.setAttribute("dragover", "true");
  57.  
  58.           if (dropPoint.folderNode) {
  59.             // We are dragging over a folder
  60.             // _overFolder should take the care of opening it on a timer
  61.             if (this._overFolder.node &&
  62.                 this._overFolder.node != dropPoint.folderNode) {
  63.               // we are dragging over a new folder, let's clear old values
  64.               this._overFolder.clear();
  65.             }
  66.             if (!this._overFolder.node) {
  67.               this._overFolder.node = dropPoint.folderNode;
  68.               // create the timer to open this folder
  69.               this._overFolder.openTimer = this._overFolder
  70.                                                .setTimer(this._overFolder.hoverTime);
  71.             }
  72.             // since we are dropping into a folder set the corresponding style
  73.             dropPoint.folderNode.setAttribute("dragover-into", "true");
  74.           }
  75.           else {
  76.             // We are not dragging over a folder
  77.             // Clear out old _overFolder information
  78.             this._overFolder.clear();
  79.           }
  80.  
  81.           // Check if we should hide the drop indicator for this target
  82.           if (!aDragSession.canDrop ||
  83.               !dropPoint || dropPoint.folderNode ||
  84.               this._hideDropIndicator(aEvent, dropPoint)) {
  85.             this._indicatorBar.hidden = true;
  86.             return;
  87.           }
  88.  
  89.           var scrollBoxObject = this._scrollBox.scrollBoxObject;
  90.           // Autoscroll the popup strip if we drag over the scroll buttons
  91.           var anonid = aEvent.originalTarget.getAttribute("anonid");
  92.           var scrollDir = anonid == "scrollbutton-up" ? -1 :
  93.                           anonid == "scrollbutton-down" ? 1 : 0;
  94.           if (scrollDir != 0)
  95.             this._scrollBox.scrollByIndex(scrollDir);
  96.  
  97.           // We should display the drop indicator relative to the arrowscrollbox
  98.           var newMarginTop = 0;
  99.           if (scrollDir == 0) {
  100.             var node = this.firstChild;
  101.             while (node && aEvent.screenY > node.boxObject.screenY +
  102.                                             node.boxObject.height / 2)
  103.               node = node.nextSibling;
  104.             newMarginTop = node ? node.boxObject.screenY - scrollBoxObject.screenY :
  105.                                   scrollBoxObject.height;
  106.           }
  107.           else if (scrollDir == 1)
  108.             newMarginTop = scrollBoxObject.height;
  109.  
  110.           // set the new marginTop based on arrowscrollbox
  111.           newMarginTop += scrollBoxObject.y - this._scrollBox.boxObject.y;
  112.           this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
  113.           this._indicatorBar.hidden = false;
  114.         ]]></body>
  115.       </method>
  116.  
  117.       <method name="onDragExit">
  118.         <parameter name="aEvent"/>
  119.         <parameter name="aDragSession"/>
  120.         <body><![CDATA[
  121.           PlacesControllerDragHelper.currentDropTarget = null;
  122.           this.removeAttribute("dragover");
  123.           // remove dragover-into style from previous target
  124.           aEvent.target.removeAttribute("dragover-into");
  125.  
  126.           // if we have not moved to a valid new target clear the drop indicator
  127.           // this happens when moving out of the popup
  128.           var target = aEvent.relatedTarget;
  129.           if (!target)
  130.             this._indicatorBar.hidden = true;
  131.  
  132.           // Close any folder being hovered over
  133.           if (this._overFolder.node) {
  134.             this._overFolder.closeTimer = this._overFolder
  135.                                               .setTimer(this._overFolder.hoverTime);
  136.           }
  137.  
  138.           // The autoopened attribute is set when this folder was automatically
  139.           // opened after the user dragged over it.  If this attribute is set,
  140.           // auto-close the folder on drag exit.
  141.           if (this.hasAttribute("autoopened")) {
  142.             this._overFolder.closeMenuTimer = this._overFolder
  143.                                                   .setTimer(this._overFolder.hoverTime);
  144.           }
  145.  
  146.           this._rootView._draggedNode = null;
  147.         ]]></body>
  148.       </method>
  149.  
  150.       <method name="onDragStart">
  151.         <parameter name="aEvent"/>
  152.         <parameter name="aXferData"/>
  153.         <parameter name="aDragAction"/>
  154.         <body><![CDATA[
  155.           // Force a copy action if parent node is a query or not-removable
  156.           if (aEvent.ctrlKey ||
  157.               PlacesUtils.nodeIsQuery(aEvent.target.node.parent) ||
  158.               !PlacesControllerDragHelper.canMoveContainerNode(aEvent.target.node))
  159.             aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
  160.  
  161.           // activate the view and cache the dragged node
  162.           this._rootView._draggedNode = aEvent.target.node;
  163.           this._rootView.focus();
  164.  
  165.           aXferData.data = this._rootView.controller
  166.                                          .getTransferData(aDragAction.action);
  167.         ]]></body>
  168.       </method>
  169.  
  170.       <method name="onDrop">
  171.         <parameter name="aEvent"/>
  172.          <parameter name="aDropData"/>
  173.         <parameter name="aSession"/>
  174.         <body><![CDATA[
  175.           var dropPoint = this._getDropPoint(aEvent);
  176.           if (!dropPoint)
  177.             return;
  178.  
  179.           PlacesControllerDragHelper.onDrop(dropPoint.ip);
  180.         ]]></body>
  181.       </method>
  182.  
  183.       <!-- This returns the FavourSet accepted by this popup -->
  184.       <method name="getSupportedFlavours">
  185.         <body><![CDATA[
  186.           var flavourSet = new FlavourSet();
  187.           var acceptedDropFlavours = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
  188.           acceptedDropFlavours.forEach(flavourSet.appendFlavour, flavourSet);
  189.           return flavourSet;
  190.         ]]></body>
  191.       </method>
  192.  
  193.       <!-- Check if we should hide the drop indicator for the target -->
  194.       <method name="_hideDropIndicator">
  195.         <parameter name="aEvent"/>
  196.         <body><![CDATA[
  197.           var target = aEvent.target;
  198.  
  199.           // in some view we have _startMarker and _endMarker, we should not
  200.           // draw the drop indicator outside of them
  201.           var betweenMarkers = true;
  202.           if (this._startMarker != -1 &&
  203.               target.boxObject.y <= this.childNodes[this._startMarker].boxObject.y)
  204.             betweenMarkers = false;
  205.           if (this._endMarker != -1 &&
  206.               target.boxObject.y >= this.childNodes[this._endMarker].boxObject.y)
  207.             betweenMarkers = false;
  208.  
  209.           // hide the dropmarker if current node is not a places bookmark item
  210.           return !(target && target.node && betweenMarkers && this.canDrop());
  211.         ]]></body>
  212.       </method>
  213.  
  214.       <!-- This function returns information about where to drop when
  215.            dragging over this popup insertion point -->
  216.       <method name="_getDropPoint">
  217.         <parameter name="aEvent"/>
  218.           <body><![CDATA[
  219.             // Can't drop if the menu isn't a folder
  220.             var resultNode = this._resultNode;
  221.             if (!PlacesUtils.nodeIsFolder(resultNode))
  222.               return null;
  223.  
  224.             var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
  225.  
  226.             // set the limits for valid items
  227.             var start = 0;
  228.             var popup = this;
  229.             var end = popup.childNodes.length;
  230.             if (this._startMarker != -1)
  231.               start = this._startMarker + 1;
  232.             if (this._endMarker != -1)
  233.               end = this._endMarker;
  234.  
  235.             // Loop through all the nodes to find the correct dropPoint
  236.             var popupY = popup.boxObject.y;
  237.             // we should add the scrollBox button height if visible
  238.             popupY += this._scrollBox.scrollBoxObject.y - popup.boxObject.y;
  239.             for (var i = start; i < end; i++) {
  240.               var xulNode = popup.childNodes[i];
  241.               var nodeY = xulNode.boxObject.y - popupY;
  242.               var nodeHeight = xulNode.boxObject.height;
  243.               if (xulNode.node &&
  244.                   (PlacesUtils.nodeIsFolder(xulNode.node) ||
  245.                    PlacesUtils.nodeIsTagQuery(xulNode.node)) &&
  246.                   !PlacesUtils.nodeIsReadOnly(xulNode.node)) {
  247.                 // This is a folder. If the mouse is in the top 25% of the
  248.                 // node, drop above the folder.  If it's in the middle
  249.                 // 50%, drop into the folder.  If it's past that, drop below.
  250.                 if (aEvent.layerY < nodeY + (nodeHeight * 0.25)) {
  251.                   // Drop above this folder.
  252.                   dropPoint.ip = new InsertionPoint(resultNode.itemId,
  253.                                                     i - start, -1);
  254.                   dropPoint.beforeIndex = i;
  255.                   return dropPoint;
  256.                 }
  257.                 else if (aEvent.layerY < nodeY + (nodeHeight * 0.75)) {
  258.                   // Drop inside this folder.
  259.                   dropPoint.ip = new InsertionPoint(xulNode.node.itemId, -1, 1);
  260.                   dropPoint.beforeIndex = i;
  261.                   dropPoint.folderNode = xulNode;
  262.                   return dropPoint;
  263.                 }
  264.               }
  265.               else {
  266.                 // This is a non-folder node. If the mouse is above the middle,
  267.                 // drop above the folder.  Otherwise, drop below.
  268.                 if (aEvent.layerY <= nodeY + (nodeHeight / 2)) {
  269.                   // Drop above this bookmark.
  270.                   dropPoint.ip = new InsertionPoint(resultNode.itemId,
  271.                                                     i - start, -1);
  272.                   dropPoint.beforeIndex = i;
  273.                   return dropPoint;
  274.                 }
  275.               }
  276.             }
  277.             // Should drop below the last node.
  278.             dropPoint.ip = new InsertionPoint(resultNode.itemId, -1, 1);
  279.             dropPoint.beforeIndex = -1;
  280.             return dropPoint;
  281.         ]]></body>
  282.       </method>
  283.  
  284.       <method name="canDrop">
  285.         <body><![CDATA[
  286.           var ip = this._rootView.insertionPoint;
  287.           return ip && PlacesControllerDragHelper.canDrop(ip);
  288.         ]]></body>
  289.       </method>
  290.  
  291.       <!-- Sub-menus should be opened when the mouse drags over them, and closed
  292.            when the mouse drags off.  The overFolder object manages opening and
  293.            closing of folders when the mouse hovers. -->
  294.       <field name="_overFolder"><![CDATA[({
  295.         _self: this,
  296.         _folder: {node: null, openTimer: null, hoverTime: 350, closeTimer: null},
  297.         _closeMenuTimer: null,
  298.  
  299.         get node() {
  300.           return this._folder.node;
  301.         },
  302.         set node(val) {
  303.           return this._folder.node = val;
  304.         },
  305.  
  306.         get openTimer() {
  307.           return this._folder.openTimer;
  308.         },
  309.         set openTimer(val) {
  310.           return this._folder.openTimer = val;
  311.         },
  312.  
  313.         get hoverTime() {
  314.           return this._folder.hoverTime;
  315.         },
  316.         set hoverTime(val) {
  317.           return this._folder.hoverTime = val;
  318.         },
  319.  
  320.         get closeTimer() {
  321.           return this._folder.closeTimer;
  322.         },
  323.         set closeTimer(val) {
  324.           return this._folder.closeTimer = val;
  325.         },
  326.  
  327.         get closeMenuTimer() {
  328.           return this._closeMenuTimer;
  329.         },
  330.         set closeMenuTimer(val) {
  331.           return this._closeMenuTimer = val;
  332.         },
  333.  
  334.         setTimer: function OF__setTimer(aTime) {
  335.           var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  336.           timer.initWithCallback(this, aTime, timer.TYPE_ONE_SHOT);
  337.           return timer;
  338.         },
  339.  
  340.         notify: function OF__notify(aTimer) {
  341.           // Function to process all timer notifications.
  342.  
  343.           if (aTimer == this._folder.openTimer) {
  344.             // Timer to open a submenu that's being dragged over.
  345.             this._folder.node.lastChild.setAttribute("autoopened", "true");
  346.             this._folder.node.lastChild.showPopup(this._folder.node);
  347.             this._folder.openTimer = null;
  348.           }
  349.  
  350.           else if (aTimer == this._folder.closeTimer) {
  351.             // Timer to close a submenu that's been dragged off of.
  352.             // Only close the submenu if the mouse isn't being dragged over any
  353.             // of its child menus.
  354.             var draggingOverChild = PlacesControllerDragHelper
  355.                                     .draggingOverChildNode(this._folder.node);
  356.             if (draggingOverChild)
  357.               this._folder.node = null;
  358.             this.clear();
  359.  
  360.             // Close any parent folders which aren't being dragged over.
  361.             // (This is necessary because of the above code that keeps a folder
  362.             // open while its children are being dragged over.)
  363.             if (!draggingOverChild)
  364.               this.closeParentMenus();
  365.           }
  366.  
  367.           else if (aTimer == this.closeMenuTimer) {
  368.             // Timer to close this menu after the drag exit.
  369.             var popup = this._self;
  370.             if (!PlacesControllerDragHelper.draggingOverChildNode(popup.parentNode)) {
  371.               popup.hidePopup();
  372.               // Close any parent menus that aren't being dragged over;
  373.               // otherwise they'll stay open because they couldn't close
  374.               // while this menu was being dragged over.
  375.               this.closeParentMenus();
  376.             }
  377.           }
  378.         },
  379.  
  380.         //  Helper function to close all parent menus of this menu,
  381.         //  as long as none of the parent's children are currently being
  382.         //  dragged over.
  383.         closeParentMenus: function OF__closeParentMenus() {
  384.           var popup = this._self;
  385.           var parent = popup.parentNode;
  386.           while (parent) {
  387.             if (parent.nodeName == "menupopup" && parent._resultNode) {
  388.               if (PlacesControllerDragHelper.draggingOverChildNode(parent.parentNode))
  389.                 break;
  390.               parent.hidePopup();
  391.             }
  392.             parent = parent.parentNode;
  393.           }
  394.         },
  395.  
  396.         //  The mouse is no longer dragging over the stored menubutton.
  397.         //  Close the menubutton, clear out drag styles, and clear all
  398.         //  timers for opening/closing it.
  399.         clear: function OF__clear() {
  400.           if (this._folder.node && this._folder.node.lastChild) {
  401.             if (!this._folder.node.lastChild.hasAttribute("dragover"))
  402.               this._folder.node.lastChild.hidePopup();
  403.             // remove dragover-into style
  404.             this._folder.node.removeAttribute("dragover-into");
  405.             this._folder.node = null;
  406.           }
  407.           if (this._folder.openTimer) {
  408.             this._folder.openTimer.cancel();
  409.             this._folder.openTimer = null;
  410.           }
  411.           if (this._folder.closeTimer) {
  412.             this._folder.closeTimer.cancel();
  413.             this._folder.closeTimer = null;
  414.           }
  415.         }
  416.       })]]></field>
  417.  
  418.     </implementation>
  419.  
  420.     <handlers>
  421.       <handler event="DOMMenuItemActive"><![CDATA[
  422.         var node = event.target;
  423.         if (node.parentNode != this)
  424.           return;
  425.  
  426.  
  427.         if (window.XULBrowserWindow) {
  428.           var nodeItem = event.target.node;
  429.           if (nodeItem && PlacesUtils.nodeIsURI(nodeItem))
  430.             window.XULBrowserWindow.setOverLink(nodeItem.uri, null);
  431.         }
  432.       ]]></handler>
  433.       <handler event="DOMMenuItemInactive"><![CDATA[
  434.         var node = event.target;
  435.         if (node.parentNode != this)
  436.           return;
  437.  
  438.         if (window.XULBrowserWindow)
  439.           window.XULBrowserWindow.setOverLink("", null);
  440.       ]]></handler>
  441.       <handler event="draggesture" action="if (event.target.node) nsDragAndDrop.startDrag(event, this);"/>
  442.       <handler event="dragdrop" action="nsDragAndDrop.drop(event, this);"/>
  443.       <handler event="dragover" action="nsDragAndDrop.dragOver(event, this);"/>
  444.       <handler event="dragexit" action="nsDragAndDrop.dragExit(event, this);"/>
  445.     </handlers>
  446.   </binding>
  447.  
  448.  
  449.   <binding id="places-menupopup"
  450.            extends="chrome://browser/content/places/menu.xml#places-popup-base">
  451.     <implementation>
  452.       <destructor><![CDATA[
  453.         this._resultNode = null;
  454.         if (this._result) {
  455.           this._result.viewer = null;
  456.           this._result = null;
  457.         }
  458.       ]]></destructor>
  459.  
  460.       <field name="_initialized">false</field>
  461.       <method name="_ensureInitialized">
  462.         <body><![CDATA[
  463.           if (this._initialized)
  464.             return;
  465.  
  466.           this._controller = new PlacesController(this);
  467.           this.controllers.appendController(this._controller);
  468.  
  469.           // This function should only be called for top-level menus like the bookmarks menu.
  470.           // Submenus get their _result and _resultNode from their parents.
  471.           if (this.hasAttribute("place")) {
  472.             // Do the initial build.
  473.             this.place = this.place;
  474.           }
  475.           this._initialized = true;
  476.         ]]></body>
  477.       </method>
  478.  
  479.       <property name="controller"
  480.                 readonly="true"
  481.                 onget="return this._controller;"/>
  482.  
  483.       <method name="onPopupShowing">
  484.         <parameter name="aEvent"/>
  485.         <body><![CDATA[
  486.           var popup = aEvent.target;
  487.           var resultNode = popup._resultNode;
  488.           if (!resultNode.containerOpen)
  489.             resultNode.containerOpen = true;
  490.           if (!popup._built)
  491.             this._rebuild(popup);
  492.         ]]></body>
  493.       </method>
  494.  
  495.       <!-- nsIPlacesView -->
  496.       <method name="getResult">
  497.         <body><![CDATA[
  498.           return this._result;
  499.         ]]></body>
  500.       </method>
  501.  
  502.       <!-- nsIPlacesView -->
  503.       <method name="getResultNode">
  504.         <body><![CDATA[
  505.           this._ensureInitialized();
  506.           return this._resultNode;
  507.         ]]></body>
  508.       </method>
  509.  
  510.       <method name="removeItem">
  511.         <parameter name="child"/>
  512.         <body><![CDATA[
  513.           if (PlacesUtils.nodeIsContainer(child.node)) {
  514.             for (var i=0; i < this._containerNodesMap.length; i++) {
  515.               if (this._containerNodesMap[i].resultNode == child.node) {
  516.                 this._containerNodesMap.splice(i, 1);
  517.                 break;
  518.               }
  519.             }
  520.           }
  521.  
  522.           // if document.popupNode pointed to this child, null it out,
  523.           // otherwise controller's command-updating may rely on the removed
  524.           // item still being "selected".
  525.           if (document.popupNode == child)
  526.             document.popupNode = null;
  527.           child.parentNode.removeChild(child);
  528.         ]]></body>
  529.       </method>
  530.  
  531.       <method name="insertNewItem">
  532.         <parameter name="aChild"/>
  533.         <parameter name="aParentPopup"/>
  534.         <parameter name="aBefore"/>
  535.         <body><![CDATA[
  536.           var element =
  537.             PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
  538.  
  539.           if (aBefore)
  540.             aParentPopup.insertBefore(element, aBefore);
  541.           else {
  542.             // Add the new element to the menu.  If there is static content at
  543.             // the end of the menu, add the element before that.  Otherwise,
  544.             // just add to the end.
  545.             if (aParentPopup._endMarker != -1)
  546.               aParentPopup.insertBefore(element,
  547.                                         aParentPopup.childNodes[aParentPopup._endMarker++]);
  548.             else
  549.               aParentPopup.appendChild(element);
  550.           }
  551.         ]]></body>
  552.       </method>
  553.  
  554.       <method name="_showEmptyMenuItem">
  555.         <parameter name="aPopup"/>
  556.         <body><![CDATA[
  557.           if (aPopup._emptyMenuItem) {
  558.             aPopup._emptyMenuItem.hidden = false;
  559.             return;
  560.           }
  561.  
  562.           var label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
  563.           aPopup._emptyMenuItem = document.createElement("menuitem");
  564.           aPopup._emptyMenuItem.setAttribute("label", label);
  565.           aPopup._emptyMenuItem.setAttribute("disabled", true);
  566.           aPopup.appendChild(aPopup._emptyMenuItem);
  567.         ]]></body>
  568.       </method>
  569.  
  570.       <method name="_rebuild">
  571.         <parameter name="aPopup"/>
  572.         <body><![CDATA[
  573.           PlacesUIUtils.cleanPlacesPopup(aPopup);
  574.  
  575.           var cc = aPopup._resultNode.childCount;
  576.           if (cc > 0) {
  577.             if (aPopup._emptyMenuItem)
  578.               aPopup._emptyMenuItem.hidden = true;
  579.  
  580.             for (var i = 0; i < cc; ++i) {
  581.               var child = aPopup._resultNode.getChild(i);
  582.               this.insertNewItem(child, aPopup, null);
  583.             }
  584.           }
  585.           else {
  586.             // This menu is empty.  If there is no static content, add
  587.             // an element to show it is empty.
  588.             if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
  589.               this._showEmptyMenuItem(aPopup);
  590.           }
  591.           aPopup._built = true;
  592.         ]]></body>
  593.       </method>
  594.  
  595.       <!-- nsINavHistoryResultViewer -->
  596.       <field name="_viewer"><![CDATA[({
  597.         _self: this,
  598.  
  599.         _getPopupForContainer:
  600.         function PMV__getPopupForContainer(aNode) {
  601.           if (this._self._resultNode == aNode)
  602.             return this._self;
  603.  
  604.           for (var i=0; i < this._self._containerNodesMap.length; i++) {
  605.             if (this._self._containerNodesMap[i].resultNode == aNode)
  606.               return this._self._containerNodesMap[i].domNode;
  607.           }
  608.           throw("Container view not found");
  609.         },
  610.  
  611.         get result() {
  612.           return this._self._result;
  613.         },
  614.  
  615.         set result(val) {
  616.           // some methods (e.g. getURLsFromContainer) temporarily null out the
  617.           // viewer when they do temporary changes to the view, this does _not_
  618.           // call setResult(null), but then, we're called again with the result
  619.           // object which is already set for this viewer. At that point,
  620.           // we should do nothing.
  621.           if (this._self._result != val) {
  622.             this._built = false;
  623.             this._self._containerNodesMap = [];
  624.             this._self._resultNode = val.root;
  625.             this._self._result = val;
  626.           }
  627.           return val;
  628.         },
  629.  
  630.         itemInserted: function PMV_itemInserted(aParentNode, aNode, aIndex) {
  631.           var popup = this._getPopupForContainer(aParentNode);
  632.           if (!popup._built)
  633.             return;
  634.  
  635.           var index = popup._startMarker + 1 + aIndex;
  636.           var before = popup.childNodes[index] || null;
  637.           this._self.insertNewItem(aNode, popup, before);
  638.           if (popup._emptyMenuItem)
  639.             popup._emptyMenuItem.hidden = true;
  640.         },
  641.  
  642.         itemRemoved: function PMV_itemRemoved(aParentNode, aNode, aIndex) {
  643.           var popup = this._getPopupForContainer(aParentNode);
  644.           if (!popup._built)
  645.             return;
  646.  
  647.           var children = popup.childNodes;
  648.           for (var i = 0; i < children.length; i++) {
  649.             if (children[i].node == aNode) {
  650.               this._self.removeItem(children[i]);
  651.               if (!popup.hasChildNodes() ||
  652.                   (popup.childNodes.length == 1 &&
  653.                    popup.firstChild == popup._emptyMenuItem)) {
  654.                 this._self._showEmptyMenuItem(popup);
  655.               }
  656.             }
  657.           }
  658.         },
  659.  
  660.         itemMoved:
  661.         function PMV_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
  662.                                aNewIndex) {
  663.           // This cannot actually happen yet (see IDL)
  664.           if (aNewParent != aOldParent)
  665.             return;
  666.  
  667.           var popup = this._getPopupForContainer(aNewParent);
  668.           var index = popup._startMarker + 1 + aNewIndex;
  669.           var children = popup.childNodes;
  670.           for (var i = 0; i < children.length; i++) {
  671.             var menuItem = children[i];
  672.             if (menuItem.node == aItem) {
  673.               popup.removeChild(menuItem);
  674.               popup.insertBefore(menuItem, children[index]);
  675.               return;
  676.             }
  677.           }
  678.         },
  679.  
  680.         itemChanged: function PMV_itemChanged(aNode) {
  681.           // this check can be removed once we fix bug #382397
  682.           var parentNode = aNode.parent;
  683.           if (!parentNode)
  684.             return;
  685.  
  686.           var popup = this._getPopupForContainer(parentNode);
  687.           if (!popup._built)
  688.             return;
  689.  
  690.           var children = popup.childNodes;
  691.           var menuitem;
  692.           for (var i = 0; i < children.length; i++) {
  693.             if (children[i].node == aNode) {
  694.               menuitem = children[i];
  695.               break;
  696.             }
  697.           }
  698.  
  699.           if (PlacesUtils.nodeIsSeparator(aNode)) {
  700.             // nothing to do when a separator changes
  701.             return;
  702.           }
  703.  
  704.           var iconURI = aNode.icon;
  705.           if (iconURI) {
  706.             var spec = iconURI.spec;
  707.             if (menuitem.getAttribute("image") != spec)
  708.               menuitem.setAttribute("image", spec);
  709.           }
  710.           else
  711.             menuitem.removeAttribute("image");
  712.  
  713.           var title = PlacesUIUtils.getBestTitle(aNode);
  714.           if (menuitem.getAttribute("label") != title)
  715.             menuitem.setAttribute("label", title);
  716.  
  717.           if (!menuitem.hasAttribute("livemark") &&
  718.               PlacesUtils.nodeIsLivemarkContainer(aNode))
  719.             menuitem.setAttribute("livemark", "true");
  720.         },
  721.  
  722.         itemReplaced:
  723.         function PMV_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
  724.           var popup = this._getPopupForContainer(aParentNode);
  725.           if (!popup._built)
  726.             return;
  727.  
  728.           var children = popup.childNodes;
  729.           for (var i = 0; i < children.length; i++) {
  730.             if (children[i].node == aOldNode) {
  731.               var next = children[i].nextSibling;
  732.               this._self.removeItem(children[i]);
  733.               this._self.insertNewItem(aNewNode, popup, next);
  734.               return;
  735.             }
  736.           }
  737.         },
  738.  
  739.         containerOpened: function PMV_containerOpened(aNode) {
  740.           this.invalidateContainer(aNode);
  741.         },
  742.  
  743.         containerClosed: function PMV_containerClosed(aNode) {
  744.           this.invalidateContainer(aNode);
  745.         },
  746.  
  747.         invalidateContainer: function PMV_invalidateContainer(aContainer) {
  748.           if (!this._self._built)
  749.             return;
  750.  
  751.           function isChildOf(node, container) {
  752.             var parent = node.parent;
  753.             while (parent) {
  754.               if (parent == container)
  755.                 return true;
  756.               parent = parent.parent;
  757.             }
  758.             return false;
  759.           }
  760.  
  761.           var popupToRebuild = null;
  762.           for (var i=0; i < this._self._containerNodesMap.length; i++) {
  763.             var node = this._self._containerNodesMap[i].resultNode;
  764.  
  765.             if (node == aContainer)
  766.               popupToRebuild = this._self._containerNodesMap[i].domNode;
  767.             if (isChildOf(node, aContainer)) {
  768.               this._self._containerNodesMap.splice(i,1);
  769.               i--;
  770.             }
  771.           }
  772.  
  773.           if (!popupToRebuild)
  774.             popupToRebuild = this._self;
  775.           popupToRebuild._built = false;
  776.  
  777.           // if the menupopup is open we should live-update it
  778.           if (popupToRebuild.parentNode.open)
  779.             this._self._rebuild(popupToRebuild);
  780.         },
  781.  
  782.         invalidateAll: function PMV_invalidateAll() {
  783.           this._self._containerNodesMap.splice(0);
  784.           this._self._built = false;
  785.         },
  786.  
  787.         sortingChanged: function PMV_sortingChanged(aSortingMode) {
  788.         }
  789.       })]]></field>
  790.  
  791.       <!-- nsIPlacesView -->
  792.       <property name="place">
  793.         <getter><![CDATA[
  794.           return this.getAttribute("place");
  795.         ]]></getter>
  796.         <setter><![CDATA[
  797.           this.setAttribute("place", val);
  798.           var queries = { }, options = { };
  799.           PlacesUtils.history.queryStringToQueries(val, queries, { }, options);
  800.           if (!queries.value.length)
  801.             queries.value = [PlacesUtils.history.getNewQuery()];
  802.           var result =
  803.             PlacesUtils.history.executeQueries(queries.value,
  804.                                                queries.value.length,
  805.                                                options.value);
  806.           result.viewer = this._viewer;
  807.           return val;
  808.         ]]></setter>
  809.       </property>
  810.  
  811.       <!-- nsIPlacesView -->
  812.       <property name="hasSelection">
  813.         <getter><![CDATA[
  814.           return this.selectedNode != null;
  815.         ]]></getter>
  816.       </property>
  817.  
  818.       <!-- nsIPlacesView -->
  819.       <method name="getSelectionNodes">
  820.         <body><![CDATA[
  821.           var selectedNode = this.selectedNode;
  822.           return selectedNode ? [selectedNode] : [];
  823.         ]]></body>
  824.       </method>
  825.  
  826.       <!-- nsIPlacesView -->
  827.       <method name="getRemovableSelectionRanges">
  828.         <body><![CDATA[
  829.           return [this.getSelectionNodes()];
  830.         ]]></body>
  831.       </method>
  832.  
  833.       <!-- nsIPlacesView -->
  834.       <method name="getDragableSelection">
  835.         <body><![CDATA[
  836.           return [this._draggedNode];
  837.         ]]></body>
  838.       </method>
  839.  
  840.       <!-- nsIPlacesView -->
  841.       <property name="selectedNode">
  842.         <getter><![CDATA[
  843.           if (this._contextMenuShown) {
  844.             var popupNode = document.popupNode;
  845.             return popupNode.node || popupNode.parentNode._resultNode || null;
  846.           }
  847.           return null;
  848.         ]]></getter>
  849.       </property>
  850.  
  851.       <!-- nsIPlacesView -->
  852.       <property name="insertionPoint">
  853.         <getter><![CDATA[
  854.           // By default, the insertion point is at the top level, at the end.
  855.           var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
  856.           var folderId = 0;
  857.           var orientation = Ci.nsITreeView.DROP_BEFORE;
  858.           var isTag = false;
  859.  
  860.           if (PlacesUtils.nodeIsFolder(this._resultNode)) {
  861.             folderId = PlacesUtils.getConcreteItemId(this._resultNode);
  862.             isTag = PlacesUtils.nodeIsTagQuery(this._resultNode);
  863.           }
  864.  
  865.           var selectedNode = this.selectedNode;
  866.           if (selectedNode) {
  867.             var popupNode = document.popupNode;
  868.             if (!popupNode.node) {
  869.               // If a static menuitem is selected the insertion point
  870.               // is inside the folder, at the end.
  871.               folderId = PlacesUtils.getConcreteItemId(selectedNode);
  872.               orientation = Ci.nsITreeView.DROP_ON;
  873.             }
  874.             else {
  875.               // In all other cases the insertion point is before that node.
  876.               folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
  877.               index = PlacesUtils.getIndexOfNode(selectedNode);
  878.               isTag = PlacesUtils.nodeIsTagQuery(selectedNode.parent);
  879.             }
  880.           }
  881.           return new InsertionPoint(folderId, index, orientation, isTag);
  882.         ]]></getter>
  883.       </property>
  884.  
  885.       <!-- nsIPlacesView -->
  886.       <method name="selectAll">
  887.         <body/>
  888.       </method>
  889.  
  890.       <method name="selectItems">
  891.         <body/>
  892.       </method>
  893.  
  894.       <property name="selType" readonly="true" onget="return 'single';"/>
  895.  
  896.       <method name="buildContextMenu">
  897.         <parameter name="aPopup"/>
  898.         <body><![CDATA[
  899.           this._ensureInitialized();
  900.           this._contextMenuShown = true;
  901.           this.focus();
  902.           var show = this.controller.buildContextMenu(aPopup);
  903.           if (show) {
  904.             // disable the Delete command if the selection isn't explicit
  905.             if (document.popupNode && document.popupNode.localName == "menupopup")
  906.               document.getElementById("cmd_delete").setAttribute("disabled", "true");
  907.             return true;
  908.           }
  909.           return false;
  910.         ]]></body>
  911.       </method>
  912.  
  913.       <method name="destroyContextMenu">
  914.         <parameter name="aPopup"/>
  915.         <body>
  916.           <![CDATA[
  917.             this._contextMenuShown = false;
  918.             if (window.content)
  919.               window.content.focus();
  920.           ]]>
  921.         </body>
  922.       </method>
  923.     </implementation>
  924.     <handlers>
  925.       <handler event="popupshowing" phase="capturing"><![CDATA[
  926.         this._ensureInitialized();
  927.         var popup = event.target;
  928.         // Avoid handling popupshowing of inner views
  929.         if (!popup._resultNode || PlacesUIUtils.getViewForNode(popup) != this)
  930.           return;
  931.  
  932.         this.onPopupShowing(event);
  933.       ]]></handler>
  934.  
  935.       <handler event="popuphidden"><![CDATA[
  936.         var popup = event.target;
  937.         // We should avoid to handle events of inner views
  938.         if (!popup._resultNode || PlacesUIUtils.getViewForNode(popup) != this)
  939.           return;
  940.  
  941.         // UI performance: folder queries are cheap, keep the resultnode open
  942.         // so we don't rebuild its contents whenever the popup is reopened.
  943.         if (!PlacesUtils.nodeIsFolder(popup._resultNode))
  944.           popup._resultNode.containerOpen = false;
  945.  
  946.         // The autoopened attribute is set for folders which have been
  947.         // automatically opened when dragged over.  Turn off this attribute
  948.         // when the folder closes because it is no longer applicable.
  949.         popup.removeAttribute("autoopened");
  950.       ]]></handler>
  951.     </handlers>
  952.   </binding>
  953.  
  954. </bindings>
  955.