Bug 627416 - Port Firefox changes from Jan 20 places merge; (Dv1) Just copy bug 394353 2nd patch, Resync' 3 nits.
authorSerge Gautherie <sgautherie.bz@free.fr>
Mon, 07 Feb 2011 12:57:06 +0100
changeset 7096 5bb7cde86a93c871cde24c21dc6e4960748b35da
parent 7095 892088e4ead3cd97f98263f54414f52500e7d9aa
child 7097 3bd81d3e9ddf19c577b795a40cb032bce908d4bb
push idunknown
push userunknown
push dateunknown
bugs627416, 394353
Bug 627416 - Port Firefox changes from Jan 20 places merge; (Dv1) Just copy bug 394353 2nd patch, Resync' 3 nits. r=neil.
suite/common/bookmarks/editBookmarkOverlay.js
--- a/suite/common/bookmarks/editBookmarkOverlay.js
+++ b/suite/common/bookmarks/editBookmarkOverlay.js
@@ -133,17 +133,17 @@ var gEditItemOverlay = {
    */
   initPanel: function EIO_initPanel(aFor, aInfo) {
     // For sanity ensure that the implementer has uninited the panel before
     // trying to init it again, or we could end up leaking due to observers.
     if (this._initialized)
       this.uninitPanel(false);
 
     var aItemIdList;
-    if (aFor.length) {
+    if (Array.isArray(aFor)) {
       aItemIdList = aFor;
       aFor = aItemIdList[0];
     }
     else if (this._multiEdit) {
       this._multiEdit = false;
       this._tags = [];
       this._uris = [];
       this._allTags = [];
@@ -206,29 +206,26 @@ var gEditItemOverlay = {
       if (!aItemIdList) {
         var tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
         this._initTextField("tagsField", tags, false);
       }
       else {
         this._multiEdit = true;
         this._allTags = [];
         this._itemIds = aItemIdList;
-        var nodeToCheck = 0;
         for (var i = 0; i < aItemIdList.length; i++) {
           if (aItemIdList[i] instanceof Components.interfaces.nsIURI) {
             this._uris[i] = aItemIdList[i];
             this._itemIds[i] = -1;
           }
           else
             this._uris[i] = PlacesUtils.bookmarks.getBookmarkURI(this._itemIds[i]);
           this._tags[i] = PlacesUtils.tagging.getTagsForURI(this._uris[i]);
-          if (this._tags[i].length < this._tags[nodeToCheck].length)
-            nodeToCheck =  i;
         }
-        this._getCommonTags(nodeToCheck);
+        this._allTags = this._getCommonTags();
         this._initTextField("tagsField", this._allTags.join(", "), false);
         this._element("itemsCountText").value =
           PlacesUIUtils.getFormattedString("detailsPane.multipleItems",
                                            [this._itemIds.length]);
       }
 
       // tags selector
       this._rebuildTagsSelectorList();
@@ -236,41 +233,40 @@ var gEditItemOverlay = {
 
     // name picker
     this._initNamePicker();
 
     this._showHideRows();
 
     // observe changes
     if (!this._observersAdded) {
-      if (this._itemId != -1)
+      // Single bookmarks observe any change.  History entries and multiEdit
+      // observe only tags changes, through bookmarks.
+      if (this._itemId != -1 || this._uri || this._multiEdit)
         PlacesUtils.bookmarks.addObserver(this, false);
       window.addEventListener("unload", this, false);
       this._observersAdded = true;
     }
 
     this._initialized = true;
   },
 
-  _getCommonTags: function(aArrIndex) {
-    var tempArray = this._tags[aArrIndex];
-    var isAllTag;
-    for (var k = 0; k < tempArray.length; k++) {
-      isAllTag = true;
-      for (var j = 0; j < this._tags.length; j++) {
-        if (j == aArrIndex)
-          continue;
-        if (this._tags[j].indexOf(tempArray[k]) == -1) {
-          isAllTag = false;
-          break;
-        }
-      }
-      if (isAllTag)
-        this._allTags.push(tempArray[k]);
-    }
+  /**
+   * Finds tags that are in common among this._tags entries that track tags
+   * for each selected uri.
+   * The tags arrays should be kept up-to-date for this to work properly.
+   *
+   * @return array of common tags for the selected uris.
+   */
+  _getCommonTags: function() {
+    return this._tags[0].filter(
+      function (aTag) this._tags.every(
+        function (aTags) aTags.indexOf(aTag) != -1
+      ), this
+    );
   },
 
   _initTextField: function(aTextFieldId, aValue, aReadOnly) {
     var field = this._element(aTextFieldId);
     field.readOnly = aReadOnly !== undefined ? aReadOnly : this._readOnly;
 
     if (field.value != aValue) {
       field.value = aValue;
@@ -453,16 +449,17 @@ var gEditItemOverlay = {
       // getMicrosummaries will throw an exception in at least two cases:
       // 1. the bookmarked URI contains a scheme that the service won't
       //    download for security reasons (currently it only handles http,
       //    https, and file);
       // 2. the page to which the URI refers isn't HTML or XML (the only two
       //    content types the service knows how to summarize).
       this._microsummaries = null;
     }
+
     if (this._microsummaries) {
       var enumerator = this._microsummaries.Enumerate();
 
       if (enumerator.hasMoreElements()) {
         // Show the drop marker if there are microsummaries
         droppable = true;
         while (enumerator.hasMoreElements()) {
           var microsummary = enumerator.getNext()
@@ -536,17 +533,17 @@ var gEditItemOverlay = {
 
       // hide the tag selector if it was previously visible
       var tagsSelectorRow = this._element("tagsSelectorRow");
       if (!tagsSelectorRow.collapsed)
         this.toggleTagsSelector();
     }
 
     if (this._observersAdded) {
-      if (this._itemId != -1)
+      if (this._itemId != -1 || this._uri || this._multiEdit)
         PlacesUtils.bookmarks.removeObserver(this);
 
       this._observersAdded = false;
     }
     if (this._microsummaries) {
       this._microsummaries.removeObserver(this);
       this._microsummaries = null;
     }
@@ -844,17 +841,17 @@ var gEditItemOverlay = {
    * the new item replaces the last menu-item.
    * @param aFolderId
    *        The identifier of the bookmarks folder.
    */
   _getFolderMenuItem:
   function EIO__getFolderMenuItem(aFolderId) {
     var menupopup = this._folderMenuList.menupopup;
 
-    for (var i = 0; i < menupopup.childNodes.length; i++) {
+    for (let i = 0; i < menupopup.childNodes.length; i++) {
       if ("folderId" in menupopup.childNodes[i] &&
           menupopup.childNodes[i].folderId == aFolderId)
         return menupopup.childNodes[i];
     }
 
     // 3 special folders + separator + folder-items-count limit
     if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
       menupopup.removeChild(menupopup.lastChild);
@@ -1062,23 +1059,59 @@ var gEditItemOverlay = {
       break;
     }
   },
 
   // nsINavBookmarkObserver
   onItemChanged: function EIO_onItemChanged(aItemId, aProperty,
                                             aIsAnnotationProperty, aValue,
                                             aLastModified, aItemType) {
+    if (aProperty == "tags") {
+      // Tags case is special, since they should be updated if either:
+      // - the notification is for the edited bookmark
+      // - the notification is for the edited history entry
+      // - the notification is for one of edited uris
+      let shouldUpdateTagsField = this._itemId == aItemId;
+      if (this._itemId == -1 || this._multiEdit) {
+        // Check if the changed uri is part of the modified ones.
+        let changedURI = PlacesUtils.bookmarks.getBookmarkURI(aItemId);
+        let uris = this._multiEdit ? this._uris : [this._uri];
+        uris.forEach(function (aURI, aIndex) {
+          if (aURI.equals(changedURI)) {
+            shouldUpdateTagsField = true;
+            if (this._multiEdit) {
+              this._tags[aIndex] = PlacesUtils.tagging.getTagsForURI(this._uris[aIndex]);
+            }
+          }
+        }, this);
+      }
+
+      if (shouldUpdateTagsField) {
+        if (this._multiEdit) {
+          this._allTags = this._getCommonTags();
+          this._initTextField("tagsField", this._allTags.join(", "), false);
+        }
+        else {
+          let tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
+          this._initTextField("tagsField", tags, false);
+        }
+      }
+
+      // Any tags change should be reflected in the tags selector.
+      this._rebuildTagsSelectorList();
+      return;
+    }
+
     if (this._itemId != aItemId) {
       if (aProperty == "title") {
         // If the title of a folder which is listed within the folders
         // menulist has been changed, we need to update the label of its
         // representing element.
         var menupopup = this._folderMenuList.menupopup;
-        for (var i = 0; i < menupopup.childNodes.length; i++) {
+        for (let i = 0; i < menupopup.childNodes.length; i++) {
           if ("folderId" in menupopup.childNodes[i] &&
               menupopup.childNodes[i].folderId == aItemId) {
             menupopup.childNodes[i].label = aValue;
             break;
           }
         }
       }
 
@@ -1157,33 +1190,16 @@ var gEditItemOverlay = {
     // just setting selectItem _does not_ trigger oncommand, so we don't
     // recurse
     this._folderMenuList.selectedItem = folderItem;
   },
 
   onItemAdded: function EIO_onItemAdded(aItemId, aParentId, aIndex, aItemType,
                                         aURI) {
     this._lastNewItem = aItemId;
-
-    if (this._uri && aItemType == PlacesUtils.bookmarks.TYPE_BOOKMARK &&
-        PlacesUtils.bookmarks.getFolderIdForItem(aParentId) ==
-          PlacesUtils.tagsFolderId) {
-      // Ensure the tagsField is in sync.
-      let tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
-      this._initTextField("tagsField", tags, false);
-    }
   },
 
-  onItemRemoved: function(aItemId, aParentId, aIndex, aItemType) {
-    if (this._uri && aItemType == PlacesUtils.bookmarks.TYPE_BOOKMARK &&
-        PlacesUtils.bookmarks.getFolderIdForItem(aParentId) ==
-          PlacesUtils.tagsFolderId) {
-      // Ensure the tagsField is in sync.
-      let tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
-      this._initTextField("tagsField", tags, false);
-    }
-  },
-
+  onItemRemoved: function() { },
   onBeginUpdateBatch: function() { },
   onEndUpdateBatch: function() { },
   onBeforeItemRemoved: function() { },
   onItemVisited: function() { },
 };