browser_views_liveupdate.js
Go to the documentation of this file.
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is mozilla.org code.
15  *
16  * The Initial Developer of the Original Code is
17  * Mozilla Corporation.
18  * Portions created by the Initial Developer are Copyright (C) 2009
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  * Marco Bonardo <mak77@bonardo.net>
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37 
42 const Cc = Components.classes;
43 const Ci = Components.interfaces;
44 
45 function test() {
47 
48  // Sanity checks.
49  ok(PlacesUtils, "PlacesUtils in context");
50  ok(PlacesUIUtils, "PlacesUIUtils in context");
51 
52  // Open bookmarks menu.
53  var popup = document.getElementById("bookmarksMenuPopup");
54  ok(popup, "Menu popup element exists");
55  fakeOpenPopup(popup);
56 
57  // Open bookmarks sidebar.
58  var sidebar = document.getElementById("sidebar");
59  sidebar.addEventListener("load", function() {
60  sidebar.removeEventListener("load", arguments.callee, true);
61  // Need to executeSoon since the tree is initialized on sidebar load.
62  executeSoon(startTest);
63  }, true);
64  toggleSidebar("viewBookmarksSidebar", true);
65 }
66 
71 function fakeOpenPopup(aPopup) {
72  var popupEvent = document.createEvent("MouseEvent");
73  popupEvent.initMouseEvent("popupshowing", true, true, window, 0,
74  0, 0, 0, 0, false, false, false, false,
75  0, null);
76  aPopup.dispatchEvent(popupEvent);
77 }
78 
82 function startTest() {
83  var bs = PlacesUtils.bookmarks;
84  // Add bookmarks observer.
85  bs.addObserver(bookmarksObserver, false);
86  var addedBookmarks = [];
87 
88  // MENU
89  info("*** Acting on menu bookmarks");
90  var id = bs.insertBookmark(bs.bookmarksMenuFolder,
91  PlacesUtils._uri("http://bm1.mozilla.org/"),
92  bs.DEFAULT_INDEX,
93  "bm1");
94  addedBookmarks.push(id);
95  // Test live update of title.
96  bs.setItemTitle(id, "bm1_edited");
97  id = bs.insertBookmark(bs.bookmarksMenuFolder,
98  PlacesUtils._uri("place:"),
99  bs.DEFAULT_INDEX,
100  "bm2");
101  addedBookmarks.push(id);
102  id = bs.insertSeparator(bs.bookmarksMenuFolder, bs.DEFAULT_INDEX);
103  addedBookmarks.push(id);
104  id = bs.createFolder(bs.bookmarksMenuFolder,
105  "bmf",
106  bs.DEFAULT_INDEX);
107  addedBookmarks.push(id);
108  id = bs.insertBookmark(id,
109  PlacesUtils._uri("http://bmf1.mozilla.org/"),
110  bs.DEFAULT_INDEX,
111  "bmf1");
112  addedBookmarks.push(id);
113  bs.moveItem(id, bs.bookmarksMenuFolder, 0);
114 
115  // TOOLBAR
116  info("*** Acting on toolbar bookmarks");
117  id = bs.insertBookmark(bs.toolbarFolder,
118  PlacesUtils._uri("http://tb1.mozilla.org/"),
119  bs.DEFAULT_INDEX,
120  "tb1");
121  addedBookmarks.push(id);
122  // Test live update of title.
123  bs.setItemTitle(id, "tb1_edited");
124  id = bs.insertBookmark(bs.toolbarFolder,
125  PlacesUtils._uri("place:"),
126  bs.DEFAULT_INDEX,
127  "tb2");
128  addedBookmarks.push(id);
129  id = bs.insertSeparator(bs.toolbarFolder, bs.DEFAULT_INDEX);
130  addedBookmarks.push(id);
131  id = bs.createFolder(bs.toolbarFolder,
132  "tbf",
133  bs.DEFAULT_INDEX);
134  addedBookmarks.push(id);
135  id = bs.insertBookmark(id,
136  PlacesUtils._uri("http://tbf1.mozilla.org/"),
137  bs.DEFAULT_INDEX,
138  "bmf1");
139  addedBookmarks.push(id);
140  bs.moveItem(id, bs.toolbarFolder, 0);
141 
142  // UNSORTED
143  info("*** Acting on unsorted bookmarks");
144  id = bs.insertBookmark(bs.unfiledBookmarksFolder,
145  PlacesUtils._uri("http://ub1.mozilla.org/"),
146  bs.DEFAULT_INDEX,
147  "ub1");
148  addedBookmarks.push(id);
149  // Test live update of title.
150  bs.setItemTitle(id, "ub1_edited");
151  id = bs.insertBookmark(bs.unfiledBookmarksFolder,
152  PlacesUtils._uri("place:"),
153  bs.DEFAULT_INDEX,
154  "ub2");
155  addedBookmarks.push(id);
156  id = bs.insertSeparator(bs.unfiledBookmarksFolder, bs.DEFAULT_INDEX);
157  addedBookmarks.push(id);
158  id = bs.createFolder(bs.unfiledBookmarksFolder,
159  "ubf",
160  bs.DEFAULT_INDEX);
161  addedBookmarks.push(id);
162  id = bs.insertBookmark(id,
163  PlacesUtils._uri("http://ubf1.mozilla.org/"),
164  bs.DEFAULT_INDEX,
165  "bubf1");
166  addedBookmarks.push(id);
167  bs.moveItem(id, bs.unfiledBookmarksFolder, 0);
168 
169  // Remove all added bookmarks.
170  addedBookmarks.forEach(function (aItem) {
171  // If we remove an item after its containing folder has been removed,
172  // this will throw, but we can ignore that.
173  try {
174  bs.removeItem(aItem);
175  } catch (ex) {}
176  });
177 
178  // Remove bookmarks observer.
179  bs.removeObserver(bookmarksObserver);
180  finishTest();
181 }
182 
186 function finishTest() {
187  // Close bookmarks sidebar.
188  toggleSidebar("viewBookmarksSidebar", false);
189 
190  finish();
191 }
192 
198  QueryInterface: function PSB_QueryInterface(aIID) {
199  if (aIID.equals(Ci.nsINavBookmarkObserver) ||
200  aIID.equals(Ci.nsISupports))
201  return this;
202  throw Cr.NS_NOINTERFACE;
203  },
204 
205  // nsINavBookmarkObserver
206  onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex,
207  aItemType) {
208  var views = getViewsForFolder(aFolderId);
209  ok(views.length > 0, "Found affected views (" + views.length + "): " + views);
210 
211  // Check that item has been added in the correct position.
212  for (var i = 0; i < views.length; i++) {
213  var [node, index] = searchItemInView(aItemId, views[i]);
214  isnot(node, null, "Found new Places node in " + views[i]);
215  is(index, aIndex, "Node is at index " + index);
216  }
217  },
218 
219  onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
220  aItemType) {
221  var views = getViewsForFolder(aFolderId);
222  ok(views.length > 0, "Found affected views (" + views.length + "): " + views);
223  // Check that item has been removed.
224  for (var i = 0; i < views.length; i++) {
225  var node = null;
226  var index = null;
227  [node, index] = searchItemInView(aItemId, views[i]);
228  is(node, null, "Places node not found in " + views[i]);
229  }
230  },
231 
232  onItemMoved: function(aItemId,
233  aOldFolderId, aOldIndex,
234  aNewFolderId, aNewIndex,
235  aItemType) {
236  var views = getViewsForFolder(aNewFolderId);
237  ok(views.length > 0, "Found affected views: " + views);
238 
239  // Check that item has been moved in the correct position.
240  for (var i = 0; i < views.length; i++) {
241  var node = null;
242  var index = null;
243  [node, index] = searchItemInView(aItemId, views[i]);
244  isnot(node, null, "Found new Places node in " + views[i]);
245  is(index, aNewIndex, "Node is at index " + index);
246  }
247  },
248 
249  onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {},
250  onEndUpdateBatch: function PSB_onEndUpdateBatch() {},
251  onBeforeItemRemoved: function PSB_onBeforeItemRemoved(aItemId) {},
252  onItemVisited: function() {},
253 
254  onItemChanged: function PSB_onItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue) {
255  if (aProperty !== "title")
256  return;
257 
258  var views = getViewsForFolder(PlacesUtils.bookmarks.getFolderIdForItem(aItemId));
259  ok(views.length > 0, "Found affected views (" + views.length + "): " + views);
260 
261  // Check that item has been moved in the correct position.
262  for (var i = 0; i < views.length; i++) {
263  var [node, index] = searchItemInView(aItemId, views[i]);
264  isnot(node, null, "Found new Places node in " + views[i]);
265  is(node.title, aValue, "Node has correct title: " + aValue);
266  }
267  }
268 };
269 
279 function searchItemInView(aItemId, aView) {
280  switch (aView) {
281  case "toolbar":
282  return getNodeForToolbarItem(aItemId);
283  case "menu":
284  return getNodeForMenuItem(aItemId);
285  case "sidebar":
286  return getNodeForSidebarItem(aItemId);
287  }
288 
289  return [null, null];
290 }
291 
299 function getNodeForToolbarItem(aItemId) {
300  var toolbar = document.getElementById("bookmarksBarContent");
301 
302  function findNode(aContainer) {
303  var children = aContainer.childNodes;
304  for (var i = 0, staticNodes = 0; i < children.length; i++) {
305  var child = children[i];
306 
307  // Is this a Places node?
308  if (!child.node) {
309  staticNodes++;
310  continue;
311  }
312 
313  if (child.node.itemId == aItemId)
314  return [child.node, i - staticNodes];
315 
316  // Don't search in queries, they could contain our item in a
317  // different position. Search only folders
318  if (PlacesUtils.nodeIsFolder(child.node)) {
319  var popup = child.lastChild;
320  popup.showPopup(popup);
321  var foundNode = findNode(popup);
322  popup.hidePopup();
323  if (foundNode[0] != null)
324  return foundNode;
325  }
326  }
327  return [null, null];
328  }
329 
330  return findNode(toolbar);
331 }
332 
340 function getNodeForMenuItem(aItemId) {
341  var menu = document.getElementById("bookmarksMenu");
342 
343  function findNode(aContainer) {
344  var children = aContainer.childNodes;
345  for (var i = 0, staticNodes = 0; i < children.length; i++) {
346  var child = children[i];
347 
348  // Is this a Places node?
349  if (!child.node) {
350  staticNodes++;
351  continue;
352  }
353 
354  if (child.node.itemId == aItemId)
355  return [child.node, i - staticNodes];
356 
357  // Don't search in queries, they could contain our item in a
358  // different position. Search only folders
359  if (PlacesUtils.nodeIsFolder(child.node)) {
360  var popup = child.lastChild;
361  fakeOpenPopup(popup);
362  var foundNode = findNode(popup);
363 
364  child.open = false;
365  if (foundNode[0] != null)
366  return foundNode;
367  }
368  }
369  return [null, null];
370  }
371 
372  return findNode(menu.lastChild);
373 }
374 
382 function getNodeForSidebarItem(aItemId) {
383  var sidebar = document.getElementById("sidebar");
384  var tree = sidebar.contentDocument.getElementById("bookmarks-view");
385 
386  function findNode(aContainerIndex) {
387  if (tree.view.isContainerEmpty(aContainerIndex))
388  return [null, null];
389 
390  // The rowCount limit is just for sanity, but we will end looping when
391  // we have checked the last child of this container or we have found node.
392  for (var i = aContainerIndex + 1; i < tree.view.rowCount; i++) {
393  var node = tree.view.nodeForTreeIndex(i);
394 
395  if (node.itemId == aItemId) {
396  // Minus one because we want relative index inside the container.
397  return [node, i - tree.view.getParentIndex(i) - 1];
398  }
399 
400  if (PlacesUtils.nodeIsFolder(node)) {
401  // Open container.
402  tree.view.toggleOpenState(i);
403  // Search inside it.
404  var foundNode = findNode(i);
405  // Close container.
406  tree.view.toggleOpenState(i);
407  // Return node if found.
408  if (foundNode[0] != null)
409  return foundNode;
410  }
411 
412  // We have finished walking this container.
413  if (!tree.view.hasNextSibling(aContainerIndex + 1, i))
414  break;
415  }
416  return [null, null]
417  }
418 
419  // Root node is hidden, so we need to manually walk the first level.
420  for (var i = 0; i < tree.view.rowCount; i++) {
421  // Open container.
422  tree.view.toggleOpenState(i);
423  // Search inside it.
424  var foundNode = findNode(i);
425  // Close container.
426  tree.view.toggleOpenState(i);
427  // Return node if found.
428  if (foundNode[0] != null)
429  return foundNode;
430  }
431  return [null, null];
432 }
433 
441 function getViewsForFolder(aFolderId) {
442  var rootId = aFolderId;
443  while (!PlacesUtils.isRootItem(rootId))
444  rootId = PlacesUtils.bookmarks.getFolderIdForItem(rootId);
445 
446  switch (rootId) {
447  case PlacesUtils.toolbarFolderId:
448  return ["toolbar", "sidebar"]
449  break;
450  case PlacesUtils.bookmarksMenuFolderId:
451  return ["menu", "sidebar"]
452  break;
453  case PlacesUtils.unfiledBookmarksFolderId:
454  return ["sidebar"]
455  break;
456  }
457  return new Array();
458 }
var PlacesUIUtils
Definition: utils.js:85
function getNodeForSidebarItem(aItemId)
onPageChanged aValue
Definition: FeedWriter.js:1395
onPageChanged onEndUpdateBatch
Definition: FeedWriter.js:1395
function getViewsForFolder(aFolderId)
var menu
function fakeOpenPopup(aPopup)
sbOSDControlService prototype QueryInterface
function getNodeForMenuItem(aItemId)
let window
function startTest()
waitForExplicitFinish()
function test()
var bookmarksObserver
onPageChanged onBeginUpdateBatch
Definition: FeedWriter.js:1395
return null
Definition: FeedWriter.js:1143
let node
return!aWindow arguments!aWindow arguments[0]
function searchItemInView(aItemId, aView)
function finishTest()
const Cr
function getNodeForToolbarItem(aItemId)
_getSelectedPageStyle s i