tree.xml 29 KB

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