1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/components/places/content/bookmarkProperties.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,650 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/** 1.10 + * The panel is initialized based on data given in the js object passed 1.11 + * as window.arguments[0]. The object must have the following fields set: 1.12 + * @ action (String). Possible values: 1.13 + * - "add" - for adding a new item. 1.14 + * @ type (String). Possible values: 1.15 + * - "bookmark" 1.16 + * @ loadBookmarkInSidebar - optional, the default state for the 1.17 + * "Load this bookmark in the sidebar" field. 1.18 + * - "folder" 1.19 + * @ URIList (Array of nsIURI objects) - optional, list of uris to 1.20 + * be bookmarked under the new folder. 1.21 + * - "livemark" 1.22 + * @ uri (nsIURI object) - optional, the default uri for the new item. 1.23 + * The property is not used for the "folder with items" type. 1.24 + * @ title (String) - optional, the default title for the new item. 1.25 + * @ description (String) - optional, the default description for the new 1.26 + * item. 1.27 + * @ defaultInsertionPoint (InsertionPoint JS object) - optional, the 1.28 + * default insertion point for the new item. 1.29 + * @ keyword (String) - optional, the default keyword for the new item. 1.30 + * @ postData (String) - optional, POST data to accompany the keyword. 1.31 + * @ charSet (String) - optional, character-set to accompany the keyword. 1.32 + * Notes: 1.33 + * 1) If |uri| is set for a bookmark/livemark item and |title| isn't, 1.34 + * the dialog will query the history tables for the title associated 1.35 + * with the given uri. If the dialog is set to adding a folder with 1.36 + * bookmark items under it (see URIList), a default static title is 1.37 + * used ("[Folder Name]"). 1.38 + * 2) The index field of the default insertion point is ignored if 1.39 + * the folder picker is shown. 1.40 + * - "edit" - for editing a bookmark item or a folder. 1.41 + * @ type (String). Possible values: 1.42 + * - "bookmark" 1.43 + * @ itemId (Integer) - the id of the bookmark item. 1.44 + * - "folder" (also applies to livemarks) 1.45 + * @ itemId (Integer) - the id of the folder. 1.46 + * @ hiddenRows (Strings array) - optional, list of rows to be hidden 1.47 + * regardless of the item edited or added by the dialog. 1.48 + * Possible values: 1.49 + * - "title" 1.50 + * - "location" 1.51 + * - "description" 1.52 + * - "keyword" 1.53 + * - "tags" 1.54 + * - "loadInSidebar" 1.55 + * - "feedLocation" 1.56 + * - "siteLocation" 1.57 + * - "folderPicker" - hides both the tree and the menu. 1.58 + * @ readOnly (Boolean) - optional, states if the panel should be read-only 1.59 + * 1.60 + * window.arguments[0].performed is set to true if any transaction has 1.61 + * been performed by the dialog. 1.62 + */ 1.63 + 1.64 +Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); 1.65 +XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", 1.66 + "resource://gre/modules/PrivateBrowsingUtils.jsm"); 1.67 + 1.68 +const BOOKMARK_ITEM = 0; 1.69 +const BOOKMARK_FOLDER = 1; 1.70 +const LIVEMARK_CONTAINER = 2; 1.71 + 1.72 +const ACTION_EDIT = 0; 1.73 +const ACTION_ADD = 1; 1.74 + 1.75 +var BookmarkPropertiesPanel = { 1.76 + 1.77 + /** UI Text Strings */ 1.78 + __strings: null, 1.79 + get _strings() { 1.80 + if (!this.__strings) { 1.81 + this.__strings = document.getElementById("stringBundle"); 1.82 + } 1.83 + return this.__strings; 1.84 + }, 1.85 + 1.86 + _action: null, 1.87 + _itemType: null, 1.88 + _itemId: -1, 1.89 + _uri: null, 1.90 + _loadInSidebar: false, 1.91 + _title: "", 1.92 + _description: "", 1.93 + _URIs: [], 1.94 + _keyword: "", 1.95 + _postData: null, 1.96 + _charSet: "", 1.97 + _feedURI: null, 1.98 + _siteURI: null, 1.99 + 1.100 + _defaultInsertionPoint: null, 1.101 + _hiddenRows: [], 1.102 + _batching: false, 1.103 + _readOnly: false, 1.104 + 1.105 + /** 1.106 + * This method returns the correct label for the dialog's "accept" 1.107 + * button based on the variant of the dialog. 1.108 + */ 1.109 + _getAcceptLabel: function BPP__getAcceptLabel() { 1.110 + if (this._action == ACTION_ADD) { 1.111 + if (this._URIs.length) 1.112 + return this._strings.getString("dialogAcceptLabelAddMulti"); 1.113 + 1.114 + if (this._itemType == LIVEMARK_CONTAINER) 1.115 + return this._strings.getString("dialogAcceptLabelAddLivemark"); 1.116 + 1.117 + if (this._dummyItem || this._loadInSidebar) 1.118 + return this._strings.getString("dialogAcceptLabelAddItem"); 1.119 + 1.120 + return this._strings.getString("dialogAcceptLabelSaveItem"); 1.121 + } 1.122 + return this._strings.getString("dialogAcceptLabelEdit"); 1.123 + }, 1.124 + 1.125 + /** 1.126 + * This method returns the correct title for the current variant 1.127 + * of this dialog. 1.128 + */ 1.129 + _getDialogTitle: function BPP__getDialogTitle() { 1.130 + if (this._action == ACTION_ADD) { 1.131 + if (this._itemType == BOOKMARK_ITEM) 1.132 + return this._strings.getString("dialogTitleAddBookmark"); 1.133 + if (this._itemType == LIVEMARK_CONTAINER) 1.134 + return this._strings.getString("dialogTitleAddLivemark"); 1.135 + 1.136 + // add folder 1.137 + NS_ASSERT(this._itemType == BOOKMARK_FOLDER, "Unknown item type"); 1.138 + if (this._URIs.length) 1.139 + return this._strings.getString("dialogTitleAddMulti"); 1.140 + 1.141 + return this._strings.getString("dialogTitleAddFolder"); 1.142 + } 1.143 + if (this._action == ACTION_EDIT) { 1.144 + return this._strings.getFormattedString("dialogTitleEdit", [this._title]); 1.145 + } 1.146 + return ""; 1.147 + }, 1.148 + 1.149 + /** 1.150 + * Determines the initial data for the item edited or added by this dialog 1.151 + */ 1.152 + _determineItemInfo: function BPP__determineItemInfo() { 1.153 + var dialogInfo = window.arguments[0]; 1.154 + this._action = dialogInfo.action == "add" ? ACTION_ADD : ACTION_EDIT; 1.155 + this._hiddenRows = dialogInfo.hiddenRows ? dialogInfo.hiddenRows : []; 1.156 + if (this._action == ACTION_ADD) { 1.157 + NS_ASSERT("type" in dialogInfo, "missing type property for add action"); 1.158 + 1.159 + if ("title" in dialogInfo) 1.160 + this._title = dialogInfo.title; 1.161 + 1.162 + if ("defaultInsertionPoint" in dialogInfo) { 1.163 + this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint; 1.164 + } 1.165 + else 1.166 + this._defaultInsertionPoint = 1.167 + new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, 1.168 + PlacesUtils.bookmarks.DEFAULT_INDEX, 1.169 + Ci.nsITreeView.DROP_ON); 1.170 + 1.171 + switch (dialogInfo.type) { 1.172 + case "bookmark": 1.173 + this._itemType = BOOKMARK_ITEM; 1.174 + if ("uri" in dialogInfo) { 1.175 + NS_ASSERT(dialogInfo.uri instanceof Ci.nsIURI, 1.176 + "uri property should be a uri object"); 1.177 + this._uri = dialogInfo.uri; 1.178 + if (typeof(this._title) != "string") { 1.179 + this._title = this._getURITitleFromHistory(this._uri) || 1.180 + this._uri.spec; 1.181 + } 1.182 + } 1.183 + else { 1.184 + this._uri = PlacesUtils._uri("about:blank"); 1.185 + this._title = this._strings.getString("newBookmarkDefault"); 1.186 + this._dummyItem = true; 1.187 + } 1.188 + 1.189 + if ("loadBookmarkInSidebar" in dialogInfo) 1.190 + this._loadInSidebar = dialogInfo.loadBookmarkInSidebar; 1.191 + 1.192 + if ("keyword" in dialogInfo) { 1.193 + this._keyword = dialogInfo.keyword; 1.194 + this._isAddKeywordDialog = true; 1.195 + if ("postData" in dialogInfo) 1.196 + this._postData = dialogInfo.postData; 1.197 + if ("charSet" in dialogInfo) 1.198 + this._charSet = dialogInfo.charSet; 1.199 + } 1.200 + break; 1.201 + 1.202 + case "folder": 1.203 + this._itemType = BOOKMARK_FOLDER; 1.204 + if (!this._title) { 1.205 + if ("URIList" in dialogInfo) { 1.206 + this._title = this._strings.getString("bookmarkAllTabsDefault"); 1.207 + this._URIs = dialogInfo.URIList; 1.208 + } 1.209 + else 1.210 + this._title = this._strings.getString("newFolderDefault"); 1.211 + this._dummyItem = true; 1.212 + } 1.213 + break; 1.214 + 1.215 + case "livemark": 1.216 + this._itemType = LIVEMARK_CONTAINER; 1.217 + if ("feedURI" in dialogInfo) 1.218 + this._feedURI = dialogInfo.feedURI; 1.219 + if ("siteURI" in dialogInfo) 1.220 + this._siteURI = dialogInfo.siteURI; 1.221 + 1.222 + if (!this._title) { 1.223 + if (this._feedURI) { 1.224 + this._title = this._getURITitleFromHistory(this._feedURI) || 1.225 + this._feedURI.spec; 1.226 + } 1.227 + else 1.228 + this._title = this._strings.getString("newLivemarkDefault"); 1.229 + } 1.230 + } 1.231 + 1.232 + if ("description" in dialogInfo) 1.233 + this._description = dialogInfo.description; 1.234 + } 1.235 + else { // edit 1.236 + NS_ASSERT("itemId" in dialogInfo); 1.237 + this._itemId = dialogInfo.itemId; 1.238 + this._title = PlacesUtils.bookmarks.getItemTitle(this._itemId); 1.239 + this._readOnly = !!dialogInfo.readOnly; 1.240 + 1.241 + switch (dialogInfo.type) { 1.242 + case "bookmark": 1.243 + this._itemType = BOOKMARK_ITEM; 1.244 + 1.245 + this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId); 1.246 + // keyword 1.247 + this._keyword = PlacesUtils.bookmarks 1.248 + .getKeywordForBookmark(this._itemId); 1.249 + // Load In Sidebar 1.250 + this._loadInSidebar = PlacesUtils.annotations 1.251 + .itemHasAnnotation(this._itemId, 1.252 + PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO); 1.253 + break; 1.254 + 1.255 + case "folder": 1.256 + this._itemType = BOOKMARK_FOLDER; 1.257 + PlacesUtils.livemarks.getLivemark({ id: this._itemId }) 1.258 + .then(aLivemark => { 1.259 + this._itemType = LIVEMARK_CONTAINER; 1.260 + this._feedURI = aLivemark.feedURI; 1.261 + this._siteURI = aLivemark.siteURI; 1.262 + this._fillEditProperties(); 1.263 + 1.264 + let acceptButton = document.documentElement.getButton("accept"); 1.265 + acceptButton.disabled = !this._inputIsValid(); 1.266 + 1.267 + let newHeight = window.outerHeight + 1.268 + this._element("descriptionField").boxObject.height; 1.269 + window.resizeTo(window.outerWidth, newHeight); 1.270 + }, () => undefined); 1.271 + 1.272 + break; 1.273 + } 1.274 + 1.275 + // Description 1.276 + if (PlacesUtils.annotations 1.277 + .itemHasAnnotation(this._itemId, PlacesUIUtils.DESCRIPTION_ANNO)) { 1.278 + this._description = PlacesUtils.annotations 1.279 + .getItemAnnotation(this._itemId, 1.280 + PlacesUIUtils.DESCRIPTION_ANNO); 1.281 + } 1.282 + } 1.283 + }, 1.284 + 1.285 + /** 1.286 + * This method returns the title string corresponding to a given URI. 1.287 + * If none is available from the bookmark service (probably because 1.288 + * the given URI doesn't appear in bookmarks or history), we synthesize 1.289 + * a title from the first 100 characters of the URI. 1.290 + * 1.291 + * @param aURI 1.292 + * nsIURI object for which we want the title 1.293 + * 1.294 + * @returns a title string 1.295 + */ 1.296 + _getURITitleFromHistory: function BPP__getURITitleFromHistory(aURI) { 1.297 + NS_ASSERT(aURI instanceof Ci.nsIURI); 1.298 + 1.299 + // get the title from History 1.300 + return PlacesUtils.history.getPageTitle(aURI); 1.301 + }, 1.302 + 1.303 + /** 1.304 + * This method should be called by the onload of the Bookmark Properties 1.305 + * dialog to initialize the state of the panel. 1.306 + */ 1.307 + onDialogLoad: function BPP_onDialogLoad() { 1.308 + this._determineItemInfo(); 1.309 + 1.310 + document.title = this._getDialogTitle(); 1.311 + var acceptButton = document.documentElement.getButton("accept"); 1.312 + acceptButton.label = this._getAcceptLabel(); 1.313 + 1.314 + this._beginBatch(); 1.315 + 1.316 + switch (this._action) { 1.317 + case ACTION_EDIT: 1.318 + this._fillEditProperties(); 1.319 + acceptButton.disabled = this._readOnly; 1.320 + break; 1.321 + case ACTION_ADD: 1.322 + this._fillAddProperties(); 1.323 + // if this is an uri related dialog disable accept button until 1.324 + // the user fills an uri value. 1.325 + if (this._itemType == BOOKMARK_ITEM) 1.326 + acceptButton.disabled = !this._inputIsValid(); 1.327 + break; 1.328 + } 1.329 + 1.330 + // When collapsible elements change their collapsed attribute we must 1.331 + // resize the dialog. 1.332 + // sizeToContent is not usable due to bug 90276, so we'll use resizeTo 1.333 + // instead and cache the element size. See WSucks in the legacy 1.334 + // UI code (addBookmark2.js). 1.335 + if (!this._element("tagsRow").collapsed) { 1.336 + this._element("tagsSelectorRow") 1.337 + .addEventListener("DOMAttrModified", this, false); 1.338 + } 1.339 + if (!this._element("folderRow").collapsed) { 1.340 + this._element("folderTreeRow") 1.341 + .addEventListener("DOMAttrModified", this, false); 1.342 + } 1.343 + 1.344 + if (!this._readOnly) { 1.345 + // Listen on uri fields to enable accept button if input is valid 1.346 + if (this._itemType == BOOKMARK_ITEM) { 1.347 + this._element("locationField") 1.348 + .addEventListener("input", this, false); 1.349 + if (this._isAddKeywordDialog) { 1.350 + this._element("keywordField") 1.351 + .addEventListener("input", this, false); 1.352 + } 1.353 + } 1.354 + else if (this._itemType == LIVEMARK_CONTAINER) { 1.355 + this._element("feedLocationField") 1.356 + .addEventListener("input", this, false); 1.357 + this._element("siteLocationField") 1.358 + .addEventListener("input", this, false); 1.359 + } 1.360 + } 1.361 + 1.362 + window.sizeToContent(); 1.363 + }, 1.364 + 1.365 + // nsIDOMEventListener 1.366 + _elementsHeight: [], 1.367 + handleEvent: function BPP_handleEvent(aEvent) { 1.368 + var target = aEvent.target; 1.369 + switch (aEvent.type) { 1.370 + case "input": 1.371 + if (target.id == "editBMPanel_locationField" || 1.372 + target.id == "editBMPanel_feedLocationField" || 1.373 + target.id == "editBMPanel_siteLocationField" || 1.374 + target.id == "editBMPanel_keywordField") { 1.375 + // Check uri fields to enable accept button if input is valid 1.376 + document.documentElement 1.377 + .getButton("accept").disabled = !this._inputIsValid(); 1.378 + } 1.379 + break; 1.380 + 1.381 + case "DOMAttrModified": 1.382 + // this is called when collapsing a node, but also its direct children, 1.383 + // we only need to resize when the original node changes. 1.384 + if ((target.id == "editBMPanel_tagsSelectorRow" || 1.385 + target.id == "editBMPanel_folderTreeRow") && 1.386 + aEvent.attrName == "collapsed" && 1.387 + target == aEvent.originalTarget) { 1.388 + var id = target.id; 1.389 + var newHeight = window.outerHeight; 1.390 + if (aEvent.newValue) // is collapsed 1.391 + newHeight -= this._elementsHeight[id]; 1.392 + else { 1.393 + this._elementsHeight[id] = target.boxObject.height; 1.394 + newHeight += this._elementsHeight[id]; 1.395 + } 1.396 + 1.397 + window.resizeTo(window.outerWidth, newHeight); 1.398 + } 1.399 + break; 1.400 + } 1.401 + }, 1.402 + 1.403 + _beginBatch: function BPP__beginBatch() { 1.404 + if (this._batching) 1.405 + return; 1.406 + 1.407 + PlacesUtils.transactionManager.beginBatch(null); 1.408 + this._batching = true; 1.409 + }, 1.410 + 1.411 + _endBatch: function BPP__endBatch() { 1.412 + if (!this._batching) 1.413 + return; 1.414 + 1.415 + PlacesUtils.transactionManager.endBatch(false); 1.416 + this._batching = false; 1.417 + }, 1.418 + 1.419 + _fillEditProperties: function BPP__fillEditProperties() { 1.420 + gEditItemOverlay.initPanel(this._itemId, 1.421 + { hiddenRows: this._hiddenRows, 1.422 + forceReadOnly: this._readOnly }); 1.423 + }, 1.424 + 1.425 + _fillAddProperties: function BPP__fillAddProperties() { 1.426 + this._createNewItem(); 1.427 + // Edit the new item 1.428 + gEditItemOverlay.initPanel(this._itemId, 1.429 + { hiddenRows: this._hiddenRows }); 1.430 + // Empty location field if the uri is about:blank, this way inserting a new 1.431 + // url will be easier for the user, Accept button will be automatically 1.432 + // disabled by the input listener until the user fills the field. 1.433 + var locationField = this._element("locationField"); 1.434 + if (locationField.value == "about:blank") 1.435 + locationField.value = ""; 1.436 + }, 1.437 + 1.438 + // nsISupports 1.439 + QueryInterface: function BPP_QueryInterface(aIID) { 1.440 + if (aIID.equals(Ci.nsIDOMEventListener) || 1.441 + aIID.equals(Ci.nsISupports)) 1.442 + return this; 1.443 + 1.444 + throw Cr.NS_NOINTERFACE; 1.445 + }, 1.446 + 1.447 + _element: function BPP__element(aID) { 1.448 + return document.getElementById("editBMPanel_" + aID); 1.449 + }, 1.450 + 1.451 + onDialogUnload: function BPP_onDialogUnload() { 1.452 + // gEditItemOverlay does not exist anymore here, so don't rely on it. 1.453 + // Calling removeEventListener with arguments which do not identify any 1.454 + // currently registered EventListener on the EventTarget has no effect. 1.455 + this._element("tagsSelectorRow") 1.456 + .removeEventListener("DOMAttrModified", this, false); 1.457 + this._element("folderTreeRow") 1.458 + .removeEventListener("DOMAttrModified", this, false); 1.459 + this._element("locationField") 1.460 + .removeEventListener("input", this, false); 1.461 + this._element("feedLocationField") 1.462 + .removeEventListener("input", this, false); 1.463 + this._element("siteLocationField") 1.464 + .removeEventListener("input", this, false); 1.465 + }, 1.466 + 1.467 + onDialogAccept: function BPP_onDialogAccept() { 1.468 + // We must blur current focused element to save its changes correctly 1.469 + document.commandDispatcher.focusedElement.blur(); 1.470 + // The order here is important! We have to uninit the panel first, otherwise 1.471 + // late changes could force it to commit more transactions. 1.472 + gEditItemOverlay.uninitPanel(true); 1.473 + gEditItemOverlay = null; 1.474 + this._endBatch(); 1.475 + window.arguments[0].performed = true; 1.476 + }, 1.477 + 1.478 + onDialogCancel: function BPP_onDialogCancel() { 1.479 + // The order here is important! We have to uninit the panel first, otherwise 1.480 + // changes done as part of Undo may change the panel contents and by 1.481 + // that force it to commit more transactions. 1.482 + gEditItemOverlay.uninitPanel(true); 1.483 + gEditItemOverlay = null; 1.484 + this._endBatch(); 1.485 + PlacesUtils.transactionManager.undoTransaction(); 1.486 + window.arguments[0].performed = false; 1.487 + }, 1.488 + 1.489 + /** 1.490 + * This method checks to see if the input fields are in a valid state. 1.491 + * 1.492 + * @returns true if the input is valid, false otherwise 1.493 + */ 1.494 + _inputIsValid: function BPP__inputIsValid() { 1.495 + if (this._itemType == BOOKMARK_ITEM && 1.496 + !this._containsValidURI("locationField")) 1.497 + return false; 1.498 + if (this._isAddKeywordDialog && !this._element("keywordField").value.length) 1.499 + return false; 1.500 + 1.501 + return true; 1.502 + }, 1.503 + 1.504 + /** 1.505 + * Determines whether the XUL textbox with the given ID contains a 1.506 + * string that can be converted into an nsIURI. 1.507 + * 1.508 + * @param aTextboxID 1.509 + * the ID of the textbox element whose contents we'll test 1.510 + * 1.511 + * @returns true if the textbox contains a valid URI string, false otherwise 1.512 + */ 1.513 + _containsValidURI: function BPP__containsValidURI(aTextboxID) { 1.514 + try { 1.515 + var value = this._element(aTextboxID).value; 1.516 + if (value) { 1.517 + PlacesUIUtils.createFixedURI(value); 1.518 + return true; 1.519 + } 1.520 + } catch (e) { } 1.521 + return false; 1.522 + }, 1.523 + 1.524 + /** 1.525 + * [New Item Mode] Get the insertion point details for the new item, given 1.526 + * dialog state and opening arguments. 1.527 + * 1.528 + * The container-identifier and insertion-index are returned separately in 1.529 + * the form of [containerIdentifier, insertionIndex] 1.530 + */ 1.531 + _getInsertionPointDetails: function BPP__getInsertionPointDetails() { 1.532 + var containerId = this._defaultInsertionPoint.itemId; 1.533 + var indexInContainer = this._defaultInsertionPoint.index; 1.534 + 1.535 + return [containerId, indexInContainer]; 1.536 + }, 1.537 + 1.538 + /** 1.539 + * Returns a transaction for creating a new bookmark item representing the 1.540 + * various fields and opening arguments of the dialog. 1.541 + */ 1.542 + _getCreateNewBookmarkTransaction: 1.543 + function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) { 1.544 + var annotations = []; 1.545 + var childTransactions = []; 1.546 + 1.547 + if (this._description) { 1.548 + let annoObj = { name : PlacesUIUtils.DESCRIPTION_ANNO, 1.549 + type : Ci.nsIAnnotationService.TYPE_STRING, 1.550 + flags : 0, 1.551 + value : this._description, 1.552 + expires: Ci.nsIAnnotationService.EXPIRE_NEVER }; 1.553 + let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj); 1.554 + childTransactions.push(editItemTxn); 1.555 + } 1.556 + 1.557 + if (this._loadInSidebar) { 1.558 + let annoObj = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO, 1.559 + value : true }; 1.560 + let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj); 1.561 + childTransactions.push(setLoadTxn); 1.562 + } 1.563 + 1.564 + if (this._postData) { 1.565 + let postDataTxn = new PlacesEditBookmarkPostDataTransaction(-1, this._postData); 1.566 + childTransactions.push(postDataTxn); 1.567 + } 1.568 + 1.569 + //XXX TODO: this should be in a transaction! 1.570 + if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window)) 1.571 + PlacesUtils.setCharsetForURI(this._uri, this._charSet); 1.572 + 1.573 + let createTxn = new PlacesCreateBookmarkTransaction(this._uri, 1.574 + aContainer, 1.575 + aIndex, 1.576 + this._title, 1.577 + this._keyword, 1.578 + annotations, 1.579 + childTransactions); 1.580 + 1.581 + return new PlacesAggregatedTransaction(this._getDialogTitle(), 1.582 + [createTxn]); 1.583 + }, 1.584 + 1.585 + /** 1.586 + * Returns a childItems-transactions array representing the URIList with 1.587 + * which the dialog has been opened. 1.588 + */ 1.589 + _getTransactionsForURIList: function BPP__getTransactionsForURIList() { 1.590 + var transactions = []; 1.591 + for (var i = 0; i < this._URIs.length; ++i) { 1.592 + var uri = this._URIs[i]; 1.593 + var title = this._getURITitleFromHistory(uri); 1.594 + var createTxn = new PlacesCreateBookmarkTransaction(uri, -1, 1.595 + PlacesUtils.bookmarks.DEFAULT_INDEX, 1.596 + title); 1.597 + transactions.push(createTxn); 1.598 + } 1.599 + return transactions; 1.600 + }, 1.601 + 1.602 + /** 1.603 + * Returns a transaction for creating a new folder item representing the 1.604 + * various fields and opening arguments of the dialog. 1.605 + */ 1.606 + _getCreateNewFolderTransaction: 1.607 + function BPP__getCreateNewFolderTransaction(aContainer, aIndex) { 1.608 + var annotations = []; 1.609 + var childItemsTransactions; 1.610 + if (this._URIs.length) 1.611 + childItemsTransactions = this._getTransactionsForURIList(); 1.612 + 1.613 + if (this._description) 1.614 + annotations.push(this._getDescriptionAnnotation(this._description)); 1.615 + 1.616 + return new PlacesCreateFolderTransaction(this._title, aContainer, 1.617 + aIndex, annotations, 1.618 + childItemsTransactions); 1.619 + }, 1.620 + 1.621 + /** 1.622 + * Returns a transaction for creating a new live-bookmark item representing 1.623 + * the various fields and opening arguments of the dialog. 1.624 + */ 1.625 + _getCreateNewLivemarkTransaction: 1.626 + function BPP__getCreateNewLivemarkTransaction(aContainer, aIndex) { 1.627 + return new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI, 1.628 + this._title, 1.629 + aContainer, aIndex); 1.630 + }, 1.631 + 1.632 + /** 1.633 + * Dialog-accept code-path for creating a new item (any type) 1.634 + */ 1.635 + _createNewItem: function BPP__getCreateItemTransaction() { 1.636 + var [container, index] = this._getInsertionPointDetails(); 1.637 + var txn; 1.638 + 1.639 + switch (this._itemType) { 1.640 + case BOOKMARK_FOLDER: 1.641 + txn = this._getCreateNewFolderTransaction(container, index); 1.642 + break; 1.643 + case LIVEMARK_CONTAINER: 1.644 + txn = this._getCreateNewLivemarkTransaction(container, index); 1.645 + break; 1.646 + default: // BOOKMARK_ITEM 1.647 + txn = this._getCreateNewBookmarkTransaction(container, index); 1.648 + } 1.649 + 1.650 + PlacesUtils.transactionManager.doTransaction(txn); 1.651 + this._itemId = PlacesUtils.bookmarks.getIdForItemAt(container, index); 1.652 + } 1.653 +};