From f9cab004186edb425a9b88ad649726605080a17c Mon Sep 17 00:00:00 2001 From: Thomas Groman Date: Mon, 20 Apr 2020 20:49:37 -0700 Subject: move browser to webbrowser/ --- components/places/content/bookmarkProperties.js | 675 ------- components/places/content/bookmarkProperties.xul | 43 - components/places/content/bookmarksPanel.js | 25 - components/places/content/bookmarksPanel.xul | 55 - components/places/content/browserPlacesViews.js | 1754 ------------------ components/places/content/controller.js | 1895 -------------------- components/places/content/downloadsViewOverlay.xul | 47 - components/places/content/editBookmarkOverlay.js | 1063 ----------- components/places/content/editBookmarkOverlay.xul | 228 --- components/places/content/history-panel.js | 91 - components/places/content/history-panel.xul | 95 - components/places/content/menu.xml | 488 ----- components/places/content/moveBookmarks.js | 54 - components/places/content/moveBookmarks.xul | 53 - components/places/content/organizer.css | 7 - components/places/content/places.css | 16 - components/places/content/places.js | 1553 ---------------- components/places/content/places.xul | 471 ----- components/places/content/placesOverlay.xul | 247 --- components/places/content/sidebarUtils.js | 108 -- components/places/content/tree.xml | 789 -------- components/places/content/treeView.js | 1770 ------------------ 22 files changed, 11527 deletions(-) delete mode 100644 components/places/content/bookmarkProperties.js delete mode 100644 components/places/content/bookmarkProperties.xul delete mode 100644 components/places/content/bookmarksPanel.js delete mode 100644 components/places/content/bookmarksPanel.xul delete mode 100644 components/places/content/browserPlacesViews.js delete mode 100644 components/places/content/controller.js delete mode 100644 components/places/content/downloadsViewOverlay.xul delete mode 100644 components/places/content/editBookmarkOverlay.js delete mode 100644 components/places/content/editBookmarkOverlay.xul delete mode 100644 components/places/content/history-panel.js delete mode 100644 components/places/content/history-panel.xul delete mode 100644 components/places/content/menu.xml delete mode 100644 components/places/content/moveBookmarks.js delete mode 100644 components/places/content/moveBookmarks.xul delete mode 100644 components/places/content/organizer.css delete mode 100644 components/places/content/places.css delete mode 100644 components/places/content/places.js delete mode 100644 components/places/content/places.xul delete mode 100644 components/places/content/placesOverlay.xul delete mode 100644 components/places/content/sidebarUtils.js delete mode 100644 components/places/content/tree.xml delete mode 100644 components/places/content/treeView.js (limited to 'components/places/content') diff --git a/components/places/content/bookmarkProperties.js b/components/places/content/bookmarkProperties.js deleted file mode 100644 index e1d1077..0000000 --- a/components/places/content/bookmarkProperties.js +++ /dev/null @@ -1,675 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * The panel is initialized based on data given in the js object passed - * as window.arguments[0]. The object must have the following fields set: - * @ action (String). Possible values: - * - "add" - for adding a new item. - * @ type (String). Possible values: - * - "bookmark" - * @ loadBookmarkInSidebar - optional, the default state for the - * "Load this bookmark in the sidebar" field. - * - "folder" - * @ URIList (Array of nsIURI objects) - optional, list of uris to - * be bookmarked under the new folder. - * - "livemark" - * @ uri (nsIURI object) - optional, the default uri for the new item. - * The property is not used for the "folder with items" type. - * @ title (String) - optional, the default title for the new item. - * @ description (String) - optional, the default description for the new - * item. - * @ defaultInsertionPoint (InsertionPoint JS object) - optional, the - * default insertion point for the new item. - * @ keyword (String) - optional, the default keyword for the new item. - * @ postData (String) - optional, POST data to accompany the keyword. - * @ charSet (String) - optional, character-set to accompany the keyword. - * Notes: - * 1) If |uri| is set for a bookmark/livemark item and |title| isn't, - * the dialog will query the history tables for the title associated - * with the given uri. If the dialog is set to adding a folder with - * bookmark items under it (see URIList), a default static title is - * used ("[Folder Name]"). - * 2) The index field of the default insertion point is ignored if - * the folder picker is shown. - * - "edit" - for editing a bookmark item or a folder. - * @ type (String). Possible values: - * - "bookmark" - * @ itemId (Integer) - the id of the bookmark item. - * - "folder" (also applies to livemarks) - * @ itemId (Integer) - the id of the folder. - * @ hiddenRows (Strings array) - optional, list of rows to be hidden - * regardless of the item edited or added by the dialog. - * Possible values: - * - "title" - * - "location" - * - "description" - * - "keyword" - * - "tags" - * - "loadInSidebar" - * - "feedLocation" - * - "siteLocation" - * - "folderPicker" - hides both the tree and the menu. - * @ readOnly (Boolean) - optional, states if the panel should be read-only - * - * window.arguments[0].performed is set to true if any transaction has - * been performed by the dialog. - */ - -Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Task", - "resource://gre/modules/Task.jsm"); - -const BOOKMARK_ITEM = 0; -const BOOKMARK_FOLDER = 1; -const LIVEMARK_CONTAINER = 2; - -const ACTION_EDIT = 0; -const ACTION_ADD = 1; - -var elementsHeight = new Map(); - -var BookmarkPropertiesPanel = { - - /** UI Text Strings */ - __strings: null, - get _strings() { - if (!this.__strings) { - this.__strings = document.getElementById("stringBundle"); - } - return this.__strings; - }, - - _action: null, - _itemType: null, - _itemId: -1, - _uri: null, - _loadInSidebar: false, - _title: "", - _description: "", - _URIs: [], - _keyword: "", - _postData: null, - _charSet: "", - _feedURI: null, - _siteURI: null, - - _defaultInsertionPoint: null, - _hiddenRows: [], - _batching: false, - _readOnly: false, - - /** - * This method returns the correct label for the dialog's "accept" - * button based on the variant of the dialog. - */ - _getAcceptLabel: function BPP__getAcceptLabel() { - if (this._action == ACTION_ADD) { - if (this._URIs.length) - return this._strings.getString("dialogAcceptLabelAddMulti"); - - if (this._itemType == LIVEMARK_CONTAINER) - return this._strings.getString("dialogAcceptLabelAddLivemark"); - - if (this._dummyItem || this._loadInSidebar) - return this._strings.getString("dialogAcceptLabelAddItem"); - - return this._strings.getString("dialogAcceptLabelSaveItem"); - } - return this._strings.getString("dialogAcceptLabelEdit"); - }, - - /** - * This method returns the correct title for the current variant - * of this dialog. - */ - _getDialogTitle: function BPP__getDialogTitle() { - if (this._action == ACTION_ADD) { - if (this._itemType == BOOKMARK_ITEM) - return this._strings.getString("dialogTitleAddBookmark"); - if (this._itemType == LIVEMARK_CONTAINER) - return this._strings.getString("dialogTitleAddLivemark"); - - // add folder - NS_ASSERT(this._itemType == BOOKMARK_FOLDER, "Unknown item type"); - if (this._URIs.length) - return this._strings.getString("dialogTitleAddMulti"); - - return this._strings.getString("dialogTitleAddFolder"); - } - if (this._action == ACTION_EDIT) { - return this._strings.getFormattedString("dialogTitleEdit", [this._title]); - } - return ""; - }, - - /** - * Determines the initial data for the item edited or added by this dialog - */ - _determineItemInfo: function BPP__determineItemInfo() { - var dialogInfo = window.arguments[0]; - this._action = dialogInfo.action == "add" ? ACTION_ADD : ACTION_EDIT; - this._hiddenRows = dialogInfo.hiddenRows ? dialogInfo.hiddenRows : []; - if (this._action == ACTION_ADD) { - NS_ASSERT("type" in dialogInfo, "missing type property for add action"); - - if ("title" in dialogInfo) - this._title = dialogInfo.title; - - if ("defaultInsertionPoint" in dialogInfo) { - this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint; - } - else - this._defaultInsertionPoint = - new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, - PlacesUtils.bookmarks.DEFAULT_INDEX, - Ci.nsITreeView.DROP_ON); - - switch (dialogInfo.type) { - case "bookmark": - this._itemType = BOOKMARK_ITEM; - if ("uri" in dialogInfo) { - NS_ASSERT(dialogInfo.uri instanceof Ci.nsIURI, - "uri property should be a uri object"); - this._uri = dialogInfo.uri; - if (typeof(this._title) != "string") { - this._title = this._getURITitleFromHistory(this._uri) || - this._uri.spec; - } - } - else { - this._uri = PlacesUtils._uri("about:blank"); - this._title = this._strings.getString("newBookmarkDefault"); - this._dummyItem = true; - } - - if ("loadBookmarkInSidebar" in dialogInfo) - this._loadInSidebar = dialogInfo.loadBookmarkInSidebar; - - if ("keyword" in dialogInfo) { - this._keyword = dialogInfo.keyword; - this._isAddKeywordDialog = true; - if ("postData" in dialogInfo) - this._postData = dialogInfo.postData; - if ("charSet" in dialogInfo) - this._charSet = dialogInfo.charSet; - } - break; - - case "folder": - this._itemType = BOOKMARK_FOLDER; - if (!this._title) { - if ("URIList" in dialogInfo) { - this._title = this._strings.getString("bookmarkAllTabsDefault"); - this._URIs = dialogInfo.URIList; - } - else - this._title = this._strings.getString("newFolderDefault"); - this._dummyItem = true; - } - break; - - case "livemark": - this._itemType = LIVEMARK_CONTAINER; - if ("feedURI" in dialogInfo) - this._feedURI = dialogInfo.feedURI; - if ("siteURI" in dialogInfo) - this._siteURI = dialogInfo.siteURI; - - if (!this._title) { - if (this._feedURI) { - this._title = this._getURITitleFromHistory(this._feedURI) || - this._feedURI.spec; - } - else - this._title = this._strings.getString("newLivemarkDefault"); - } - } - - if ("description" in dialogInfo) - this._description = dialogInfo.description; - } - else { // edit - NS_ASSERT("itemId" in dialogInfo); - this._itemId = dialogInfo.itemId; - this._title = PlacesUtils.bookmarks.getItemTitle(this._itemId); - this._readOnly = !!dialogInfo.readOnly; - - switch (dialogInfo.type) { - case "bookmark": - this._itemType = BOOKMARK_ITEM; - - this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId); - // keyword - this._keyword = PlacesUtils.bookmarks - .getKeywordForBookmark(this._itemId); - // Load In Sidebar - this._loadInSidebar = PlacesUtils.annotations - .itemHasAnnotation(this._itemId, - PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO); - break; - - case "folder": - this._itemType = BOOKMARK_FOLDER; - PlacesUtils.livemarks.getLivemark({ id: this._itemId }) - .then(aLivemark => { - this._itemType = LIVEMARK_CONTAINER; - this._feedURI = aLivemark.feedURI; - this._siteURI = aLivemark.siteURI; - this._fillEditProperties(); - - let acceptButton = document.documentElement.getButton("accept"); - acceptButton.disabled = !this._inputIsValid(); - - let newHeight = window.outerHeight + - this._element("descriptionField").boxObject.height; - window.resizeTo(window.outerWidth, newHeight); - }, () => undefined); - - break; - } - - // Description - if (PlacesUtils.annotations - .itemHasAnnotation(this._itemId, PlacesUIUtils.DESCRIPTION_ANNO)) { - this._description = PlacesUtils.annotations - .getItemAnnotation(this._itemId, - PlacesUIUtils.DESCRIPTION_ANNO); - } - } - }, - - /** - * This method returns the title string corresponding to a given URI. - * If none is available from the bookmark service (probably because - * the given URI doesn't appear in bookmarks or history), we synthesize - * a title from the first 100 characters of the URI. - * - * @param aURI - * nsIURI object for which we want the title - * - * @returns a title string - */ - _getURITitleFromHistory: function BPP__getURITitleFromHistory(aURI) { - NS_ASSERT(aURI instanceof Ci.nsIURI); - - // get the title from History - return PlacesUtils.history.getPageTitle(aURI); - }, - - /** - * This method should be called by the onload of the Bookmark Properties - * dialog to initialize the state of the panel. - */ - onDialogLoad: Task.async(function* BPP_onDialogLoad() { - this._determineItemInfo(); - - document.title = this._getDialogTitle(); - var acceptButton = document.documentElement.getButton("accept"); - acceptButton.label = this._getAcceptLabel(); - - // Do not use sizeToContent, otherwise, due to bug 90276, the dialog will - // grow at every opening. - // Since elements can be uncollapsed asynchronously, we must observe their - // mutations and resize the dialog using a cached element size. - this._height = window.outerHeight; - this._mutationObserver = new MutationObserver(mutations => { - for (let mutation of mutations) { - let target = mutation.target; - let id = target.id; - if (!/^editBMPanel_.*(Row|Checkbox)$/.test(id)) - continue; - - let collapsed = target.getAttribute("collapsed") === "true"; - let wasCollapsed = mutation.oldValue === "true"; - if (collapsed == wasCollapsed) - continue; - - if (collapsed) { - this._height -= elementsHeight.get(id); - elementsHeight.delete(id); - } else { - elementsHeight.set(id, target.boxObject.height); - this._height += elementsHeight.get(id); - } - window.resizeTo(window.outerWidth, this._height); - } - }); - - this._mutationObserver.observe(document, - { subtree: true, - attributeOldValue: true, - attributeFilter: ["collapsed"] }); - - // Some controls are flexible and we want to update their cached size when - // the dialog is resized. - window.addEventListener("resize", this); - - this._beginBatch(); - - switch (this._action) { - case ACTION_EDIT: - this._fillEditProperties(); - acceptButton.disabled = this._readOnly; - break; - case ACTION_ADD: - yield this._fillAddProperties(); - // if this is an uri related dialog disable accept button until - // the user fills an uri value. - if (this._itemType == BOOKMARK_ITEM) - acceptButton.disabled = !this._inputIsValid(); - break; - } - - if (!this._readOnly) { - // Listen on uri fields to enable accept button if input is valid - if (this._itemType == BOOKMARK_ITEM) { - this._element("locationField") - .addEventListener("input", this, false); - if (this._isAddKeywordDialog) { - this._element("keywordField") - .addEventListener("input", this, false); - } - } - else if (this._itemType == LIVEMARK_CONTAINER) { - this._element("feedLocationField") - .addEventListener("input", this, false); - this._element("siteLocationField") - .addEventListener("input", this, false); - } - } - - // Ensure the Name Picker textbox is focused on load - var namePickerElem = document.getElementById('editBMPanel_namePicker'); - namePickerElem.focus(); - namePickerElem.select(); - }), - - // nsIDOMEventListener - handleEvent: function BPP_handleEvent(aEvent) { - var target = aEvent.target; - switch (aEvent.type) { - case "input": - if (target.id == "editBMPanel_locationField" || - target.id == "editBMPanel_feedLocationField" || - target.id == "editBMPanel_siteLocationField" || - target.id == "editBMPanel_keywordField") { - // Check uri fields to enable accept button if input is valid - document.documentElement - .getButton("accept").disabled = !this._inputIsValid(); - } - break; - case "resize": - for (let [id, oldHeight] of elementsHeight) { - let newHeight = document.getElementById(id).boxObject.height; - this._height += - oldHeight + newHeight; - elementsHeight.set(id, newHeight); - } - break; - } - }, - - _beginBatch: function BPP__beginBatch() { - if (this._batching) - return; - - PlacesUtils.transactionManager.beginBatch(null); - this._batching = true; - }, - - _endBatch: function BPP__endBatch() { - if (!this._batching) - return; - - PlacesUtils.transactionManager.endBatch(false); - this._batching = false; - }, - - _fillEditProperties: function BPP__fillEditProperties() { - gEditItemOverlay.initPanel(this._itemId, - { hiddenRows: this._hiddenRows, - forceReadOnly: this._readOnly }); - }, - - _fillAddProperties: Task.async(function* BPP__fillAddProperties() { - yield this._createNewItem(); - // Edit the new item - gEditItemOverlay.initPanel(this._itemId, - { hiddenRows: this._hiddenRows }); - // Empty location field if the uri is about:blank, this way inserting a new - // url will be easier for the user, Accept button will be automatically - // disabled by the input listener until the user fills the field. - var locationField = this._element("locationField"); - if (locationField.value == "about:blank") - locationField.value = ""; - }), - - // nsISupports - QueryInterface: function BPP_QueryInterface(aIID) { - if (aIID.equals(Ci.nsIDOMEventListener) || - aIID.equals(Ci.nsISupports)) - return this; - - throw Cr.NS_NOINTERFACE; - }, - - _element: function BPP__element(aID) { - return document.getElementById("editBMPanel_" + aID); - }, - - onDialogUnload: function BPP_onDialogUnload() { - // gEditItemOverlay does not exist anymore here, so don't rely on it. - this._mutationObserver.disconnect(); - delete this._mutationObserver; - - window.removeEventListener("resize", this); - - // Calling removeEventListener with arguments which do not identify any - // currently registered EventListener on the EventTarget has no effect. - this._element("locationField") - .removeEventListener("input", this, false); - this._element("feedLocationField") - .removeEventListener("input", this, false); - this._element("siteLocationField") - .removeEventListener("input", this, false); - }, - - onDialogAccept: function BPP_onDialogAccept() { - // We must blur current focused element to save its changes correctly - document.commandDispatcher.focusedElement.blur(); - // The order here is important! We have to uninit the panel first, otherwise - // late changes could force it to commit more transactions. - gEditItemOverlay.uninitPanel(true); - this._endBatch(); - window.arguments[0].performed = true; - }, - - onDialogCancel: function BPP_onDialogCancel() { - // The order here is important! We have to uninit the panel first, otherwise - // changes done as part of Undo may change the panel contents and by - // that force it to commit more transactions. - gEditItemOverlay.uninitPanel(true); - this._endBatch(); - PlacesUtils.transactionManager.undoTransaction(); - window.arguments[0].performed = false; - }, - - /** - * This method checks to see if the input fields are in a valid state. - * - * @returns true if the input is valid, false otherwise - */ - _inputIsValid: function BPP__inputIsValid() { - if (this._itemType == BOOKMARK_ITEM && - !this._containsValidURI("locationField")) - return false; - if (this._isAddKeywordDialog && !this._element("keywordField").value.length) - return false; - - return true; - }, - - /** - * Determines whether the XUL textbox with the given ID contains a - * string that can be converted into an nsIURI. - * - * @param aTextboxID - * the ID of the textbox element whose contents we'll test - * - * @returns true if the textbox contains a valid URI string, false otherwise - */ - _containsValidURI: function BPP__containsValidURI(aTextboxID) { - try { - var value = this._element(aTextboxID).value; - if (value) { - PlacesUIUtils.createFixedURI(value); - return true; - } - } catch (e) { } - return false; - }, - - /** - * [New Item Mode] Get the insertion point details for the new item, given - * dialog state and opening arguments. - * - * The container-identifier and insertion-index are returned separately in - * the form of [containerIdentifier, insertionIndex] - */ - _getInsertionPointDetails: function BPP__getInsertionPointDetails() { - var containerId = this._defaultInsertionPoint.itemId; - var indexInContainer = this._defaultInsertionPoint.index; - - return [containerId, indexInContainer]; - }, - - /** - * Returns a transaction for creating a new bookmark item representing the - * various fields and opening arguments of the dialog. - */ - _getCreateNewBookmarkTransaction: - function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) { - var annotations = []; - var childTransactions = []; - - if (this._description) { - let annoObj = { name : PlacesUIUtils.DESCRIPTION_ANNO, - type : Ci.nsIAnnotationService.TYPE_STRING, - flags : 0, - value : this._description, - expires: Ci.nsIAnnotationService.EXPIRE_NEVER }; - let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj); - childTransactions.push(editItemTxn); - } - - if (this._loadInSidebar) { - let annoObj = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO, - value : true }; - let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj); - childTransactions.push(setLoadTxn); - } - - if (this._postData) { - let postDataTxn = new PlacesEditBookmarkPostDataTransaction(-1, this._postData); - childTransactions.push(postDataTxn); - } - - //XXX TODO: this should be in a transaction! - if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window)) - PlacesUtils.setCharsetForURI(this._uri, this._charSet); - - let createTxn = new PlacesCreateBookmarkTransaction(this._uri, - aContainer, - aIndex, - this._title, - this._keyword, - annotations, - childTransactions); - - return new PlacesAggregatedTransaction(this._getDialogTitle(), - [createTxn]); - }, - - /** - * Returns a childItems-transactions array representing the URIList with - * which the dialog has been opened. - */ - _getTransactionsForURIList: function BPP__getTransactionsForURIList() { - var transactions = []; - for (var i = 0; i < this._URIs.length; ++i) { - var uri = this._URIs[i]; - var title = this._getURITitleFromHistory(uri); - var createTxn = new PlacesCreateBookmarkTransaction(uri, -1, - PlacesUtils.bookmarks.DEFAULT_INDEX, - title); - transactions.push(createTxn); - } - return transactions; - }, - - /** - * Returns a transaction for creating a new folder item representing the - * various fields and opening arguments of the dialog. - */ - _getCreateNewFolderTransaction: - function BPP__getCreateNewFolderTransaction(aContainer, aIndex) { - var annotations = []; - var childItemsTransactions; - if (this._URIs.length) - childItemsTransactions = this._getTransactionsForURIList(); - - if (this._description) - annotations.push(this._getDescriptionAnnotation(this._description)); - - return new PlacesCreateFolderTransaction(this._title, aContainer, - aIndex, annotations, - childItemsTransactions); - }, - - /** - * Returns a transaction for creating a new live-bookmark item representing - * the various fields and opening arguments of the dialog. - */ - _getCreateNewLivemarkTransaction: - function BPP__getCreateNewLivemarkTransaction(aContainer, aIndex) { - return new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI, - this._title, - aContainer, aIndex); - }, - - /** - * Dialog-accept code-path for creating a new item (any type) - */ - _createNewItem: Task.async(function* BPP__getCreateItemTransaction() { - var [container, index] = this._getInsertionPointDetails(); - var txn; - - switch (this._itemType) { - case BOOKMARK_FOLDER: - txn = this._getCreateNewFolderTransaction(container, index); - break; - case LIVEMARK_CONTAINER: - txn = this._getCreateNewLivemarkTransaction(container, index); - break; - default: // BOOKMARK_ITEM - txn = this._getCreateNewBookmarkTransaction(container, index); - } - - PlacesUtils.transactionManager.doTransaction(txn); - // This is a temporary hack until we use PlacesTransactions.jsm - if (txn._promise) { - yield txn._promise; - } - - let folderGuid = yield PlacesUtils.promiseItemGuid(container); - let bm = yield PlacesUtils.bookmarks.fetch({ - parentGuid: folderGuid, - index: index - }); - this._itemId = yield PlacesUtils.promiseItemId(bm.guid); - }) -}; diff --git a/components/places/content/bookmarkProperties.xul b/components/places/content/bookmarkProperties.xul deleted file mode 100644 index 2c04f8b..0000000 --- a/components/places/content/bookmarkProperties.xul +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - %editBookmarkOverlayDTD; -]> - - - - - - - - - - - - - - - - - - - - - - - diff --git a/components/places/content/editBookmarkOverlay.js b/components/places/content/editBookmarkOverlay.js deleted file mode 100644 index 69d7d32..0000000 --- a/components/places/content/editBookmarkOverlay.js +++ /dev/null @@ -1,1063 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const LAST_USED_ANNO = "bookmarkPropertiesDialog/folderLastUsed"; -const MAX_FOLDER_ITEM_IN_MENU_LIST = 5; - -var gEditItemOverlay = { - _uri: null, - _itemId: -1, - _itemIds: [], - _uris: [], - _tags: [], - _allTags: [], - _keyword: null, - _multiEdit: false, - _itemType: -1, - _readOnly: false, - _hiddenRows: [], - _onPanelReady: false, - _observersAdded: false, - _staticFoldersListBuilt: false, - _initialized: false, - _titleOverride: "", - - // the first field which was edited after this panel was initialized for - // a certain item - _firstEditedField: "", - - get itemId() { - return this._itemId; - }, - - get uri() { - return this._uri; - }, - - get multiEdit() { - return this._multiEdit; - }, - - /** - * Determines the initial data for the item edited or added by this dialog - */ - _determineInfo: function EIO__determineInfo(aInfo) { - // hidden rows - if (aInfo && aInfo.hiddenRows) - this._hiddenRows = aInfo.hiddenRows; - else - this._hiddenRows.splice(0, this._hiddenRows.length); - // force-read-only - this._readOnly = aInfo && aInfo.forceReadOnly; - this._titleOverride = aInfo && aInfo.titleOverride ? aInfo.titleOverride - : ""; - this._onPanelReady = aInfo && aInfo.onPanelReady; - }, - - _showHideRows: function EIO__showHideRows() { - var isBookmark = this._itemId != -1 && - this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK; - var isQuery = false; - if (this._uri) - isQuery = this._uri.schemeIs("place"); - - this._element("nameRow").collapsed = this._hiddenRows.indexOf("name") != -1; - this._element("folderRow").collapsed = - this._hiddenRows.indexOf("folderPicker") != -1 || this._readOnly; - this._element("tagsRow").collapsed = !this._uri || - this._hiddenRows.indexOf("tags") != -1 || isQuery; - // Collapse the tag selector if the item does not accept tags. - if (!this._element("tagsSelectorRow").collapsed && - this._element("tagsRow").collapsed) - this.toggleTagsSelector(); - this._element("descriptionRow").collapsed = - this._hiddenRows.indexOf("description") != -1 || this._readOnly; - this._element("keywordRow").collapsed = !isBookmark || this._readOnly || - this._hiddenRows.indexOf("keyword") != -1 || isQuery; - this._element("locationRow").collapsed = !(this._uri && !isQuery) || - this._hiddenRows.indexOf("location") != -1; - this._element("loadInSidebarCheckbox").collapsed = !isBookmark || isQuery || - this._readOnly || this._hiddenRows.indexOf("loadInSidebar") != -1; - this._element("feedLocationRow").collapsed = !this._isLivemark || - this._hiddenRows.indexOf("feedLocation") != -1; - this._element("siteLocationRow").collapsed = !this._isLivemark || - this._hiddenRows.indexOf("siteLocation") != -1; - this._element("selectionCount").hidden = !this._multiEdit; - }, - - /** - * Initialize the panel - * @param aFor - * Either a places-itemId (of a bookmark, folder or a live bookmark), - * an array of itemIds (used for bulk tagging), or a URI object (in - * which case, the panel would be initialized in read-only mode). - * @param [optional] aInfo - * JS object which stores additional info for the panel - * initialization. The following properties may bet set: - * * hiddenRows (Strings array): list of rows to be hidden regardless - * of the item edited. Possible values: "title", "location", - * "description", "keyword", "loadInSidebar", "feedLocation", - * "siteLocation", folderPicker" - * * forceReadOnly - set this flag to initialize the panel to its - * read-only (view) mode even if the given item is editable. - */ - 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 (Array.isArray(aFor)) { - aItemIdList = aFor; - aFor = aItemIdList[0]; - } - else if (this._multiEdit) { - this._multiEdit = false; - this._tags = []; - this._uris = []; - this._allTags = []; - this._itemIds = []; - this._element("selectionCount").hidden = true; - } - - this._folderMenuList = this._element("folderMenuList"); - this._folderTree = this._element("folderTree"); - - this._determineInfo(aInfo); - if (aFor instanceof Ci.nsIURI) { - this._itemId = -1; - this._uri = aFor; - this._readOnly = true; - } - else { - this._itemId = aFor; - // We can't store information on invalid itemIds. - this._readOnly = this._readOnly || this._itemId == -1; - - var containerId = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId); - this._itemType = PlacesUtils.bookmarks.getItemType(this._itemId); - if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) { - this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId); - this._keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this._itemId); - this._initTextField("keywordField", this._keyword); - this._element("loadInSidebarCheckbox").checked = - PlacesUtils.annotations.itemHasAnnotation(this._itemId, - PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO); - } - else { - this._uri = null; - this._isLivemark = false; - PlacesUtils.livemarks.getLivemark({id: this._itemId }) - .then(aLivemark => { - this._isLivemark = true; - this._initTextField("feedLocationField", aLivemark.feedURI.spec, true); - this._initTextField("siteLocationField", aLivemark.siteURI ? aLivemark.siteURI.spec : "", true); - this._showHideRows(); - }, () => undefined); - } - - // folder picker - this._initFolderMenuList(containerId); - - // description field - this._initTextField("descriptionField", - PlacesUIUtils.getItemDescription(this._itemId)); - } - - if (this._itemId == -1 || - this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) { - this._isLivemark = false; - - this._initTextField("locationField", this._uri.spec); - if (!aItemIdList) { - var tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", "); - this._initTextField("tagsField", tags, false); - } - else { - this._multiEdit = true; - this._allTags = []; - this._itemIds = aItemIdList; - for (var i = 0; i < aItemIdList.length; i++) { - if (aItemIdList[i] instanceof Ci.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]); - } - this._allTags = this._getCommonTags(); - this._initTextField("tagsField", this._allTags.join(", "), false); - this._element("itemsCountText").value = - PlacesUIUtils.getPluralString("detailsPane.itemsCountLabel", - this._itemIds.length, - [this._itemIds.length]); - } - - // tags selector - this._rebuildTagsSelectorList(); - } - - // name picker - this._initNamePicker(); - - this._showHideRows(); - - // observe changes - if (!this._observersAdded) { - // 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); - - this._element("namePicker").addEventListener("blur", this); - this._element("locationField").addEventListener("blur", this); - this._element("tagsField").addEventListener("blur", this); - this._element("keywordField").addEventListener("blur", this); - this._element("descriptionField").addEventListener("blur", this); - window.addEventListener("unload", this, false); - this._observersAdded = true; - } - - let focusElement = () => { - this._initialized = true; - }; - - if (this._onPanelReady) { - this._onPanelReady(focusElement); - } else { - focusElement(); - } - }, - - /** - * 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; - this._editorTransactionManagerClear(field); - } - }, - - /** - * Appends a menu-item representing a bookmarks folder to a menu-popup. - * @param aMenupopup - * The popup to which the menu-item should be added. - * @param aFolderId - * The identifier of the bookmarks folder. - * @return the new menu item. - */ - _appendFolderItemToMenupopup: - function EIO__appendFolderItemToMenuList(aMenupopup, aFolderId) { - // First make sure the folders-separator is visible - this._element("foldersSeparator").hidden = false; - - var folderMenuItem = document.createElement("menuitem"); - var folderTitle = PlacesUtils.bookmarks.getItemTitle(aFolderId) - folderMenuItem.folderId = aFolderId; - folderMenuItem.setAttribute("label", folderTitle); - folderMenuItem.className = "menuitem-iconic folder-icon"; - aMenupopup.appendChild(folderMenuItem); - return folderMenuItem; - }, - - _initFolderMenuList: function EIO__initFolderMenuList(aSelectedFolder) { - // clean up first - var menupopup = this._folderMenuList.menupopup; - while (menupopup.childNodes.length > 6) - menupopup.removeChild(menupopup.lastChild); - - const bms = PlacesUtils.bookmarks; - const annos = PlacesUtils.annotations; - - // Build the static list - var unfiledItem = this._element("unfiledRootItem"); - if (!this._staticFoldersListBuilt) { - unfiledItem.label = bms.getItemTitle(PlacesUtils.unfiledBookmarksFolderId); - unfiledItem.folderId = PlacesUtils.unfiledBookmarksFolderId; - var bmMenuItem = this._element("bmRootItem"); - bmMenuItem.label = bms.getItemTitle(PlacesUtils.bookmarksMenuFolderId); - bmMenuItem.folderId = PlacesUtils.bookmarksMenuFolderId; - var toolbarItem = this._element("toolbarFolderItem"); - toolbarItem.label = bms.getItemTitle(PlacesUtils.toolbarFolderId); - toolbarItem.folderId = PlacesUtils.toolbarFolderId; - this._staticFoldersListBuilt = true; - } - - // List of recently used folders: - var folderIds = annos.getItemsWithAnnotation(LAST_USED_ANNO); - - /** - * The value of the LAST_USED_ANNO annotation is the time (in the form of - * Date.getTime) at which the folder has been last used. - * - * First we build the annotated folders array, each item has both the - * folder identifier and the time at which it was last-used by this dialog - * set. Then we sort it descendingly based on the time field. - */ - this._recentFolders = []; - for (var i = 0; i < folderIds.length; i++) { - var lastUsed = annos.getItemAnnotation(folderIds[i], LAST_USED_ANNO); - this._recentFolders.push({ folderId: folderIds[i], lastUsed: lastUsed }); - } - this._recentFolders.sort(function(a, b) { - if (b.lastUsed < a.lastUsed) - return -1; - if (b.lastUsed > a.lastUsed) - return 1; - return 0; - }); - - var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST, - this._recentFolders.length); - for (var i = 0; i < numberOfItems; i++) { - this._appendFolderItemToMenupopup(menupopup, - this._recentFolders[i].folderId); - } - - var defaultItem = this._getFolderMenuItem(aSelectedFolder); - this._folderMenuList.selectedItem = defaultItem; - - // Set a selectedIndex attribute to show special icons - this._folderMenuList.setAttribute("selectedIndex", - this._folderMenuList.selectedIndex); - - // Hide the folders-separator if no folder is annotated as recently-used - this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 6); - this._folderMenuList.disabled = this._readOnly; - }, - - QueryInterface: function EIO_QueryInterface(aIID) { - if (aIID.equals(Ci.nsIDOMEventListener) || - aIID.equals(Ci.nsINavBookmarkObserver) || - aIID.equals(Ci.nsISupports)) - return this; - - throw Cr.NS_ERROR_NO_INTERFACE; - }, - - _element: function EIO__element(aID) { - return document.getElementById("editBMPanel_" + aID); - }, - - _editorTransactionManagerClear: function EIO__editorTransactionManagerClear(aItem) { - // Clear the editor's undo stack - let transactionManager; - try { - transactionManager = aItem.editor.transactionManager; - } catch (e) { - // When retrieving the transaction manager, editor may be null resulting - // in a TypeError. Additionally, the transaction manager may not - // exist yet, which causes access to it to throw NS_ERROR_FAILURE. - // In either event, the transaction manager doesn't exist it, so we - // don't need to worry about clearing it. - if (!(e instanceof TypeError) && e.result != Cr.NS_ERROR_FAILURE) { - throw e; - } - } - if (transactionManager) { - transactionManager.clear(); - } - }, - - _getItemStaticTitle: function EIO__getItemStaticTitle() { - if (this._titleOverride) - return this._titleOverride; - - let title = ""; - if (this._itemId == -1) { - title = PlacesUtils.history.getPageTitle(this._uri); - } - else { - title = PlacesUtils.bookmarks.getItemTitle(this._itemId); - } - return title; - }, - - _initNamePicker: function EIO_initNamePicker() { - var namePicker = this._element("namePicker"); - namePicker.value = this._getItemStaticTitle(); - namePicker.readOnly = this._readOnly; - this._editorTransactionManagerClear(namePicker); - }, - - uninitPanel: function EIO_uninitPanel(aHideCollapsibleElements) { - if (aHideCollapsibleElements) { - // hide the folder tree if it was previously visible - var folderTreeRow = this._element("folderTreeRow"); - if (!folderTreeRow.collapsed) - this.toggleFolderTreeVisibility(); - - // 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 || this._uri || this._multiEdit) - PlacesUtils.bookmarks.removeObserver(this); - - this._element("namePicker").removeEventListener("blur", this); - this._element("locationField").removeEventListener("blur", this); - this._element("tagsField").removeEventListener("blur", this); - this._element("keywordField").removeEventListener("blur", this); - this._element("descriptionField").removeEventListener("blur", this); - - this._observersAdded = false; - } - - this._itemId = -1; - this._uri = null; - this._uris = []; - this._tags = []; - this._allTags = []; - this._itemIds = []; - this._multiEdit = false; - this._firstEditedField = ""; - this._initialized = false; - this._titleOverride = ""; - this._readOnly = false; - }, - - onTagsFieldBlur: function EIO_onTagsFieldBlur() { - if (this._updateTags()) // if anything has changed - this._mayUpdateFirstEditField("tagsField"); - }, - - _updateTags: function EIO__updateTags() { - if (this._multiEdit) - return this._updateMultipleTagsForItems(); - return this._updateSingleTagForItem(); - }, - - _updateSingleTagForItem: function EIO__updateSingleTagForItem() { - var currentTags = PlacesUtils.tagging.getTagsForURI(this._uri); - var tags = this._getTagsArrayFromTagField(); - if (tags.length > 0 || currentTags.length > 0) { - var tagsToRemove = []; - var tagsToAdd = []; - var txns = []; - for (var i = 0; i < currentTags.length; i++) { - if (tags.indexOf(currentTags[i]) == -1) - tagsToRemove.push(currentTags[i]); - } - for (var i = 0; i < tags.length; i++) { - if (currentTags.indexOf(tags[i]) == -1) - tagsToAdd.push(tags[i]); - } - - if (tagsToRemove.length > 0) { - let untagTxn = new PlacesUntagURITransaction(this._uri, tagsToRemove); - txns.push(untagTxn); - } - if (tagsToAdd.length > 0) { - let tagTxn = new PlacesTagURITransaction(this._uri, tagsToAdd); - txns.push(tagTxn); - } - - if (txns.length > 0) { - let aggregate = new PlacesAggregatedTransaction("Update tags", txns); - PlacesUtils.transactionManager.doTransaction(aggregate); - - // Ensure the tagsField is in sync, clean it up from empty tags - var tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", "); - this._initTextField("tagsField", tags, false); - return true; - } - } - return false; - }, - - /** - * Stores the first-edit field for this dialog, if the passed-in field - * is indeed the first edited field - * @param aNewField - * the id of the field that may be set (without the "editBMPanel_" - * prefix) - */ - _mayUpdateFirstEditField: function EIO__mayUpdateFirstEditField(aNewField) { - // * The first-edit-field behavior is not applied in the multi-edit case - // * if this._firstEditedField is already set, this is not the first field, - // so there's nothing to do - if (this._multiEdit || this._firstEditedField) - return; - - this._firstEditedField = aNewField; - - // set the pref - var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - prefs.setCharPref("browser.bookmarks.editDialog.firstEditField", aNewField); - }, - - _updateMultipleTagsForItems: function EIO__updateMultipleTagsForItems() { - var tags = this._getTagsArrayFromTagField(); - if (tags.length > 0 || this._allTags.length > 0) { - var tagsToRemove = []; - var tagsToAdd = []; - var txns = []; - for (var i = 0; i < this._allTags.length; i++) { - if (tags.indexOf(this._allTags[i]) == -1) - tagsToRemove.push(this._allTags[i]); - } - for (var i = 0; i < this._tags.length; i++) { - tagsToAdd[i] = []; - for (var j = 0; j < tags.length; j++) { - if (this._tags[i].indexOf(tags[j]) == -1) - tagsToAdd[i].push(tags[j]); - } - } - - if (tagsToAdd.length > 0) { - for (let i = 0; i < this._uris.length; i++) { - if (tagsToAdd[i].length > 0) { - let tagTxn = new PlacesTagURITransaction(this._uris[i], - tagsToAdd[i]); - txns.push(tagTxn); - } - } - } - if (tagsToRemove.length > 0) { - for (let i = 0; i < this._uris.length; i++) { - let untagTxn = new PlacesUntagURITransaction(this._uris[i], - tagsToRemove); - txns.push(untagTxn); - } - } - - if (txns.length > 0) { - let aggregate = new PlacesAggregatedTransaction("Update tags", txns); - PlacesUtils.transactionManager.doTransaction(aggregate); - - this._allTags = tags; - this._tags = []; - for (let i = 0; i < this._uris.length; i++) { - this._tags[i] = PlacesUtils.tagging.getTagsForURI(this._uris[i]); - } - - // Ensure the tagsField is in sync, clean it up from empty tags - this._initTextField("tagsField", tags, false); - return true; - } - } - return false; - }, - - onNamePickerBlur: function EIO_onNamePickerBlur() { - if (this._itemId == -1) - return; - - var namePicker = this._element("namePicker") - - // Here we update either the item title or its cached static title - var newTitle = namePicker.value; - if (!newTitle && - PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) == PlacesUtils.tagsFolderId) { - // We don't allow setting an empty title for a tag, restore the old one. - this._initNamePicker(); - } - else if (this._getItemStaticTitle() != newTitle) { - this._mayUpdateFirstEditField("namePicker"); - let txn = new PlacesEditItemTitleTransaction(this._itemId, newTitle); - PlacesUtils.transactionManager.doTransaction(txn); - } - }, - - onDescriptionFieldBlur: function EIO_onDescriptionFieldBlur() { - var description = this._element("descriptionField").value; - if (description != PlacesUIUtils.getItemDescription(this._itemId)) { - var annoObj = { name : PlacesUIUtils.DESCRIPTION_ANNO, - type : Ci.nsIAnnotationService.TYPE_STRING, - flags : 0, - value : description, - expires: Ci.nsIAnnotationService.EXPIRE_NEVER }; - var txn = new PlacesSetItemAnnotationTransaction(this._itemId, annoObj); - PlacesUtils.transactionManager.doTransaction(txn); - } - }, - - onLocationFieldBlur: function EIO_onLocationFieldBlur() { - var uri; - try { - uri = PlacesUIUtils.createFixedURI(this._element("locationField").value); - } - catch(ex) { return; } - - if (!this._uri.equals(uri)) { - var txn = new PlacesEditBookmarkURITransaction(this._itemId, uri); - PlacesUtils.transactionManager.doTransaction(txn); - this._uri = uri; - } - }, - - onKeywordFieldBlur: function EIO_onKeywordFieldBlur() { - let oldKeyword = this._keyword; - let keyword = this._keyword = this._element("keywordField").value; - if (keyword != oldKeyword) { - let txn = new PlacesEditBookmarkKeywordTransaction(this._itemId, - keyword, - null, - oldKeyword); - PlacesUtils.transactionManager.doTransaction(txn); - } - }, - - onLoadInSidebarCheckboxCommand: - function EIO_onLoadInSidebarCheckboxCommand() { - let annoObj = { name : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO }; - if (this._element("loadInSidebarCheckbox").checked) - annoObj.value = true; - let txn = new PlacesSetItemAnnotationTransaction(this._itemId, annoObj); - PlacesUtils.transactionManager.doTransaction(txn); - }, - - toggleFolderTreeVisibility: function EIO_toggleFolderTreeVisibility() { - var expander = this._element("foldersExpander"); - var folderTreeRow = this._element("folderTreeRow"); - if (!folderTreeRow.collapsed) { - expander.className = "expander-down"; - expander.setAttribute("tooltiptext", - expander.getAttribute("tooltiptextdown")); - folderTreeRow.collapsed = true; - this._element("chooseFolderSeparator").hidden = - this._element("chooseFolderMenuItem").hidden = false; - } - else { - expander.className = "expander-up" - expander.setAttribute("tooltiptext", - expander.getAttribute("tooltiptextup")); - folderTreeRow.collapsed = false; - - // XXXmano: Ideally we would only do this once, but for some odd reason, - // the editable mode set on this tree, together with its collapsed state - // breaks the view. - const FOLDER_TREE_PLACE_URI = - "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" + - PlacesUIUtils.allBookmarksFolderId; - this._folderTree.place = FOLDER_TREE_PLACE_URI; - - this._element("chooseFolderSeparator").hidden = - this._element("chooseFolderMenuItem").hidden = true; - var currentFolder = this._getFolderIdFromMenuList(); - this._folderTree.selectItems([currentFolder]); - this._folderTree.focus(); - } - }, - - _getFolderIdFromMenuList: - function EIO__getFolderIdFromMenuList() { - var selectedItem = this._folderMenuList.selectedItem; - NS_ASSERT("folderId" in selectedItem, - "Invalid menuitem in the folders-menulist"); - return selectedItem.folderId; - }, - - /** - * Get the corresponding menu-item in the folder-menu-list for a bookmarks - * folder if such an item exists. Otherwise, this creates a menu-item for the - * folder. If the items-count limit (see MAX_FOLDERS_IN_MENU_LIST) is reached, - * 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 (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); - - return this._appendFolderItemToMenupopup(menupopup, aFolderId); - }, - - onFolderMenuListCommand: function EIO_onFolderMenuListCommand(aEvent) { - // Set a selectedIndex attribute to show special icons - this._folderMenuList.setAttribute("selectedIndex", - this._folderMenuList.selectedIndex); - - if (aEvent.target.id == "editBMPanel_chooseFolderMenuItem") { - // reset the selection back to where it was and expand the tree - // (this menu-item is hidden when the tree is already visible - var container = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId); - var item = this._getFolderMenuItem(container); - this._folderMenuList.selectedItem = item; - // XXXmano HACK: setTimeout 100, otherwise focus goes back to the - // menulist right away - setTimeout(function(self) self.toggleFolderTreeVisibility(), 100, this); - return; - } - - // Move the item - var container = this._getFolderIdFromMenuList(); - if (PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) != container) { - var txn = new PlacesMoveItemTransaction(this._itemId, - container, - PlacesUtils.bookmarks.DEFAULT_INDEX); - PlacesUtils.transactionManager.doTransaction(txn); - - // Mark the containing folder as recently-used if it isn't in the - // static list - if (container != PlacesUtils.unfiledBookmarksFolderId && - container != PlacesUtils.toolbarFolderId && - container != PlacesUtils.bookmarksMenuFolderId) - this._markFolderAsRecentlyUsed(container); - } - - // Update folder-tree selection - var folderTreeRow = this._element("folderTreeRow"); - if (!folderTreeRow.collapsed) { - var selectedNode = this._folderTree.selectedNode; - if (!selectedNode || - PlacesUtils.getConcreteItemId(selectedNode) != container) - this._folderTree.selectItems([container]); - } - }, - - onFolderTreeSelect: function EIO_onFolderTreeSelect() { - var selectedNode = this._folderTree.selectedNode; - - // Disable the "New Folder" button if we cannot create a new folder - this._element("newFolderButton") - .disabled = !this._folderTree.insertionPoint || !selectedNode; - - if (!selectedNode) - return; - - var folderId = PlacesUtils.getConcreteItemId(selectedNode); - if (this._getFolderIdFromMenuList() == folderId) - return; - - var folderItem = this._getFolderMenuItem(folderId); - this._folderMenuList.selectedItem = folderItem; - folderItem.doCommand(); - }, - - _markFolderAsRecentlyUsed: - function EIO__markFolderAsRecentlyUsed(aFolderId) { - var txns = []; - - // Expire old unused recent folders - var anno = this._getLastUsedAnnotationObject(false); - while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) { - var folderId = this._recentFolders.pop().folderId; - let annoTxn = new PlacesSetItemAnnotationTransaction(folderId, anno); - txns.push(annoTxn); - } - - // Mark folder as recently used - anno = this._getLastUsedAnnotationObject(true); - let annoTxn = new PlacesSetItemAnnotationTransaction(aFolderId, anno); - txns.push(annoTxn); - - let aggregate = new PlacesAggregatedTransaction("Update last used folders", txns); - PlacesUtils.transactionManager.doTransaction(aggregate); - }, - - /** - * Returns an object which could then be used to set/unset the - * LAST_USED_ANNO annotation for a folder. - * - * @param aLastUsed - * Whether to set or unset the LAST_USED_ANNO annotation. - * @returns an object representing the annotation which could then be used - * with the transaction manager. - */ - _getLastUsedAnnotationObject: - function EIO__getLastUsedAnnotationObject(aLastUsed) { - var anno = { name: LAST_USED_ANNO, - type: Ci.nsIAnnotationService.TYPE_INT32, - flags: 0, - value: aLastUsed ? new Date().getTime() : null, - expires: Ci.nsIAnnotationService.EXPIRE_NEVER }; - - return anno; - }, - - _rebuildTagsSelectorList: function EIO__rebuildTagsSelectorList() { - var tagsSelector = this._element("tagsSelector"); - var tagsSelectorRow = this._element("tagsSelectorRow"); - if (tagsSelectorRow.collapsed) - return; - - // Save the current scroll position and restore it after the rebuild. - let firstIndex = tagsSelector.getIndexOfFirstVisibleRow(); - let selectedIndex = tagsSelector.selectedIndex; - let selectedTag = selectedIndex >= 0 ? tagsSelector.selectedItem.label - : null; - - while (tagsSelector.hasChildNodes()) - tagsSelector.removeChild(tagsSelector.lastChild); - - var tagsInField = this._getTagsArrayFromTagField(); - var allTags = PlacesUtils.tagging.allTags; - for (var i = 0; i < allTags.length; i++) { - var tag = allTags[i]; - var elt = document.createElement("listitem"); - elt.setAttribute("type", "checkbox"); - elt.setAttribute("label", tag); - if (tagsInField.indexOf(tag) != -1) - elt.setAttribute("checked", "true"); - tagsSelector.appendChild(elt); - if (selectedTag === tag) - selectedIndex = tagsSelector.getIndexOfItem(elt); - } - - // Restore position. - // The listbox allows to scroll only if the required offset doesn't - // overflow its capacity, thus need to adjust the index for removals. - firstIndex = - Math.min(firstIndex, - tagsSelector.itemCount - tagsSelector.getNumberOfVisibleRows()); - tagsSelector.scrollToIndex(firstIndex); - if (selectedIndex >= 0 && tagsSelector.itemCount > 0) { - selectedIndex = Math.min(selectedIndex, tagsSelector.itemCount - 1); - tagsSelector.selectedIndex = selectedIndex; - tagsSelector.ensureIndexIsVisible(selectedIndex); - } - }, - - toggleTagsSelector: function EIO_toggleTagsSelector() { - var tagsSelector = this._element("tagsSelector"); - var tagsSelectorRow = this._element("tagsSelectorRow"); - var expander = this._element("tagsSelectorExpander"); - if (tagsSelectorRow.collapsed) { - expander.className = "expander-up"; - expander.setAttribute("tooltiptext", - expander.getAttribute("tooltiptextup")); - tagsSelectorRow.collapsed = false; - this._rebuildTagsSelectorList(); - - // This is a no-op if we've added the listener. - tagsSelector.addEventListener("CheckboxStateChange", this, false); - } - else { - expander.className = "expander-down"; - expander.setAttribute("tooltiptext", - expander.getAttribute("tooltiptextdown")); - tagsSelectorRow.collapsed = true; - } - }, - - /** - * Splits "tagsField" element value, returning an array of valid tag strings. - * - * @return Array of tag strings found in the field value. - */ - _getTagsArrayFromTagField: function EIO__getTagsArrayFromTagField() { - let tags = this._element("tagsField").value; - return tags.trim() - .split(/\s*,\s*/) // Split on commas and remove spaces. - .filter(function (tag) tag.length > 0); // Kill empty tags. - }, - - newFolder: function EIO_newFolder() { - var ip = this._folderTree.insertionPoint; - - // default to the bookmarks menu folder - if (!ip || ip.itemId == PlacesUIUtils.allBookmarksFolderId) { - ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId, - PlacesUtils.bookmarks.DEFAULT_INDEX, - Ci.nsITreeView.DROP_ON); - } - - // XXXmano: add a separate "New Folder" string at some point... - var defaultLabel = this._element("newFolderButton").label; - var txn = new PlacesCreateFolderTransaction(defaultLabel, ip.itemId, ip.index); - PlacesUtils.transactionManager.doTransaction(txn); - this._folderTree.focus(); - this._folderTree.selectItems([this._lastNewItem]); - this._folderTree.startEditing(this._folderTree.view.selection.currentIndex, - this._folderTree.columns.getFirstColumn()); - }, - - // nsIDOMEventListener - handleEvent: function EIO_nsIDOMEventListener(aEvent) { - switch (aEvent.type) { - case "CheckboxStateChange": - // Update the tags field when items are checked/unchecked in the listbox - var tags = this._getTagsArrayFromTagField(); - - if (aEvent.target.checked) { - if (tags.indexOf(aEvent.target.label) == -1) - tags.push(aEvent.target.label); - } - else { - var indexOfItem = tags.indexOf(aEvent.target.label); - if (indexOfItem != -1) - tags.splice(indexOfItem, 1); - } - this._element("tagsField").value = tags.join(", "); - this._updateTags(); - break; - case "blur": - let replaceFn = (str, firstLetter) => firstLetter.toUpperCase(); - let nodeName = aEvent.target.id.replace(/editBMPanel_(\w)/, replaceFn); - this["on" + nodeName + "Blur"](); - break; - case "unload": - this.uninitPanel(false); - 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 (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; - } - } - } - - return; - } - - switch (aProperty) { - case "title": - var namePicker = this._element("namePicker"); - if (namePicker.value != aValue) { - namePicker.value = aValue; - this._editorTransactionManagerClear(namePicker); - } - break; - case "uri": - var locationField = this._element("locationField"); - if (locationField.value != aValue) { - this._uri = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService). - newURI(aValue, null, null); - this._initTextField("locationField", this._uri.spec); - this._initNamePicker(); - this._initTextField("tagsField", - PlacesUtils.tagging - .getTagsForURI(this._uri).join(", "), - false); - this._rebuildTagsSelectorList(); - } - break; - case "keyword": - this._keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this._itemId); - this._initTextField("keywordField", this._keyword); - break; - case PlacesUIUtils.DESCRIPTION_ANNO: - this._initTextField("descriptionField", - PlacesUIUtils.getItemDescription(this._itemId)); - break; - case PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO: - this._element("loadInSidebarCheckbox").checked = - PlacesUtils.annotations.itemHasAnnotation(this._itemId, - PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO); - break; - case PlacesUtils.LMANNO_FEEDURI: - let feedURISpec = - PlacesUtils.annotations.getItemAnnotation(this._itemId, - PlacesUtils.LMANNO_FEEDURI); - this._initTextField("feedLocationField", feedURISpec, true); - break; - case PlacesUtils.LMANNO_SITEURI: - let siteURISpec = ""; - try { - siteURISpec = - PlacesUtils.annotations.getItemAnnotation(this._itemId, - PlacesUtils.LMANNO_SITEURI); - } catch (ex) {} - this._initTextField("siteLocationField", siteURISpec, true); - break; - } - }, - - onItemMoved: function EIO_onItemMoved(aItemId, aOldParent, aOldIndex, - aNewParent, aNewIndex, aItemType) { - if (aItemId != this._itemId || - aNewParent == this._getFolderIdFromMenuList()) - return; - - var folderItem = this._getFolderMenuItem(aNewParent); - - // 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; - }, - - onItemRemoved: function() { }, - onBeginUpdateBatch: function() { }, - onEndUpdateBatch: function() { }, - onItemVisited: function() { }, -}; diff --git a/components/places/content/editBookmarkOverlay.xul b/components/places/content/editBookmarkOverlay.xul deleted file mode 100644 index 196369d..0000000 --- a/components/places/content/editBookmarkOverlay.xul +++ /dev/null @@ -1,228 +0,0 @@ - - - -%editBookmarkOverlayDTD; -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -