browser/components/places/content/editBookmarkOverlay.js

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.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const LAST_USED_ANNO = "bookmarkPropertiesDialog/folderLastUsed";
michael@0 6 const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
michael@0 7
michael@0 8 var gEditItemOverlay = {
michael@0 9 _uri: null,
michael@0 10 _itemId: -1,
michael@0 11 _itemIds: [],
michael@0 12 _uris: [],
michael@0 13 _tags: [],
michael@0 14 _allTags: [],
michael@0 15 _multiEdit: false,
michael@0 16 _itemType: -1,
michael@0 17 _readOnly: false,
michael@0 18 _hiddenRows: [],
michael@0 19 _observersAdded: false,
michael@0 20 _staticFoldersListBuilt: false,
michael@0 21 _initialized: false,
michael@0 22 _titleOverride: "",
michael@0 23
michael@0 24 // the first field which was edited after this panel was initialized for
michael@0 25 // a certain item
michael@0 26 _firstEditedField: "",
michael@0 27
michael@0 28 get itemId() {
michael@0 29 return this._itemId;
michael@0 30 },
michael@0 31
michael@0 32 get uri() {
michael@0 33 return this._uri;
michael@0 34 },
michael@0 35
michael@0 36 get multiEdit() {
michael@0 37 return this._multiEdit;
michael@0 38 },
michael@0 39
michael@0 40 /**
michael@0 41 * Determines the initial data for the item edited or added by this dialog
michael@0 42 */
michael@0 43 _determineInfo: function EIO__determineInfo(aInfo) {
michael@0 44 // hidden rows
michael@0 45 if (aInfo && aInfo.hiddenRows)
michael@0 46 this._hiddenRows = aInfo.hiddenRows;
michael@0 47 else
michael@0 48 this._hiddenRows.splice(0, this._hiddenRows.length);
michael@0 49 // force-read-only
michael@0 50 this._readOnly = aInfo && aInfo.forceReadOnly;
michael@0 51 this._titleOverride = aInfo && aInfo.titleOverride ? aInfo.titleOverride
michael@0 52 : "";
michael@0 53 },
michael@0 54
michael@0 55 _showHideRows: function EIO__showHideRows() {
michael@0 56 var isBookmark = this._itemId != -1 &&
michael@0 57 this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK;
michael@0 58 var isQuery = false;
michael@0 59 if (this._uri)
michael@0 60 isQuery = this._uri.schemeIs("place");
michael@0 61
michael@0 62 this._element("nameRow").collapsed = this._hiddenRows.indexOf("name") != -1;
michael@0 63 this._element("folderRow").collapsed =
michael@0 64 this._hiddenRows.indexOf("folderPicker") != -1 || this._readOnly;
michael@0 65 this._element("tagsRow").collapsed = !this._uri ||
michael@0 66 this._hiddenRows.indexOf("tags") != -1 || isQuery;
michael@0 67 // Collapse the tag selector if the item does not accept tags.
michael@0 68 if (!this._element("tagsSelectorRow").collapsed &&
michael@0 69 this._element("tagsRow").collapsed)
michael@0 70 this.toggleTagsSelector();
michael@0 71 this._element("descriptionRow").collapsed =
michael@0 72 this._hiddenRows.indexOf("description") != -1 || this._readOnly;
michael@0 73 this._element("keywordRow").collapsed = !isBookmark || this._readOnly ||
michael@0 74 this._hiddenRows.indexOf("keyword") != -1 || isQuery;
michael@0 75 this._element("locationRow").collapsed = !(this._uri && !isQuery) ||
michael@0 76 this._hiddenRows.indexOf("location") != -1;
michael@0 77 this._element("loadInSidebarCheckbox").collapsed = !isBookmark || isQuery ||
michael@0 78 this._readOnly || this._hiddenRows.indexOf("loadInSidebar") != -1;
michael@0 79 this._element("feedLocationRow").collapsed = !this._isLivemark ||
michael@0 80 this._hiddenRows.indexOf("feedLocation") != -1;
michael@0 81 this._element("siteLocationRow").collapsed = !this._isLivemark ||
michael@0 82 this._hiddenRows.indexOf("siteLocation") != -1;
michael@0 83 this._element("selectionCount").hidden = !this._multiEdit;
michael@0 84 },
michael@0 85
michael@0 86 /**
michael@0 87 * Initialize the panel
michael@0 88 * @param aFor
michael@0 89 * Either a places-itemId (of a bookmark, folder or a live bookmark),
michael@0 90 * an array of itemIds (used for bulk tagging), or a URI object (in
michael@0 91 * which case, the panel would be initialized in read-only mode).
michael@0 92 * @param [optional] aInfo
michael@0 93 * JS object which stores additional info for the panel
michael@0 94 * initialization. The following properties may bet set:
michael@0 95 * * hiddenRows (Strings array): list of rows to be hidden regardless
michael@0 96 * of the item edited. Possible values: "title", "location",
michael@0 97 * "description", "keyword", "loadInSidebar", "feedLocation",
michael@0 98 * "siteLocation", folderPicker"
michael@0 99 * * forceReadOnly - set this flag to initialize the panel to its
michael@0 100 * read-only (view) mode even if the given item is editable.
michael@0 101 */
michael@0 102 initPanel: function EIO_initPanel(aFor, aInfo) {
michael@0 103 // For sanity ensure that the implementer has uninited the panel before
michael@0 104 // trying to init it again, or we could end up leaking due to observers.
michael@0 105 if (this._initialized)
michael@0 106 this.uninitPanel(false);
michael@0 107
michael@0 108 var aItemIdList;
michael@0 109 if (Array.isArray(aFor)) {
michael@0 110 aItemIdList = aFor;
michael@0 111 aFor = aItemIdList[0];
michael@0 112 }
michael@0 113 else if (this._multiEdit) {
michael@0 114 this._multiEdit = false;
michael@0 115 this._tags = [];
michael@0 116 this._uris = [];
michael@0 117 this._allTags = [];
michael@0 118 this._itemIds = [];
michael@0 119 this._element("selectionCount").hidden = true;
michael@0 120 }
michael@0 121
michael@0 122 this._folderMenuList = this._element("folderMenuList");
michael@0 123 this._folderTree = this._element("folderTree");
michael@0 124
michael@0 125 this._determineInfo(aInfo);
michael@0 126 if (aFor instanceof Ci.nsIURI) {
michael@0 127 this._itemId = -1;
michael@0 128 this._uri = aFor;
michael@0 129 this._readOnly = true;
michael@0 130 }
michael@0 131 else {
michael@0 132 this._itemId = aFor;
michael@0 133 // We can't store information on invalid itemIds.
michael@0 134 this._readOnly = this._readOnly || this._itemId == -1;
michael@0 135
michael@0 136 var containerId = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
michael@0 137 this._itemType = PlacesUtils.bookmarks.getItemType(this._itemId);
michael@0 138 if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
michael@0 139 this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
michael@0 140 this._initTextField("keywordField",
michael@0 141 PlacesUtils.bookmarks
michael@0 142 .getKeywordForBookmark(this._itemId));
michael@0 143 this._element("loadInSidebarCheckbox").checked =
michael@0 144 PlacesUtils.annotations.itemHasAnnotation(this._itemId,
michael@0 145 PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
michael@0 146 }
michael@0 147 else {
michael@0 148 this._uri = null;
michael@0 149 this._isLivemark = false;
michael@0 150 PlacesUtils.livemarks.getLivemark({id: this._itemId })
michael@0 151 .then(aLivemark => {
michael@0 152 this._isLivemark = true;
michael@0 153 this._initTextField("feedLocationField", aLivemark.feedURI.spec, true);
michael@0 154 this._initTextField("siteLocationField", aLivemark.siteURI ? aLivemark.siteURI.spec : "", true);
michael@0 155 this._showHideRows();
michael@0 156 }, () => undefined);
michael@0 157 }
michael@0 158
michael@0 159 // folder picker
michael@0 160 this._initFolderMenuList(containerId);
michael@0 161
michael@0 162 // description field
michael@0 163 this._initTextField("descriptionField",
michael@0 164 PlacesUIUtils.getItemDescription(this._itemId));
michael@0 165 }
michael@0 166
michael@0 167 if (this._itemId == -1 ||
michael@0 168 this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
michael@0 169 this._isLivemark = false;
michael@0 170
michael@0 171 this._initTextField("locationField", this._uri.spec);
michael@0 172 if (!aItemIdList) {
michael@0 173 var tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
michael@0 174 this._initTextField("tagsField", tags, false);
michael@0 175 }
michael@0 176 else {
michael@0 177 this._multiEdit = true;
michael@0 178 this._allTags = [];
michael@0 179 this._itemIds = aItemIdList;
michael@0 180 for (var i = 0; i < aItemIdList.length; i++) {
michael@0 181 if (aItemIdList[i] instanceof Ci.nsIURI) {
michael@0 182 this._uris[i] = aItemIdList[i];
michael@0 183 this._itemIds[i] = -1;
michael@0 184 }
michael@0 185 else
michael@0 186 this._uris[i] = PlacesUtils.bookmarks.getBookmarkURI(this._itemIds[i]);
michael@0 187 this._tags[i] = PlacesUtils.tagging.getTagsForURI(this._uris[i]);
michael@0 188 }
michael@0 189 this._allTags = this._getCommonTags();
michael@0 190 this._initTextField("tagsField", this._allTags.join(", "), false);
michael@0 191 this._element("itemsCountText").value =
michael@0 192 PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel",
michael@0 193 this._itemIds.length,
michael@0 194 [this._itemIds.length]);
michael@0 195 }
michael@0 196
michael@0 197 // tags selector
michael@0 198 this._rebuildTagsSelectorList();
michael@0 199 }
michael@0 200
michael@0 201 // name picker
michael@0 202 this._initNamePicker();
michael@0 203
michael@0 204 this._showHideRows();
michael@0 205
michael@0 206 // observe changes
michael@0 207 if (!this._observersAdded) {
michael@0 208 // Single bookmarks observe any change. History entries and multiEdit
michael@0 209 // observe only tags changes, through bookmarks.
michael@0 210 if (this._itemId != -1 || this._uri || this._multiEdit)
michael@0 211 PlacesUtils.bookmarks.addObserver(this, false);
michael@0 212 window.addEventListener("unload", this, false);
michael@0 213 this._observersAdded = true;
michael@0 214 }
michael@0 215
michael@0 216 this._initialized = true;
michael@0 217 },
michael@0 218
michael@0 219 /**
michael@0 220 * Finds tags that are in common among this._tags entries that track tags
michael@0 221 * for each selected uri.
michael@0 222 * The tags arrays should be kept up-to-date for this to work properly.
michael@0 223 *
michael@0 224 * @return array of common tags for the selected uris.
michael@0 225 */
michael@0 226 _getCommonTags: function() {
michael@0 227 return this._tags[0].filter(
michael@0 228 function (aTag) this._tags.every(
michael@0 229 function (aTags) aTags.indexOf(aTag) != -1
michael@0 230 ), this
michael@0 231 );
michael@0 232 },
michael@0 233
michael@0 234 _initTextField: function(aTextFieldId, aValue, aReadOnly) {
michael@0 235 var field = this._element(aTextFieldId);
michael@0 236 field.readOnly = aReadOnly !== undefined ? aReadOnly : this._readOnly;
michael@0 237
michael@0 238 if (field.value != aValue) {
michael@0 239 field.value = aValue;
michael@0 240
michael@0 241 // clear the undo stack
michael@0 242 var editor = field.editor;
michael@0 243 if (editor)
michael@0 244 editor.transactionManager.clear();
michael@0 245 }
michael@0 246 },
michael@0 247
michael@0 248 /**
michael@0 249 * Appends a menu-item representing a bookmarks folder to a menu-popup.
michael@0 250 * @param aMenupopup
michael@0 251 * The popup to which the menu-item should be added.
michael@0 252 * @param aFolderId
michael@0 253 * The identifier of the bookmarks folder.
michael@0 254 * @return the new menu item.
michael@0 255 */
michael@0 256 _appendFolderItemToMenupopup:
michael@0 257 function EIO__appendFolderItemToMenuList(aMenupopup, aFolderId) {
michael@0 258 // First make sure the folders-separator is visible
michael@0 259 this._element("foldersSeparator").hidden = false;
michael@0 260
michael@0 261 var folderMenuItem = document.createElement("menuitem");
michael@0 262 var folderTitle = PlacesUtils.bookmarks.getItemTitle(aFolderId)
michael@0 263 folderMenuItem.folderId = aFolderId;
michael@0 264 folderMenuItem.setAttribute("label", folderTitle);
michael@0 265 folderMenuItem.className = "menuitem-iconic folder-icon";
michael@0 266 aMenupopup.appendChild(folderMenuItem);
michael@0 267 return folderMenuItem;
michael@0 268 },
michael@0 269
michael@0 270 _initFolderMenuList: function EIO__initFolderMenuList(aSelectedFolder) {
michael@0 271 // clean up first
michael@0 272 var menupopup = this._folderMenuList.menupopup;
michael@0 273 while (menupopup.childNodes.length > 6)
michael@0 274 menupopup.removeChild(menupopup.lastChild);
michael@0 275
michael@0 276 const bms = PlacesUtils.bookmarks;
michael@0 277 const annos = PlacesUtils.annotations;
michael@0 278
michael@0 279 // Build the static list
michael@0 280 var unfiledItem = this._element("unfiledRootItem");
michael@0 281 if (!this._staticFoldersListBuilt) {
michael@0 282 unfiledItem.label = bms.getItemTitle(PlacesUtils.unfiledBookmarksFolderId);
michael@0 283 unfiledItem.folderId = PlacesUtils.unfiledBookmarksFolderId;
michael@0 284 var bmMenuItem = this._element("bmRootItem");
michael@0 285 bmMenuItem.label = bms.getItemTitle(PlacesUtils.bookmarksMenuFolderId);
michael@0 286 bmMenuItem.folderId = PlacesUtils.bookmarksMenuFolderId;
michael@0 287 var toolbarItem = this._element("toolbarFolderItem");
michael@0 288 toolbarItem.label = bms.getItemTitle(PlacesUtils.toolbarFolderId);
michael@0 289 toolbarItem.folderId = PlacesUtils.toolbarFolderId;
michael@0 290 this._staticFoldersListBuilt = true;
michael@0 291 }
michael@0 292
michael@0 293 // List of recently used folders:
michael@0 294 var folderIds = annos.getItemsWithAnnotation(LAST_USED_ANNO);
michael@0 295
michael@0 296 /**
michael@0 297 * The value of the LAST_USED_ANNO annotation is the time (in the form of
michael@0 298 * Date.getTime) at which the folder has been last used.
michael@0 299 *
michael@0 300 * First we build the annotated folders array, each item has both the
michael@0 301 * folder identifier and the time at which it was last-used by this dialog
michael@0 302 * set. Then we sort it descendingly based on the time field.
michael@0 303 */
michael@0 304 this._recentFolders = [];
michael@0 305 for (var i = 0; i < folderIds.length; i++) {
michael@0 306 var lastUsed = annos.getItemAnnotation(folderIds[i], LAST_USED_ANNO);
michael@0 307 this._recentFolders.push({ folderId: folderIds[i], lastUsed: lastUsed });
michael@0 308 }
michael@0 309 this._recentFolders.sort(function(a, b) {
michael@0 310 if (b.lastUsed < a.lastUsed)
michael@0 311 return -1;
michael@0 312 if (b.lastUsed > a.lastUsed)
michael@0 313 return 1;
michael@0 314 return 0;
michael@0 315 });
michael@0 316
michael@0 317 var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST,
michael@0 318 this._recentFolders.length);
michael@0 319 for (var i = 0; i < numberOfItems; i++) {
michael@0 320 this._appendFolderItemToMenupopup(menupopup,
michael@0 321 this._recentFolders[i].folderId);
michael@0 322 }
michael@0 323
michael@0 324 var defaultItem = this._getFolderMenuItem(aSelectedFolder);
michael@0 325 this._folderMenuList.selectedItem = defaultItem;
michael@0 326
michael@0 327 // Set a selectedIndex attribute to show special icons
michael@0 328 this._folderMenuList.setAttribute("selectedIndex",
michael@0 329 this._folderMenuList.selectedIndex);
michael@0 330
michael@0 331 // Hide the folders-separator if no folder is annotated as recently-used
michael@0 332 this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 6);
michael@0 333 this._folderMenuList.disabled = this._readOnly;
michael@0 334 },
michael@0 335
michael@0 336 QueryInterface: function EIO_QueryInterface(aIID) {
michael@0 337 if (aIID.equals(Ci.nsIDOMEventListener) ||
michael@0 338 aIID.equals(Ci.nsINavBookmarkObserver) ||
michael@0 339 aIID.equals(Ci.nsISupports))
michael@0 340 return this;
michael@0 341
michael@0 342 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 343 },
michael@0 344
michael@0 345 _element: function EIO__element(aID) {
michael@0 346 return document.getElementById("editBMPanel_" + aID);
michael@0 347 },
michael@0 348
michael@0 349 _getItemStaticTitle: function EIO__getItemStaticTitle() {
michael@0 350 if (this._titleOverride)
michael@0 351 return this._titleOverride;
michael@0 352
michael@0 353 let title = "";
michael@0 354 if (this._itemId == -1) {
michael@0 355 title = PlacesUtils.history.getPageTitle(this._uri);
michael@0 356 }
michael@0 357 else {
michael@0 358 title = PlacesUtils.bookmarks.getItemTitle(this._itemId);
michael@0 359 }
michael@0 360 return title;
michael@0 361 },
michael@0 362
michael@0 363 _initNamePicker: function EIO_initNamePicker() {
michael@0 364 var namePicker = this._element("namePicker");
michael@0 365 namePicker.value = this._getItemStaticTitle();
michael@0 366 namePicker.readOnly = this._readOnly;
michael@0 367
michael@0 368 // clear the undo stack
michael@0 369 var editor = namePicker.editor;
michael@0 370 if (editor)
michael@0 371 editor.transactionManager.clear();
michael@0 372 },
michael@0 373
michael@0 374 uninitPanel: function EIO_uninitPanel(aHideCollapsibleElements) {
michael@0 375 if (aHideCollapsibleElements) {
michael@0 376 // hide the folder tree if it was previously visible
michael@0 377 var folderTreeRow = this._element("folderTreeRow");
michael@0 378 if (!folderTreeRow.collapsed)
michael@0 379 this.toggleFolderTreeVisibility();
michael@0 380
michael@0 381 // hide the tag selector if it was previously visible
michael@0 382 var tagsSelectorRow = this._element("tagsSelectorRow");
michael@0 383 if (!tagsSelectorRow.collapsed)
michael@0 384 this.toggleTagsSelector();
michael@0 385 }
michael@0 386
michael@0 387 if (this._observersAdded) {
michael@0 388 if (this._itemId != -1 || this._uri || this._multiEdit)
michael@0 389 PlacesUtils.bookmarks.removeObserver(this);
michael@0 390
michael@0 391 this._observersAdded = false;
michael@0 392 }
michael@0 393
michael@0 394 this._itemId = -1;
michael@0 395 this._uri = null;
michael@0 396 this._uris = [];
michael@0 397 this._tags = [];
michael@0 398 this._allTags = [];
michael@0 399 this._itemIds = [];
michael@0 400 this._multiEdit = false;
michael@0 401 this._firstEditedField = "";
michael@0 402 this._initialized = false;
michael@0 403 this._titleOverride = "";
michael@0 404 this._readOnly = false;
michael@0 405 },
michael@0 406
michael@0 407 onTagsFieldBlur: function EIO_onTagsFieldBlur() {
michael@0 408 if (this._updateTags()) // if anything has changed
michael@0 409 this._mayUpdateFirstEditField("tagsField");
michael@0 410 },
michael@0 411
michael@0 412 _updateTags: function EIO__updateTags() {
michael@0 413 if (this._multiEdit)
michael@0 414 return this._updateMultipleTagsForItems();
michael@0 415 return this._updateSingleTagForItem();
michael@0 416 },
michael@0 417
michael@0 418 _updateSingleTagForItem: function EIO__updateSingleTagForItem() {
michael@0 419 var currentTags = PlacesUtils.tagging.getTagsForURI(this._uri);
michael@0 420 var tags = this._getTagsArrayFromTagField();
michael@0 421 if (tags.length > 0 || currentTags.length > 0) {
michael@0 422 var tagsToRemove = [];
michael@0 423 var tagsToAdd = [];
michael@0 424 var txns = [];
michael@0 425 for (var i = 0; i < currentTags.length; i++) {
michael@0 426 if (tags.indexOf(currentTags[i]) == -1)
michael@0 427 tagsToRemove.push(currentTags[i]);
michael@0 428 }
michael@0 429 for (var i = 0; i < tags.length; i++) {
michael@0 430 if (currentTags.indexOf(tags[i]) == -1)
michael@0 431 tagsToAdd.push(tags[i]);
michael@0 432 }
michael@0 433
michael@0 434 if (tagsToRemove.length > 0) {
michael@0 435 let untagTxn = new PlacesUntagURITransaction(this._uri, tagsToRemove);
michael@0 436 txns.push(untagTxn);
michael@0 437 }
michael@0 438 if (tagsToAdd.length > 0) {
michael@0 439 let tagTxn = new PlacesTagURITransaction(this._uri, tagsToAdd);
michael@0 440 txns.push(tagTxn);
michael@0 441 }
michael@0 442
michael@0 443 if (txns.length > 0) {
michael@0 444 let aggregate = new PlacesAggregatedTransaction("Update tags", txns);
michael@0 445 PlacesUtils.transactionManager.doTransaction(aggregate);
michael@0 446
michael@0 447 // Ensure the tagsField is in sync, clean it up from empty tags
michael@0 448 var tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
michael@0 449 this._initTextField("tagsField", tags, false);
michael@0 450 return true;
michael@0 451 }
michael@0 452 }
michael@0 453 return false;
michael@0 454 },
michael@0 455
michael@0 456 /**
michael@0 457 * Stores the first-edit field for this dialog, if the passed-in field
michael@0 458 * is indeed the first edited field
michael@0 459 * @param aNewField
michael@0 460 * the id of the field that may be set (without the "editBMPanel_"
michael@0 461 * prefix)
michael@0 462 */
michael@0 463 _mayUpdateFirstEditField: function EIO__mayUpdateFirstEditField(aNewField) {
michael@0 464 // * The first-edit-field behavior is not applied in the multi-edit case
michael@0 465 // * if this._firstEditedField is already set, this is not the first field,
michael@0 466 // so there's nothing to do
michael@0 467 if (this._multiEdit || this._firstEditedField)
michael@0 468 return;
michael@0 469
michael@0 470 this._firstEditedField = aNewField;
michael@0 471
michael@0 472 // set the pref
michael@0 473 var prefs = Cc["@mozilla.org/preferences-service;1"].
michael@0 474 getService(Ci.nsIPrefBranch);
michael@0 475 prefs.setCharPref("browser.bookmarks.editDialog.firstEditField", aNewField);
michael@0 476 },
michael@0 477
michael@0 478 _updateMultipleTagsForItems: function EIO__updateMultipleTagsForItems() {
michael@0 479 var tags = this._getTagsArrayFromTagField();
michael@0 480 if (tags.length > 0 || this._allTags.length > 0) {
michael@0 481 var tagsToRemove = [];
michael@0 482 var tagsToAdd = [];
michael@0 483 var txns = [];
michael@0 484 for (var i = 0; i < this._allTags.length; i++) {
michael@0 485 if (tags.indexOf(this._allTags[i]) == -1)
michael@0 486 tagsToRemove.push(this._allTags[i]);
michael@0 487 }
michael@0 488 for (var i = 0; i < this._tags.length; i++) {
michael@0 489 tagsToAdd[i] = [];
michael@0 490 for (var j = 0; j < tags.length; j++) {
michael@0 491 if (this._tags[i].indexOf(tags[j]) == -1)
michael@0 492 tagsToAdd[i].push(tags[j]);
michael@0 493 }
michael@0 494 }
michael@0 495
michael@0 496 if (tagsToAdd.length > 0) {
michael@0 497 for (let i = 0; i < this._uris.length; i++) {
michael@0 498 if (tagsToAdd[i].length > 0) {
michael@0 499 let tagTxn = new PlacesTagURITransaction(this._uris[i],
michael@0 500 tagsToAdd[i]);
michael@0 501 txns.push(tagTxn);
michael@0 502 }
michael@0 503 }
michael@0 504 }
michael@0 505 if (tagsToRemove.length > 0) {
michael@0 506 for (let i = 0; i < this._uris.length; i++) {
michael@0 507 let untagTxn = new PlacesUntagURITransaction(this._uris[i],
michael@0 508 tagsToRemove);
michael@0 509 txns.push(untagTxn);
michael@0 510 }
michael@0 511 }
michael@0 512
michael@0 513 if (txns.length > 0) {
michael@0 514 let aggregate = new PlacesAggregatedTransaction("Update tags", txns);
michael@0 515 PlacesUtils.transactionManager.doTransaction(aggregate);
michael@0 516
michael@0 517 this._allTags = tags;
michael@0 518 this._tags = [];
michael@0 519 for (let i = 0; i < this._uris.length; i++) {
michael@0 520 this._tags[i] = PlacesUtils.tagging.getTagsForURI(this._uris[i]);
michael@0 521 }
michael@0 522
michael@0 523 // Ensure the tagsField is in sync, clean it up from empty tags
michael@0 524 this._initTextField("tagsField", tags, false);
michael@0 525 return true;
michael@0 526 }
michael@0 527 }
michael@0 528 return false;
michael@0 529 },
michael@0 530
michael@0 531 onNamePickerChange: function EIO_onNamePickerChange() {
michael@0 532 if (this._itemId == -1)
michael@0 533 return;
michael@0 534
michael@0 535 var namePicker = this._element("namePicker")
michael@0 536
michael@0 537 // Here we update either the item title or its cached static title
michael@0 538 var newTitle = namePicker.value;
michael@0 539 if (!newTitle &&
michael@0 540 PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) == PlacesUtils.tagsFolderId) {
michael@0 541 // We don't allow setting an empty title for a tag, restore the old one.
michael@0 542 this._initNamePicker();
michael@0 543 }
michael@0 544 else if (this._getItemStaticTitle() != newTitle) {
michael@0 545 this._mayUpdateFirstEditField("namePicker");
michael@0 546 let txn = new PlacesEditItemTitleTransaction(this._itemId, newTitle);
michael@0 547 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 548 }
michael@0 549 },
michael@0 550
michael@0 551 onDescriptionFieldBlur: function EIO_onDescriptionFieldBlur() {
michael@0 552 var description = this._element("descriptionField").value;
michael@0 553 if (description != PlacesUIUtils.getItemDescription(this._itemId)) {
michael@0 554 var annoObj = { name : PlacesUIUtils.DESCRIPTION_ANNO,
michael@0 555 type : Ci.nsIAnnotationService.TYPE_STRING,
michael@0 556 flags : 0,
michael@0 557 value : description,
michael@0 558 expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
michael@0 559 var txn = new PlacesSetItemAnnotationTransaction(this._itemId, annoObj);
michael@0 560 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 561 }
michael@0 562 },
michael@0 563
michael@0 564 onLocationFieldBlur: function EIO_onLocationFieldBlur() {
michael@0 565 var uri;
michael@0 566 try {
michael@0 567 uri = PlacesUIUtils.createFixedURI(this._element("locationField").value);
michael@0 568 }
michael@0 569 catch(ex) { return; }
michael@0 570
michael@0 571 if (!this._uri.equals(uri)) {
michael@0 572 var txn = new PlacesEditBookmarkURITransaction(this._itemId, uri);
michael@0 573 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 574 this._uri = uri;
michael@0 575 }
michael@0 576 },
michael@0 577
michael@0 578 onKeywordFieldBlur: function EIO_onKeywordFieldBlur() {
michael@0 579 var keyword = this._element("keywordField").value;
michael@0 580 if (keyword != PlacesUtils.bookmarks.getKeywordForBookmark(this._itemId)) {
michael@0 581 var txn = new PlacesEditBookmarkKeywordTransaction(this._itemId, keyword);
michael@0 582 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 583 }
michael@0 584 },
michael@0 585
michael@0 586 onLoadInSidebarCheckboxCommand:
michael@0 587 function EIO_onLoadInSidebarCheckboxCommand() {
michael@0 588 let annoObj = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO };
michael@0 589 if (this._element("loadInSidebarCheckbox").checked)
michael@0 590 annoObj.value = true;
michael@0 591 let txn = new PlacesSetItemAnnotationTransaction(this._itemId, annoObj);
michael@0 592 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 593 },
michael@0 594
michael@0 595 toggleFolderTreeVisibility: function EIO_toggleFolderTreeVisibility() {
michael@0 596 var expander = this._element("foldersExpander");
michael@0 597 var folderTreeRow = this._element("folderTreeRow");
michael@0 598 if (!folderTreeRow.collapsed) {
michael@0 599 expander.className = "expander-down";
michael@0 600 expander.setAttribute("tooltiptext",
michael@0 601 expander.getAttribute("tooltiptextdown"));
michael@0 602 folderTreeRow.collapsed = true;
michael@0 603 this._element("chooseFolderSeparator").hidden =
michael@0 604 this._element("chooseFolderMenuItem").hidden = false;
michael@0 605 }
michael@0 606 else {
michael@0 607 expander.className = "expander-up"
michael@0 608 expander.setAttribute("tooltiptext",
michael@0 609 expander.getAttribute("tooltiptextup"));
michael@0 610 folderTreeRow.collapsed = false;
michael@0 611
michael@0 612 // XXXmano: Ideally we would only do this once, but for some odd reason,
michael@0 613 // the editable mode set on this tree, together with its collapsed state
michael@0 614 // breaks the view.
michael@0 615 const FOLDER_TREE_PLACE_URI =
michael@0 616 "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
michael@0 617 PlacesUIUtils.allBookmarksFolderId;
michael@0 618 this._folderTree.place = FOLDER_TREE_PLACE_URI;
michael@0 619
michael@0 620 this._element("chooseFolderSeparator").hidden =
michael@0 621 this._element("chooseFolderMenuItem").hidden = true;
michael@0 622 var currentFolder = this._getFolderIdFromMenuList();
michael@0 623 this._folderTree.selectItems([currentFolder]);
michael@0 624 this._folderTree.focus();
michael@0 625 }
michael@0 626 },
michael@0 627
michael@0 628 _getFolderIdFromMenuList:
michael@0 629 function EIO__getFolderIdFromMenuList() {
michael@0 630 var selectedItem = this._folderMenuList.selectedItem;
michael@0 631 NS_ASSERT("folderId" in selectedItem,
michael@0 632 "Invalid menuitem in the folders-menulist");
michael@0 633 return selectedItem.folderId;
michael@0 634 },
michael@0 635
michael@0 636 /**
michael@0 637 * Get the corresponding menu-item in the folder-menu-list for a bookmarks
michael@0 638 * folder if such an item exists. Otherwise, this creates a menu-item for the
michael@0 639 * folder. If the items-count limit (see MAX_FOLDERS_IN_MENU_LIST) is reached,
michael@0 640 * the new item replaces the last menu-item.
michael@0 641 * @param aFolderId
michael@0 642 * The identifier of the bookmarks folder.
michael@0 643 */
michael@0 644 _getFolderMenuItem:
michael@0 645 function EIO__getFolderMenuItem(aFolderId) {
michael@0 646 var menupopup = this._folderMenuList.menupopup;
michael@0 647
michael@0 648 for (let i = 0; i < menupopup.childNodes.length; i++) {
michael@0 649 if ("folderId" in menupopup.childNodes[i] &&
michael@0 650 menupopup.childNodes[i].folderId == aFolderId)
michael@0 651 return menupopup.childNodes[i];
michael@0 652 }
michael@0 653
michael@0 654 // 3 special folders + separator + folder-items-count limit
michael@0 655 if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
michael@0 656 menupopup.removeChild(menupopup.lastChild);
michael@0 657
michael@0 658 return this._appendFolderItemToMenupopup(menupopup, aFolderId);
michael@0 659 },
michael@0 660
michael@0 661 onFolderMenuListCommand: function EIO_onFolderMenuListCommand(aEvent) {
michael@0 662 // Set a selectedIndex attribute to show special icons
michael@0 663 this._folderMenuList.setAttribute("selectedIndex",
michael@0 664 this._folderMenuList.selectedIndex);
michael@0 665
michael@0 666 if (aEvent.target.id == "editBMPanel_chooseFolderMenuItem") {
michael@0 667 // reset the selection back to where it was and expand the tree
michael@0 668 // (this menu-item is hidden when the tree is already visible
michael@0 669 var container = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
michael@0 670 var item = this._getFolderMenuItem(container);
michael@0 671 this._folderMenuList.selectedItem = item;
michael@0 672 // XXXmano HACK: setTimeout 100, otherwise focus goes back to the
michael@0 673 // menulist right away
michael@0 674 setTimeout(function(self) self.toggleFolderTreeVisibility(), 100, this);
michael@0 675 return;
michael@0 676 }
michael@0 677
michael@0 678 // Move the item
michael@0 679 var container = this._getFolderIdFromMenuList();
michael@0 680 if (PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) != container) {
michael@0 681 var txn = new PlacesMoveItemTransaction(this._itemId,
michael@0 682 container,
michael@0 683 PlacesUtils.bookmarks.DEFAULT_INDEX);
michael@0 684 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 685
michael@0 686 // Mark the containing folder as recently-used if it isn't in the
michael@0 687 // static list
michael@0 688 if (container != PlacesUtils.unfiledBookmarksFolderId &&
michael@0 689 container != PlacesUtils.toolbarFolderId &&
michael@0 690 container != PlacesUtils.bookmarksMenuFolderId)
michael@0 691 this._markFolderAsRecentlyUsed(container);
michael@0 692 }
michael@0 693
michael@0 694 // Update folder-tree selection
michael@0 695 var folderTreeRow = this._element("folderTreeRow");
michael@0 696 if (!folderTreeRow.collapsed) {
michael@0 697 var selectedNode = this._folderTree.selectedNode;
michael@0 698 if (!selectedNode ||
michael@0 699 PlacesUtils.getConcreteItemId(selectedNode) != container)
michael@0 700 this._folderTree.selectItems([container]);
michael@0 701 }
michael@0 702 },
michael@0 703
michael@0 704 onFolderTreeSelect: function EIO_onFolderTreeSelect() {
michael@0 705 var selectedNode = this._folderTree.selectedNode;
michael@0 706
michael@0 707 // Disable the "New Folder" button if we cannot create a new folder
michael@0 708 this._element("newFolderButton")
michael@0 709 .disabled = !this._folderTree.insertionPoint || !selectedNode;
michael@0 710
michael@0 711 if (!selectedNode)
michael@0 712 return;
michael@0 713
michael@0 714 var folderId = PlacesUtils.getConcreteItemId(selectedNode);
michael@0 715 if (this._getFolderIdFromMenuList() == folderId)
michael@0 716 return;
michael@0 717
michael@0 718 var folderItem = this._getFolderMenuItem(folderId);
michael@0 719 this._folderMenuList.selectedItem = folderItem;
michael@0 720 folderItem.doCommand();
michael@0 721 },
michael@0 722
michael@0 723 _markFolderAsRecentlyUsed:
michael@0 724 function EIO__markFolderAsRecentlyUsed(aFolderId) {
michael@0 725 var txns = [];
michael@0 726
michael@0 727 // Expire old unused recent folders
michael@0 728 var anno = this._getLastUsedAnnotationObject(false);
michael@0 729 while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
michael@0 730 var folderId = this._recentFolders.pop().folderId;
michael@0 731 let annoTxn = new PlacesSetItemAnnotationTransaction(folderId, anno);
michael@0 732 txns.push(annoTxn);
michael@0 733 }
michael@0 734
michael@0 735 // Mark folder as recently used
michael@0 736 anno = this._getLastUsedAnnotationObject(true);
michael@0 737 let annoTxn = new PlacesSetItemAnnotationTransaction(aFolderId, anno);
michael@0 738 txns.push(annoTxn);
michael@0 739
michael@0 740 let aggregate = new PlacesAggregatedTransaction("Update last used folders", txns);
michael@0 741 PlacesUtils.transactionManager.doTransaction(aggregate);
michael@0 742 },
michael@0 743
michael@0 744 /**
michael@0 745 * Returns an object which could then be used to set/unset the
michael@0 746 * LAST_USED_ANNO annotation for a folder.
michael@0 747 *
michael@0 748 * @param aLastUsed
michael@0 749 * Whether to set or unset the LAST_USED_ANNO annotation.
michael@0 750 * @returns an object representing the annotation which could then be used
michael@0 751 * with the transaction manager.
michael@0 752 */
michael@0 753 _getLastUsedAnnotationObject:
michael@0 754 function EIO__getLastUsedAnnotationObject(aLastUsed) {
michael@0 755 var anno = { name: LAST_USED_ANNO,
michael@0 756 type: Ci.nsIAnnotationService.TYPE_INT32,
michael@0 757 flags: 0,
michael@0 758 value: aLastUsed ? new Date().getTime() : null,
michael@0 759 expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
michael@0 760
michael@0 761 return anno;
michael@0 762 },
michael@0 763
michael@0 764 _rebuildTagsSelectorList: function EIO__rebuildTagsSelectorList() {
michael@0 765 var tagsSelector = this._element("tagsSelector");
michael@0 766 var tagsSelectorRow = this._element("tagsSelectorRow");
michael@0 767 if (tagsSelectorRow.collapsed)
michael@0 768 return;
michael@0 769
michael@0 770 // Save the current scroll position and restore it after the rebuild.
michael@0 771 let firstIndex = tagsSelector.getIndexOfFirstVisibleRow();
michael@0 772 let selectedIndex = tagsSelector.selectedIndex;
michael@0 773 let selectedTag = selectedIndex >= 0 ? tagsSelector.selectedItem.label
michael@0 774 : null;
michael@0 775
michael@0 776 while (tagsSelector.hasChildNodes())
michael@0 777 tagsSelector.removeChild(tagsSelector.lastChild);
michael@0 778
michael@0 779 var tagsInField = this._getTagsArrayFromTagField();
michael@0 780 var allTags = PlacesUtils.tagging.allTags;
michael@0 781 for (var i = 0; i < allTags.length; i++) {
michael@0 782 var tag = allTags[i];
michael@0 783 var elt = document.createElement("listitem");
michael@0 784 elt.setAttribute("type", "checkbox");
michael@0 785 elt.setAttribute("label", tag);
michael@0 786 if (tagsInField.indexOf(tag) != -1)
michael@0 787 elt.setAttribute("checked", "true");
michael@0 788 tagsSelector.appendChild(elt);
michael@0 789 if (selectedTag === tag)
michael@0 790 selectedIndex = tagsSelector.getIndexOfItem(elt);
michael@0 791 }
michael@0 792
michael@0 793 // Restore position.
michael@0 794 // The listbox allows to scroll only if the required offset doesn't
michael@0 795 // overflow its capacity, thus need to adjust the index for removals.
michael@0 796 firstIndex =
michael@0 797 Math.min(firstIndex,
michael@0 798 tagsSelector.itemCount - tagsSelector.getNumberOfVisibleRows());
michael@0 799 tagsSelector.scrollToIndex(firstIndex);
michael@0 800 if (selectedIndex >= 0 && tagsSelector.itemCount > 0) {
michael@0 801 selectedIndex = Math.min(selectedIndex, tagsSelector.itemCount - 1);
michael@0 802 tagsSelector.selectedIndex = selectedIndex;
michael@0 803 tagsSelector.ensureIndexIsVisible(selectedIndex);
michael@0 804 }
michael@0 805 },
michael@0 806
michael@0 807 toggleTagsSelector: function EIO_toggleTagsSelector() {
michael@0 808 var tagsSelector = this._element("tagsSelector");
michael@0 809 var tagsSelectorRow = this._element("tagsSelectorRow");
michael@0 810 var expander = this._element("tagsSelectorExpander");
michael@0 811 if (tagsSelectorRow.collapsed) {
michael@0 812 expander.className = "expander-up";
michael@0 813 expander.setAttribute("tooltiptext",
michael@0 814 expander.getAttribute("tooltiptextup"));
michael@0 815 tagsSelectorRow.collapsed = false;
michael@0 816 this._rebuildTagsSelectorList();
michael@0 817
michael@0 818 // This is a no-op if we've added the listener.
michael@0 819 tagsSelector.addEventListener("CheckboxStateChange", this, false);
michael@0 820 }
michael@0 821 else {
michael@0 822 expander.className = "expander-down";
michael@0 823 expander.setAttribute("tooltiptext",
michael@0 824 expander.getAttribute("tooltiptextdown"));
michael@0 825 tagsSelectorRow.collapsed = true;
michael@0 826 }
michael@0 827 },
michael@0 828
michael@0 829 /**
michael@0 830 * Splits "tagsField" element value, returning an array of valid tag strings.
michael@0 831 *
michael@0 832 * @return Array of tag strings found in the field value.
michael@0 833 */
michael@0 834 _getTagsArrayFromTagField: function EIO__getTagsArrayFromTagField() {
michael@0 835 let tags = this._element("tagsField").value;
michael@0 836 return tags.trim()
michael@0 837 .split(/\s*,\s*/) // Split on commas and remove spaces.
michael@0 838 .filter(function (tag) tag.length > 0); // Kill empty tags.
michael@0 839 },
michael@0 840
michael@0 841 newFolder: function EIO_newFolder() {
michael@0 842 var ip = this._folderTree.insertionPoint;
michael@0 843
michael@0 844 // default to the bookmarks menu folder
michael@0 845 if (!ip || ip.itemId == PlacesUIUtils.allBookmarksFolderId) {
michael@0 846 ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
michael@0 847 PlacesUtils.bookmarks.DEFAULT_INDEX,
michael@0 848 Ci.nsITreeView.DROP_ON);
michael@0 849 }
michael@0 850
michael@0 851 // XXXmano: add a separate "New Folder" string at some point...
michael@0 852 var defaultLabel = this._element("newFolderButton").label;
michael@0 853 var txn = new PlacesCreateFolderTransaction(defaultLabel, ip.itemId, ip.index);
michael@0 854 PlacesUtils.transactionManager.doTransaction(txn);
michael@0 855 this._folderTree.focus();
michael@0 856 this._folderTree.selectItems([ip.itemId]);
michael@0 857 PlacesUtils.asContainer(this._folderTree.selectedNode).containerOpen = true;
michael@0 858 this._folderTree.selectItems([this._lastNewItem]);
michael@0 859 this._folderTree.startEditing(this._folderTree.view.selection.currentIndex,
michael@0 860 this._folderTree.columns.getFirstColumn());
michael@0 861 },
michael@0 862
michael@0 863 // nsIDOMEventListener
michael@0 864 handleEvent: function EIO_nsIDOMEventListener(aEvent) {
michael@0 865 switch (aEvent.type) {
michael@0 866 case "CheckboxStateChange":
michael@0 867 // Update the tags field when items are checked/unchecked in the listbox
michael@0 868 var tags = this._getTagsArrayFromTagField();
michael@0 869
michael@0 870 if (aEvent.target.checked) {
michael@0 871 if (tags.indexOf(aEvent.target.label) == -1)
michael@0 872 tags.push(aEvent.target.label);
michael@0 873 }
michael@0 874 else {
michael@0 875 var indexOfItem = tags.indexOf(aEvent.target.label);
michael@0 876 if (indexOfItem != -1)
michael@0 877 tags.splice(indexOfItem, 1);
michael@0 878 }
michael@0 879 this._element("tagsField").value = tags.join(", ");
michael@0 880 this._updateTags();
michael@0 881 break;
michael@0 882 case "unload":
michael@0 883 this.uninitPanel(false);
michael@0 884 break;
michael@0 885 }
michael@0 886 },
michael@0 887
michael@0 888 // nsINavBookmarkObserver
michael@0 889 onItemChanged: function EIO_onItemChanged(aItemId, aProperty,
michael@0 890 aIsAnnotationProperty, aValue,
michael@0 891 aLastModified, aItemType) {
michael@0 892 if (aProperty == "tags") {
michael@0 893 // Tags case is special, since they should be updated if either:
michael@0 894 // - the notification is for the edited bookmark
michael@0 895 // - the notification is for the edited history entry
michael@0 896 // - the notification is for one of edited uris
michael@0 897 let shouldUpdateTagsField = this._itemId == aItemId;
michael@0 898 if (this._itemId == -1 || this._multiEdit) {
michael@0 899 // Check if the changed uri is part of the modified ones.
michael@0 900 let changedURI = PlacesUtils.bookmarks.getBookmarkURI(aItemId);
michael@0 901 let uris = this._multiEdit ? this._uris : [this._uri];
michael@0 902 uris.forEach(function (aURI, aIndex) {
michael@0 903 if (aURI.equals(changedURI)) {
michael@0 904 shouldUpdateTagsField = true;
michael@0 905 if (this._multiEdit) {
michael@0 906 this._tags[aIndex] = PlacesUtils.tagging.getTagsForURI(this._uris[aIndex]);
michael@0 907 }
michael@0 908 }
michael@0 909 }, this);
michael@0 910 }
michael@0 911
michael@0 912 if (shouldUpdateTagsField) {
michael@0 913 if (this._multiEdit) {
michael@0 914 this._allTags = this._getCommonTags();
michael@0 915 this._initTextField("tagsField", this._allTags.join(", "), false);
michael@0 916 }
michael@0 917 else {
michael@0 918 let tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
michael@0 919 this._initTextField("tagsField", tags, false);
michael@0 920 }
michael@0 921 }
michael@0 922
michael@0 923 // Any tags change should be reflected in the tags selector.
michael@0 924 this._rebuildTagsSelectorList();
michael@0 925 return;
michael@0 926 }
michael@0 927
michael@0 928 if (this._itemId != aItemId) {
michael@0 929 if (aProperty == "title") {
michael@0 930 // If the title of a folder which is listed within the folders
michael@0 931 // menulist has been changed, we need to update the label of its
michael@0 932 // representing element.
michael@0 933 var menupopup = this._folderMenuList.menupopup;
michael@0 934 for (let i = 0; i < menupopup.childNodes.length; i++) {
michael@0 935 if ("folderId" in menupopup.childNodes[i] &&
michael@0 936 menupopup.childNodes[i].folderId == aItemId) {
michael@0 937 menupopup.childNodes[i].label = aValue;
michael@0 938 break;
michael@0 939 }
michael@0 940 }
michael@0 941 }
michael@0 942
michael@0 943 return;
michael@0 944 }
michael@0 945
michael@0 946 switch (aProperty) {
michael@0 947 case "title":
michael@0 948 var namePicker = this._element("namePicker");
michael@0 949 if (namePicker.value != aValue) {
michael@0 950 namePicker.value = aValue;
michael@0 951 // clear undo stack
michael@0 952 namePicker.editor.transactionManager.clear();
michael@0 953 }
michael@0 954 break;
michael@0 955 case "uri":
michael@0 956 var locationField = this._element("locationField");
michael@0 957 if (locationField.value != aValue) {
michael@0 958 this._uri = Cc["@mozilla.org/network/io-service;1"].
michael@0 959 getService(Ci.nsIIOService).
michael@0 960 newURI(aValue, null, null);
michael@0 961 this._initTextField("locationField", this._uri.spec);
michael@0 962 this._initNamePicker();
michael@0 963 this._initTextField("tagsField",
michael@0 964 PlacesUtils.tagging
michael@0 965 .getTagsForURI(this._uri).join(", "),
michael@0 966 false);
michael@0 967 this._rebuildTagsSelectorList();
michael@0 968 }
michael@0 969 break;
michael@0 970 case "keyword":
michael@0 971 this._initTextField("keywordField",
michael@0 972 PlacesUtils.bookmarks
michael@0 973 .getKeywordForBookmark(this._itemId));
michael@0 974 break;
michael@0 975 case PlacesUIUtils.DESCRIPTION_ANNO:
michael@0 976 this._initTextField("descriptionField",
michael@0 977 PlacesUIUtils.getItemDescription(this._itemId));
michael@0 978 break;
michael@0 979 case PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO:
michael@0 980 this._element("loadInSidebarCheckbox").checked =
michael@0 981 PlacesUtils.annotations.itemHasAnnotation(this._itemId,
michael@0 982 PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO);
michael@0 983 break;
michael@0 984 case PlacesUtils.LMANNO_FEEDURI:
michael@0 985 let feedURISpec =
michael@0 986 PlacesUtils.annotations.getItemAnnotation(this._itemId,
michael@0 987 PlacesUtils.LMANNO_FEEDURI);
michael@0 988 this._initTextField("feedLocationField", feedURISpec, true);
michael@0 989 break;
michael@0 990 case PlacesUtils.LMANNO_SITEURI:
michael@0 991 let siteURISpec = "";
michael@0 992 try {
michael@0 993 siteURISpec =
michael@0 994 PlacesUtils.annotations.getItemAnnotation(this._itemId,
michael@0 995 PlacesUtils.LMANNO_SITEURI);
michael@0 996 } catch (ex) {}
michael@0 997 this._initTextField("siteLocationField", siteURISpec, true);
michael@0 998 break;
michael@0 999 }
michael@0 1000 },
michael@0 1001
michael@0 1002 onItemMoved: function EIO_onItemMoved(aItemId, aOldParent, aOldIndex,
michael@0 1003 aNewParent, aNewIndex, aItemType) {
michael@0 1004 if (aItemId != this._itemId ||
michael@0 1005 aNewParent == this._getFolderIdFromMenuList())
michael@0 1006 return;
michael@0 1007
michael@0 1008 var folderItem = this._getFolderMenuItem(aNewParent);
michael@0 1009
michael@0 1010 // just setting selectItem _does not_ trigger oncommand, so we don't
michael@0 1011 // recurse
michael@0 1012 this._folderMenuList.selectedItem = folderItem;
michael@0 1013 },
michael@0 1014
michael@0 1015 onItemAdded: function EIO_onItemAdded(aItemId, aParentId, aIndex, aItemType,
michael@0 1016 aURI) {
michael@0 1017 this._lastNewItem = aItemId;
michael@0 1018 },
michael@0 1019
michael@0 1020 onItemRemoved: function() { },
michael@0 1021 onBeginUpdateBatch: function() { },
michael@0 1022 onEndUpdateBatch: function() { },
michael@0 1023 onItemVisited: function() { },
michael@0 1024 };

mercurial