Merge mozilla-central to inbound on a CLOSED TREE
|
@ -118,6 +118,9 @@ jobs:
|
|||
mozilla-esr60:
|
||||
- {weekday: 'Monday', hour: 10, minute: 0}
|
||||
- {weekday: 'Thursday', hour: 10, minute: 0}
|
||||
mozilla-release:
|
||||
- {weekday: 'Monday', hour: 10, minute: 0}
|
||||
- {weekday: 'Thursday', hour: 10, minute: 0}
|
||||
mozilla-beta:
|
||||
- {weekday: 'Monday', hour: 10, minute: 0}
|
||||
- {weekday: 'Thursday', hour: 10, minute: 0}
|
||||
|
|
10
.eslintrc.js
|
@ -48,16 +48,6 @@ module.exports = {
|
|||
"rules": {
|
||||
"mozilla/no-define-cc-etc": "off",
|
||||
}
|
||||
}, {
|
||||
// XXX Bug 1452706. These directories are still being fixed, so turn off
|
||||
// mozilla/require-expected-throws-or-rejects for now.
|
||||
"files": [
|
||||
"devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js",
|
||||
"storage/test/unit/**",
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/require-expected-throws-or-rejects": "off",
|
||||
}
|
||||
}, {
|
||||
// XXX Bug 1452706. These directories are still being fixed, so turn off
|
||||
// mozilla/require-expected-throws-or-rejects for now.
|
||||
|
|
|
@ -19,6 +19,9 @@ var StarUI = {
|
|||
// popup, such as making a change through typing or clicking on
|
||||
// the popup.
|
||||
_autoCloseTimerEnabled: true,
|
||||
// The autoclose timeout length. 3500ms matches the timeout that Pocket uses
|
||||
// in browser/extensions/pocket/content/panels/js/saved.js.
|
||||
_autoCloseTimeout: 3500,
|
||||
_removeBookmarksOnPopupHidden: false,
|
||||
|
||||
_element(aID) {
|
||||
|
@ -84,8 +87,13 @@ var StarUI = {
|
|||
case "popuphidden": {
|
||||
clearTimeout(this._autoCloseTimer);
|
||||
if (aEvent.originalTarget == this.panel) {
|
||||
if (!this._element("editBookmarkPanelContent").hidden)
|
||||
let selectedFolderGuid;
|
||||
|
||||
if (!this._element("editBookmarkPanelContent").hidden) {
|
||||
// Get the folder first, before we uninit the overlay.
|
||||
selectedFolderGuid = gEditItemOverlay.selectedFolderGuid;
|
||||
this.quitEditMode();
|
||||
}
|
||||
|
||||
if (this._anchorToolbarButton) {
|
||||
this._anchorToolbarButton.removeAttribute("open");
|
||||
|
@ -113,6 +121,10 @@ var StarUI = {
|
|||
} else if (this._isNewBookmark) {
|
||||
LibraryUI.triggerLibraryAnimation("bookmark");
|
||||
}
|
||||
|
||||
if (!removeBookmarksOnPopupHidden) {
|
||||
this._storeRecentlyUsedFolder(selectedFolderGuid).catch(console.error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -186,9 +198,7 @@ var StarUI = {
|
|||
}
|
||||
// auto-close if new and not interacted with
|
||||
if (this._isNewBookmark && !this._isComposing) {
|
||||
// 3500ms matches the timeout that Pocket uses in
|
||||
// browser/extensions/pocket/content/panels/js/saved.js
|
||||
let delay = 3500;
|
||||
let delay = this._autoCloseTimeout;
|
||||
if (this._closePanelQuickForTesting) {
|
||||
delay /= 10;
|
||||
}
|
||||
|
@ -340,6 +350,33 @@ var StarUI = {
|
|||
this._batchBlockingDeferred.resolve();
|
||||
this._batchBlockingDeferred = null;
|
||||
this._batching = false;
|
||||
},
|
||||
|
||||
async _storeRecentlyUsedFolder(selectedFolderGuid) {
|
||||
// These are displayed by default, so don't save the folder for them.
|
||||
if (!selectedFolderGuid ||
|
||||
PlacesUtils.bookmarks.userContentRoots.includes(selectedFolderGuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// List of recently used folders:
|
||||
let lastUsedFolderGuids =
|
||||
await PlacesUtils.metadata.get(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, []);
|
||||
|
||||
let index = lastUsedFolderGuids.indexOf(selectedFolderGuid);
|
||||
if (index > 1) {
|
||||
// The guid is in the array but not the most recent.
|
||||
lastUsedFolderGuids.splice(index, 1);
|
||||
lastUsedFolderGuids.unshift(selectedFolderGuid);
|
||||
} else if (index == -1) {
|
||||
lastUsedFolderGuids.unshift(selectedFolderGuid);
|
||||
}
|
||||
if (lastUsedFolderGuids.length > 5) {
|
||||
lastUsedFolderGuids.pop();
|
||||
}
|
||||
|
||||
await PlacesUtils.metadata.set(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY,
|
||||
lastUsedFolderGuids);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -796,14 +796,13 @@ var gPopupBlockerObserver = {
|
|||
}
|
||||
} catch (e) { }
|
||||
|
||||
var bundlePreferences = document.getElementById("bundle_preferences");
|
||||
var params = { blockVisible: false,
|
||||
sessionVisible: false,
|
||||
allowVisible: true,
|
||||
prefilledHost: prefillValue,
|
||||
permissionType: "popup",
|
||||
windowTitle: bundlePreferences.getString("popuppermissionstitle2"),
|
||||
introText: bundlePreferences.getString("popuppermissionstext") };
|
||||
};
|
||||
|
||||
var existingWindow = Services.wm.getMostRecentWindow("Browser:Permissions");
|
||||
if (existingWindow) {
|
||||
existingWindow.initWithParams(params);
|
||||
|
|
|
@ -136,7 +136,7 @@ window._gBrowser = {
|
|||
|
||||
_removingTabs: [],
|
||||
|
||||
_multiSelectedTabsMap: new WeakMap(),
|
||||
_multiSelectedTabsSet: new WeakSet(),
|
||||
|
||||
_lastMultiSelectedTabRef: null,
|
||||
|
||||
|
@ -2624,7 +2624,7 @@ window._gBrowser = {
|
|||
return;
|
||||
}
|
||||
|
||||
let selectedTabs = ChromeUtils.nondeterministicGetWeakMapKeys(this._multiSelectedTabsMap)
|
||||
let selectedTabs = ChromeUtils.nondeterministicGetWeakSetKeys(this._multiSelectedTabsSet)
|
||||
.filter(tab => tab.isConnected);
|
||||
this.removeCollectionOfTabs(selectedTabs);
|
||||
},
|
||||
|
@ -3630,7 +3630,7 @@ window._gBrowser = {
|
|||
}
|
||||
|
||||
aTab.setAttribute("multiselected", "true");
|
||||
this._multiSelectedTabsMap.set(aTab, null);
|
||||
this._multiSelectedTabsSet.add(aTab);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3661,28 +3661,28 @@ window._gBrowser = {
|
|||
return;
|
||||
}
|
||||
aTab.removeAttribute("multiselected");
|
||||
this._multiSelectedTabsMap.delete(aTab);
|
||||
this._multiSelectedTabsSet.delete(aTab);
|
||||
},
|
||||
|
||||
clearMultiSelectedTabs() {
|
||||
const selectedTabs = ChromeUtils.nondeterministicGetWeakMapKeys(this._multiSelectedTabsMap);
|
||||
const selectedTabs = ChromeUtils.nondeterministicGetWeakSetKeys(this._multiSelectedTabsSet);
|
||||
for (let tab of selectedTabs) {
|
||||
if (tab.isConnected && tab.multiselected) {
|
||||
tab.removeAttribute("multiselected");
|
||||
}
|
||||
}
|
||||
this._multiSelectedTabsMap = new WeakMap();
|
||||
this._multiSelectedTabsSet = new WeakSet();
|
||||
},
|
||||
|
||||
get multiSelectedTabsCount() {
|
||||
return ChromeUtils.nondeterministicGetWeakMapKeys(this._multiSelectedTabsMap)
|
||||
return ChromeUtils.nondeterministicGetWeakSetKeys(this._multiSelectedTabsSet)
|
||||
.filter(tab => tab.isConnected && !tab.closing)
|
||||
.length;
|
||||
},
|
||||
|
||||
get lastMultiSelectedTab() {
|
||||
let tab = this._lastMultiSelectedTabRef ? this._lastMultiSelectedTabRef.get() : null;
|
||||
if (tab && tab.isConnected && this._multiSelectedTabsMap.has(tab)) {
|
||||
if (tab && tab.isConnected && this._multiSelectedTabsSet.has(tab)) {
|
||||
return tab;
|
||||
}
|
||||
return gBrowser.selectedTab;
|
||||
|
|
|
@ -119,6 +119,7 @@ const startupPhases = {
|
|||
"resource://gre/modules/AsyncPrefs.jsm",
|
||||
"resource://gre/modules/LoginManagerContextMenu.jsm",
|
||||
"resource://gre/modules/Task.jsm",
|
||||
"resource://pdf.js/PdfStreamConverter.jsm",
|
||||
]),
|
||||
}},
|
||||
};
|
||||
|
|
|
@ -29,6 +29,8 @@ const blacklist = {
|
|||
"resource://gre/modules/Promise.jsm",
|
||||
"resource://gre/modules/Task.jsm",
|
||||
"resource://gre/modules/osfile.jsm",
|
||||
"resource://pdf.js/PdfJs.jsm",
|
||||
"resource://pdf.js/PdfStreamConverter.jsm",
|
||||
]),
|
||||
services: new Set([
|
||||
"@mozilla.org/base/telemetry-startup;1",
|
||||
|
|
|
@ -12,7 +12,6 @@ var isDevtools = SimpleTest.harnessParameters.subsuite == "devtools";
|
|||
|
||||
var gExceptionPaths = [
|
||||
"chrome://browser/content/defaultthemes/",
|
||||
"chrome://browser/locale/searchplugins/",
|
||||
"resource://app/defaults/settings/blocklists/",
|
||||
"resource://app/defaults/settings/main/",
|
||||
"resource://app/defaults/settings/pinning/",
|
||||
|
@ -36,6 +35,9 @@ var gExceptionPaths = [
|
|||
// Exclude all the metadata paths under the country metadata folder because these
|
||||
// paths will be concatenated in FormAutofillUtils.jsm based on different country/region.
|
||||
"resource://formautofill/addressmetadata/",
|
||||
|
||||
// Exclude all search-plugins because they aren't referenced by filename
|
||||
"resource://search-plugins/",
|
||||
];
|
||||
|
||||
// These are not part of the omni.ja file, so we find them only when running
|
||||
|
|
|
@ -2,7 +2,7 @@ const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
|
|||
|
||||
add_task(async function clickWithoutPrefSet() {
|
||||
let tab = await addTab();
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsMap;
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsSet;
|
||||
|
||||
isnot(gBrowser.selectedTab, tab, "Tab doesn't have focus");
|
||||
|
||||
|
@ -29,7 +29,7 @@ add_task(async function clickWithPrefSet() {
|
|||
]
|
||||
});
|
||||
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsMap;
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsSet;
|
||||
const initialFocusedTab = gBrowser.selectedTab;
|
||||
const tab = await addTab();
|
||||
|
||||
|
@ -60,8 +60,8 @@ add_task(async function clearSelection() {
|
|||
await triggerClickOn(tab1, { ctrlKey: true });
|
||||
await triggerClickOn(tab2, { ctrlKey: true });
|
||||
|
||||
ok(tab1.multiselected && gBrowser._multiSelectedTabsMap.has(tab1), "Tab1 is (multi) selected");
|
||||
ok(tab2.multiselected && gBrowser._multiSelectedTabsMap.has(tab2), "Tab2 is (multi) selected");
|
||||
ok(tab1.multiselected && gBrowser._multiSelectedTabsSet.has(tab1), "Tab1 is (multi) selected");
|
||||
ok(tab2.multiselected && gBrowser._multiSelectedTabsSet.has(tab2), "Tab2 is (multi) selected");
|
||||
is(gBrowser.multiSelectedTabsCount, 2, "Two tabs (multi) selected");
|
||||
isnot(tab3, gBrowser.selectedTab, "Tab3 doesn't have focus");
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ add_task(async function prefNotSet() {
|
|||
let tab2 = await addTab();
|
||||
let tab3 = await addTab();
|
||||
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsMap;
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsSet;
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
|
||||
|
@ -42,7 +42,7 @@ add_task(async function noItemsInTheCollectionBeforeShiftClicking() {
|
|||
let tab3 = await addTab();
|
||||
let tab4 = await addTab();
|
||||
let tab5 = await addTab();
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsMap;
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsSet;
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
|
||||
|
@ -77,7 +77,7 @@ add_task(async function itemsInTheCollectionBeforeShiftClicking() {
|
|||
let tab4 = await addTab();
|
||||
let tab5 = await addTab();
|
||||
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsMap;
|
||||
let mSelectedTabs = gBrowser._multiSelectedTabsSet;
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, () => triggerClickOn(tab1, {}));
|
||||
|
||||
|
|
|
@ -117,4 +117,3 @@ browser.jar:
|
|||
% override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
|
||||
% override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
|
||||
% override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
|
||||
% resource search-plugins chrome://browser/locale/searchplugins/
|
||||
|
|
|
@ -211,6 +211,7 @@ let InternalFaviconLoader = {
|
|||
var PlacesUIUtils = {
|
||||
LOAD_IN_SIDEBAR_ANNO: "bookmarkProperties/loadInSidebar",
|
||||
DESCRIPTION_ANNO: "bookmarkProperties/description",
|
||||
LAST_USED_FOLDERS_META_KEY: "bookmarks/lastusedfolders",
|
||||
|
||||
/**
|
||||
* Makes a URI from a spec, and do fixup
|
||||
|
@ -1032,7 +1033,7 @@ var PlacesUIUtils = {
|
|||
if (win.top.XULBrowserWindow) {
|
||||
win.top.XULBrowserWindow.setOverLink(url, null);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// These are lazy getters to avoid importing PlacesUtils immediately.
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const LAST_USED_ANNO = "bookmarkPropertiesDialog/folderLastUsed";
|
||||
const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
|
||||
|
||||
var gEditItemOverlay = {
|
||||
|
@ -46,7 +45,6 @@ var gEditItemOverlay = {
|
|||
let visibleRows = new Set();
|
||||
let isParentReadOnly = false;
|
||||
let postData = aInitInfo.postData;
|
||||
let parentId = -1;
|
||||
let parentGuid = null;
|
||||
|
||||
if (node && isItem) {
|
||||
|
@ -55,14 +53,13 @@ var gEditItemOverlay = {
|
|||
}
|
||||
let parent = node.parent;
|
||||
isParentReadOnly = !PlacesUtils.nodeIsFolder(parent);
|
||||
parentId = parent.itemId;
|
||||
parentGuid = parent.bookmarkGuid;
|
||||
}
|
||||
|
||||
let focusedElement = aInitInfo.focusedElement;
|
||||
let onPanelReady = aInitInfo.onPanelReady;
|
||||
|
||||
return this._paneInfo = { itemId, itemGuid, parentId, parentGuid, isItem,
|
||||
return this._paneInfo = { itemId, itemGuid, parentGuid, isItem,
|
||||
isURI, uri, title,
|
||||
isBookmark, isFolderShortcut, isParentReadOnly,
|
||||
bulkTagging, uris,
|
||||
|
@ -209,7 +206,7 @@ var gEditItemOverlay = {
|
|||
if (this.initialized)
|
||||
this.uninitPanel(false);
|
||||
|
||||
let { parentId, isItem, isURI,
|
||||
let { parentGuid, isItem, isURI,
|
||||
isBookmark, bulkTagging, uris,
|
||||
visibleRows, focusedElement,
|
||||
onPanelReady } = this._setPaneInfo(aInfo);
|
||||
|
@ -258,7 +255,7 @@ var gEditItemOverlay = {
|
|||
// not cheap (we don't always have the parent), and there's no use case for
|
||||
// this (it's only the Star UI that shows the folderPicker)
|
||||
if (showOrCollapse("folderRow", isItem, "folderPicker")) {
|
||||
this._initFolderMenuList(parentId).catch(Cu.reportError);
|
||||
this._initFolderMenuList(parentGuid).catch(Cu.reportError);
|
||||
}
|
||||
|
||||
// Selection count.
|
||||
|
@ -357,26 +354,25 @@ var gEditItemOverlay = {
|
|||
* 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
|
||||
* @param aFolderGuid
|
||||
* The identifier of the bookmarks folder.
|
||||
* @param aTitle
|
||||
* The title to use as a label.
|
||||
* @return the new menu item.
|
||||
*/
|
||||
_appendFolderItemToMenupopup(aMenupopup, aFolderId, aTitle) {
|
||||
_appendFolderItemToMenupopup(aMenupopup, aFolderGuid, aTitle) {
|
||||
// First make sure the folders-separator is visible
|
||||
this._element("foldersSeparator").hidden = false;
|
||||
|
||||
var folderMenuItem = document.createElement("menuitem");
|
||||
var folderTitle = aTitle;
|
||||
folderMenuItem.folderId = aFolderId;
|
||||
folderMenuItem.setAttribute("label", folderTitle);
|
||||
folderMenuItem.folderGuid = aFolderGuid;
|
||||
folderMenuItem.setAttribute("label", aTitle);
|
||||
folderMenuItem.className = "menuitem-iconic folder-icon";
|
||||
aMenupopup.appendChild(folderMenuItem);
|
||||
return folderMenuItem;
|
||||
},
|
||||
|
||||
async _initFolderMenuList(aSelectedFolder) {
|
||||
async _initFolderMenuList(aSelectedFolderGuid) {
|
||||
// clean up first
|
||||
var menupopup = this._folderMenuList.menupopup;
|
||||
while (menupopup.childNodes.length > 6)
|
||||
|
@ -386,58 +382,46 @@ var gEditItemOverlay = {
|
|||
if (!this._staticFoldersListBuilt) {
|
||||
let unfiledItem = this._element("unfiledRootItem");
|
||||
unfiledItem.label = PlacesUtils.getString("OtherBookmarksFolderTitle");
|
||||
unfiledItem.folderId = PlacesUtils.unfiledBookmarksFolderId;
|
||||
unfiledItem.folderGuid = PlacesUtils.bookmarks.unfiledGuid;
|
||||
let bmMenuItem = this._element("bmRootItem");
|
||||
bmMenuItem.label = PlacesUtils.getString("BookmarksMenuFolderTitle");
|
||||
bmMenuItem.folderId = PlacesUtils.bookmarksMenuFolderId;
|
||||
bmMenuItem.folderGuid = PlacesUtils.bookmarks.menuGuid;
|
||||
let toolbarItem = this._element("toolbarFolderItem");
|
||||
toolbarItem.label = PlacesUtils.getString("BookmarksToolbarFolderTitle");
|
||||
toolbarItem.folderId = PlacesUtils.toolbarFolderId;
|
||||
toolbarItem.folderGuid = PlacesUtils.bookmarks.toolbarGuid;
|
||||
this._staticFoldersListBuilt = true;
|
||||
}
|
||||
|
||||
// List of recently used folders:
|
||||
var folderIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(LAST_USED_ANNO);
|
||||
let lastUsedFolderGuids =
|
||||
await PlacesUtils.metadata.get(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY, []);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The list of last used folders is sorted in most-recent first order.
|
||||
*
|
||||
* 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 (let folderId of folderIds) {
|
||||
var lastUsed =
|
||||
PlacesUtils.annotations.getItemAnnotation(folderId, LAST_USED_ANNO);
|
||||
let guid = await PlacesUtils.promiseItemGuid(folderId);
|
||||
for (let guid of lastUsedFolderGuids) {
|
||||
let bm = await PlacesUtils.bookmarks.fetch(guid);
|
||||
// Since this could be a root mobile folder, we should get the proper
|
||||
// title.
|
||||
if (bm) {
|
||||
let title = PlacesUtils.bookmarks.getLocalizedTitle(bm);
|
||||
this._recentFolders.push({ folderId, guid, title, lastUsed });
|
||||
this._recentFolders.push({ guid, title });
|
||||
}
|
||||
}
|
||||
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 (let i = 0; i < numberOfItems; i++) {
|
||||
await this._appendFolderItemToMenupopup(menupopup,
|
||||
this._recentFolders[i].folderId,
|
||||
this._recentFolders[i].guid,
|
||||
this._recentFolders[i].title);
|
||||
}
|
||||
|
||||
let selectedFolderGuid = await PlacesUtils.promiseItemGuid(aSelectedFolder);
|
||||
let title = (await PlacesUtils.bookmarks.fetch(selectedFolderGuid)).title;
|
||||
var defaultItem = this._getFolderMenuItem(aSelectedFolder, title);
|
||||
let title = (await PlacesUtils.bookmarks.fetch(aSelectedFolderGuid)).title;
|
||||
var defaultItem = this._getFolderMenuItem(aSelectedFolderGuid, title);
|
||||
this._folderMenuList.selectedItem = defaultItem;
|
||||
|
||||
// Set a selectedIndex attribute to show special icons
|
||||
|
@ -478,6 +462,10 @@ var gEditItemOverlay = {
|
|||
this._firstEditedField = "";
|
||||
},
|
||||
|
||||
get selectedFolderGuid() {
|
||||
return this._folderMenuList.selectedItem && this._folderMenuList.selectedItem.folderGuid;
|
||||
},
|
||||
|
||||
onTagsFieldChange() {
|
||||
// Check for _paneInfo existing as the dialog may be closing but receiving
|
||||
// async updates from unresolved promises.
|
||||
|
@ -695,16 +683,16 @@ var gEditItemOverlay = {
|
|||
* 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
|
||||
* @param aFolderGuid
|
||||
* The identifier of the bookmarks folder.
|
||||
* @param aTitle
|
||||
* The title to use in case of menuitem creation.
|
||||
* @return handle to the menuitem.
|
||||
*/
|
||||
_getFolderMenuItem(aFolderId, aTitle) {
|
||||
_getFolderMenuItem(aFolderGuid, aTitle) {
|
||||
let menupopup = this._folderMenuList.menupopup;
|
||||
let menuItem = Array.prototype.find.call(
|
||||
menupopup.childNodes, item => item.folderId === aFolderId);
|
||||
menupopup.childNodes, item => item.folderGuid === aFolderGuid);
|
||||
if (menuItem !== undefined)
|
||||
return menuItem;
|
||||
|
||||
|
@ -712,7 +700,7 @@ var gEditItemOverlay = {
|
|||
if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
|
||||
menupopup.removeChild(menupopup.lastChild);
|
||||
|
||||
return this._appendFolderItemToMenupopup(menupopup, aFolderId, aTitle);
|
||||
return this._appendFolderItemToMenupopup(menupopup, aFolderGuid, aTitle);
|
||||
},
|
||||
|
||||
async onFolderMenuListCommand(aEvent) {
|
||||
|
@ -728,7 +716,7 @@ var gEditItemOverlay = {
|
|||
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
|
||||
let item = this._getFolderMenuItem(this._paneInfo.parentId,
|
||||
let item = this._getFolderMenuItem(this._paneInfo.parentGuid,
|
||||
this._paneInfo.title);
|
||||
this._folderMenuList.selectedItem = item;
|
||||
// XXXmano HACK: setTimeout 100, otherwise focus goes back to the
|
||||
|
@ -738,24 +726,16 @@ var gEditItemOverlay = {
|
|||
}
|
||||
|
||||
// Move the item
|
||||
let containerId = this._folderMenuList.selectedItem.folderId;
|
||||
if (this._paneInfo.parentId != containerId &&
|
||||
this._paneInfo.itemId != containerId) {
|
||||
let newParentGuid = await PlacesUtils.promiseItemGuid(containerId);
|
||||
let guid = this._paneInfo.itemGuid;
|
||||
await PlacesTransactions.Move({ guid, newParentGuid }).transact();
|
||||
|
||||
// Mark the containing folder as recently-used if it isn't in the
|
||||
// static list
|
||||
if (containerId != PlacesUtils.unfiledBookmarksFolderId &&
|
||||
containerId != PlacesUtils.toolbarFolderId &&
|
||||
containerId != PlacesUtils.bookmarksMenuFolderId) {
|
||||
this._markFolderAsRecentlyUsed(containerId)
|
||||
.catch(Cu.reportError);
|
||||
}
|
||||
let containerGuid = this._folderMenuList.selectedItem.folderGuid;
|
||||
if (this._paneInfo.parentGuid != containerGuid &&
|
||||
this._paneInfo.itemGuid != containerGuid) {
|
||||
await PlacesTransactions.Move({
|
||||
guid: this._paneInfo.itemGuid,
|
||||
newParentGuid: containerGuid
|
||||
}).transact();
|
||||
|
||||
// Auto-show the bookmarks toolbar when adding / moving an item there.
|
||||
if (containerId == PlacesUtils.toolbarFolderId) {
|
||||
if (containerGuid == PlacesUtils.bookmarks.toolbarGuid) {
|
||||
Services.obs.notifyObservers(null, "autoshow-bookmarks-toolbar");
|
||||
}
|
||||
}
|
||||
|
@ -765,8 +745,8 @@ var gEditItemOverlay = {
|
|||
if (!folderTreeRow.collapsed) {
|
||||
var selectedNode = this._folderTree.selectedNode;
|
||||
if (!selectedNode ||
|
||||
PlacesUtils.getConcreteItemId(selectedNode) != containerId)
|
||||
this._folderTree.selectItems([containerId]);
|
||||
PlacesUtils.getConcreteItemGuid(selectedNode) != containerGuid)
|
||||
this._folderTree.selectItems([containerGuid]);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -780,50 +760,15 @@ var gEditItemOverlay = {
|
|||
if (!selectedNode)
|
||||
return;
|
||||
|
||||
var folderId = PlacesUtils.getConcreteItemId(selectedNode);
|
||||
if (this._folderMenuList.selectedItem.folderId == folderId)
|
||||
var folderGuid = PlacesUtils.getConcreteItemGuid(selectedNode);
|
||||
if (this._folderMenuList.selectedItem.folderGuid == folderGuid)
|
||||
return;
|
||||
|
||||
var folderItem = this._getFolderMenuItem(folderId, selectedNode.title);
|
||||
var folderItem = this._getFolderMenuItem(folderGuid, selectedNode.title);
|
||||
this._folderMenuList.selectedItem = folderItem;
|
||||
folderItem.doCommand();
|
||||
},
|
||||
|
||||
async _markFolderAsRecentlyUsed(aFolderId) {
|
||||
// Expire old unused recent folders.
|
||||
let guids = [];
|
||||
while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
|
||||
let folderId = this._recentFolders.pop().folderId;
|
||||
let guid = await PlacesUtils.promiseItemGuid(folderId);
|
||||
guids.push(guid);
|
||||
}
|
||||
if (guids.length > 0) {
|
||||
let annotation = this._getLastUsedAnnotationObject(false);
|
||||
PlacesTransactions.Annotate({ guids, annotation })
|
||||
.transact().catch(Cu.reportError);
|
||||
}
|
||||
|
||||
// Mark folder as recently used
|
||||
let annotation = this._getLastUsedAnnotationObject(true);
|
||||
let guid = await PlacesUtils.promiseItemGuid(aFolderId);
|
||||
PlacesTransactions.Annotate({ guid, annotation })
|
||||
.transact().catch(Cu.reportError);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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(aLastUsed) {
|
||||
return { name: LAST_USED_ANNO,
|
||||
value: aLastUsed ? new Date().getTime() : null };
|
||||
},
|
||||
|
||||
_rebuildTagsSelectorList() {
|
||||
let tagsSelector = this._element("tagsSelector");
|
||||
let tagsSelectorRow = this._element("tagsSelectorRow");
|
||||
|
@ -1074,18 +1019,17 @@ var gEditItemOverlay = {
|
|||
return;
|
||||
}
|
||||
|
||||
this._paneInfo.parentId = newParentId;
|
||||
this._paneInfo.parentGuid = newParentGuid;
|
||||
|
||||
if (!this._paneInfo.visibleRows.has("folderRow") ||
|
||||
newParentId == this._folderMenuList.selectedItem.folderId) {
|
||||
newParentGuid == this._folderMenuList.selectedItem.folderGuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Just setting selectItem _does not_ trigger oncommand, so we don't
|
||||
// recurse.
|
||||
PlacesUtils.bookmarks.fetch(newParentGuid).then(bm => {
|
||||
this._folderMenuList.selectedItem = this._getFolderMenuItem(newParentId,
|
||||
this._folderMenuList.selectedItem = this._getFolderMenuItem(newParentGuid,
|
||||
bm.title);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -35,6 +35,7 @@ support-files =
|
|||
[browser_bookmarkProperties_editTagContainer.js]
|
||||
[browser_bookmarkProperties_no_user_actions.js]
|
||||
[browser_bookmarkProperties_readOnlyRoot.js]
|
||||
[browser_bookmarkProperties_remember_folders.js]
|
||||
[browser_bookmarksProperties.js]
|
||||
[browser_check_correct_controllers.js]
|
||||
[browser_click_bookmarks_on_toolbar.js]
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that multiple tags can be added to a bookmark using the star-shaped button, the library and the sidebar.
|
||||
*/
|
||||
|
||||
const bookmarkPanel = document.getElementById("editBookmarkPanel");
|
||||
let folders;
|
||||
|
||||
async function clickBookmarkStar() {
|
||||
let shownPromise = promisePopupShown(bookmarkPanel);
|
||||
BookmarkingUI.star.click();
|
||||
await shownPromise;
|
||||
}
|
||||
|
||||
async function hideBookmarksPanel() {
|
||||
let hiddenPromise = promisePopupHidden(bookmarkPanel);
|
||||
// Confirm and close the dialog.
|
||||
document.getElementById("editBookmarkPanelDoneButton").click();
|
||||
await hiddenPromise;
|
||||
}
|
||||
|
||||
async function openPopupAndSelectFolder(guid) {
|
||||
await clickBookmarkStar();
|
||||
|
||||
// Expand the folder tree.
|
||||
document.getElementById("editBMPanel_foldersExpander").click();
|
||||
document.getElementById("editBMPanel_folderTree").selectItems([guid]);
|
||||
|
||||
await hideBookmarksPanel();
|
||||
// Ensure the meta data has had chance to be written to disk.
|
||||
await PlacesTestUtils.promiseAsyncUpdates();
|
||||
}
|
||||
|
||||
async function assertRecentFolders(expectedGuids, msg) {
|
||||
await clickBookmarkStar();
|
||||
|
||||
let actualGuids = [];
|
||||
function getGuids() {
|
||||
const folderMenuPopup = document.getElementById("editBMPanel_folderMenuList").children[0];
|
||||
|
||||
let separatorFound = false;
|
||||
// The list of folders goes from editBMPanel_foldersSeparator to the end.
|
||||
for (let child of folderMenuPopup.children) {
|
||||
if (separatorFound) {
|
||||
actualGuids.push(child.folderGuid);
|
||||
} else if (child.id == "editBMPanel_foldersSeparator") {
|
||||
separatorFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await TestUtils.waitForCondition(() => {
|
||||
getGuids();
|
||||
return actualGuids.length == expectedGuids.length;
|
||||
}, msg);
|
||||
|
||||
Assert.deepEqual(actualGuids, expectedGuids, msg);
|
||||
|
||||
await hideBookmarksPanel();
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesUtils.metadata.delete(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY);
|
||||
|
||||
bookmarkPanel.setAttribute("animate", false);
|
||||
|
||||
let oldTimeout = StarUI._autoCloseTimeout;
|
||||
// Make the timeout something big, so it doesn't iteract badly with tests.
|
||||
StarUI._autoCloseTimeout = 6000000;
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
opening: "about:robots",
|
||||
waitForStateStop: true
|
||||
});
|
||||
|
||||
folders = await PlacesUtils.bookmarks.insertTree({
|
||||
guid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
children: [{
|
||||
title: "Bob",
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
}, {
|
||||
title: "Place",
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
}, {
|
||||
title: "Delight",
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
}, {
|
||||
title: "Surprise",
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
}, {
|
||||
title: "Treble Bob",
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
}, {
|
||||
title: "Principal",
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
}]
|
||||
});
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
StarUI._autoCloseTimeout = oldTimeout;
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
bookmarkPanel.removeAttribute("animate");
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesUtils.metadata.delete(PlacesUIUtils.LAST_USED_FOLDERS_META_KEY);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_remember_last_folder() {
|
||||
await assertRecentFolders([], "Should have no recent folders to start with.");
|
||||
|
||||
await openPopupAndSelectFolder(folders[0].guid);
|
||||
|
||||
await assertRecentFolders([folders[0].guid], "Should have one folder in the list.");
|
||||
});
|
||||
|
||||
add_task(async function test_forget_oldest_folder() {
|
||||
// Add some more folders.
|
||||
let expectedFolders = [folders[0].guid];
|
||||
for (let i = 1; i < folders.length; i++) {
|
||||
await assertRecentFolders(expectedFolders,
|
||||
"Should have only the expected folders in the list");
|
||||
|
||||
await openPopupAndSelectFolder(folders[i].guid);
|
||||
|
||||
expectedFolders.unshift(folders[i].guid);
|
||||
if (expectedFolders.length > 5) {
|
||||
expectedFolders.pop();
|
||||
}
|
||||
}
|
||||
|
||||
await assertRecentFolders(expectedFolders,
|
||||
"Should have expired the original folder");
|
||||
});
|
||||
|
||||
add_task(async function test_reorder_folders() {
|
||||
let expectedFolders = [
|
||||
folders[2].guid,
|
||||
folders[5].guid,
|
||||
folders[4].guid,
|
||||
folders[3].guid,
|
||||
folders[1].guid,
|
||||
];
|
||||
|
||||
// Take an old one and put it at the front.
|
||||
await openPopupAndSelectFolder(folders[2].guid);
|
||||
|
||||
await assertRecentFolders(expectedFolders,
|
||||
"Should have correctly re-ordered the list");
|
||||
});
|
|
@ -67,6 +67,7 @@
|
|||
return;
|
||||
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified");
|
||||
Services.obs.addObserver(this, "browser-search-service");
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
|
@ -114,6 +115,7 @@
|
|||
this._initialized = false;
|
||||
|
||||
Services.obs.removeObserver(this, "browser-search-engine-modified");
|
||||
Services.obs.removeObserver(this, "browser-search-service");
|
||||
}
|
||||
|
||||
// Make sure to break the cycle from _textbox to us. Otherwise we leak
|
||||
|
@ -183,7 +185,8 @@
|
|||
<parameter name="aTopic"/>
|
||||
<parameter name="aVerb"/>
|
||||
<body><![CDATA[
|
||||
if (aTopic == "browser-search-engine-modified") {
|
||||
if (aTopic == "browser-search-engine-modified" ||
|
||||
(aTopic == "browser-search-service" && aVerb == "init-complete")) {
|
||||
// Make sure the engine list is refetched next time it's needed
|
||||
this._engines = null;
|
||||
|
||||
|
@ -1306,6 +1309,7 @@
|
|||
// Add weak referenced observers to invalidate our cached list of engines.
|
||||
Services.prefs.addObserver("browser.search.hiddenOneOffs", this, true);
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified", true);
|
||||
Services.obs.addObserver(this, "browser-search-service", true);
|
||||
|
||||
// Rebuild the buttons when the theme changes. See bug 1357800 for
|
||||
// details. Summary: On Linux, switching between themes can cause a row
|
||||
|
|
|
@ -6,3 +6,7 @@ browser.jar:
|
|||
content/browser/search/search.xml (content/search.xml)
|
||||
content/browser/search/searchReset.xhtml (content/searchReset.xhtml)
|
||||
content/browser/search/searchReset.js (content/searchReset.js)
|
||||
|
||||
searchplugins/ (searchplugins/**)
|
||||
|
||||
% resource search-plugins %searchplugins/
|
||||
|
|
До Ширина: | Высота: | Размер: 1.4 KiB После Ширина: | Высота: | Размер: 1.4 KiB |
До Ширина: | Высота: | Размер: 1.4 KiB После Ширина: | Высота: | Размер: 1.4 KiB |
До Ширина: | Высота: | Размер: 884 B После Ширина: | Высота: | Размер: 884 B |
До Ширина: | Высота: | Размер: 1.7 KiB После Ширина: | Высота: | Размер: 1.7 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB После Ширина: | Высота: | Размер: 2.0 KiB |