browser/components/places/content/tree.xml

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 <?xml version="1.0"?>
     3 <!-- This Source Code Form is subject to the terms of the Mozilla Public
     4    - License, v. 2.0. If a copy of the MPL was not distributed with this
     5    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
     7 <bindings id="placesTreeBindings"
     8           xmlns="http://www.mozilla.org/xbl"
     9           xmlns:xbl="http://www.mozilla.org/xbl"
    10           xmlns:html="http://www.w3.org/1999/xhtml"
    11           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    13   <binding id="places-tree" extends="chrome://global/content/bindings/tree.xml#tree">
    14     <implementation>
    15       <constructor><![CDATA[
    16         // Force an initial build.
    17         if (this.place)
    18           this.place = this.place;
    19       ]]></constructor>
    21       <destructor><![CDATA[
    22         // Break the treeviewer->result->treeviewer cycle.
    23         // Note: unsetting the result's viewer also unsets
    24         // the viewer's reference to our treeBoxObject.
    25         var result = this.result;
    26         if (result) {
    27           result.root.containerOpen = false;
    28         }
    30         // Unregister the controllber before unlinking the view, otherwise it
    31         // may still try to update commands on a view with a null result.
    32         if (this._controller) {
    33           this._controller.terminate();
    34           this.controllers.removeController(this._controller);
    35         }
    37         this.view = null;
    38       ]]></destructor>
    40       <property name="controller"
    41                 readonly="true"
    42                 onget="return this._controller"/>
    44       <!-- overriding -->
    45       <property name="view">
    46         <getter><![CDATA[
    47           try {
    48             return this.treeBoxObject.view.wrappedJSObject || null;
    49           }
    50           catch(e) {
    51             return null;
    52           }
    53         ]]></getter>
    54         <setter><![CDATA[
    55           return this.treeBoxObject.view = val;
    56         ]]></setter>
    57       </property>
    59       <property name="associatedElement"
    60                 readonly="true"
    61                 onget="return this"/>
    63       <method name="applyFilter">
    64         <parameter name="filterString"/>
    65         <parameter name="folderRestrict"/>
    66         <parameter name="includeHidden"/>
    67         <body><![CDATA[
    68           // preserve grouping
    69           var queryNode = PlacesUtils.asQuery(this.result.root);
    70           var options = queryNode.queryOptions.clone();
    72           // Make sure we're getting uri results.
    73           // We do not yet support searching into grouped queries or into
    74           // tag containers, so we must fall to the default case.
    75           if (PlacesUtils.nodeIsHistoryContainer(queryNode) ||
    76               options.resultType == options.RESULTS_AS_TAG_QUERY ||
    77               options.resultType == options.RESULTS_AS_TAG_CONTENTS)
    78             options.resultType = options.RESULTS_AS_URI;
    80           var query = PlacesUtils.history.getNewQuery();
    81           query.searchTerms = filterString;
    83           if (folderRestrict) {
    84             query.setFolders(folderRestrict, folderRestrict.length);
    85             options.queryType = options.QUERY_TYPE_BOOKMARKS;
    86           }
    88           options.includeHidden = !!includeHidden;
    90           this.load([query], options);
    91         ]]></body>
    92       </method>
    94       <method name="load">
    95         <parameter name="queries"/>
    96         <parameter name="options"/>
    97         <body><![CDATA[
    98           let result = PlacesUtils.history
    99                                   .executeQueries(queries, queries.length,
   100                                                   options);
   101           let callback;
   102           if (this.flatList) {
   103             let onOpenFlatContainer = this.onOpenFlatContainer;
   104             if (onOpenFlatContainer)
   105               callback = new Function("aContainer", onOpenFlatContainer);
   106           }
   108           if (!this._controller) {
   109             this._controller = new PlacesController(this);
   110             this.controllers.appendController(this._controller);
   111           }
   113           let treeView = new PlacesTreeView(this.flatList, callback, this._controller);
   115           // Observer removal is done within the view itself.  When the tree
   116           // goes away, treeboxobject calls view.setTree(null), which then
   117           // calls removeObserver.
   118           result.addObserver(treeView, false);
   119           this.view = treeView;
   121           if (this.getAttribute("selectfirstnode") == "true" && treeView.rowCount > 0) {
   122             treeView.selection.select(0);
   123           }
   125           this._cachedInsertionPoint = undefined;
   126         ]]></body>
   127       </method>
   129       <property name="flatList">
   130         <getter><![CDATA[
   131           return this.getAttribute("flatList") == "true";
   132         ]]></getter>
   133         <setter><![CDATA[
   134           if (this.flatList != val) {
   135             this.setAttribute("flatList", val);
   136             // reload with the last place set
   137             if (this.place)
   138               this.place = this.place;
   139           }
   140           return val;
   141         ]]></setter>
   142       </property>
   144       <property name="onOpenFlatContainer">
   145         <getter><![CDATA[
   146           return this.getAttribute("onopenflatcontainer");
   147         ]]></getter>
   148         <setter><![CDATA[
   149           if (this.onOpenFlatContainer != val) {
   150             this.setAttribute("onopenflatcontainer", val);
   151             // reload with the last place set
   152             if (this.place)
   153               this.place = this.place;
   154           }
   155           return val;
   156         ]]></setter>
   157       </property>
   159       <!--
   160         Causes a particular node represented by the specified placeURI to be
   161         selected in the tree. All containers above the node in the hierarchy
   162         will be opened, so that the node is visible.
   163         -->
   164       <method name="selectPlaceURI">
   165         <parameter name="placeURI"/>
   166         <body><![CDATA[
   167           // Do nothing if a node matching the given uri is already selected
   168           if (this.hasSelection && this.selectedNode.uri == placeURI)
   169             return;
   171           function findNode(container, placeURI, nodesURIChecked) {
   172             var containerURI = container.uri;
   173             if (containerURI == placeURI)
   174               return container;
   175             if (nodesURIChecked.indexOf(containerURI) != -1)
   176               return null;
   178             // never check the contents of the same query
   179             nodesURIChecked.push(containerURI);
   181             var wasOpen = container.containerOpen;
   182             if (!wasOpen)
   183               container.containerOpen = true;
   184             for (var i = 0; i < container.childCount; ++i) {
   185               var child = container.getChild(i);
   186               var childURI = child.uri;
   187               if (childURI == placeURI)
   188                 return child;
   189               else if (PlacesUtils.nodeIsContainer(child)) {
   190                 var nested = findNode(PlacesUtils.asContainer(child), placeURI, nodesURIChecked);
   191                 if (nested)
   192                   return nested;
   193               }
   194             }
   196             if (!wasOpen)
   197               container.containerOpen = false;
   199             return null;
   200           }
   202           var container = this.result.root;
   203           NS_ASSERT(container, "No result, cannot select place URI!");
   204           if (!container)
   205             return;
   207           var child = findNode(container, placeURI, []);
   208           if (child)
   209             this.selectNode(child);
   210           else {
   211             // If the specified child could not be located, clear the selection
   212             var selection = this.view.selection;
   213             selection.clearSelection();
   214           }
   215         ]]></body>
   216       </method>
   218       <!--
   219         Causes a particular node to be selected in the tree, resulting in all
   220         containers above the node in the hierarchy to be opened, so that the
   221         node is visible.
   222         -->
   223       <method name="selectNode">
   224         <parameter name="node"/>
   225         <body><![CDATA[
   226           var view = this.view;
   228           var parent = node.parent;
   229           if (parent && !parent.containerOpen) {
   230             // Build a list of all of the nodes that are the parent of this one
   231             // in the result.
   232             var parents = [];
   233             var root = this.result.root;
   234             while (parent && parent != root) {
   235               parents.push(parent);
   236               parent = parent.parent;
   237             }
   239             // Walk the list backwards (opening from the root of the hierarchy)
   240             // opening each folder as we go.
   241             for (var i = parents.length - 1; i >= 0; --i) {
   242               var index = view.treeIndexForNode(parents[i]);
   243               if (index != Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE &&
   244                   view.isContainer(index) && !view.isContainerOpen(index))
   245                 view.toggleOpenState(index);
   246             }
   247             // Select the specified node...
   248           }
   250           var index = view.treeIndexForNode(node);
   251           if (index == Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE)
   252             return;
   254           view.selection.select(index);
   255           // ... and ensure it's visible, not scrolled off somewhere.
   256           this.treeBoxObject.ensureRowIsVisible(index);
   257         ]]></body>
   258       </method>
   260       <!-- nsIPlacesView -->
   261       <property name="result">
   262         <getter><![CDATA[
   263           try {
   264             return this.view.QueryInterface(Ci.nsINavHistoryResultObserver).result;
   265           }
   266           catch (e) {
   267             return null;
   268           }
   269         ]]></getter>
   270       </property>
   272       <!-- nsIPlacesView -->
   273       <property name="place">
   274         <getter><![CDATA[
   275           return this.getAttribute("place");
   276         ]]></getter>
   277         <setter><![CDATA[
   278           this.setAttribute("place", val);
   280           var queriesRef = { };
   281           var queryCountRef = { };
   282           var optionsRef = { };
   283           PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef);
   284           if (queryCountRef.value == 0)
   285             queriesRef.value = [PlacesUtils.history.getNewQuery()];
   286           if (!optionsRef.value)
   287             optionsRef.value = PlacesUtils.history.getNewQueryOptions();
   289           this.load(queriesRef.value, optionsRef.value);
   291           return val;
   292         ]]></setter>
   293       </property>
   295       <!-- nsIPlacesView -->
   296       <property name="hasSelection">
   297         <getter><![CDATA[
   298           return this.view && this.view.selection.count >= 1;
   299         ]]></getter>
   300       </property>
   302       <!-- nsIPlacesView -->
   303       <property name="selectedNodes">
   304         <getter><![CDATA[
   305           let nodes = [];
   306           if (!this.hasSelection)
   307             return nodes;
   309           let selection = this.view.selection;
   310           let rc = selection.getRangeCount();
   311           let resultview = this.view;
   312           for (let i = 0; i < rc; ++i) {
   313             let min = { }, max = { };
   314             selection.getRangeAt(i, min, max);
   315             for (let j = min.value; j <= max.value; ++j) {
   316               nodes.push(resultview.nodeForTreeIndex(j));
   317             }
   318           }
   319           return nodes;
   320         ]]></getter>
   321       </property>
   323       <method name="toggleCutNode">
   324         <parameter name="aNode"/>
   325         <parameter name="aValue"/>
   326         <body><![CDATA[
   327           this.view.toggleCutNode(aNode, aValue);
   328         ]]></body>
   329       </method>
   331       <!-- nsIPlacesView -->
   332       <property name="removableSelectionRanges">
   333         <getter><![CDATA[
   334           // This property exists in addition to selectedNodes because it
   335           // encodes selection ranges (which only occur in list views) into
   336           // the return value. For each removed range, the index at which items
   337           // will be re-inserted upon the remove transaction being performed is
   338           // the first index of the range, so that the view updates correctly.
   339           //
   340           // For example, if we remove rows 2,3,4 and 7,8 from a list, when we
   341           // undo that operation, if we insert what was at row 3 at row 3 again,
   342           // it will show up _after_ the item that was at row 5. So we need to
   343           // insert all items at row 2, and the tree view will update correctly.
   344           //
   345           // Also, this function collapses the selection to remove redundant
   346           // data, e.g. when deleting this selection:
   347           //
   348           //      http://www.foo.com/
   349           //  (-) Some Folder
   350           //        http://www.bar.com/
   351           //
   352           // ... returning http://www.bar.com/ as part of the selection is
   353           // redundant because it is implied by removing "Some Folder". We
   354           // filter out all such redundancies since some partial amount of
   355           // the folder's children may be selected.
   356           //
   357           let nodes = [];
   358           if (!this.hasSelection)
   359             return nodes;
   361           var selection = this.view.selection;
   362           var rc = selection.getRangeCount();
   363           var resultview = this.view;
   364           // This list is kept independently of the range selected (i.e. OUTSIDE
   365           // the for loop) since the row index of a container is unique for the
   366           // entire view, and we could have some really wacky selection and we
   367           // don't want to blow up.
   368           var containers = { };
   369           for (var i = 0; i < rc; ++i) {
   370             var range = [];
   371             var min = { }, max = { };
   372             selection.getRangeAt(i, min, max);
   374             for (var j = min.value; j <= max.value; ++j) {
   375               if (this.view.isContainer(j))
   376                 containers[j] = true;
   377               if (!(this.view.getParentIndex(j) in containers))
   378                 range.push(resultview.nodeForTreeIndex(j));
   379             }
   380             nodes.push(range);
   381           }
   382           return nodes;
   383         ]]></getter>
   384       </property>
   386       <!-- nsIPlacesView -->
   387       <property name="draggableSelection"
   388                 onget="return this.selectedNodes"/>
   390       <!-- nsIPlacesView -->
   391       <property name="selectedNode">
   392         <getter><![CDATA[
   393           var view = this.view;
   394           if (!view || view.selection.count != 1)
   395             return null;
   397           var selection = view.selection;
   398           var min = { }, max = { };
   399           selection.getRangeAt(0, min, max);
   401           return this.view.nodeForTreeIndex(min.value);
   402         ]]></getter>
   403       </property>
   405       <!-- nsIPlacesView -->
   406       <property name="insertionPoint">
   407         <getter><![CDATA[
   408           // invalidated on selection and focus changes
   409           if (this._cachedInsertionPoint !== undefined)
   410             return this._cachedInsertionPoint;
   412           // there is no insertion point for history queries
   413           // so bail out now and save a lot of work when updating commands
   414           var resultNode = this.result.root;
   415           if (PlacesUtils.nodeIsQuery(resultNode) &&
   416               PlacesUtils.asQuery(resultNode).queryOptions.queryType ==
   417                 Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
   418               return this._cachedInsertionPoint = null;
   420           var orientation = Ci.nsITreeView.DROP_BEFORE;
   421           // If there is no selection, insert at the end of the container.
   422           if (!this.hasSelection) {
   423             var index = this.view.rowCount - 1;
   424             this._cachedInsertionPoint =
   425               this._getInsertionPoint(index, orientation);
   426             return this._cachedInsertionPoint;
   427           }
   429           // This is a two-part process. The first part is determining the drop
   430           // orientation.
   431           // * The default orientation is to drop _before_ the selected item.
   432           // * If the selected item is a container, the default orientation
   433           //   is to drop _into_ that container.
   434           //
   435           // Warning: It may be tempting to use tree indexes in this code, but
   436           //          you must not, since the tree is nested and as your tree
   437           //          index may change when folders before you are opened and
   438           //          closed. You must convert your tree index to a node, and
   439           //          then use getChildIndex to find your absolute index in
   440           //          the parent container instead.
   441           //
   442           var resultView = this.view;
   443           var selection = resultView.selection;
   444           var rc = selection.getRangeCount();
   445           var min = { }, max = { };
   446           selection.getRangeAt(rc - 1, min, max);
   448           // If the sole selection is a container, and we are not in
   449           // a flatlist, insert into it.
   450           // Note that this only applies to _single_ selections,
   451           // if the last element within a multi-selection is a
   452           // container, insert _adjacent_ to the selection.
   453           //
   454           // If the sole selection is the bookmarks toolbar folder, we insert
   455           // into it even if it is not opened
   456           if (selection.count == 1 && resultView.isContainer(max.value) &&
   457               !this.flatList)
   458             orientation = Ci.nsITreeView.DROP_ON;
   460           this._cachedInsertionPoint =
   461             this._getInsertionPoint(max.value, orientation);
   462           return this._cachedInsertionPoint;
   463         ]]></getter>
   464       </property>
   466       <method name="_getInsertionPoint">
   467         <parameter name="index"/>
   468         <parameter name="orientation"/>
   469         <body><![CDATA[
   470           var result = this.result;
   471           var resultview = this.view;
   472           var container = result.root;
   473           var dropNearItemId = -1;
   474           NS_ASSERT(container, "null container");
   475           // When there's no selection, assume the container is the container
   476           // the view is populated from (i.e. the result's itemId).
   477           if (index != -1) {
   478             var lastSelected = resultview.nodeForTreeIndex(index);
   479             if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
   480               // If the last selected item is an open container, append _into_
   481               // it, rather than insert adjacent to it.
   482               container = lastSelected;
   483               index = -1;
   484             }
   485             else if (lastSelected.containerOpen &&
   486                      orientation == Ci.nsITreeView.DROP_AFTER &&
   487                      lastSelected.hasChildren) {
   488              // If the last selected item is an open container and the user is
   489              // trying to drag into it as a first item, really insert into it.
   490              container = lastSelected;
   491              orientation = Ci.nsITreeView.DROP_ON;
   492              index = 0;
   493             }
   494             else {
   495               // Use the last-selected node's container.
   496               container = lastSelected.parent;
   498               // See comment in the treeView.js's copy of this method
   499               if (!container || !container.containerOpen)
   500                 return null;
   502               // Avoid the potentially expensive call to getChildIndex
   503               // if we know this container doesn't allow insertion
   504               if (PlacesControllerDragHelper.disallowInsertion(container))
   505                 return null;
   507               var queryOptions = PlacesUtils.asQuery(result.root).queryOptions;
   508               if (queryOptions.sortingMode !=
   509                     Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
   510                 // If we are within a sorted view, insert at the end
   511                 index = -1;
   512               }
   513               else if (queryOptions.excludeItems ||
   514                        queryOptions.excludeQueries ||
   515                        queryOptions.excludeReadOnlyFolders) {
   516                 // Some item may be invisible, insert near last selected one.
   517                 // We don't replace index here to avoid requests to the db,
   518                 // instead it will be calculated later by the controller.
   519                 index = -1;
   520                 dropNearItemId = lastSelected.itemId;
   521               }
   522               else {
   523                 var lsi = container.getChildIndex(lastSelected);
   524                 index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
   525               }
   526             }
   527           }
   529           if (PlacesControllerDragHelper.disallowInsertion(container))
   530             return null;
   532           return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
   533                                     index, orientation,
   534                                     PlacesUtils.nodeIsTagQuery(container),
   535                                     dropNearItemId);
   536         ]]></body>
   537       </method>
   539       <!-- nsIPlacesView -->
   540       <method name="selectAll">
   541         <body><![CDATA[
   542           this.view.selection.selectAll();
   543         ]]></body>
   544       </method>
   546       <!-- This method will select the first node in the tree that matches
   547            each given item id. It will open any folder nodes that it needs
   548            to in order to show the selected items.
   549       -->
   550       <method name="selectItems">
   551         <parameter name="aIDs"/>
   552         <parameter name="aOpenContainers"/>
   553         <body><![CDATA[
   554           // Never open containers in flat lists.
   555           if (this.flatList)
   556             aOpenContainers = false;
   557           // By default, we do search and select within containers which were
   558           // closed (note that containers in which nodes were not found are
   559           // closed).
   560           if (aOpenContainers === undefined)
   561             aOpenContainers = true;
   563           var ids = aIDs; // don't manipulate the caller's array
   565           // Array of nodes found by findNodes which are to be selected
   566           var nodes = [];
   568           // Array of nodes found by findNodes which should be opened
   569           var nodesToOpen = [];
   571           // A set of URIs of container-nodes that were previously searched,
   572           // and thus shouldn't be searched again. This is empty at the initial
   573           // start of the recursion and gets filled in as the recursion
   574           // progresses.
   575           var nodesURIChecked = [];
   577           /**
   578            * Recursively search through a node's children for items
   579            * with the given IDs. When a matching item is found, remove its ID
   580            * from the IDs array, and add the found node to the nodes dictionary.
   581            *
   582            * NOTE: This method will leave open any node that had matching items
   583            * in its subtree.
   584            */
   585           function findNodes(node) {
   586             var foundOne = false;
   587             // See if node matches an ID we wanted; add to results.
   588             // For simple folder queries, check both itemId and the concrete
   589             // item id.
   590             var index = ids.indexOf(node.itemId);
   591             if (index == -1 &&
   592                 node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
   593               index = ids.indexOf(PlacesUtils.asQuery(node).folderItemId);
   595             if (index != -1) {
   596               nodes.push(node);
   597               foundOne = true;
   598               ids.splice(index, 1);
   599             }
   601             if (ids.length == 0 || !PlacesUtils.nodeIsContainer(node) ||
   602                 nodesURIChecked.indexOf(node.uri) != -1)
   603               return foundOne;
   605             // Don't try to open a query or a shurtcut, since it may return
   606             // any duplicate data and be infinitely nested.  Though, if it has
   607             // been explicitly opened by the caller, search into it.
   608             let shouldOpen = aOpenContainers &&
   609                              node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER;
   610             PlacesUtils.asContainer(node);
   611             if (!node.containerOpen && !shouldOpen)
   612               return foundOne;
   614             nodesURIChecked.push(node.uri);
   616             // Remember the beginning state so that we can re-close
   617             // this node if we don't find any additional results here.
   618             var previousOpenness = node.containerOpen;
   619             node.containerOpen = true;
   620             for (var child = 0;  child < node.childCount && ids.length > 0;
   621                  child++) {
   622               var childNode = node.getChild(child);
   623               var found = findNodes(childNode);
   624               if (!foundOne)
   625                 foundOne = found;
   626             }
   628             // If we didn't find any additional matches in this node's
   629             // subtree, revert the node to its previous openness.
   630             if (foundOne)
   631               nodesToOpen.unshift(node);
   632             node.containerOpen = previousOpenness;
   633             return foundOne;
   634           }
   636           // Disable notifications while looking for nodes.
   637           let result = this.result;
   638           let didSuppressNotifications = result.suppressNotifications;
   639           if (!didSuppressNotifications)
   640             result.suppressNotifications = true
   641           try {
   642             findNodes(this.result.root);
   643           }
   644           finally {
   645             if (!didSuppressNotifications)
   646               result.suppressNotifications = false;
   647           }
   649           // For all the nodes we've found, highlight the corresponding
   650           // index in the tree.
   651           var resultview = this.view;
   652           var selection = this.view.selection;
   653           selection.selectEventsSuppressed = true;
   654           selection.clearSelection();
   655           // Open nodes containing found items
   656           for (var i = 0; i < nodesToOpen.length; i++) {
   657             nodesToOpen[i].containerOpen = true;
   658           }
   659           for (var i = 0; i < nodes.length; i++) {
   660             var index = resultview.treeIndexForNode(nodes[i]);
   661             if (index == Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE)
   662               continue;
   663             selection.rangedSelect(index, index, true);
   664           }
   665           selection.selectEventsSuppressed = false;
   666         ]]></body>
   667       </method>
   669       <field name="_contextMenuShown">false</field>
   671       <method name="buildContextMenu">
   672         <parameter name="aPopup"/>
   673         <body><![CDATA[
   674           this._contextMenuShown = true;
   675           return this.controller.buildContextMenu(aPopup);
   676         ]]></body>
   677       </method>
   679       <method name="destroyContextMenu">
   680         <parameter name="aPopup"/>
   681           this._contextMenuShown = false;
   682         <body/>
   683       </method>
   685       <property name="ownerWindow"
   686                 readonly="true"
   687                 onget="return window;"/>
   689       <field name="_active">true</field>
   690       <property name="active"
   691                 onget="return this._active"
   692                 onset="return this._active = val"/>
   694     </implementation>
   695     <handlers>
   696       <handler event="focus"><![CDATA[
   697         this._cachedInsertionPoint = undefined;
   699         // See select handler. We need the sidebar's places commandset to be
   700         // updated as well
   701         document.commandDispatcher.updateCommands("focus");
   702       ]]></handler>
   703       <handler event="select"><![CDATA[
   704         this._cachedInsertionPoint = undefined;
   706         // This additional complexity is here for the sidebars
   707         var win = window;
   708         while (true) {
   709           win.document.commandDispatcher.updateCommands("focus");
   710           if (win == window.top)
   711             break;
   713           win = win.parent;
   714         }
   715       ]]></handler>
   717       <handler event="dragstart"><![CDATA[
   718         if (event.target.localName != "treechildren")
   719           return;
   721         let nodes = this.selectedNodes;
   722         for (let i = 0; i < nodes.length; i++) {
   723           let node = nodes[i];
   725           // Disallow dragging the root node of a tree.
   726           if (!node.parent) {
   727             event.preventDefault();
   728             event.stopPropagation();
   729             return;
   730           }
   732           // If this node is child of a readonly container (e.g. a livemark)
   733           // or cannot be moved, we must force a copy.
   734           if (!PlacesControllerDragHelper.canMoveNode(node)) {
   735             event.dataTransfer.effectAllowed = "copyLink";
   736             break;
   737           }
   738         }
   740         this._controller.setDataTransfer(event);
   741         event.stopPropagation();
   742       ]]></handler>
   744       <handler event="dragover"><![CDATA[
   745         if (event.target.localName != "treechildren")
   746           return;
   748         let row = { }, col = { }, child = { };
   749         this.treeBoxObject.getCellAt(event.clientX, event.clientY,
   750                                      row, col, child);
   751         let node = row.value != -1 ?
   752                    this.view.nodeForTreeIndex(row.value) :
   753                    this.result.root;
   754         // cache the dropTarget for the view
   755         PlacesControllerDragHelper.currentDropTarget = node;
   757         // We have to calculate the orientation since view.canDrop will use
   758         // it and we want to be consistent with the dropfeedback.
   759         let tbo = this.treeBoxObject;
   760         let rowHeight = tbo.rowHeight;
   761         let eventY = event.clientY - tbo.treeBody.boxObject.y -
   762                      rowHeight * (row.value - tbo.getFirstVisibleRow());
   764         let orientation = Ci.nsITreeView.DROP_BEFORE;
   766         if (row.value == -1) {
   767           // If the row is not valid we try to insert inside the resultNode.
   768           orientation = Ci.nsITreeView.DROP_ON;
   769         }
   770         else if (PlacesUtils.nodeIsContainer(node) &&
   771                  eventY > rowHeight * 0.75) {
   772           // If we are below the 75% of a container the treeview we try
   773           // to drop after the node.
   774           orientation = Ci.nsITreeView.DROP_AFTER;
   775         }
   776         else if (PlacesUtils.nodeIsContainer(node) &&
   777                  eventY > rowHeight * 0.25) {
   778           // If we are below the 25% of a container the treeview we try
   779           // to drop inside the node.
   780           orientation = Ci.nsITreeView.DROP_ON;
   781         }
   783         if (!this.view.canDrop(row.value, orientation, event.dataTransfer))
   784           return;
   786         event.preventDefault();
   787         event.stopPropagation();
   788       ]]></handler>
   790       <handler event="dragend"><![CDATA[
   791         PlacesControllerDragHelper.currentDropTarget = null;
   792       ]]></handler>
   794     </handlers>
   795   </binding>
   797 </bindings>

mercurial