зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
109ad47bbf
|
@ -1472,7 +1472,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
|
|||
{
|
||||
nsAutoString role;
|
||||
nsCoreUtils::XBLBindingRole(aContent, role);
|
||||
if (role.IsEmpty() || role.EqualsLiteral("none"))
|
||||
if (role.IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
RefPtr<Accessible> accessible;
|
||||
|
@ -1487,9 +1487,6 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
|
|||
} else if (role.EqualsLiteral("xul:link")) {
|
||||
accessible = new XULLinkAccessible(aContent, aDoc);
|
||||
|
||||
} else if(role.EqualsLiteral("xul:pane")) {
|
||||
accessible = new EnumRoleAccessible<roles::PANE>(aContent, aDoc);
|
||||
|
||||
} else if (role.EqualsLiteral("xul:panel")) {
|
||||
if (aContent->IsElement() &&
|
||||
aContent->AsElement()->AttrValueIs(kNameSpaceID_None,
|
||||
|
|
|
@ -381,7 +381,7 @@ var FeedHandler = {
|
|||
// http://foo.com/index.rdf -> feed://foo.com/index.rdf
|
||||
// other urls: prepend feed: scheme, e.g.
|
||||
// https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
|
||||
let feedURI = NetUtil.newURI(aSpec);
|
||||
let feedURI = Services.io.newURI(aSpec);
|
||||
if (feedURI.schemeIs("http")) {
|
||||
feedURI = feedURI.mutate()
|
||||
.setScheme("feed")
|
||||
|
|
|
@ -481,7 +481,7 @@ var PlacesCommandHook = {
|
|||
let parentGuid = parentId == PlacesUtils.bookmarksMenuFolderId ?
|
||||
PlacesUtils.bookmarks.menuGuid :
|
||||
await PlacesUtils.promiseItemGuid(parentId);
|
||||
let defaultInsertionPoint = new InsertionPoint({ parentId, parentGuid });
|
||||
let defaultInsertionPoint = new PlacesInsertionPoint({ parentId, parentGuid });
|
||||
PlacesUIUtils.showBookmarkDialog({ action: "add",
|
||||
type: "bookmark",
|
||||
uri: makeURI(url),
|
||||
|
@ -557,7 +557,7 @@ var PlacesCommandHook = {
|
|||
* A short description of the feed. Optional.
|
||||
*/
|
||||
async addLiveBookmark(url, feedTitle, feedSubtitle) {
|
||||
let toolbarIP = new InsertionPoint({
|
||||
let toolbarIP = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.toolbarFolderId,
|
||||
parentGuid: PlacesUtils.bookmarks.toolbarGuid
|
||||
});
|
||||
|
@ -993,7 +993,7 @@ var PlacesMenuDNDHandler = {
|
|||
* The DragOver event.
|
||||
*/
|
||||
onDragOver: function PMDH_onDragOver(event) {
|
||||
let ip = new InsertionPoint({
|
||||
let ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.bookmarksMenuFolderId,
|
||||
parentGuid: PlacesUtils.bookmarks.menuGuid
|
||||
});
|
||||
|
@ -1010,7 +1010,7 @@ var PlacesMenuDNDHandler = {
|
|||
*/
|
||||
onDrop: function PMDH_onDrop(event) {
|
||||
// Put the item at the end of bookmark menu.
|
||||
let ip = new InsertionPoint({
|
||||
let ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.bookmarksMenuFolderId,
|
||||
parentGuid: PlacesUtils.bookmarks.menuGuid
|
||||
});
|
||||
|
|
|
@ -34,6 +34,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
|
||||
NetUtil: "resource://gre/modules/NetUtil.jsm",
|
||||
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
|
||||
OpenInTabsUtils: "resource:///modules/OpenInTabsUtils.jsm",
|
||||
PageActions: "resource:///modules/PageActions.jsm",
|
||||
|
|
|
@ -16,6 +16,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
|
||||
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
|
||||
DevToolsShim: "chrome://devtools-shim/content/DevToolsShim.jsm",
|
||||
NetUtil: "resource://gre/modules/NetUtil.jsm",
|
||||
});
|
||||
|
||||
var gContextMenuContentData = null;
|
||||
|
|
|
@ -69,6 +69,72 @@ let whitelist = [
|
|||
intermittent: true,
|
||||
errorMessage: /Property contained reference to invalid variable.*color/i,
|
||||
isFromDevTools: true},
|
||||
|
||||
// These are CSS custom properties that we found a definition of but
|
||||
// no reference to.
|
||||
// Bug 1441837
|
||||
{propName: "--in-content-category-text-active",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441844
|
||||
{propName: "--chrome-nav-bar-separator-color",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441855
|
||||
{propName: "--chrome-nav-buttons-background",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441855
|
||||
{propName: "--chrome-nav-buttons-hover-background",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--muteButton-width",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--closedCaptionButton-width",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--fullscreenButton-width",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--durationSpan-width",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--durationSpan-width-long",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--positionDurationBox-width",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441857
|
||||
{propName: "--positionDurationBox-width-long",
|
||||
isFromDevTools: false},
|
||||
// Bug 1441860
|
||||
{propName: "--rule-flex-toggle-color",
|
||||
isFromDevTools: true},
|
||||
// Bug 1441929
|
||||
{propName: "--theme-search-overlays-semitransparent",
|
||||
isFromDevTools: true},
|
||||
// Bug 1441878
|
||||
{propName: "--theme-codemirror-gutter-background",
|
||||
isFromDevTools: true},
|
||||
// Bug 1441879
|
||||
{propName: "--arrow-width",
|
||||
isFromDevTools: true},
|
||||
// Bug 1442300
|
||||
{propName: "--in-content-category-background",
|
||||
isFromDevTools: false},
|
||||
// Bug 1442314
|
||||
{propName: "--separator-border-image",
|
||||
isFromDevTools: true},
|
||||
|
||||
// Used on Linux
|
||||
{propName: "--in-content-box-background-odd",
|
||||
platforms: ["win", "macosx"],
|
||||
isFromDevTools: false},
|
||||
|
||||
// These properties *are* actually referenced. Need to find why
|
||||
// their reference isn't getting counted.
|
||||
{propName: "--bezier-diagonal-color",
|
||||
isFromDevTools: true},
|
||||
{propName: "--bezier-grid-color",
|
||||
isFromDevTools: true},
|
||||
];
|
||||
|
||||
if (!Services.prefs.getBoolPref("full-screen-api.unprefix.enabled")) {
|
||||
|
@ -194,6 +260,7 @@ function messageIsCSSError(msg) {
|
|||
}
|
||||
|
||||
let imageURIsToReferencesMap = new Map();
|
||||
let customPropsToReferencesMap = new Map();
|
||||
|
||||
function processCSSRules(sheet) {
|
||||
for (let rule of sheet.cssRules) {
|
||||
|
@ -208,10 +275,11 @@ function processCSSRules(sheet) {
|
|||
// Note: CSSStyleRule.cssText always has double quotes around URLs even
|
||||
// when the original CSS file didn't.
|
||||
let urls = rule.cssText.match(/url\("[^"]*"\)/g);
|
||||
if (!urls)
|
||||
let props = rule.cssText.match(/(var\()?(--[\w\-]+)/g);
|
||||
if (!urls && !props)
|
||||
continue;
|
||||
|
||||
for (let url of urls) {
|
||||
for (let url of (urls || [])) {
|
||||
// Remove the url(" prefix and the ") suffix.
|
||||
url = url.replace(/url\("(.*)"\)/, "$1");
|
||||
if (url.startsWith("data:"))
|
||||
|
@ -229,6 +297,16 @@ function processCSSRules(sheet) {
|
|||
imageURIsToReferencesMap.get(url).add(baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
for (let prop of (props || [])) {
|
||||
if (prop.startsWith("var(")) {
|
||||
prop = prop.substring(4);
|
||||
let prevValue = customPropsToReferencesMap.get(prop) || 0;
|
||||
customPropsToReferencesMap.set(prop, prevValue + 1);
|
||||
} else if (!customPropsToReferencesMap.has(prop)) {
|
||||
customPropsToReferencesMap.set(prop, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,6 +432,26 @@ add_task(async function checkAllTheCSS() {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if all the properties that are defined are referenced.
|
||||
for (let [prop, refCount] of customPropsToReferencesMap) {
|
||||
if (!refCount) {
|
||||
let ignored = false;
|
||||
for (let item of whitelist) {
|
||||
if (item.propName == prop &&
|
||||
isDevtools == item.isFromDevTools) {
|
||||
item.used = true;
|
||||
if (!item.platforms || item.platforms.includes(AppConstants.platform)) {
|
||||
ignored = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ignored) {
|
||||
ok(false, "custom property `" + prop + "` is not referenced");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let messages = Services.console.getMessageArray();
|
||||
// Count errors (the test output will list actual issues for us, as well
|
||||
// as the ok(false) in messageIsCSSError.
|
||||
|
@ -362,8 +460,12 @@ add_task(async function checkAllTheCSS() {
|
|||
|
||||
// Confirm that all whitelist rules have been used.
|
||||
for (let item of whitelist) {
|
||||
if (!item.used && isDevtools == item.isFromDevTools && !item.intermittent) {
|
||||
if (!item.used &&
|
||||
(!item.platforms || item.platforms.includes(AppConstants.platform)) &&
|
||||
isDevtools == item.isFromDevTools &&
|
||||
!item.intermittent) {
|
||||
ok(false, "Unused whitelist item. " +
|
||||
(item.propName ? " propName: " + item.propName : "") +
|
||||
(item.sourceName ? " sourceName: " + item.sourceName : "") +
|
||||
(item.errorMessage ? " errorMessage: " + item.errorMessage : ""));
|
||||
}
|
||||
|
@ -388,4 +490,5 @@ add_task(async function checkAllTheCSS() {
|
|||
hiddenFrame.destroy();
|
||||
hiddenFrame = null;
|
||||
imageURIsToReferencesMap = null;
|
||||
customPropsToReferencesMap = null;
|
||||
});
|
||||
|
|
|
@ -256,61 +256,6 @@ var PlacesUIUtils = {
|
|||
return bundle.GetStringFromName(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a Places Transaction for the drop or paste of a blob of data
|
||||
* into a container.
|
||||
*
|
||||
* @param aData
|
||||
* The unwrapped data blob of dropped or pasted data.
|
||||
* @param aNewParentGuid
|
||||
* GUID of the container the data was dropped or pasted into.
|
||||
* @param aIndex
|
||||
* The index within the container the item was dropped or pasted at.
|
||||
* @param aCopy
|
||||
* The drag action was copy, so don't move folders or links.
|
||||
*
|
||||
* @return a Places Transaction that can be transacted for performing the
|
||||
* move/insert command.
|
||||
*/
|
||||
getTransactionForData(aData, aNewParentGuid, aIndex, aCopy) {
|
||||
if (!this.SUPPORTED_FLAVORS.includes(aData.type))
|
||||
throw new Error(`Unsupported '${aData.type}' data type`);
|
||||
|
||||
if ("itemGuid" in aData && "instanceId" in aData &&
|
||||
aData.instanceId == PlacesUtils.instanceId) {
|
||||
if (!this.PLACES_FLAVORS.includes(aData.type))
|
||||
throw new Error(`itemGuid unexpectedly set on ${aData.type} data`);
|
||||
|
||||
let info = { guid: aData.itemGuid,
|
||||
newParentGuid: aNewParentGuid,
|
||||
newIndex: aIndex };
|
||||
if (aCopy) {
|
||||
info.excludingAnnotation = "Places/SmartBookmark";
|
||||
return PlacesTransactions.Copy(info);
|
||||
}
|
||||
return PlacesTransactions.Move(info);
|
||||
}
|
||||
|
||||
// Since it's cheap and harmless, we allow the paste of separators and
|
||||
// bookmarks from builds that use legacy transactions (i.e. when itemGuid
|
||||
// was not set on PLACES_FLAVORS data). Containers are a different story,
|
||||
// and thus disallowed.
|
||||
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER)
|
||||
throw new Error("Can't copy a container from a legacy-transactions build");
|
||||
|
||||
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
|
||||
return PlacesTransactions.NewSeparator({ parentGuid: aNewParentGuid,
|
||||
index: aIndex });
|
||||
}
|
||||
|
||||
let title = aData.type != PlacesUtils.TYPE_UNICODE ? aData.title
|
||||
: aData.uri;
|
||||
return PlacesTransactions.NewBookmark({ url: Services.io.newURI(aData.uri),
|
||||
title,
|
||||
parentGuid: aNewParentGuid,
|
||||
index: aIndex });
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the bookmark dialog corresponding to the specified info.
|
||||
*
|
||||
|
@ -404,6 +349,77 @@ var PlacesUIUtils = {
|
|||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the active PlacesController for a given command.
|
||||
*
|
||||
* @param win The window containing the affected view
|
||||
* @param command The command
|
||||
* @return a PlacesController
|
||||
*/
|
||||
getControllerForCommand(win, command) {
|
||||
// A context menu may be built for non-focusable views. Thus, we first try
|
||||
// to look for a view associated with document.popupNode
|
||||
let popupNode;
|
||||
try {
|
||||
popupNode = win.document.popupNode;
|
||||
} catch (e) {
|
||||
// The document went away (bug 797307).
|
||||
return null;
|
||||
}
|
||||
if (popupNode) {
|
||||
let view = this.getViewForNode(popupNode);
|
||||
if (view && view._contextMenuShown)
|
||||
return view.controllers.getControllerForCommand(command);
|
||||
}
|
||||
|
||||
// When we're not building a context menu, only focusable views
|
||||
// are possible. Thus, we can safely use the command dispatcher.
|
||||
let controller = win.top.document.commandDispatcher
|
||||
.getControllerForCommand(command);
|
||||
return controller || null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update all the Places commands for the given window.
|
||||
*
|
||||
* @param win The window to update.
|
||||
*/
|
||||
updateCommands(win) {
|
||||
// Get the controller for one of the places commands.
|
||||
let controller = this.getControllerForCommand(win, "placesCmd_open");
|
||||
for (let command of [
|
||||
"placesCmd_open",
|
||||
"placesCmd_open:window",
|
||||
"placesCmd_open:privatewindow",
|
||||
"placesCmd_open:tab",
|
||||
"placesCmd_new:folder",
|
||||
"placesCmd_new:bookmark",
|
||||
"placesCmd_new:separator",
|
||||
"placesCmd_show:info",
|
||||
"placesCmd_reload",
|
||||
"placesCmd_sortBy:name",
|
||||
"placesCmd_cut",
|
||||
"placesCmd_copy",
|
||||
"placesCmd_paste",
|
||||
"placesCmd_delete",
|
||||
]) {
|
||||
win.goSetCommandEnabled(command,
|
||||
controller && controller.isCommandEnabled(command));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the given command on the currently active controller.
|
||||
*
|
||||
* @param win The window containing the affected view
|
||||
* @param command The command to execute
|
||||
*/
|
||||
doCommand(win, command) {
|
||||
let controller = this.getControllerForCommand(win, command);
|
||||
if (controller && controller.isCommandEnabled(command))
|
||||
controller.doCommand(command);
|
||||
},
|
||||
|
||||
/**
|
||||
* By calling this before visiting an URL, the visit will be associated to a
|
||||
* TRANSITION_TYPED transition (if there is no a referrer).
|
||||
|
@ -1176,19 +1192,135 @@ var PlacesUIUtils = {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a Places Transaction for the drop or paste of a blob of data
|
||||
* into a container.
|
||||
*
|
||||
* @param aData
|
||||
* The unwrapped data blob of dropped or pasted data.
|
||||
* @param aNewParentGuid
|
||||
* GUID of the container the data was dropped or pasted into.
|
||||
* @param aIndex
|
||||
* The index within the container the item was dropped or pasted at.
|
||||
* @param aCopy
|
||||
* The drag action was copy, so don't move folders or links.
|
||||
*
|
||||
* @return a Places Transaction that can be transacted for performing the
|
||||
* move/insert command.
|
||||
*/
|
||||
getTransactionForData(aData, aNewParentGuid, aIndex, aCopy) {
|
||||
if (!this.SUPPORTED_FLAVORS.includes(aData.type))
|
||||
throw new Error(`Unsupported '${aData.type}' data type`);
|
||||
|
||||
if ("itemGuid" in aData && "instanceId" in aData &&
|
||||
aData.instanceId == PlacesUtils.instanceId) {
|
||||
if (!this.PLACES_FLAVORS.includes(aData.type))
|
||||
throw new Error(`itemGuid unexpectedly set on ${aData.type} data`);
|
||||
|
||||
let info = { guid: aData.itemGuid,
|
||||
newParentGuid: aNewParentGuid,
|
||||
newIndex: aIndex };
|
||||
if (aCopy) {
|
||||
info.excludingAnnotation = "Places/SmartBookmark";
|
||||
return PlacesTransactions.Copy(info);
|
||||
}
|
||||
return PlacesTransactions.Move(info);
|
||||
}
|
||||
|
||||
// Since it's cheap and harmless, we allow the paste of separators and
|
||||
// bookmarks from builds that use legacy transactions (i.e. when itemGuid
|
||||
// was not set on PLACES_FLAVORS data). Containers are a different story,
|
||||
// and thus disallowed.
|
||||
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER)
|
||||
throw new Error("Can't copy a container from a legacy-transactions build");
|
||||
|
||||
if (aData.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
|
||||
return PlacesTransactions.NewSeparator({ parentGuid: aNewParentGuid,
|
||||
index: aIndex });
|
||||
}
|
||||
|
||||
let title = aData.type != PlacesUtils.TYPE_UNICODE ? aData.title
|
||||
: aData.uri;
|
||||
return PlacesTransactions.NewBookmark({ url: Services.io.newURI(aData.uri),
|
||||
title,
|
||||
parentGuid: aNewParentGuid,
|
||||
index: aIndex });
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes a set of transfer items that have been dropped or pasted.
|
||||
* Batching will be applied where necessary.
|
||||
*
|
||||
* @param {Array} items A list of unwrapped nodes to process.
|
||||
* @param {Object} insertionPoint The requested point for insertion.
|
||||
* @param {Boolean} doCopy Set to true to copy the items, false will move them
|
||||
* if possible.
|
||||
* @paramt {Object} view The view that should be used for batching.
|
||||
* @return {Array} Returns an empty array when the insertion point is a tag, else
|
||||
* returns an array of copied or moved guids.
|
||||
*/
|
||||
async handleTransferItems(items, insertionPoint, doCopy, view) {
|
||||
let transactions;
|
||||
let itemsCount;
|
||||
if (insertionPoint.isTag) {
|
||||
let urls = items.filter(item => "uri" in item).map(item => item.uri);
|
||||
itemsCount = urls.length;
|
||||
transactions = [PlacesTransactions.Tag({ urls, tag: insertionPoint.tagName })];
|
||||
} else {
|
||||
let insertionIndex = await insertionPoint.getIndex();
|
||||
itemsCount = items.length;
|
||||
transactions = await getTransactionsForTransferItems(
|
||||
items, insertionIndex, insertionPoint.guid, doCopy);
|
||||
}
|
||||
|
||||
// Check if we actually have something to add, if we don't it probably wasn't
|
||||
// valid, or it was moving to the same location, so just ignore it.
|
||||
if (!transactions.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let guidsToSelect = [];
|
||||
let resultForBatching = getResultForBatching(view);
|
||||
|
||||
// If we're inserting into a tag, we don't get the guid, so we'll just
|
||||
// pass the transactions direct to the batch function.
|
||||
let batchingItem = transactions;
|
||||
if (!insertionPoint.isTag) {
|
||||
// If we're not a tag, then we need to get the ids of the items to select.
|
||||
batchingItem = async () => {
|
||||
for (let transaction of transactions) {
|
||||
let guid = await transaction.transact();
|
||||
if (guid) {
|
||||
guidsToSelect.push(guid);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await this.batchUpdatesForNode(resultForBatching, itemsCount, async () => {
|
||||
await PlacesTransactions.batch(batchingItem);
|
||||
});
|
||||
|
||||
return guidsToSelect;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
PlacesUIUtils.PLACES_FLAVORS = [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE];
|
||||
|
||||
PlacesUIUtils.URI_FLAVORS = [PlacesUtils.TYPE_X_MOZ_URL,
|
||||
TAB_DROP_TYPE,
|
||||
PlacesUtils.TYPE_UNICODE],
|
||||
|
||||
PlacesUIUtils.SUPPORTED_FLAVORS = [...PlacesUIUtils.PLACES_FLAVORS,
|
||||
...PlacesUIUtils.URI_FLAVORS];
|
||||
// These are lazy getters to avoid importing PlacesUtils immediately.
|
||||
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "PLACES_FLAVORS", () => {
|
||||
return [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
|
||||
PlacesUtils.TYPE_X_MOZ_PLACE];
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "URI_FLAVORS", () => {
|
||||
return [PlacesUtils.TYPE_X_MOZ_URL,
|
||||
TAB_DROP_TYPE,
|
||||
PlacesUtils.TYPE_UNICODE];
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "SUPPORTED_FLAVORS", () => {
|
||||
return [...PlacesUIUtils.PLACES_FLAVORS,
|
||||
...PlacesUIUtils.URI_FLAVORS];
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ellipsis", function() {
|
||||
return Services.prefs.getComplexValue("intl.ellipsis",
|
||||
|
@ -1201,3 +1333,117 @@ XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "loadBookmarksInTabs",
|
|||
PREF_LOAD_BOOKMARKS_IN_TABS, false);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "openInTabClosesMenu",
|
||||
"browser.bookmarks.openInTabClosesMenu", false);
|
||||
|
||||
/**
|
||||
* Determines if an unwrapped node can be moved.
|
||||
*
|
||||
* @param unwrappedNode
|
||||
* A node unwrapped by PlacesUtils.unwrapNodes().
|
||||
* @return True if the node can be moved, false otherwise.
|
||||
*/
|
||||
function canMoveUnwrappedNode(unwrappedNode) {
|
||||
if ((unwrappedNode.concreteGuid && PlacesUtils.isRootItem(unwrappedNode.concreteGuid)) ||
|
||||
unwrappedNode.id <= 0 || PlacesUtils.isRootItem(unwrappedNode.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let parentGuid = unwrappedNode.parentGuid;
|
||||
// If there's no parent Guid, this was likely a virtual query that returns
|
||||
// bookmarks, such as a tags query.
|
||||
if (!parentGuid ||
|
||||
parentGuid == PlacesUtils.bookmarks.rootGuid) {
|
||||
return false;
|
||||
}
|
||||
// leftPaneFolderId and allBookmarksFolderId are lazy getters running
|
||||
// at least a synchronous DB query. Therefore we don't want to invoke
|
||||
// them first, especially because isCommandEnabled may be called way
|
||||
// before the left pane folder is even necessary.
|
||||
if (typeof Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId").get != "function" &&
|
||||
(unwrappedNode.parent == PlacesUIUtils.leftPaneFolderId)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets the most appropriate item for using for batching. In the case of multiple
|
||||
* views being related, the method returns the most expensive result to batch.
|
||||
* For example, if it detects the left-hand library pane, then it will look for
|
||||
* and return the reference to the right-hand pane.
|
||||
*
|
||||
* @param {Object} viewOrElement The item to check.
|
||||
* @return {Object} Will return the best result node to batch, or null
|
||||
* if one could not be found.
|
||||
*/
|
||||
function getResultForBatching(viewOrElement) {
|
||||
if (viewOrElement && viewOrElement instanceof Ci.nsIDOMElement &&
|
||||
viewOrElement.id === "placesList") {
|
||||
// Note: fall back to the existing item if we can't find the right-hane pane.
|
||||
viewOrElement = viewOrElement.ownerDocument.getElementById("placeContent") || viewOrElement;
|
||||
}
|
||||
|
||||
if (viewOrElement && viewOrElement.result) {
|
||||
return viewOrElement.result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a set of transfer items and returns transactions to insert or
|
||||
* move them.
|
||||
*
|
||||
* @param {Array} items A list of unwrapped nodes to get transactions for.
|
||||
* @param {Integer} insertionIndex The requested index for insertion.
|
||||
* @param {String} insertionParentGuid The guid of the parent folder to insert
|
||||
* or move the items to.
|
||||
* @param {Boolean} doCopy Set to true to copy the items, false will move them
|
||||
* if possible.
|
||||
* @return {Array} Returns an array of created PlacesTransactions.
|
||||
*/
|
||||
async function getTransactionsForTransferItems(items, insertionIndex,
|
||||
insertionParentGuid, doCopy) {
|
||||
let transactions = [];
|
||||
let index = insertionIndex;
|
||||
|
||||
for (let item of items) {
|
||||
if (index != -1 && item.itemGuid) {
|
||||
// Note: we use the parent from the existing bookmark as the sidebar
|
||||
// gives us an unwrapped.parent that is actually a query and not the real
|
||||
// parent.
|
||||
let existingBookmark = await PlacesUtils.bookmarks.fetch(item.itemGuid);
|
||||
|
||||
// If we're dropping on the same folder, then we may need to adjust
|
||||
// the index to insert at the correct place.
|
||||
if (existingBookmark && insertionParentGuid == existingBookmark.parentGuid) {
|
||||
if (index > existingBookmark.index) {
|
||||
// If we're dragging down, we need to go one lower to insert at
|
||||
// the real point as moving the element changes the index of
|
||||
// everything below by 1.
|
||||
index--;
|
||||
} else if (index == existingBookmark.index) {
|
||||
// This isn't moving so we skip it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not a copy, check for safety that we can move the
|
||||
// source, otherwise report an error and fallback to a copy.
|
||||
if (!doCopy && !canMoveUnwrappedNode(item)) {
|
||||
Cu.reportError("Tried to move an unmovable Places " +
|
||||
"node, reverting to a copy operation.");
|
||||
doCopy = true;
|
||||
}
|
||||
transactions.push(
|
||||
PlacesUIUtils.getTransactionForData(item,
|
||||
insertionParentGuid,
|
||||
index,
|
||||
doCopy));
|
||||
|
||||
if (index != -1 && item.itemGuid) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ var BookmarkPropertiesPanel = {
|
|||
this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint;
|
||||
} else {
|
||||
this._defaultInsertionPoint =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.bookmarksMenuFolderId,
|
||||
parentGuid: PlacesUtils.bookmarks.menuGuid
|
||||
});
|
||||
|
|
|
@ -217,10 +217,10 @@ PlacesViewBase.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container, this))
|
||||
if (this.controller.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
return new InsertionPoint({
|
||||
return new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(container),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(container),
|
||||
index, orientation, tagName
|
||||
|
@ -1519,7 +1519,7 @@ PlacesToolbar.prototype = {
|
|||
: (aEvent.clientX < eltRect.left + threshold)) {
|
||||
// Drop before this folder.
|
||||
dropPoint.ip =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
|
||||
index: eltIndex,
|
||||
|
@ -1532,7 +1532,7 @@ PlacesToolbar.prototype = {
|
|||
let tagName = PlacesUtils.nodeIsTagQuery(elt._placesNode) ?
|
||||
elt._placesNode.title : null;
|
||||
dropPoint.ip =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(elt._placesNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(elt._placesNode),
|
||||
tagName
|
||||
|
@ -1546,7 +1546,7 @@ PlacesToolbar.prototype = {
|
|||
-1 : eltIndex + 1;
|
||||
|
||||
dropPoint.ip =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
|
||||
index: beforeIndex,
|
||||
|
@ -1562,7 +1562,7 @@ PlacesToolbar.prototype = {
|
|||
: (aEvent.clientX < eltRect.left + threshold)) {
|
||||
// Drop before this bookmark.
|
||||
dropPoint.ip =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
|
||||
index: eltIndex,
|
||||
|
@ -1575,7 +1575,7 @@ PlacesToolbar.prototype = {
|
|||
eltIndex == this._rootElt.childNodes.length - 1 ?
|
||||
-1 : eltIndex + 1;
|
||||
dropPoint.ip =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
|
||||
index: beforeIndex,
|
||||
|
@ -1588,7 +1588,7 @@ PlacesToolbar.prototype = {
|
|||
// We are most likely dragging on the empty area of the
|
||||
// toolbar, we should drop after the last node.
|
||||
dropPoint.ip =
|
||||
new InsertionPoint({
|
||||
new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(this._resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(this._resultNode),
|
||||
orientation: Ci.nsITreeView.DROP_BEFORE
|
||||
|
|
|
@ -3,13 +3,6 @@
|
|||
* 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/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "ForgetAboutSite",
|
||||
"resource://gre/modules/ForgetAboutSite.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
/**
|
||||
* Represents an insertion point within a container where we can insert
|
||||
* items.
|
||||
|
@ -30,11 +23,11 @@ ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
|||
* - dropNearNode
|
||||
* When defined index will be calculated based on this node
|
||||
*/
|
||||
function InsertionPoint({ parentId, parentGuid,
|
||||
index = PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
orientation = Ci.nsITreeView.DROP_ON,
|
||||
tagName = null,
|
||||
dropNearNode = null }) {
|
||||
function PlacesInsertionPoint({ parentId, parentGuid,
|
||||
index = PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
orientation = Ci.nsITreeView.DROP_ON,
|
||||
tagName = null,
|
||||
dropNearNode = null }) {
|
||||
this.itemId = parentId;
|
||||
this.guid = parentGuid;
|
||||
this._index = index;
|
||||
|
@ -43,7 +36,7 @@ function InsertionPoint({ parentId, parentGuid,
|
|||
this.dropNearNode = dropNearNode;
|
||||
}
|
||||
|
||||
InsertionPoint.prototype = {
|
||||
PlacesInsertionPoint.prototype = {
|
||||
set index(val) {
|
||||
return this._index = val;
|
||||
},
|
||||
|
@ -230,7 +223,7 @@ PlacesController.prototype = {
|
|||
var queries = this._view.selectedNode.getQueries();
|
||||
host = queries[0].domain;
|
||||
} else
|
||||
host = NetUtil.newURI(this._view.selectedNode.uri).host;
|
||||
host = Services.io.newURI(this._view.selectedNode.uri).host;
|
||||
ForgetAboutSite.removeDataFromDomain(host)
|
||||
.catch(Cu.reportError);
|
||||
break;
|
||||
|
@ -275,7 +268,7 @@ PlacesController.prototype = {
|
|||
"keyword",
|
||||
"location",
|
||||
"loadInSidebar" ],
|
||||
uri: NetUtil.newURI(node.uri),
|
||||
uri: Services.io.newURI(node.uri),
|
||||
title: node.title
|
||||
}, window.top);
|
||||
break;
|
||||
|
@ -428,7 +421,7 @@ PlacesController.prototype = {
|
|||
break;
|
||||
case Ci.nsINavHistoryResultNode.RESULT_TYPE_URI:
|
||||
nodeData.link = true;
|
||||
uri = NetUtil.newURI(node.uri);
|
||||
uri = Services.io.newURI(node.uri);
|
||||
if (PlacesUtils.nodeIsBookmark(node)) {
|
||||
nodeData.bookmark = true;
|
||||
var parentNode = node.parent;
|
||||
|
@ -1213,7 +1206,7 @@ PlacesController.prototype = {
|
|||
}
|
||||
|
||||
let doCopy = action == "copy";
|
||||
let itemsToSelect = await handleTransferItems(items, ip, doCopy, this._view);
|
||||
let itemsToSelect = await PlacesUIUtils.handleTransferItems(items, ip, doCopy, this._view);
|
||||
|
||||
// Cut/past operations are not repeatable, so clear the clipboard.
|
||||
if (action == "cut") {
|
||||
|
@ -1256,7 +1249,41 @@ PlacesController.prototype = {
|
|||
*/
|
||||
getCachedLivemarkInfo: function PC_getCachedLivemarkInfo(aNode) {
|
||||
return this._cachedLivemarkInfoObjects.get(aNode, null);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if we can insert into a container.
|
||||
* @param container
|
||||
* The container were we are want to drop
|
||||
*/
|
||||
disallowInsertion(container) {
|
||||
NS_ASSERT(container, "empty container");
|
||||
// Allow dropping into Tag containers and editable folders.
|
||||
return !PlacesUtils.nodeIsTagQuery(container) &&
|
||||
(!PlacesUtils.nodeIsFolder(container) ||
|
||||
PlacesUIUtils.isFolderReadOnly(container, this._view));
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if a node can be moved.
|
||||
*
|
||||
* @param aNode
|
||||
* A nsINavHistoryResultNode node.
|
||||
* @return True if the node can be moved, false otherwise.
|
||||
*/
|
||||
canMoveNode(node) {
|
||||
// Only bookmark items are movable.
|
||||
if (node.itemId == -1)
|
||||
return false;
|
||||
|
||||
// Once tags and bookmarked are divorced, the tag-query check should be
|
||||
// removed.
|
||||
let parentNode = node.parent;
|
||||
return parentNode != null &&
|
||||
PlacesUtils.nodeIsFolder(parentNode) &&
|
||||
!PlacesUIUtils.isFolderReadOnly(parentNode, this._view) &&
|
||||
!PlacesUtils.nodeIsTagQuery(parentNode);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1378,62 +1405,6 @@ var PlacesControllerDragHelper = {
|
|||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if an unwrapped node can be moved.
|
||||
*
|
||||
* @param unwrappedNode
|
||||
* A node unwrapped by PlacesUtils.unwrapNodes().
|
||||
* @return True if the node can be moved, false otherwise.
|
||||
*/
|
||||
canMoveUnwrappedNode(unwrappedNode) {
|
||||
if ((unwrappedNode.concreteGuid && PlacesUtils.isRootItem(unwrappedNode.concreteGuid)) ||
|
||||
unwrappedNode.id <= 0 || PlacesUtils.isRootItem(unwrappedNode.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let parentGuid = unwrappedNode.parentGuid;
|
||||
// If there's no parent Guid, this was likely a virtual query that returns
|
||||
// bookmarks, such as a tags query.
|
||||
if (!parentGuid ||
|
||||
parentGuid == PlacesUtils.bookmarks.rootGuid) {
|
||||
return false;
|
||||
}
|
||||
// leftPaneFolderId and allBookmarksFolderId are lazy getters running
|
||||
// at least a synchronous DB query. Therefore we don't want to invoke
|
||||
// them first, especially because isCommandEnabled may be called way
|
||||
// before the left pane folder is even necessary.
|
||||
if (typeof Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId").get != "function" &&
|
||||
(unwrappedNode.parent == PlacesUIUtils.leftPaneFolderId)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if a node can be moved.
|
||||
*
|
||||
* @param aNode
|
||||
* A nsINavHistoryResultNode node.
|
||||
* @param aView
|
||||
* The view originating the request
|
||||
* @param [optional] aDOMNode
|
||||
* A XUL DOM node.
|
||||
* @return True if the node can be moved, false otherwise.
|
||||
*/
|
||||
canMoveNode(aNode, aView) {
|
||||
// Only bookmark items are movable.
|
||||
if (aNode.itemId == -1)
|
||||
return false;
|
||||
|
||||
// Once tags and bookmarked are divorced, the tag-query check should be
|
||||
// removed.
|
||||
let parentNode = aNode.parent;
|
||||
return parentNode != null &&
|
||||
PlacesUtils.nodeIsFolder(parentNode) &&
|
||||
!PlacesUIUtils.isFolderReadOnly(parentNode, aView) &&
|
||||
!PlacesUtils.nodeIsTagQuery(parentNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the drop of one or more items onto a view.
|
||||
*
|
||||
|
@ -1486,221 +1457,10 @@ var PlacesControllerDragHelper = {
|
|||
}
|
||||
}
|
||||
|
||||
await handleTransferItems(nodes, insertionPoint, doCopy, view);
|
||||
await PlacesUIUtils.handleTransferItems(nodes, insertionPoint, doCopy, view);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if we can insert into a container.
|
||||
* @param aContainer
|
||||
* The container were we are want to drop
|
||||
* @param aView
|
||||
* The view generating the request
|
||||
*/
|
||||
disallowInsertion(aContainer, aView) {
|
||||
NS_ASSERT(aContainer, "empty container");
|
||||
// Allow dropping into Tag containers and editable folders.
|
||||
return !PlacesUtils.nodeIsTagQuery(aContainer) &&
|
||||
(!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||
PlacesUIUtils.isFolderReadOnly(aContainer, aView));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(PlacesControllerDragHelper, "dragService",
|
||||
"@mozilla.org/widget/dragservice;1",
|
||||
"nsIDragService");
|
||||
|
||||
function goUpdatePlacesCommands() {
|
||||
// Get the controller for one of the places commands.
|
||||
var placesController = doGetPlacesControllerForCommand("placesCmd_open");
|
||||
function updatePlacesCommand(aCommand) {
|
||||
goSetCommandEnabled(aCommand, placesController &&
|
||||
placesController.isCommandEnabled(aCommand));
|
||||
}
|
||||
|
||||
updatePlacesCommand("placesCmd_open");
|
||||
updatePlacesCommand("placesCmd_open:window");
|
||||
updatePlacesCommand("placesCmd_open:privatewindow");
|
||||
updatePlacesCommand("placesCmd_open:tab");
|
||||
updatePlacesCommand("placesCmd_new:folder");
|
||||
updatePlacesCommand("placesCmd_new:bookmark");
|
||||
updatePlacesCommand("placesCmd_new:separator");
|
||||
updatePlacesCommand("placesCmd_show:info");
|
||||
updatePlacesCommand("placesCmd_reload");
|
||||
updatePlacesCommand("placesCmd_sortBy:name");
|
||||
updatePlacesCommand("placesCmd_cut");
|
||||
updatePlacesCommand("placesCmd_copy");
|
||||
updatePlacesCommand("placesCmd_paste");
|
||||
updatePlacesCommand("placesCmd_delete");
|
||||
}
|
||||
|
||||
function doGetPlacesControllerForCommand(aCommand) {
|
||||
// A context menu may be built for non-focusable views. Thus, we first try
|
||||
// to look for a view associated with document.popupNode
|
||||
let popupNode;
|
||||
try {
|
||||
popupNode = document.popupNode;
|
||||
} catch (e) {
|
||||
// The document went away (bug 797307).
|
||||
return null;
|
||||
}
|
||||
if (popupNode) {
|
||||
let view = PlacesUIUtils.getViewForNode(popupNode);
|
||||
if (view && view._contextMenuShown)
|
||||
return view.controllers.getControllerForCommand(aCommand);
|
||||
}
|
||||
|
||||
// When we're not building a context menu, only focusable views
|
||||
// are possible. Thus, we can safely use the command dispatcher.
|
||||
let controller = top.document.commandDispatcher
|
||||
.getControllerForCommand(aCommand);
|
||||
if (controller)
|
||||
return controller;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function goDoPlacesCommand(aCommand) {
|
||||
let controller = doGetPlacesControllerForCommand(aCommand);
|
||||
if (controller && controller.isCommandEnabled(aCommand))
|
||||
controller.doCommand(aCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets the most appropriate item for using for batching. In the case of multiple
|
||||
* views being related, the method returns the most expensive result to batch.
|
||||
* For example, if it detects the left-hand library pane, then it will look for
|
||||
* and return the reference to the right-hand pane.
|
||||
*
|
||||
* @param {Object} viewOrElement The item to check.
|
||||
* @return {Object} Will return the best result node to batch, or null
|
||||
* if one could not be found.
|
||||
*/
|
||||
function getResultForBatching(viewOrElement) {
|
||||
if (viewOrElement && viewOrElement instanceof Ci.nsIDOMElement &&
|
||||
viewOrElement.id === "placesList") {
|
||||
// Note: fall back to the existing item if we can't find the right-hane pane.
|
||||
viewOrElement = document.getElementById("placeContent") || viewOrElement;
|
||||
}
|
||||
|
||||
if (viewOrElement && viewOrElement.result) {
|
||||
return viewOrElement.result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a set of transfer items that have been dropped or pasted.
|
||||
* Batching will be applied where necessary.
|
||||
*
|
||||
* @param {Array} items A list of unwrapped nodes to process.
|
||||
* @param {Object} insertionPoint The requested point for insertion.
|
||||
* @param {Boolean} doCopy Set to true to copy the items, false will move them
|
||||
* if possible.
|
||||
* @return {Array} Returns an empty array when the insertion point is a tag, else
|
||||
* returns an array of copied or moved guids.
|
||||
*/
|
||||
async function handleTransferItems(items, insertionPoint, doCopy, view) {
|
||||
let transactions;
|
||||
let itemsCount;
|
||||
if (insertionPoint.isTag) {
|
||||
let urls = items.filter(item => "uri" in item).map(item => item.uri);
|
||||
itemsCount = urls.length;
|
||||
transactions = [PlacesTransactions.Tag({ urls, tag: insertionPoint.tagName })];
|
||||
} else {
|
||||
let insertionIndex = await insertionPoint.getIndex();
|
||||
itemsCount = items.length;
|
||||
transactions = await getTransactionsForTransferItems(
|
||||
items, insertionIndex, insertionPoint.guid, doCopy);
|
||||
}
|
||||
|
||||
// Check if we actually have something to add, if we don't it probably wasn't
|
||||
// valid, or it was moving to the same location, so just ignore it.
|
||||
if (!transactions.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let guidsToSelect = [];
|
||||
let resultForBatching = getResultForBatching(view);
|
||||
|
||||
// If we're inserting into a tag, we don't get the guid, so we'll just
|
||||
// pass the transactions direct to the batch function.
|
||||
let batchingItem = transactions;
|
||||
if (!insertionPoint.isTag) {
|
||||
// If we're not a tag, then we need to get the ids of the items to select.
|
||||
batchingItem = async () => {
|
||||
for (let transaction of transactions) {
|
||||
let guid = await transaction.transact();
|
||||
if (guid) {
|
||||
guidsToSelect.push(guid);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await PlacesUIUtils.batchUpdatesForNode(resultForBatching, itemsCount, async () => {
|
||||
await PlacesTransactions.batch(batchingItem);
|
||||
});
|
||||
|
||||
return guidsToSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a set of transfer items and returns transactions to insert or
|
||||
* move them.
|
||||
*
|
||||
* @param {Array} items A list of unwrapped nodes to get transactions for.
|
||||
* @param {Integer} insertionIndex The requested index for insertion.
|
||||
* @param {String} insertionParentGuid The guid of the parent folder to insert
|
||||
* or move the items to.
|
||||
* @param {Boolean} doCopy Set to true to copy the items, false will move them
|
||||
* if possible.
|
||||
* @return {Array} Returns an array of created PlacesTransactions.
|
||||
*/
|
||||
async function getTransactionsForTransferItems(items, insertionIndex,
|
||||
insertionParentGuid, doCopy) {
|
||||
let transactions = [];
|
||||
let index = insertionIndex;
|
||||
|
||||
for (let item of items) {
|
||||
if (index != -1 && item.itemGuid) {
|
||||
// Note: we use the parent from the existing bookmark as the sidebar
|
||||
// gives us an unwrapped.parent that is actually a query and not the real
|
||||
// parent.
|
||||
let existingBookmark = await PlacesUtils.bookmarks.fetch(item.itemGuid);
|
||||
|
||||
// If we're dropping on the same folder, then we may need to adjust
|
||||
// the index to insert at the correct place.
|
||||
if (existingBookmark && insertionParentGuid == existingBookmark.parentGuid) {
|
||||
if (index > existingBookmark.index) {
|
||||
// If we're dragging down, we need to go one lower to insert at
|
||||
// the real point as moving the element changes the index of
|
||||
// everything below by 1.
|
||||
index--;
|
||||
} else if (index == existingBookmark.index) {
|
||||
// This isn't moving so we skip it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is not a copy, check for safety that we can move the
|
||||
// source, otherwise report an error and fallback to a copy.
|
||||
if (!doCopy && !PlacesControllerDragHelper.canMoveUnwrappedNode(item)) {
|
||||
Cu.reportError("Tried to move an unmovable Places " +
|
||||
"node, reverting to a copy operation.");
|
||||
doCopy = true;
|
||||
}
|
||||
transactions.push(
|
||||
PlacesUIUtils.getTransactionForData(item,
|
||||
insertionParentGuid,
|
||||
index,
|
||||
doCopy));
|
||||
|
||||
if (index != -1 && item.itemGuid) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ var gEditItemOverlay = {
|
|||
// so we'll need to fetch it later.
|
||||
}
|
||||
let isURI = node && PlacesUtils.nodeIsURI(node);
|
||||
let uri = isURI ? NetUtil.newURI(node.uri) : null;
|
||||
let uri = isURI ? Services.io.newURI(node.uri) : null;
|
||||
let title = node ? node.title : null;
|
||||
let isBookmark = isItem && isURI;
|
||||
let bulkTagging = !node;
|
||||
|
@ -932,7 +932,7 @@ var gEditItemOverlay = {
|
|||
|
||||
// default to the bookmarks menu folder
|
||||
if (!ip) {
|
||||
ip = new InsertionPoint({
|
||||
ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.bookmarksMenuFolderId,
|
||||
parentGuid: PlacesUtils.bookmarks.menuGuid
|
||||
});
|
||||
|
@ -1072,7 +1072,7 @@ var gEditItemOverlay = {
|
|||
|
||||
switch (aProperty) {
|
||||
case "uri":
|
||||
let newURI = NetUtil.newURI(aValue);
|
||||
let newURI = Services.ui.newURI(aValue);
|
||||
if (!newURI.equals(this._paneInfo.uri)) {
|
||||
this._paneInfo.uri = newURI;
|
||||
if (this._paneInfo.visibleRows.has("locationRow"))
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
|
||||
if (!elt._placesNode) {
|
||||
// If we are dragging over a non places node drop at the end.
|
||||
dropPoint.ip = new InsertionPoint({
|
||||
dropPoint.ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode)
|
||||
});
|
||||
|
@ -113,7 +113,7 @@
|
|||
// This is a folder or a tag container.
|
||||
if (eventY - eltY < eltHeight * 0.20) {
|
||||
// If mouse is in the top part of the element, drop above folder.
|
||||
dropPoint.ip = new InsertionPoint({
|
||||
dropPoint.ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode),
|
||||
orientation: Ci.nsITreeView.DROP_BEFORE,
|
||||
|
@ -123,7 +123,7 @@
|
|||
return dropPoint;
|
||||
} else if (eventY - eltY < eltHeight * 0.80) {
|
||||
// If mouse is in the middle of the element, drop inside folder.
|
||||
dropPoint.ip = new InsertionPoint({
|
||||
dropPoint.ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(elt._placesNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(elt._placesNode),
|
||||
tagName
|
||||
|
@ -134,7 +134,7 @@
|
|||
} else if (eventY - eltY <= eltHeight / 2) {
|
||||
// This is a non-folder node or a readonly folder.
|
||||
// If the mouse is above the middle, drop above this item.
|
||||
dropPoint.ip = new InsertionPoint({
|
||||
dropPoint.ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode),
|
||||
orientation: Ci.nsITreeView.DROP_BEFORE,
|
||||
|
@ -145,7 +145,7 @@
|
|||
}
|
||||
|
||||
// Drop below the item.
|
||||
dropPoint.ip = new InsertionPoint({
|
||||
dropPoint.ip = new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(resultNode),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(resultNode),
|
||||
orientation: Ci.nsITreeView.DROP_AFTER,
|
||||
|
@ -350,7 +350,7 @@
|
|||
|
||||
// Force a copy action if parent node is a query or we are dragging a
|
||||
// not-removable node.
|
||||
if (!PlacesControllerDragHelper.canMoveNode(draggedElt, this._rootView))
|
||||
if (!this._rootView.controller.canMoveNode(draggedElt))
|
||||
event.dataTransfer.effectAllowed = "copyLink";
|
||||
|
||||
// Activate the view and cache the dragged element.
|
||||
|
|
|
@ -25,11 +25,15 @@
|
|||
"PlacesUIUtils", "resource:///modules/PlacesUIUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(window,
|
||||
"PlacesTransactions", "resource://gre/modules/PlacesTransactions.jsm");
|
||||
ChromeUtils.defineModuleGetter(window,
|
||||
"ForgetAboutSite", "resource://gre/modules/ForgetAboutSite.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyScriptGetter(window, "PlacesTreeView",
|
||||
"chrome://browser/content/places/treeView.js");
|
||||
XPCOMUtils.defineLazyScriptGetter(window,
|
||||
["PlacesInsertionPoint", "PlacesController", "PlacesControllerDragHelper"],
|
||||
"chrome://browser/content/places/controller.js");
|
||||
]]></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/controller.js"/>
|
||||
|
||||
<!-- Bookmarks and history tooltip -->
|
||||
<tooltip id="bhTooltip" noautohide="true"
|
||||
|
@ -43,45 +47,45 @@
|
|||
<commandset id="placesCommands"
|
||||
commandupdater="true"
|
||||
events="focus,sort,places"
|
||||
oncommandupdate="goUpdatePlacesCommands();">
|
||||
oncommandupdate="PlacesUIUtils.updateCommands(window);">
|
||||
<command id="placesCmd_open"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open');"/>
|
||||
<command id="placesCmd_open:window"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open:window');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open:window');"/>
|
||||
<command id="placesCmd_open:privatewindow"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open:privatewindow');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open:privatewindow');"/>
|
||||
<command id="placesCmd_open:tab"
|
||||
oncommand="goDoPlacesCommand('placesCmd_open:tab');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_open:tab');"/>
|
||||
|
||||
<command id="placesCmd_new:bookmark"
|
||||
oncommand="goDoPlacesCommand('placesCmd_new:bookmark');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_new:bookmark');"/>
|
||||
<command id="placesCmd_new:folder"
|
||||
oncommand="goDoPlacesCommand('placesCmd_new:folder');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_new:folder');"/>
|
||||
<command id="placesCmd_new:separator"
|
||||
oncommand="goDoPlacesCommand('placesCmd_new:separator');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_new:separator');"/>
|
||||
<command id="placesCmd_show:info"
|
||||
oncommand="goDoPlacesCommand('placesCmd_show:info');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_show:info');"/>
|
||||
<command id="placesCmd_rename"
|
||||
oncommand="goDoPlacesCommand('placesCmd_show:info');"
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_show:info');"
|
||||
observes="placesCmd_show:info"/>
|
||||
<command id="placesCmd_reload"
|
||||
oncommand="goDoPlacesCommand('placesCmd_reload');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_reload');"/>
|
||||
<command id="placesCmd_sortBy:name"
|
||||
oncommand="goDoPlacesCommand('placesCmd_sortBy:name');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_sortBy:name');"/>
|
||||
<command id="placesCmd_deleteDataHost"
|
||||
oncommand="goDoPlacesCommand('placesCmd_deleteDataHost');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_deleteDataHost');"/>
|
||||
<command id="placesCmd_createBookmark"
|
||||
oncommand="goDoPlacesCommand('placesCmd_createBookmark');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_createBookmark');"/>
|
||||
|
||||
<!-- Special versions of cut/copy/paste/delete which check for an open context menu. -->
|
||||
<command id="placesCmd_cut"
|
||||
oncommand="goDoPlacesCommand('placesCmd_cut');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_cut');"/>
|
||||
<command id="placesCmd_copy"
|
||||
oncommand="goDoPlacesCommand('placesCmd_copy');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_copy');"/>
|
||||
<command id="placesCmd_paste"
|
||||
oncommand="goDoPlacesCommand('placesCmd_paste');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_paste');"/>
|
||||
<command id="placesCmd_delete"
|
||||
oncommand="goDoPlacesCommand('placesCmd_delete');"/>
|
||||
oncommand="PlacesUIUtils.doCommand(window, 'placesCmd_delete');"/>
|
||||
</commandset>
|
||||
|
||||
<menupopup id="placesContext"
|
||||
|
|
|
@ -507,7 +507,7 @@
|
|||
|
||||
// Avoid the potentially expensive call to getChildIndex
|
||||
// if we know this container doesn't allow insertion
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container, this))
|
||||
if (this.controller.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
var queryOptions = PlacesUtils.asQuery(result.root).queryOptions;
|
||||
|
@ -530,7 +530,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container, this))
|
||||
if (this.controller.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
// TODO (Bug 1160193): properly support dropping on a tag root.
|
||||
|
@ -541,7 +541,7 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
return new InsertionPoint({
|
||||
return new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(container),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(container),
|
||||
index, orientation, tagName, dropNearNode
|
||||
|
@ -762,7 +762,7 @@
|
|||
|
||||
// If this node is child of a readonly container (e.g. a livemark)
|
||||
// or cannot be moved, we must force a copy.
|
||||
if (!PlacesControllerDragHelper.canMoveNode(node, this)) {
|
||||
if (!this.controller.canMoveNode(node)) {
|
||||
event.dataTransfer.effectAllowed = "copyLink";
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1436,7 +1436,7 @@ PlacesTreeView.prototype = {
|
|||
|
||||
// Avoid the potentially expensive call to getChildIndex
|
||||
// if we know this container doesn't allow insertion.
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container, this._tree.element))
|
||||
if (this._controller.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions;
|
||||
|
@ -1459,7 +1459,7 @@ PlacesTreeView.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
if (PlacesControllerDragHelper.disallowInsertion(container, this._tree.element))
|
||||
if (this._controller.disallowInsertion(container))
|
||||
return null;
|
||||
|
||||
// TODO (Bug 1160193): properly support dropping on a tag root.
|
||||
|
@ -1470,7 +1470,7 @@ PlacesTreeView.prototype = {
|
|||
return null;
|
||||
}
|
||||
|
||||
return new InsertionPoint({
|
||||
return new PlacesInsertionPoint({
|
||||
parentId: PlacesUtils.getConcreteItemId(container),
|
||||
parentGuid: PlacesUtils.getConcreteItemGuid(container),
|
||||
index, orientation, tagName, dropNearNode
|
||||
|
|
|
@ -28,7 +28,7 @@ add_task(async function() {
|
|||
Assert.equal(tree.selectedNode.bookmarkGuid, folder.guid,
|
||||
"Selected the expected node");
|
||||
Assert.equal(tree.selectedNode.type, 6, "node is a folder");
|
||||
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
|
||||
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
|
||||
"can move regular folder node");
|
||||
|
||||
info("Test a folder shortcut");
|
||||
|
@ -43,7 +43,7 @@ add_task(async function() {
|
|||
Assert.equal(tree.selectedNode.type, 9, "node is a folder shortcut");
|
||||
Assert.equal(PlacesUtils.getConcreteItemGuid(tree.selectedNode),
|
||||
folder.guid, "shortcut node guid and concrete guid match");
|
||||
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
|
||||
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
|
||||
"can move folder shortcut node");
|
||||
|
||||
info("Test a query");
|
||||
|
@ -63,7 +63,7 @@ add_task(async function() {
|
|||
tree.selectItems([query.guid]);
|
||||
Assert.equal(tree.selectedNode.bookmarkGuid, query.guid,
|
||||
"Selected the expected node");
|
||||
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
|
||||
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
|
||||
"can move query node");
|
||||
|
||||
|
||||
|
@ -79,7 +79,7 @@ add_task(async function() {
|
|||
PlacesUtils.asQuery(tree.selectedNode).containerOpen = true;
|
||||
Assert.equal(tree.selectedNode.childCount, 1, "has tags");
|
||||
let tagNode = tree.selectedNode.getChild(0);
|
||||
Assert.ok(!PlacesControllerDragHelper.canMoveNode(tagNode, tree),
|
||||
Assert.ok(!tree.controller.canMoveNode(tagNode),
|
||||
"should not be able to move tag container node");
|
||||
tree.selectedNode.containerOpen = false;
|
||||
|
||||
|
@ -92,7 +92,7 @@ add_task(async function() {
|
|||
|
||||
for (let guid of roots) {
|
||||
tree.selectItems([guid]);
|
||||
Assert.ok(!PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
|
||||
Assert.ok(!tree.controller.canMoveNode(tree.selectedNode),
|
||||
"shouldn't be able to move default shortcuts to roots");
|
||||
let id = await PlacesUtils.promiseItemId(guid);
|
||||
let s = await PlacesUtils.bookmarks.insert({
|
||||
|
@ -103,7 +103,7 @@ add_task(async function() {
|
|||
tree.selectItems([s.guid]);
|
||||
Assert.equal(tree.selectedNode.bookmarkGuid, s.guid,
|
||||
"Selected the expected node");
|
||||
Assert.ok(PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
|
||||
Assert.ok(tree.controller.canMoveNode(tree.selectedNode),
|
||||
"should be able to move user-created shortcuts to roots");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@ add_task(async function test() {
|
|||
let tree = sidebar.contentDocument.getElementById("bookmarks-view");
|
||||
tree.focus();
|
||||
|
||||
let controller = doGetPlacesControllerForCommand("placesCmd_copy");
|
||||
let controller = PlacesUIUtils.getControllerForCommand(window, "placesCmd_copy");
|
||||
let treeController = tree.controllers
|
||||
.getControllerForCommand("placesCmd_copy");
|
||||
ok(controller == treeController, "tree controller was returned");
|
||||
|
@ -45,7 +45,7 @@ add_task(async function test() {
|
|||
EventUtils.synthesizeMouse(toolbarItems.childNodes[0],
|
||||
4, 4, { type: "contextmenu", button: 2 },
|
||||
window);
|
||||
controller = doGetPlacesControllerForCommand("placesCmd_copy");
|
||||
controller = PlacesUIUtils.getControllerForCommand(window, "placesCmd_copy");
|
||||
let toolbarController = document.getElementById("PlacesToolbar")
|
||||
.controllers
|
||||
.getControllerForCommand("placesCmd_copy");
|
||||
|
@ -55,7 +55,7 @@ add_task(async function test() {
|
|||
|
||||
// Now that the context menu is closed, try to get the tree controller again.
|
||||
tree.focus();
|
||||
controller = doGetPlacesControllerForCommand("placesCmd_copy");
|
||||
controller = PlacesUIUtils.getControllerForCommand(window, "placesCmd_copy");
|
||||
ok(controller == treeController, "tree controller was returned");
|
||||
|
||||
if (wasCollapsed) {
|
||||
|
|
|
@ -76,7 +76,7 @@ async function run_drag_test(startBookmarkIndex, insertionIndex, newParentGuid,
|
|||
// Simulating a drag-drop with a tree view turns out to be really difficult
|
||||
// as you can't get a node for the source/target. Hence, we fake the
|
||||
// insertion point and drag data and call the function direct.
|
||||
let ip = new InsertionPoint({
|
||||
let ip = new PlacesInsertionPoint({
|
||||
parentId: await PlacesUtils.promiseItemId(PlacesUtils.bookmarks.unfiledGuid),
|
||||
parentGuid: newParentGuid,
|
||||
index: insertionIndex,
|
||||
|
|
|
@ -69,7 +69,7 @@ async function simulateDrop(selectTargets, sourceBm, dropEffect, targetGuid,
|
|||
|
||||
Assert.equal(dataTransfer.dropEffect, dropEffect);
|
||||
|
||||
let ip = new InsertionPoint({
|
||||
let ip = new PlacesInsertionPoint({
|
||||
parentId: await PlacesUtils.promiseItemId(targetGuid),
|
||||
parentGuid: targetGuid,
|
||||
index: 0,
|
||||
|
|
|
@ -56,7 +56,7 @@ async function run_drag_test(startBookmarkIndex, newParentGuid) {
|
|||
// Simulating a drag-drop with a tree view turns out to be really difficult
|
||||
// as you can't get a node for the source/target. Hence, we fake the
|
||||
// insertion point and drag data and call the function direct.
|
||||
let ip = new InsertionPoint({
|
||||
let ip = new PlacesInsertionPoint({
|
||||
isTag: true,
|
||||
tagName: TAG_NAME,
|
||||
orientation: Ci.nsITreeView.DROP_ON
|
||||
|
|
|
@ -25,38 +25,38 @@ add_task(async function test_date_container() {
|
|||
let PO = library.PlacesOrganizer;
|
||||
|
||||
PO.selectLeftPaneBuiltIn("History");
|
||||
isnot(PO._places.selectedNode, null, "We correctly selected History");
|
||||
Assert.notEqual(PO._places.selectedNode, null, "We correctly selected History");
|
||||
|
||||
// Check that both delete and cut commands are disabled, cause this is
|
||||
// a child of the left pane folder.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is disabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is disabled");
|
||||
let historyNode = PlacesUtils.asContainer(PO._places.selectedNode);
|
||||
historyNode.containerOpen = true;
|
||||
|
||||
// Check that we have a child container. It is "Today" container.
|
||||
is(historyNode.childCount, 1, "History node has one child");
|
||||
Assert.equal(historyNode.childCount, 1, "History node has one child");
|
||||
let todayNode = historyNode.getChild(0);
|
||||
let todayNodeExpectedTitle = PlacesUtils.getString("finduri-AgeInDays-is-0");
|
||||
is(todayNode.title, todayNodeExpectedTitle,
|
||||
"History child is the expected container");
|
||||
Assert.equal(todayNode.title, todayNodeExpectedTitle,
|
||||
"History child is the expected container");
|
||||
|
||||
// Select "Today" container.
|
||||
PO._places.selectNode(todayNode);
|
||||
is(PO._places.selectedNode, todayNode,
|
||||
"We correctly selected Today container");
|
||||
Assert.equal(PO._places.selectedNode, todayNode,
|
||||
"We correctly selected Today container");
|
||||
// Check that delete command is enabled but cut command is disabled, cause
|
||||
// this is an history item.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
|
||||
// Execute the delete command and check visit has been removed.
|
||||
let promiseURIRemoved = PlacesTestUtils.waitForNotification(
|
||||
|
@ -65,11 +65,11 @@ add_task(async function test_date_container() {
|
|||
await promiseURIRemoved;
|
||||
|
||||
// Test live update of "History" query.
|
||||
is(historyNode.childCount, 0, "History node has no more children");
|
||||
Assert.equal(historyNode.childCount, 0, "History node has no more children");
|
||||
|
||||
historyNode.containerOpen = false;
|
||||
|
||||
ok(!(await PlacesUtils.history.hasVisits(TEST_URI)), "Visit has been removed");
|
||||
Assert.ok(!(await PlacesUtils.history.hasVisits(TEST_URI)), "Visit has been removed");
|
||||
|
||||
library.close();
|
||||
});
|
||||
|
@ -82,19 +82,19 @@ add_task(async function test_query_on_toolbar() {
|
|||
let PO = library.PlacesOrganizer;
|
||||
|
||||
PO.selectLeftPaneBuiltIn("BookmarksToolbar");
|
||||
isnot(PO._places.selectedNode, null, "We have a valid selection");
|
||||
is(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
|
||||
PlacesUtils.toolbarFolderId,
|
||||
"We have correctly selected bookmarks toolbar node.");
|
||||
Assert.notEqual(PO._places.selectedNode, null, "We have a valid selection");
|
||||
Assert.equal(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
|
||||
PlacesUtils.toolbarFolderId,
|
||||
"We have correctly selected bookmarks toolbar node.");
|
||||
|
||||
// Check that both cut and delete commands are disabled, cause this is a child
|
||||
// of the All Bookmarks special query.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is disabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is disabled");
|
||||
|
||||
let toolbarNode = PlacesUtils.asContainer(PO._places.selectedNode);
|
||||
toolbarNode.containerOpen = true;
|
||||
|
@ -107,21 +107,21 @@ add_task(async function test_query_on_toolbar() {
|
|||
index: 0 });
|
||||
|
||||
// Get first child and check it is the just inserted query.
|
||||
ok(toolbarNode.childCount > 0, "Toolbar node has children");
|
||||
Assert.ok(toolbarNode.childCount > 0, "Toolbar node has children");
|
||||
let queryNode = toolbarNode.getChild(0);
|
||||
is(queryNode.title, "special_query", "Query node is correctly selected");
|
||||
Assert.equal(queryNode.title, "special_query", "Query node is correctly selected");
|
||||
|
||||
// Select query node.
|
||||
PO._places.selectNode(queryNode);
|
||||
is(PO._places.selectedNode, queryNode, "We correctly selected query node");
|
||||
Assert.equal(PO._places.selectedNode, queryNode, "We correctly selected query node");
|
||||
|
||||
// Check that both cut and delete commands are enabled.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is enabled");
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is enabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
|
||||
// Execute the delete command and check bookmark has been removed.
|
||||
let promiseItemRemoved = PlacesTestUtils.waitForNotification(
|
||||
|
@ -129,7 +129,7 @@ add_task(async function test_query_on_toolbar() {
|
|||
PO._places.controller.doCommand("cmd_delete");
|
||||
await promiseItemRemoved;
|
||||
|
||||
is((await PlacesUtils.bookmarks.fetch(query.guid)), null,
|
||||
Assert.equal((await PlacesUtils.bookmarks.fetch(query.guid)), null,
|
||||
"Query node bookmark has been correctly removed");
|
||||
|
||||
toolbarNode.containerOpen = false;
|
||||
|
@ -151,25 +151,25 @@ add_task(async function test_search_contents() {
|
|||
let PO = library.PlacesOrganizer;
|
||||
|
||||
PO.selectLeftPaneBuiltIn("BookmarksToolbar");
|
||||
isnot(PO._places.selectedNode, null, "We have a valid selection");
|
||||
is(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
|
||||
PlacesUtils.toolbarFolderId,
|
||||
"We have correctly selected bookmarks toolbar node.");
|
||||
Assert.notEqual(PO._places.selectedNode, null, "We have a valid selection");
|
||||
Assert.equal(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
|
||||
PlacesUtils.toolbarFolderId,
|
||||
"We have correctly selected bookmarks toolbar node.");
|
||||
|
||||
let searchBox = library.document.getElementById("searchFilter");
|
||||
searchBox.value = "example";
|
||||
library.PlacesSearchBox.search(searchBox.value);
|
||||
|
||||
let bookmarkNode = library.ContentTree.view.selectedNode;
|
||||
is(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
|
||||
Assert.equal(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
|
||||
|
||||
// Check that both cut and delete commands are enabled.
|
||||
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is enabled");
|
||||
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is enabled");
|
||||
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
|
||||
library.close();
|
||||
});
|
||||
|
@ -190,44 +190,44 @@ add_task(async function test_tags() {
|
|||
|
||||
PO.selectLeftPaneBuiltIn("Tags");
|
||||
let tagsNode = PO._places.selectedNode;
|
||||
isnot(tagsNode, null, "We have a valid selection");
|
||||
Assert.notEqual(tagsNode, null, "We have a valid selection");
|
||||
let tagsTitle = PlacesUtils.getString("TagsFolderTitle");
|
||||
is(tagsNode.title, tagsTitle,
|
||||
"Tags has been properly selected");
|
||||
Assert.equal(tagsNode.title, tagsTitle,
|
||||
"Tags has been properly selected");
|
||||
|
||||
// Check that both cut and delete commands are disabled.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is disabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is disabled");
|
||||
|
||||
// Now select the tag.
|
||||
PlacesUtils.asContainer(tagsNode).containerOpen = true;
|
||||
let tag = tagsNode.getChild(0);
|
||||
PO._places.selectNode(tag);
|
||||
is(PO._places.selectedNode.title, "test",
|
||||
"The created tag has been properly selected");
|
||||
Assert.equal(PO._places.selectedNode.title, "test",
|
||||
"The created tag has been properly selected");
|
||||
|
||||
// Check that cut is disabled but delete is enabled.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
|
||||
let bookmarkNode = library.ContentTree.view.selectedNode;
|
||||
is(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
|
||||
Assert.equal(bookmarkNode.uri, "http://example.com/", "Found the expected bookmark");
|
||||
|
||||
// Check that both cut and delete commands are enabled.
|
||||
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
Assert.ok(!library.ContentTree.view.controller.isCommandEnabled("cmd_cut"),
|
||||
"Cut command is disabled");
|
||||
Assert.ok(library.ContentTree.view.controller.isCommandEnabled("cmd_delete"),
|
||||
"Delete command is enabled");
|
||||
|
||||
tagsNode.containerOpen = false;
|
||||
|
||||
|
|
|
@ -174,7 +174,6 @@ skip-if = true # Bug 1437843
|
|||
skip-if = true # Bug 1437844
|
||||
[browser_console_context_menu_entries.js]
|
||||
[browser_console_dead_objects.js]
|
||||
skip-if = true # Bug 1437845
|
||||
[browser_console_error_source_click.js]
|
||||
[browser_console_filters.js]
|
||||
[browser_console_nsiconsolemessage.js]
|
||||
|
|
|
@ -3,93 +3,41 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
// Check that Dead Objects do not break the Web/Browser Consoles.
|
||||
// See bug 883649.
|
||||
// This test does:
|
||||
// - opens a new tab,
|
||||
// - opens the Browser Console,
|
||||
// - stores a reference to the content document of the tab on the chrome
|
||||
// window object,
|
||||
// - closes the tab,
|
||||
// - tries to use the object that was pointing to the now-defunct content
|
||||
// document. This is the dead object.
|
||||
//
|
||||
// This test:
|
||||
// - Opens the Browser Console.
|
||||
// - Creates a sandbox.
|
||||
// - Stores a reference to the sandbox on the chrome window object.
|
||||
// - Nukes the sandbox
|
||||
// - Tries to use the sandbox. This is the dead object.
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,<p>dead objects!";
|
||||
add_task(async function () {
|
||||
let hud = await HUDService.toggleBrowserConsole();
|
||||
ok(hud, "browser console opened");
|
||||
|
||||
function test() {
|
||||
let hud = null;
|
||||
let jsterm = hud.jsterm;
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("devtools.chrome.enabled");
|
||||
});
|
||||
// Add the reference to the nuked sandbox.
|
||||
await jsterm.execute("window.nukedSandbox = Cu.Sandbox(null);" +
|
||||
"Cu.nukeSandbox(nukedSandbox);");
|
||||
|
||||
Task.spawn(runner).then(finishTest);
|
||||
await jsterm.execute("nukedSandbox");
|
||||
await waitFor(() => findMessage(hud, "DeadObject", ".objectTitle"));
|
||||
|
||||
function* runner() {
|
||||
Services.prefs.setBoolPref("devtools.chrome.enabled", true);
|
||||
yield loadTab(TEST_URI);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let winID = browser.outerWindowID;
|
||||
jsterm.execute("nukedSandbox.hello");
|
||||
let msg = await waitFor(() => findMessage(hud, "can't access dead object"));
|
||||
|
||||
info("open the browser console");
|
||||
// Check that the link contains an anchor. We can't click on the link because
|
||||
// clicking links from tests attempts to access an external URL and crashes
|
||||
// Firefox.
|
||||
let anchor = msg.querySelector("a");
|
||||
is(anchor.textContent, "[Learn More]", "Link text is correct");
|
||||
|
||||
hud = yield HUDService.toggleBrowserConsole();
|
||||
ok(hud, "browser console opened");
|
||||
|
||||
let jsterm = hud.jsterm;
|
||||
|
||||
jsterm.clearOutput();
|
||||
|
||||
// Add the reference to the content document.
|
||||
yield jsterm.execute("Cu = Components.utils;" +
|
||||
"Cu.import('resource://gre/modules/Services.jsm');" +
|
||||
"chromeWindow = Services.wm.getMostRecentWindow('" +
|
||||
"navigator:browser');" +
|
||||
"foobarzTezt = chromeWindow.content.document;" +
|
||||
"delete chromeWindow");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
yield TestUtils.topicObserved("outer-window-nuked", (subject, data) => {
|
||||
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
return id == winID;
|
||||
});
|
||||
|
||||
let msg = yield jsterm.execute("foobarzTezt");
|
||||
|
||||
isnot(hud.outputNode.textContent.indexOf("DeadObject"), -1,
|
||||
"dead object found");
|
||||
|
||||
jsterm.setInputValue("foobarzTezt");
|
||||
|
||||
for (let c of ".hello") {
|
||||
EventUtils.synthesizeKey(c, {}, hud.iframeWindow);
|
||||
}
|
||||
|
||||
yield jsterm.execute();
|
||||
|
||||
isnot(hud.outputNode.textContent.indexOf("can't access dead object"), -1,
|
||||
"'cannot access dead object' message found");
|
||||
|
||||
// Click the second execute output.
|
||||
let clickable = msg.querySelector("a");
|
||||
ok(clickable, "clickable object found");
|
||||
isnot(clickable.textContent.indexOf("DeadObject"), -1,
|
||||
"message text check");
|
||||
|
||||
msg.scrollIntoView();
|
||||
|
||||
executeSoon(() => {
|
||||
EventUtils.synthesizeMouseAtCenter(clickable, {}, hud.iframeWindow);
|
||||
});
|
||||
|
||||
yield jsterm.once("variablesview-fetched");
|
||||
ok(true, "variables view fetched");
|
||||
|
||||
msg = yield jsterm.execute("delete window.foobarzTezt; 2013-26");
|
||||
|
||||
isnot(msg.textContent.indexOf("1987"), -1, "result message found");
|
||||
}
|
||||
}
|
||||
await jsterm.execute("delete window.nukedSandbox; 2013-26");
|
||||
await waitFor(() => findMessage(hud, "1987"));
|
||||
});
|
||||
|
|
|
@ -2544,14 +2544,7 @@ Console::MonotonicTimer(JSContext* aCx, MethodName aMethodName,
|
|||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
double duration = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
|
||||
|
||||
// Round down to the nearest 5us, because if the timer is too accurate
|
||||
// people can do nasty timing attacks with it. See similar code in the
|
||||
// worker Performance implementation.
|
||||
const double maxResolutionMs = 0.005;
|
||||
*aTimeStamp = nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
floor(duration / maxResolutionMs) * maxResolutionMs);
|
||||
*aTimeStamp = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -447,7 +447,7 @@ MP3TrackDemuxer::FindFirstFrame()
|
|||
" Length()=%" PRIu64,
|
||||
candidateFrame.mStart, candidateFrame.Length());
|
||||
|
||||
while (candidateFrame.Length() && numSuccFrames < MIN_SUCCESSIVE_FRAMES) {
|
||||
while (candidateFrame.Length()) {
|
||||
mParser.EndFrameSession();
|
||||
mOffset = currentFrame.mEnd;
|
||||
const MediaByteRange prevFrame = currentFrame;
|
||||
|
@ -473,16 +473,26 @@ MP3TrackDemuxer::FindFirstFrame()
|
|||
MP3LOGV("FindFirst() new candidate frame: mOffset=%" PRIu64
|
||||
" Length()=%" PRIu64,
|
||||
candidateFrame.mStart, candidateFrame.Length());
|
||||
} else if (numSuccFrames >= MIN_SUCCESSIVE_FRAMES) {
|
||||
MP3LOG("FindFirst() accepting candidate frame: "
|
||||
"successiveFrames=%d", numSuccFrames);
|
||||
mFrameLock = true;
|
||||
return candidateFrame;
|
||||
} else if (prevFrame.mStart == mParser.ID3Header().TotalTagSize() &&
|
||||
currentFrame.mEnd == StreamLength()) {
|
||||
// We accept streams with only two frames if both frames are valid. This
|
||||
// is to handle very short files and provide parity with Chrome. See
|
||||
// bug 1432195 for more information. This will not handle short files
|
||||
// with a trailing tag, but as of writing we lack infrastructure to
|
||||
// handle such tags.
|
||||
MP3LOG("FindFirst() accepting candidate frame for short stream: "
|
||||
"successiveFrames=%d", numSuccFrames);
|
||||
mFrameLock = true;
|
||||
return candidateFrame;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSuccFrames >= MIN_SUCCESSIVE_FRAMES) {
|
||||
MP3LOG("FindFirst() accepting candidate frame: "
|
||||
"successiveFrames=%d", numSuccFrames);
|
||||
mFrameLock = true;
|
||||
} else {
|
||||
MP3LOG("FindFirst() no suitable first frame found");
|
||||
}
|
||||
MP3LOG("FindFirst() no suitable first frame found");
|
||||
return candidateFrame;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,12 @@ IsWhitelistedH264Codec(const nsAString& aCodec)
|
|||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
|
||||
// "The Media Foundation H.264 video decoder is a Media Foundation Transform
|
||||
// that supports decoding of Baseline, Main, and High profiles, up to level
|
||||
// 5.1.". We also report that we can play Extended profile, as there are
|
||||
// 5.1.". We extend the limit to level 5.2, relying on the decoder to handle
|
||||
// any potential errors, the level limit being rather arbitrary.
|
||||
// We also report that we can play Extended profile, as there are
|
||||
// bitstreams that are Extended compliant that are also Baseline compliant.
|
||||
return level >= H264_LEVEL_1 &&
|
||||
level <= H264_LEVEL_5_1 &&
|
||||
level <= H264_LEVEL_5_2 &&
|
||||
(profile == H264_PROFILE_BASE ||
|
||||
profile == H264_PROFILE_MAIN ||
|
||||
profile == H264_PROFILE_EXTENDED ||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "WebRenderTypes.h"
|
||||
#include "webrender_ffi.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "FrameLayerBuilder.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -267,7 +266,7 @@ PrintDisplayItemToStdout(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
|
|||
{
|
||||
std::stringstream stream;
|
||||
PrintDisplayItemTo(aBuilder, aItem, stream, 0, true, false);
|
||||
std::cout << stream.str() << std::endl;
|
||||
puts(stream.str().c_str());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -275,7 +274,7 @@ PrintDisplayListToStdout(nsDisplayListBuilder* aBuilder, const nsDisplayList& aL
|
|||
{
|
||||
std::stringstream stream;
|
||||
PrintDisplayListTo(aBuilder, aList, stream, 0, false);
|
||||
std::cout << stream.str() << std::endl;
|
||||
puts(stream.str().c_str());
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "WebrtcGmpVideoCodec.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#ifndef WEBRTCGMPVIDEOCODEC_H_
|
||||
#define WEBRTCGMPVIDEOCODEC_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
#include "CSFLog.h"
|
||||
|
|
|
@ -82,6 +82,10 @@ class CentOSFedoraBootstrapper(StyloInstall, BaseBootstrapper):
|
|||
'python-dbus',
|
||||
]
|
||||
|
||||
self.mobile_android_packages += [
|
||||
'ncurses-compat-libs',
|
||||
]
|
||||
|
||||
def install_system_packages(self):
|
||||
self.dnf_groupinstall(*self.group_packages)
|
||||
self.dnf_install(*self.packages)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#define security_sandbox_loggingCallbacks_h__
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
|
|
@ -727,7 +727,9 @@ BufferedBookmarksEngine.prototype = {
|
|||
let buf = await this._store.ensureOpenMirror();
|
||||
let recordsToUpload = await buf.apply({
|
||||
remoteTimeSeconds: Resource.serverTime,
|
||||
weakUpload: [...this._needWeakUpload.keys()],
|
||||
});
|
||||
this._needWeakUpload.clear();
|
||||
this._modified.replace(recordsToUpload);
|
||||
},
|
||||
|
||||
|
@ -736,9 +738,6 @@ BufferedBookmarksEngine.prototype = {
|
|||
},
|
||||
|
||||
async _createRecord(id) {
|
||||
if (this._needWeakUpload.has(id)) {
|
||||
return this._store.createRecord(id, this.name);
|
||||
}
|
||||
let change = this._modified.changes[id];
|
||||
if (!change) {
|
||||
this._log.error("Creating record for item ${id} not in strong " +
|
||||
|
|
|
@ -90,14 +90,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "azure"
|
||||
version = "0.27.0"
|
||||
source = "git+https://github.com/servo/rust-azure#46a9c9c6279ba46354b48f6fc849ee20624cbf90"
|
||||
version = "0.28.0"
|
||||
source = "git+https://github.com/servo/rust-azure#29f0c063ad366b5364e06af26d3e9d1ee588e3b2"
|
||||
dependencies = [
|
||||
"cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-skia 0.30000012.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-skia 0.30000013.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "canvas"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"azure 0.27.0 (git+https://github.com/servo/rust-azure)",
|
||||
"azure 0.28.0 (git+https://github.com/servo/rust-azure)",
|
||||
"canvas_traits 0.0.1",
|
||||
"compositing 0.0.1",
|
||||
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -757,6 +757,15 @@ dependencies = [
|
|||
"dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dwmapi-sys"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dwrote"
|
||||
version = "0.4.2"
|
||||
|
@ -2634,7 +2643,7 @@ dependencies = [
|
|||
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"script_traits 0.0.1",
|
||||
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-glutin 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-glutin 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_config 0.0.1",
|
||||
"servo_geometry 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
|
@ -2684,7 +2693,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "servo-glutin"
|
||||
version = "0.14.2"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"android_glue 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2692,20 +2701,25 @@ dependencies = [
|
|||
"cocoa 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dwmapi-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x11-dl 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "servo-skia"
|
||||
version = "0.30000012.0"
|
||||
version = "0.30000013.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2719,7 +2733,7 @@ dependencies = [
|
|||
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-glutin 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo-glutin 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"x11 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2840,6 +2854,15 @@ dependencies = [
|
|||
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell32-sys"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sig"
|
||||
version = "0.1.1"
|
||||
|
@ -3585,7 +3608,7 @@ dependencies = [
|
|||
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
|
||||
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
|
||||
"checksum audio-video-metadata 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "71536082079f5ba92c274fba7c2dcd4e2f9d5c13ce6d7f8fe9acbbb258916d18"
|
||||
"checksum azure 0.27.0 (git+https://github.com/servo/rust-azure)" = "<none>"
|
||||
"checksum azure 0.28.0 (git+https://github.com/servo/rust-azure)" = "<none>"
|
||||
"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
|
||||
"checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff"
|
||||
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
|
||||
|
@ -3639,6 +3662,7 @@ dependencies = [
|
|||
"checksum device 0.0.1 (git+https://github.com/servo/devices)" = "<none>"
|
||||
"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
|
||||
"checksum dtoa-short 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe6f727b406462fd57c95fed84d1b0dbfb5f0136fcac005adba9ea0367c05cc8"
|
||||
"checksum dwmapi-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b44b6442aeab12e609aee505bd1066bdfd36b79c3fe5aad604aae91537623e76"
|
||||
"checksum dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b26e30aaa6bf31ec830db15fec14ed04f0f2ecfcc486ecfce88c55d3389b237f"
|
||||
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
|
||||
"checksum encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5215aabf22b83153be3ee44dfe3f940214541b2ce13d419c55e7a115c8c51a9"
|
||||
|
@ -3790,11 +3814,12 @@ dependencies = [
|
|||
"checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262"
|
||||
"checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a"
|
||||
"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
|
||||
"checksum servo-glutin 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf265a35f2d23d3ed2fae943fda4b6dda861c86b25c1c99f9ca77a37cfa6ee7c"
|
||||
"checksum servo-skia 0.30000012.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80980e6eb854c06e8e45fa3cfbd439bf4223a6840f38c3caec34efa39cf9405e"
|
||||
"checksum servo-glutin 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a36b9398e9cade5b1e3011d841d9d98d4e86a538a1b639db62100d86134c10f6"
|
||||
"checksum servo-skia 0.30000013.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1be5e09cb97ea135d1223fa226f8880f124aed2fa887bf5acf10ef16ad94e072"
|
||||
"checksum servo-websocket 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efde78dfcf2178d5a11e1e2268e0d8df0627dfe2724546db8585d6678e1af150"
|
||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||
"checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
|
||||
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
||||
"checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5"
|
||||
"checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>"
|
||||
"checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
|
||||
|
|
|
@ -76,16 +76,6 @@ fn generate_properties() {
|
|||
.arg(&script)
|
||||
.arg(product)
|
||||
.arg("style-crate")
|
||||
.envs(if std::mem::size_of::<Option<bool>>() == 1 {
|
||||
// FIXME: remove this envs() call
|
||||
// and make unconditional code that depends on RUSTC_HAS_PR45225
|
||||
// once Firefox requires Rust 1.23+
|
||||
|
||||
// https://github.com/rust-lang/rust/pull/45225
|
||||
vec![("RUSTC_HAS_PR45225", "1")]
|
||||
} else {
|
||||
vec![]
|
||||
})
|
||||
.status()
|
||||
.unwrap();
|
||||
if !status.success() {
|
||||
|
|
|
@ -32,8 +32,7 @@ def main():
|
|||
|
||||
properties = data.PropertiesData(product=product)
|
||||
template = os.path.join(BASE, "properties.mako.rs")
|
||||
rust = render(template, product=product, data=properties, __file__=template,
|
||||
RUSTC_HAS_PR45225=os.environ.get("RUSTC_HAS_PR45225"))
|
||||
rust = render(template, product=product, data=properties, __file__=template)
|
||||
if output == "style-crate":
|
||||
write(os.environ["OUT_DIR"], "properties.rs", rust)
|
||||
if product == "gecko":
|
||||
|
|
|
@ -66,9 +66,9 @@ ${helpers.predefined_type(
|
|||
"stroke-width", "SVGWidth",
|
||||
"::values::computed::NonNegativeLength::new(1.).into()",
|
||||
products="gecko",
|
||||
boxed=not RUSTC_HAS_PR45225,
|
||||
animation_value_type="::values::computed::SVGWidth",
|
||||
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
|
||||
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth",
|
||||
)}
|
||||
|
||||
${helpers.single_keyword("stroke-linecap", "butt round square",
|
||||
products="gecko", animation_value_type="discrete",
|
||||
|
@ -101,9 +101,9 @@ ${helpers.predefined_type(
|
|||
"stroke-dashoffset", "SVGLength",
|
||||
"Au(0).into()",
|
||||
products="gecko",
|
||||
boxed=not RUSTC_HAS_PR45225,
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
|
||||
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
|
||||
)}
|
||||
|
||||
// Section 14 - Clipping, Masking and Compositing
|
||||
${helpers.single_keyword("clip-rule", "nonzero evenodd",
|
||||
|
|
|
@ -47,7 +47,6 @@ ${helpers.predefined_type(
|
|||
"generics::pointing::CaretColor::Auto",
|
||||
spec="https://drafts.csswg.org/css-ui/#caret-color",
|
||||
animation_value_type="AnimatedCaretColor",
|
||||
boxed=not RUSTC_HAS_PR45225,
|
||||
ignored_when_colors_disabled=True,
|
||||
products="gecko",
|
||||
)}
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.23.0
|
||||
1.24.0
|
||||
|
|
|
@ -35,7 +35,7 @@ log = "0.3.5"
|
|||
msg = {path = "../../components/msg"}
|
||||
net_traits = {path = "../../components/net_traits"}
|
||||
script_traits = {path = "../../components/script_traits"}
|
||||
servo-glutin = "0.14"
|
||||
servo-glutin = "0.15"
|
||||
servo_geometry = {path = "../../components/geometry"}
|
||||
servo_config = {path = "../../components/config"}
|
||||
servo_url = {path = "../../components/url"}
|
||||
|
|
|
@ -535,6 +535,7 @@ Connection::Connection(Service *aService,
|
|||
, mAsyncExecutionThreadShuttingDown(false)
|
||||
, mConnectionClosed(false)
|
||||
, mTransactionInProgress(false)
|
||||
, mDestroying(false)
|
||||
, mProgressHandler(nullptr)
|
||||
, mFlags(aFlags)
|
||||
, mIgnoreLockingMode(aIgnoreLockingMode)
|
||||
|
@ -572,56 +573,51 @@ NS_IMETHODIMP_(MozExternalRefCountType) Connection::Release(void)
|
|||
nsrefcnt count = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, count, "Connection");
|
||||
if (1 == count) {
|
||||
// If the refcount is 1, the single reference must be from
|
||||
// gService->mConnections (in class |Service|). Which means we can
|
||||
// perform our failsafe Close() and unregister...
|
||||
// If the refcount went to 1, the single reference must be from
|
||||
// gService->mConnections (in class |Service|). And the code calling
|
||||
// Release is either:
|
||||
// - The "user" code that had created the connection, releasing on any
|
||||
// thread.
|
||||
// - One of Service's getConnections() callers had acquired a strong
|
||||
// reference to the Connection that out-lived the last "user" reference,
|
||||
// and now that just got dropped. Note that this reference could be
|
||||
// getting dropped on the main thread or Connection->threadOpenedOn
|
||||
// (because of the NewRunnableMethod used by minimizeMemory).
|
||||
//
|
||||
// HOWEVER, there is an edge-case where our failsafe Close() may trigger
|
||||
// a call to AsyncClose() which obtains a strong reference. This reference
|
||||
// will be released via NS_ReleaseOnMainThreadSystemGroup() before Close()
|
||||
// returns, which can potentially result in reentrancy into this method and
|
||||
// this branch a second time. (It may also be deferred if we're not in
|
||||
// that event target ourselves.) To avoid reentrancy madness, we explicitly
|
||||
// bump our refcount up to 2 without going through AddRef().
|
||||
++mRefCnt;
|
||||
// Okay, now our refcount is 2, we trigger Close().
|
||||
Unused << Close();
|
||||
// Now our refcount should either be at 2 (because nothing happened, or the
|
||||
// addref and release pair happened due to SpinningSynchronousClose) or
|
||||
// 3 (because SpinningSynchronousClose happened but didn't release yet).
|
||||
//
|
||||
// We *really* want to avoid re-entrancy, and we have potentially two strong
|
||||
// references remaining that will invoke Release() and potentially trigger
|
||||
// a transition to 1 again. Since the second reference would be just a
|
||||
// proxy release of an already-closed connection, it's not a big deal for us
|
||||
// to unregister the connection now. We do need to take care to avoid a
|
||||
// strong refcount transition to 1 from 2 because that would induce
|
||||
// reentrancy. Note that we do not have any concerns about other threads
|
||||
// being involved here; we MUST be the main thread if AsyncClose() is
|
||||
// involved.
|
||||
//
|
||||
// Note: While Close() potentially spins the nested event loop, it is
|
||||
// conceivable that Service::CollectReports or Service::minimizeMemory might
|
||||
// be invoked. These call Service::getConnections() and will perform
|
||||
// matching AddRef and Release calls but will definitely not retain any
|
||||
// references. (Because connectionReady() will return false so both loops
|
||||
// will immediately "continue" to bypass the connection in question.)
|
||||
// Because our refcount is at least 2 at the lowest point, these do not pose
|
||||
// a problem.
|
||||
if (mRefCnt == 3) {
|
||||
// pending proxy release, strong release to 2
|
||||
// Either way, we should now perform our failsafe Close() and unregister.
|
||||
// However, we only want to do this once, and the reality is that our
|
||||
// refcount could go back up above 1 and down again at any time if we are
|
||||
// off the main thread and getConnections() gets called on the main thread,
|
||||
// so we use an atomic here to do this exactly once.
|
||||
if (mDestroying.compareExchange(false, true)) {
|
||||
// Close the connection, dispatching to the opening thread if we're not
|
||||
// on that thread already and that thread is still accepting runnables.
|
||||
// We do this because it's possible we're on the main thread because of
|
||||
// getConnections(), and we REALLY don't want to transfer I/O to the main
|
||||
// thread if we can avoid it.
|
||||
if (threadOpenedOn->IsOnCurrentThread()) {
|
||||
// This could cause SpinningSynchronousClose() to be invoked and AddRef
|
||||
// triggered for AsyncCloseConnection's strong ref if the conn was ever
|
||||
// use for async purposes. (Main-thread only, though.)
|
||||
Unused << Close();
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NewRunnableMethod("storage::Connection::Close",
|
||||
this, &Connection::Close);
|
||||
if (NS_FAILED(threadOpenedOn->Dispatch(event.forget(),
|
||||
NS_DISPATCH_NORMAL))) {
|
||||
// The target thread was dead and so we've just leaked our runnable.
|
||||
// This should not happen because our non-main-thread consumers should
|
||||
// be explicitly closing their connections, not relying on us to close
|
||||
// them for them. (It's okay to let a statement go out of scope for
|
||||
// automatic cleanup, but not a Connection.)
|
||||
MOZ_ASSERT(false, "Leaked Connection::Close(), ownership fail.");
|
||||
Unused << Close();
|
||||
}
|
||||
}
|
||||
|
||||
// This will drop its strong reference right here, right now.
|
||||
mStorageService->unregisterConnection(this);
|
||||
// now weak release to 1, the outstanding refcount will strong release to
|
||||
// 0 and result in destruction later.
|
||||
--mRefCnt;
|
||||
} else if (mRefCnt == 2) {
|
||||
// weak release to 1
|
||||
--mRefCnt;
|
||||
// strong release to 0, destruction will happen, we must NOT touch
|
||||
// `this` after this point.
|
||||
mStorageService->unregisterConnection(this);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Connection refcount invariant violated.");
|
||||
}
|
||||
} else if (0 == count) {
|
||||
mRefCnt = 1; /* stabilize */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
@ -380,6 +381,16 @@ private:
|
|||
*/
|
||||
bool mTransactionInProgress;
|
||||
|
||||
/**
|
||||
* Used to trigger cleanup logic only the first time our refcount hits 1. We
|
||||
* may trigger a failsafe Close() that invokes SpinningSynchronousClose()
|
||||
* which invokes AsyncClose() which may bump our refcount back up to 2 (and
|
||||
* which will then fall back down to 1 again). It's also possible that the
|
||||
* Service may bump our refcount back above 1 if getConnections() runs before
|
||||
* we invoke unregisterConnection().
|
||||
*/
|
||||
mozilla::Atomic<bool> mDestroying;
|
||||
|
||||
/**
|
||||
* Stores the mapping of a given function by name to its instance. Access is
|
||||
* protected by sharedDBMutex.
|
||||
|
|
|
@ -297,17 +297,12 @@ Service::unregisterConnection(Connection *aConnection)
|
|||
MOZ_ASSERT(forgettingRef,
|
||||
"Attempt to unregister unknown storage connection!");
|
||||
|
||||
// Ensure the connection is released on its opening thread. We explicitly use
|
||||
// aAlwaysDispatch=false because at the time of writing this, LocalStorage's
|
||||
// StorageDBThread uses a hand-rolled PRThread implementation that cannot
|
||||
// handle us dispatching events at it during shutdown. However, it is
|
||||
// arguably also desirable for callers to not be aware of our connection
|
||||
// tracking mechanism. And by synchronously dropping the reference (when
|
||||
// on the correct thread), this avoids surprises for the caller and weird
|
||||
// shutdown edge cases.
|
||||
nsCOMPtr<nsIThread> thread = forgettingRef->threadOpenedOn;
|
||||
NS_ProxyRelease(
|
||||
"storage::Service::mConnections", thread, forgettingRef.forget(), false);
|
||||
// Do not proxy the release anywhere, just let this reference drop here. (We
|
||||
// previously did proxy the release, but that was because we invoked Close()
|
||||
// in the destructor and Close() likes to complain if it's not invoked on the
|
||||
// opener thread, so it was essential that the last reference be dropped on
|
||||
// the opener thread. We now enqueue Close() inside our caller, Release(), so
|
||||
// it doesn't actually matter what thread our reference drops on.)
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -20,10 +20,11 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
|
|||
});
|
||||
|
||||
const PREF_ENABLED = "marionette.enabled";
|
||||
const PREF_PORT = "marionette.port";
|
||||
const PREF_PORT_FALLBACK = "marionette.defaultPrefs.port";
|
||||
const PREF_LOG_LEVEL = "marionette.log.level";
|
||||
const PREF_LOG_LEVEL_FALLBACK = "marionette.logging";
|
||||
const PREF_LOG_LEVEL = "marionette.log.level";
|
||||
const PREF_PORT_FALLBACK = "marionette.defaultPrefs.port";
|
||||
const PREF_PORT = "marionette.port";
|
||||
const PREF_RECOMMENDED = "marionette.prefs.recommended";
|
||||
|
||||
const DEFAULT_LOG_LEVEL = "info";
|
||||
const NOTIFY_RUNNING = "remote-active";
|
||||
|
@ -46,6 +47,241 @@ const ENV_ENABLED = "MOZ_MARIONETTE";
|
|||
// pref being set to 4444.
|
||||
const ENV_PRESERVE_PREFS = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
|
||||
|
||||
// Marionette sets preferences recommended for automation when it starts,
|
||||
// unless marionette.prefs.recommended has been set to false.
|
||||
// Where noted, some prefs should also be set in the profile passed to
|
||||
// Marionette to prevent them from affecting startup, since some of these
|
||||
// are checked before Marionette initialises.
|
||||
const RECOMMENDED_PREFS = new Map([
|
||||
|
||||
// Disable automatic downloading of new releases.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["app.update.auto", false],
|
||||
|
||||
// Disable automatically upgrading Firefox.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["app.update.enabled", false],
|
||||
|
||||
// Increase the APZ content response timeout in tests to 1 minute.
|
||||
// This is to accommodate the fact that test environments tends to be
|
||||
// slower than production environments (with the b2g emulator being
|
||||
// the slowest of them all), resulting in the production timeout value
|
||||
// sometimes being exceeded and causing false-positive test failures.
|
||||
//
|
||||
// (bug 1176798, bug 1177018, bug 1210465)
|
||||
["apz.content_response_timeout", 60000],
|
||||
|
||||
// Indicate that the download panel has been shown once so that
|
||||
// whichever download test runs first doesn't show the popup
|
||||
// inconsistently.
|
||||
["browser.download.panel.shown", true],
|
||||
|
||||
// Do not show the EULA notification.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.EULA.override", true],
|
||||
|
||||
// Turn off about:newtab and make use of about:blank instead for new
|
||||
// opened tabs.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.newtabpage.enabled", false],
|
||||
|
||||
// Assume the about:newtab page's intro panels have been shown to not
|
||||
// depend on which test runs first and happens to open about:newtab
|
||||
["browser.newtabpage.introShown", true],
|
||||
|
||||
// Never start the browser in offline mode
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.offline", false],
|
||||
|
||||
// Background thumbnails in particular cause grief, and disabling
|
||||
// thumbnails in general cannot hurt
|
||||
["browser.pagethumbnails.capturing_disabled", true],
|
||||
|
||||
// Disable safebrowsing components.
|
||||
//
|
||||
// These should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.safebrowsing.blockedURIs.enabled", false],
|
||||
["browser.safebrowsing.downloads.enabled", false],
|
||||
["browser.safebrowsing.passwords.enabled", false],
|
||||
["browser.safebrowsing.malware.enabled", false],
|
||||
["browser.safebrowsing.phishing.enabled", false],
|
||||
|
||||
// Disable updates to search engines.
|
||||
//
|
||||
// Should be set in profile.
|
||||
["browser.search.update", false],
|
||||
|
||||
// Do not restore the last open set of tabs if the browser has crashed
|
||||
["browser.sessionstore.resume_from_crash", false],
|
||||
|
||||
// Don't check for the default web browser during startup.
|
||||
//
|
||||
// These should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.shell.checkDefaultBrowser", false],
|
||||
|
||||
// Start with a blank page (about:blank)
|
||||
["browser.startup.page", 0],
|
||||
|
||||
// Do not redirect user when a milstone upgrade of Firefox is detected
|
||||
["browser.startup.homepage_override.mstone", "ignore"],
|
||||
|
||||
// Disable browser animations
|
||||
["toolkit.cosmeticAnimations.enabled", false],
|
||||
|
||||
// Do not allow background tabs to be zombified, otherwise for tests
|
||||
// that open additional tabs, the test harness tab itself might get
|
||||
// unloaded
|
||||
["browser.tabs.disableBackgroundZombification", false],
|
||||
|
||||
// Do not warn when closing all other open tabs
|
||||
["browser.tabs.warnOnCloseOtherTabs", false],
|
||||
|
||||
// Do not warn when multiple tabs will be opened
|
||||
["browser.tabs.warnOnOpen", false],
|
||||
|
||||
// Disable first run splash page on Windows 10
|
||||
["browser.usedOnWindows10.introURL", ""],
|
||||
|
||||
// Disable the UI tour.
|
||||
//
|
||||
// Should be set in profile.
|
||||
["browser.uitour.enabled", false],
|
||||
|
||||
// Turn off search suggestions in the location bar so as not to trigger
|
||||
// network connections.
|
||||
["browser.urlbar.suggest.searches", false],
|
||||
|
||||
// Turn off the location bar search suggestions opt-in. It interferes with
|
||||
// tests that don't expect it to be there.
|
||||
["browser.urlbar.userMadeSearchSuggestionsChoice", true],
|
||||
|
||||
// Do not show datareporting policy notifications which can
|
||||
// interfere with tests
|
||||
[
|
||||
"datareporting.healthreport.documentServerURI",
|
||||
"http://%(server)s/dummy/healthreport/",
|
||||
],
|
||||
["datareporting.healthreport.logging.consoleEnabled", false],
|
||||
["datareporting.healthreport.service.enabled", false],
|
||||
["datareporting.healthreport.service.firstRun", false],
|
||||
["datareporting.healthreport.uploadEnabled", false],
|
||||
["datareporting.policy.dataSubmissionEnabled", false],
|
||||
["datareporting.policy.dataSubmissionPolicyAccepted", false],
|
||||
["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
|
||||
|
||||
// Disable popup-blocker
|
||||
["dom.disable_open_during_load", false],
|
||||
|
||||
// Enabling the support for File object creation in the content process
|
||||
["dom.file.createInChild", true],
|
||||
|
||||
// Disable the ProcessHangMonitor
|
||||
["dom.ipc.reportProcessHangs", false],
|
||||
|
||||
// Disable slow script dialogues
|
||||
["dom.max_chrome_script_run_time", 0],
|
||||
["dom.max_script_run_time", 0],
|
||||
|
||||
// Only load extensions from the application and user profile
|
||||
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
||||
//
|
||||
// Should be set in profile.
|
||||
["extensions.autoDisableScopes", 0],
|
||||
["extensions.enabledScopes", 5],
|
||||
|
||||
// Disable metadata caching for installed add-ons by default
|
||||
["extensions.getAddons.cache.enabled", false],
|
||||
|
||||
// Disable installing any distribution extensions or add-ons.
|
||||
// Should be set in profile.
|
||||
["extensions.installDistroAddons", false],
|
||||
|
||||
// Make sure Shield doesn't hit the network.
|
||||
["extensions.shield-recipe-client.api_url", ""],
|
||||
|
||||
["extensions.showMismatchUI", false],
|
||||
|
||||
// Turn off extension updates so they do not bother tests
|
||||
["extensions.update.enabled", false],
|
||||
["extensions.update.notifyUser", false],
|
||||
|
||||
// Make sure opening about:addons will not hit the network
|
||||
[
|
||||
"extensions.webservice.discoverURL",
|
||||
"http://%(server)s/dummy/discoveryURL",
|
||||
],
|
||||
|
||||
// Allow the application to have focus even it runs in the background
|
||||
["focusmanager.testmode", true],
|
||||
|
||||
// Disable useragent updates
|
||||
["general.useragent.updates.enabled", false],
|
||||
|
||||
// Always use network provider for geolocation tests so we bypass the
|
||||
// macOS dialog raised by the corelocation provider
|
||||
["geo.provider.testing", true],
|
||||
|
||||
// Do not scan Wifi
|
||||
["geo.wifi.scan", false],
|
||||
|
||||
// No hang monitor
|
||||
["hangmonitor.timeout", 0],
|
||||
|
||||
// Show chrome errors and warnings in the error console
|
||||
["javascript.options.showInConsole", true],
|
||||
|
||||
// Do not prompt for temporary redirects
|
||||
["network.http.prompt-temp-redirect", false],
|
||||
|
||||
// Disable speculative connections so they are not reported as leaking
|
||||
// when they are hanging around
|
||||
["network.http.speculative-parallel-limit", 0],
|
||||
|
||||
// Do not automatically switch between offline and online
|
||||
["network.manage-offline-status", false],
|
||||
|
||||
// Make sure SNTP requests do not hit the network
|
||||
["network.sntp.pools", "%(server)s"],
|
||||
|
||||
// Local documents have access to all other local documents,
|
||||
// including directory listings
|
||||
["security.fileuri.strict_origin_policy", false],
|
||||
|
||||
// Tests do not wait for the notification button security delay
|
||||
["security.notification_enable_delay", 0],
|
||||
|
||||
// Ensure blocklist updates do not hit the network
|
||||
["services.settings.server", "http://%(server)s/dummy/blocklist/"],
|
||||
|
||||
// Do not automatically fill sign-in forms with known usernames and
|
||||
// passwords
|
||||
["signon.autofillForms", false],
|
||||
|
||||
// Disable password capture, so that tests that include forms are not
|
||||
// influenced by the presence of the persistent doorhanger notification
|
||||
["signon.rememberSignons", false],
|
||||
|
||||
// Disable first-run welcome page
|
||||
["startup.homepage_welcome_url", "about:blank"],
|
||||
["startup.homepage_welcome_url.additional", ""],
|
||||
|
||||
// Prevent starting into safe mode after application crashes
|
||||
["toolkit.startup.max_resumed_crashes", -1],
|
||||
|
||||
]);
|
||||
|
||||
const isRemote = Services.appinfo.processType ==
|
||||
Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
|
||||
|
@ -155,6 +391,7 @@ class MarionetteMainProcess {
|
|||
log.level = prefs.logLevel;
|
||||
|
||||
this.enabled = env.exists(ENV_ENABLED);
|
||||
this.alteredPrefs = new Set();
|
||||
|
||||
Services.prefs.addObserver(PREF_ENABLED, this);
|
||||
Services.ppmm.addMessageListener("Marionette:IsRunning", this);
|
||||
|
@ -225,7 +462,7 @@ class MarionetteMainProcess {
|
|||
if (this.gfxWindow === null || subject === this.gfxWindow) {
|
||||
Services.obs.removeObserver(this, topic);
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown");
|
||||
Services.obs.addObserver(this, "xpcom-will-shutdown");
|
||||
this.finalUIStartup = true;
|
||||
this.init();
|
||||
}
|
||||
|
@ -254,15 +491,15 @@ class MarionetteMainProcess {
|
|||
if (this.gfxWindow) {
|
||||
Services.obs.addObserver(this, "domwindowclosed");
|
||||
} else {
|
||||
Services.obs.addObserver(this, "xpcom-shutdown");
|
||||
Services.obs.addObserver(this, "xpcom-will-shutdown");
|
||||
this.finalUIStartup = true;
|
||||
this.init();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "xpcom-shutdown":
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
case "xpcom-will-shutdown":
|
||||
Services.obs.removeObserver(this, "xpcom-will-shutdown");
|
||||
this.uninit();
|
||||
break;
|
||||
}
|
||||
|
@ -295,6 +532,16 @@ class MarionetteMainProcess {
|
|||
}
|
||||
await startupRecorder;
|
||||
|
||||
if (Preferences.get(PREF_RECOMMENDED)) {
|
||||
for (let [k, v] of RECOMMENDED_PREFS) {
|
||||
if (!Preferences.isSet(k)) {
|
||||
log.debug(`Setting recommended pref ${k} to ${v}`);
|
||||
Preferences.set(k, v);
|
||||
this.alteredPrefs.add(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ChromeUtils.import("chrome://marionette/content/server.js");
|
||||
let listener = new server.TCPListener(prefs.port);
|
||||
|
@ -302,9 +549,11 @@ class MarionetteMainProcess {
|
|||
this.server = listener;
|
||||
} catch (e) {
|
||||
log.fatal("Remote protocol server failed to start", e);
|
||||
this.uninit();
|
||||
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
|
||||
}
|
||||
|
||||
env.set(ENV_ENABLED, "1");
|
||||
Services.obs.notifyObservers(this, NOTIFY_RUNNING, true);
|
||||
log.info(`Listening on port ${this.server.port}`);
|
||||
});
|
||||
|
@ -313,6 +562,11 @@ class MarionetteMainProcess {
|
|||
uninit() {
|
||||
if (this.running) {
|
||||
this.server.stop();
|
||||
for (let k of this.alteredPrefs) {
|
||||
log.debug(`Resetting recommended pref ${k}`);
|
||||
Preferences.reset(k);
|
||||
}
|
||||
this.alteredPrefs.clear();
|
||||
Services.obs.notifyObservers(this, NOTIFY_RUNNING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ error module
|
|||
.. js:autoclass:: InvalidSessionIDError
|
||||
.. js:autoclass:: JavaScriptError
|
||||
.. js:autoclass:: MoveTargetOutOfBoundsError
|
||||
.. js:autoclass:: NoAlertOpenError
|
||||
.. js:autoclass:: NoSuchAlertError
|
||||
.. js:autoclass:: NoSuchElementError
|
||||
.. js:autoclass:: NoSuchFrameError
|
||||
.. js:autoclass:: NoSuchWindowError
|
||||
|
|
|
@ -32,7 +32,7 @@ const {
|
|||
InvalidArgumentError,
|
||||
InvalidCookieDomainError,
|
||||
InvalidSelectorError,
|
||||
NoAlertOpenError,
|
||||
NoSuchAlertError,
|
||||
NoSuchFrameError,
|
||||
NoSuchWindowError,
|
||||
SessionNotCreatedError,
|
||||
|
@ -3162,7 +3162,7 @@ GeckoDriver.prototype.sendKeysToDialog = async function(cmd) {
|
|||
|
||||
GeckoDriver.prototype._checkIfAlertIsPresent = function() {
|
||||
if (!this.dialog || !this.dialog.ui) {
|
||||
throw new NoAlertOpenError("No modal dialog is currently open");
|
||||
throw new NoSuchAlertError("No modal dialog is currently open");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ const ERRORS = new Set([
|
|||
"InvalidSessionIDError",
|
||||
"JavaScriptError",
|
||||
"MoveTargetOutOfBoundsError",
|
||||
"NoAlertOpenError",
|
||||
"NoSuchAlertError",
|
||||
"NoSuchElementError",
|
||||
"NoSuchFrameError",
|
||||
"NoSuchWindowError",
|
||||
|
@ -418,7 +418,7 @@ class MoveTargetOutOfBoundsError extends WebDriverError {
|
|||
* An attempt was made to operate on a modal dialog when one was
|
||||
* not open.
|
||||
*/
|
||||
class NoAlertOpenError extends WebDriverError {
|
||||
class NoSuchAlertError extends WebDriverError {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.status = "no such alert";
|
||||
|
@ -554,7 +554,7 @@ const STATUSES = new Map([
|
|||
["invalid session id", InvalidSessionIDError],
|
||||
["javascript error", JavaScriptError],
|
||||
["move target out of bounds", MoveTargetOutOfBoundsError],
|
||||
["no alert open", NoAlertOpenError],
|
||||
["no such alert", NoSuchAlertError],
|
||||
["no such element", NoSuchElementError],
|
||||
["no such frame", NoSuchFrameError],
|
||||
["no such window", NoSuchWindowError],
|
||||
|
|
|
@ -6,12 +6,7 @@ from __future__ import absolute_import
|
|||
|
||||
import json
|
||||
|
||||
from marionette_driver.transport import (
|
||||
Command,
|
||||
Proto2Command,
|
||||
Proto2Response,
|
||||
Response,
|
||||
)
|
||||
from marionette_driver.transport import Command, Response
|
||||
|
||||
from marionette_harness import MarionetteTestCase
|
||||
|
||||
|
@ -116,46 +111,3 @@ class TestResponse(MessageTestCase):
|
|||
self.assertEquals(msg[1], resp.id)
|
||||
self.assertEquals(msg[2], resp.error)
|
||||
self.assertEquals(msg[3], resp.result)
|
||||
|
||||
|
||||
class TestProto2Command(MessageTestCase):
|
||||
def create(self, name="name", params="params"):
|
||||
return Proto2Command(name, params)
|
||||
|
||||
def test_initialise(self):
|
||||
cmd = self.create()
|
||||
self.assert_attr(cmd, "id")
|
||||
self.assert_attr(cmd, "name")
|
||||
self.assert_attr(cmd, "params")
|
||||
self.assertEqual(None, cmd.id)
|
||||
self.assertEqual("name", cmd.name)
|
||||
self.assertEqual("params", cmd.params)
|
||||
|
||||
def test_from_data_unknown(self):
|
||||
with self.assertRaises(ValueError):
|
||||
cmd = Proto2Command.from_data({})
|
||||
|
||||
|
||||
class TestProto2Response(MessageTestCase):
|
||||
def create(self, error="error", result="result"):
|
||||
return Proto2Response(error, result)
|
||||
|
||||
def test_initialise(self):
|
||||
resp = self.create()
|
||||
self.assert_attr(resp, "id")
|
||||
self.assert_attr(resp, "error")
|
||||
self.assert_attr(resp, "result")
|
||||
self.assertEqual(None, resp.id)
|
||||
self.assertEqual("error", resp.error)
|
||||
self.assertEqual("result", resp.result)
|
||||
|
||||
def test_from_data_error(self):
|
||||
data = {"error": "error"}
|
||||
resp = Proto2Response.from_data(data)
|
||||
self.assertEqual(data, resp.error)
|
||||
self.assertEqual(None, resp.result)
|
||||
|
||||
def test_from_data_result(self):
|
||||
resp = Proto2Response.from_data("result")
|
||||
self.assertEqual(None, resp.error)
|
||||
self.assertEqual("result", resp.result)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[test_marionette.py]
|
||||
[test_transport.py]
|
||||
[test_cli_arguments.py]
|
||||
skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921
|
||||
[test_geckoinstance.py]
|
||||
|
|
|
@ -14,7 +14,6 @@ const ServerSocket = CC(
|
|||
ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {GeckoDriver} = ChromeUtils.import("chrome://marionette/content/driver.js", {});
|
||||
|
@ -30,9 +29,6 @@ const {
|
|||
} = ChromeUtils.import("chrome://marionette/content/message.js", {});
|
||||
const {DebuggerTransport} = ChromeUtils.import("chrome://marionette/content/transport.js", {});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
|
||||
|
||||
const logger = Log.repository.getLogger("Marionette");
|
||||
|
||||
const {KeepWhenOffline, LoopbackOnly} = Ci.nsIServerSocket;
|
||||
|
@ -44,246 +40,8 @@ this.server = {};
|
|||
|
||||
const PROTOCOL_VERSION = 3;
|
||||
|
||||
const ENV_ENABLED = "MOZ_MARIONETTE";
|
||||
|
||||
const PREF_CONTENT_LISTENER = "marionette.contentListener";
|
||||
const PREF_PORT = "marionette.port";
|
||||
const PREF_RECOMMENDED = "marionette.prefs.recommended";
|
||||
|
||||
// Marionette sets preferences recommended for automation when it starts,
|
||||
// unless marionette.prefs.recommended has been set to false.
|
||||
// Where noted, some prefs should also be set in the profile passed to
|
||||
// Marionette to prevent them from affecting startup, since some of these
|
||||
// are checked before Marionette initialises.
|
||||
const RECOMMENDED_PREFS = new Map([
|
||||
|
||||
// Disable automatic downloading of new releases.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["app.update.auto", false],
|
||||
|
||||
// Disable automatically upgrading Firefox.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["app.update.enabled", false],
|
||||
|
||||
// Increase the APZ content response timeout in tests to 1 minute.
|
||||
// This is to accommodate the fact that test environments tends to be
|
||||
// slower than production environments (with the b2g emulator being
|
||||
// the slowest of them all), resulting in the production timeout value
|
||||
// sometimes being exceeded and causing false-positive test failures.
|
||||
//
|
||||
// (bug 1176798, bug 1177018, bug 1210465)
|
||||
["apz.content_response_timeout", 60000],
|
||||
|
||||
// Indicate that the download panel has been shown once so that
|
||||
// whichever download test runs first doesn't show the popup
|
||||
// inconsistently.
|
||||
["browser.download.panel.shown", true],
|
||||
|
||||
// Do not show the EULA notification.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.EULA.override", true],
|
||||
|
||||
// Turn off about:newtab and make use of about:blank instead for new
|
||||
// opened tabs.
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.newtabpage.enabled", false],
|
||||
|
||||
// Assume the about:newtab page's intro panels have been shown to not
|
||||
// depend on which test runs first and happens to open about:newtab
|
||||
["browser.newtabpage.introShown", true],
|
||||
|
||||
// Never start the browser in offline mode
|
||||
//
|
||||
// This should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.offline", false],
|
||||
|
||||
// Background thumbnails in particular cause grief, and disabling
|
||||
// thumbnails in general cannot hurt
|
||||
["browser.pagethumbnails.capturing_disabled", true],
|
||||
|
||||
// Disable safebrowsing components.
|
||||
//
|
||||
// These should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.safebrowsing.blockedURIs.enabled", false],
|
||||
["browser.safebrowsing.downloads.enabled", false],
|
||||
["browser.safebrowsing.passwords.enabled", false],
|
||||
["browser.safebrowsing.malware.enabled", false],
|
||||
["browser.safebrowsing.phishing.enabled", false],
|
||||
|
||||
// Disable updates to search engines.
|
||||
//
|
||||
// Should be set in profile.
|
||||
["browser.search.update", false],
|
||||
|
||||
// Do not restore the last open set of tabs if the browser has crashed
|
||||
["browser.sessionstore.resume_from_crash", false],
|
||||
|
||||
// Don't check for the default web browser during startup.
|
||||
//
|
||||
// These should also be set in the profile prior to starting Firefox,
|
||||
// as it is picked up at runtime.
|
||||
["browser.shell.checkDefaultBrowser", false],
|
||||
|
||||
// Start with a blank page (about:blank)
|
||||
["browser.startup.page", 0],
|
||||
|
||||
// Do not redirect user when a milstone upgrade of Firefox is detected
|
||||
["browser.startup.homepage_override.mstone", "ignore"],
|
||||
|
||||
// Disable browser animations
|
||||
["toolkit.cosmeticAnimations.enabled", false],
|
||||
|
||||
// Do not allow background tabs to be zombified, otherwise for tests
|
||||
// that open additional tabs, the test harness tab itself might get
|
||||
// unloaded
|
||||
["browser.tabs.disableBackgroundZombification", false],
|
||||
|
||||
// Do not warn when closing all other open tabs
|
||||
["browser.tabs.warnOnCloseOtherTabs", false],
|
||||
|
||||
// Do not warn when multiple tabs will be opened
|
||||
["browser.tabs.warnOnOpen", false],
|
||||
|
||||
// Disable first run splash page on Windows 10
|
||||
["browser.usedOnWindows10.introURL", ""],
|
||||
|
||||
// Disable the UI tour.
|
||||
//
|
||||
// Should be set in profile.
|
||||
["browser.uitour.enabled", false],
|
||||
|
||||
// Turn off search suggestions in the location bar so as not to trigger
|
||||
// network connections.
|
||||
["browser.urlbar.suggest.searches", false],
|
||||
|
||||
// Turn off the location bar search suggestions opt-in. It interferes with
|
||||
// tests that don't expect it to be there.
|
||||
["browser.urlbar.userMadeSearchSuggestionsChoice", true],
|
||||
|
||||
// Do not show datareporting policy notifications which can
|
||||
// interfere with tests
|
||||
[
|
||||
"datareporting.healthreport.documentServerURI",
|
||||
"http://%(server)s/dummy/healthreport/",
|
||||
],
|
||||
["datareporting.healthreport.logging.consoleEnabled", false],
|
||||
["datareporting.healthreport.service.enabled", false],
|
||||
["datareporting.healthreport.service.firstRun", false],
|
||||
["datareporting.healthreport.uploadEnabled", false],
|
||||
["datareporting.policy.dataSubmissionEnabled", false],
|
||||
["datareporting.policy.dataSubmissionPolicyAccepted", false],
|
||||
["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
|
||||
|
||||
// Disable popup-blocker
|
||||
["dom.disable_open_during_load", false],
|
||||
|
||||
// Enabling the support for File object creation in the content process
|
||||
["dom.file.createInChild", true],
|
||||
|
||||
// Disable the ProcessHangMonitor
|
||||
["dom.ipc.reportProcessHangs", false],
|
||||
|
||||
// Disable slow script dialogues
|
||||
["dom.max_chrome_script_run_time", 0],
|
||||
["dom.max_script_run_time", 0],
|
||||
|
||||
// Only load extensions from the application and user profile
|
||||
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
||||
//
|
||||
// Should be set in profile.
|
||||
["extensions.autoDisableScopes", 0],
|
||||
["extensions.enabledScopes", 5],
|
||||
|
||||
// Disable metadata caching for installed add-ons by default
|
||||
["extensions.getAddons.cache.enabled", false],
|
||||
|
||||
// Disable installing any distribution extensions or add-ons.
|
||||
// Should be set in profile.
|
||||
["extensions.installDistroAddons", false],
|
||||
|
||||
// Make sure Shield doesn't hit the network.
|
||||
["extensions.shield-recipe-client.api_url", ""],
|
||||
|
||||
["extensions.showMismatchUI", false],
|
||||
|
||||
// Turn off extension updates so they do not bother tests
|
||||
["extensions.update.enabled", false],
|
||||
["extensions.update.notifyUser", false],
|
||||
|
||||
// Make sure opening about:addons will not hit the network
|
||||
[
|
||||
"extensions.webservice.discoverURL",
|
||||
"http://%(server)s/dummy/discoveryURL",
|
||||
],
|
||||
|
||||
// Allow the application to have focus even it runs in the background
|
||||
["focusmanager.testmode", true],
|
||||
|
||||
// Disable useragent updates
|
||||
["general.useragent.updates.enabled", false],
|
||||
|
||||
// Always use network provider for geolocation tests so we bypass the
|
||||
// macOS dialog raised by the corelocation provider
|
||||
["geo.provider.testing", true],
|
||||
|
||||
// Do not scan Wifi
|
||||
["geo.wifi.scan", false],
|
||||
|
||||
// No hang monitor
|
||||
["hangmonitor.timeout", 0],
|
||||
|
||||
// Show chrome errors and warnings in the error console
|
||||
["javascript.options.showInConsole", true],
|
||||
|
||||
// Do not prompt for temporary redirects
|
||||
["network.http.prompt-temp-redirect", false],
|
||||
|
||||
// Disable speculative connections so they are not reported as leaking
|
||||
// when they are hanging around
|
||||
["network.http.speculative-parallel-limit", 0],
|
||||
|
||||
// Do not automatically switch between offline and online
|
||||
["network.manage-offline-status", false],
|
||||
|
||||
// Make sure SNTP requests do not hit the network
|
||||
["network.sntp.pools", "%(server)s"],
|
||||
|
||||
// Local documents have access to all other local documents,
|
||||
// including directory listings
|
||||
["security.fileuri.strict_origin_policy", false],
|
||||
|
||||
// Tests do not wait for the notification button security delay
|
||||
["security.notification_enable_delay", 0],
|
||||
|
||||
// Ensure blocklist updates do not hit the network
|
||||
["services.settings.server", "http://%(server)s/dummy/blocklist/"],
|
||||
|
||||
// Do not automatically fill sign-in forms with known usernames and
|
||||
// passwords
|
||||
["signon.autofillForms", false],
|
||||
|
||||
// Disable password capture, so that tests that include forms are not
|
||||
// influenced by the presence of the persistent doorhanger notification
|
||||
["signon.rememberSignons", false],
|
||||
|
||||
// Disable first-run welcome page
|
||||
["startup.homepage_welcome_url", "about:blank"],
|
||||
["startup.homepage_welcome_url.additional", ""],
|
||||
|
||||
// Prevent starting into safe mode after application crashes
|
||||
["toolkit.startup.max_resumed_crashes", -1],
|
||||
|
||||
]);
|
||||
|
||||
/**
|
||||
* Bootstraps Marionette and handles incoming client connections.
|
||||
|
@ -303,7 +61,6 @@ server.TCPListener = class {
|
|||
this.conns = new Set();
|
||||
this.nextConnID = 0;
|
||||
this.alive = false;
|
||||
this.alteredPrefs = new Set();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,23 +107,9 @@ server.TCPListener = class {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Preferences.get(PREF_RECOMMENDED)) {
|
||||
// set recommended prefs if they are not already user-defined
|
||||
for (let [k, v] of RECOMMENDED_PREFS) {
|
||||
if (!Preferences.isSet(k)) {
|
||||
logger.debug(`Setting recommended pref ${k} to ${v}`);
|
||||
Preferences.set(k, v);
|
||||
this.alteredPrefs.add(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start socket server and listening for connection attempts
|
||||
this.acceptConnections = true;
|
||||
|
||||
Preferences.set(PREF_PORT, this.port);
|
||||
env.set(ENV_ENABLED, "1");
|
||||
|
||||
this.alive = true;
|
||||
}
|
||||
|
||||
|
@ -375,12 +118,6 @@ server.TCPListener = class {
|
|||
return;
|
||||
}
|
||||
|
||||
for (let k of this.alteredPrefs) {
|
||||
logger.debug(`Resetting recommended pref ${k}`);
|
||||
Preferences.reset(k);
|
||||
}
|
||||
this.alteredPrefs.clear();
|
||||
|
||||
// Shutdown server socket, and no longer listen for new connections
|
||||
this.acceptConnections = false;
|
||||
this.alive = false;
|
||||
|
|
|
@ -15,7 +15,7 @@ const {
|
|||
InvalidSessionIDError,
|
||||
JavaScriptError,
|
||||
MoveTargetOutOfBoundsError,
|
||||
NoAlertOpenError,
|
||||
NoSuchAlertError,
|
||||
NoSuchElementError,
|
||||
NoSuchFrameError,
|
||||
NoSuchWindowError,
|
||||
|
@ -333,9 +333,9 @@ add_test(function test_JavaScriptError() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_NoAlertOpenError() {
|
||||
let err = new NoAlertOpenError("foo");
|
||||
equal("NoAlertOpenError", err.name);
|
||||
add_test(function test_NoSuchAlertError() {
|
||||
let err = new NoSuchAlertError("foo");
|
||||
equal("NoSuchAlertError", err.name);
|
||||
equal("foo", err.message);
|
||||
equal("no such alert", err.status);
|
||||
ok(err instanceof WebDriverError);
|
||||
|
|
|
@ -155,6 +155,8 @@ class PaymentDialog extends PaymentStateSubscriberMixin(HTMLElement) {
|
|||
switch (state.completionState) {
|
||||
case "initial":
|
||||
case "processing":
|
||||
case "success":
|
||||
case "fail":
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid completionState");
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
<button id="setShippingError">Shipping Error</button>
|
||||
<button id="setStateDefault">Default</button>
|
||||
<button id="setStateProcessing">Processing</button>
|
||||
<button id="setStateSuccess">Success</button>
|
||||
<button id="setStateFail">Fail</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -293,6 +293,18 @@ let buttonActions = {
|
|||
completionState: "processing",
|
||||
});
|
||||
},
|
||||
|
||||
setStateSuccess() {
|
||||
requestStore.setState({
|
||||
completionState: "success",
|
||||
});
|
||||
},
|
||||
|
||||
setStateFail() {
|
||||
requestStore.setState({
|
||||
completionState: "fail",
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
window.addEventListener("click", function onButtonClick(evt) {
|
||||
|
|
|
@ -82,7 +82,9 @@ payment-dialog > footer {
|
|||
border: none;
|
||||
}
|
||||
|
||||
payment-dialog[changes-prevented][completion-state="processing"] #pay {
|
||||
payment-dialog[changes-prevented][completion-state="fail"] #pay,
|
||||
payment-dialog[changes-prevented][completion-state="processing"] #pay,
|
||||
payment-dialog[changes-prevented][completion-state="success"] #pay {
|
||||
/* Show the pay button above #disabled-overlay */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
<!ENTITY cancelPaymentButton.label "Cancel">
|
||||
<!ENTITY approvePaymentButton.label "Pay">
|
||||
<!ENTITY processingPaymentButton.label "Processing">
|
||||
<!ENTITY successPaymentButton.label "Done">
|
||||
<!ENTITY failPaymentButton.label "Fail">
|
||||
<!ENTITY orderDetailsLabel "Order Details">
|
||||
<!ENTITY orderTotalLabel "Total">
|
||||
]>
|
||||
|
@ -87,7 +89,9 @@
|
|||
<button id="cancel">&cancelPaymentButton.label;</button>
|
||||
<button id="pay"
|
||||
data-initial-label="&approvePaymentButton.label;"
|
||||
data-processing-label="&processingPaymentButton.label;"></button>
|
||||
data-processing-label="&processingPaymentButton.label;"
|
||||
data-fail-label="&failPaymentButton.label;"
|
||||
data-success-label="&successPaymentButton.label;"></button>
|
||||
</footer>
|
||||
</section>
|
||||
<section id="order-details-overlay" hidden="hidden">
|
||||
|
|
|
@ -36,6 +36,12 @@ Test the payment-dialog custom element
|
|||
|
||||
let el1;
|
||||
|
||||
let completionStates = [
|
||||
["processing", "Processing"],
|
||||
["success", "Done"],
|
||||
["fail", "Fail"],
|
||||
];
|
||||
|
||||
/* test that:
|
||||
the view-all-items button exists
|
||||
that clicking it changes the state on the store
|
||||
|
@ -117,10 +123,12 @@ add_task(async function test_completionState() {
|
|||
let payButton = document.getElementById("pay");
|
||||
is(payButton.textContent, "Pay", "Check default label");
|
||||
ok(!payButton.disabled, "Button is enabled");
|
||||
await el1.requestStore.setState({completionState: "processing"});
|
||||
await asyncElementRendered();
|
||||
is(payButton.textContent, "Processing", "Check processing label");
|
||||
ok(!payButton.disabled, "Button is still enabled");
|
||||
for (let [completionState, label] of completionStates) {
|
||||
await el1.requestStore.setState({completionState});
|
||||
await asyncElementRendered();
|
||||
is(payButton.textContent, label, "Check payButton label");
|
||||
ok(!payButton.disabled, "Button is still enabled");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_completionStateChangesPrevented() {
|
||||
|
@ -132,21 +140,19 @@ add_task(async function test_completionStateChangesPrevented() {
|
|||
is(payButton.textContent, "Pay", "Check default label");
|
||||
ok(!payButton.disabled, "Button is enabled");
|
||||
|
||||
await el1.requestStore.setState({
|
||||
changesPrevented: true,
|
||||
completionState: "processing",
|
||||
});
|
||||
await asyncElementRendered();
|
||||
is(payButton.textContent, "Processing", "Check processing label");
|
||||
ok(payButton.disabled, "Button is disabled");
|
||||
let {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
} = payButton.getBoundingClientRect();
|
||||
let visibleElement = document.elementFromPoint(x + width / 2, y + height / 2);
|
||||
ok(payButton === visibleElement, "Pay button is on top of the overlay");
|
||||
for (let [completionState, label] of completionStates) {
|
||||
await el1.requestStore.setState({
|
||||
changesPrevented: true,
|
||||
completionState,
|
||||
});
|
||||
await asyncElementRendered();
|
||||
is(payButton.textContent, label, "Check payButton label");
|
||||
ok(payButton.disabled, "Button is disabled");
|
||||
let rect = payButton.getBoundingClientRect();
|
||||
let visibleElement =
|
||||
document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
|
||||
ok(payButton === visibleElement, "Pay button is on top of the overlay");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_disconnect() {
|
||||
|
|
|
@ -310,14 +310,17 @@ class SyncedBookmarksMirror {
|
|||
* The current local time, in seconds.
|
||||
* @param {Number} [options.remoteTimeSeconds]
|
||||
* The current server time, in seconds.
|
||||
* @param {String[]} [options.weakUpload]
|
||||
* GUIDs of bookmarks to weakly upload.
|
||||
* @return {Object.<String, BookmarkChangeRecord>}
|
||||
* A changeset containing locally changed and reconciled records to
|
||||
* upload to the server, and to store in the mirror once upload
|
||||
* succeeds.
|
||||
*/
|
||||
async apply({ localTimeSeconds = Date.now() / 1000,
|
||||
remoteTimeSeconds = 0 } = {}) {
|
||||
let hasChanges = await this.hasChanges();
|
||||
remoteTimeSeconds = 0,
|
||||
weakUpload = [] } = {}) {
|
||||
let hasChanges = weakUpload.length > 0 || (await this.hasChanges());
|
||||
if (!hasChanges) {
|
||||
MirrorLog.debug("No changes detected in both mirror and Places");
|
||||
return {};
|
||||
|
@ -425,7 +428,7 @@ class SyncedBookmarksMirror {
|
|||
await this.noteObserverChanges(observersToNotify);
|
||||
|
||||
MirrorLog.debug("Staging locally changed items for upload");
|
||||
await this.stageItemsToUpload();
|
||||
await this.stageItemsToUpload(weakUpload);
|
||||
|
||||
MirrorLog.debug("Fetching records for local items to upload");
|
||||
let changeRecords = await this.fetchLocalChangeRecords();
|
||||
|
@ -1472,8 +1475,21 @@ class SyncedBookmarksMirror {
|
|||
* items. The change counter in Places is the persistent record of items that
|
||||
* we need to upload, so, if upload is interrupted or fails, we'll stage the
|
||||
* items again on the next sync.
|
||||
*
|
||||
* @param {String[]} weakUpload
|
||||
* GUIDs of bookmarks to weakly upload.
|
||||
*/
|
||||
async stageItemsToUpload() {
|
||||
async stageItemsToUpload(weakUpload) {
|
||||
// Stage explicit weak uploads such as repair responses.
|
||||
for (let chunk of PlacesSyncUtils.chunkArray(weakUpload,
|
||||
SQLITE_MAX_VARIABLE_NUMBER)) {
|
||||
await this.db.execute(`
|
||||
INSERT INTO itemsToWeaklyReupload(id)
|
||||
SELECT b.id FROM moz_bookmarks b
|
||||
WHERE b.guid IN (${new Array(chunk.length).fill("?").join(",")})`,
|
||||
chunk);
|
||||
}
|
||||
|
||||
// Stage remotely changed items with older local creation dates. These are
|
||||
// tracked "weakly": if the upload is interrupted or fails, we won't
|
||||
// reupload the record on the next sync.
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_missing_children() {
|
||||
let buf = await openMirror("missing_childen");
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_duping() {
|
||||
let buf = await openMirror("duping");
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_complex_orphaning() {
|
||||
let buf = await openMirror("complex_orphaning");
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_explicit_weakupload() {
|
||||
let buf = await openMirror("weakupload");
|
||||
|
||||
await PlacesUtils.bookmarks.insertTree({
|
||||
guid: PlacesUtils.bookmarks.menuGuid,
|
||||
children: [{
|
||||
guid: "mozBmk______",
|
||||
url: "https://mozilla.org",
|
||||
title: "Mozilla",
|
||||
tags: ["moz", "dot", "org"],
|
||||
}],
|
||||
});
|
||||
await buf.store(shuffle([{
|
||||
id: "menu",
|
||||
type: "folder",
|
||||
children: ["mozBmk______"],
|
||||
}, {
|
||||
id: "mozBmk______",
|
||||
type: "bookmark",
|
||||
title: "Mozilla",
|
||||
bmkUri: "https://mozilla.org",
|
||||
tags: ["moz", "dot", "org"],
|
||||
}]), { needsMerge: false });
|
||||
await PlacesTestUtils.markBookmarksAsSynced();
|
||||
|
||||
let changesToUpload = await buf.apply({
|
||||
weakUpload: ["mozBmk______"]
|
||||
});
|
||||
|
||||
ok("mozBmk______" in changesToUpload);
|
||||
equal(changesToUpload.mozBmk______.counter, 0);
|
||||
|
||||
await buf.finalize();
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesSyncUtils.bookmarks.reset();
|
||||
});
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_no_changes() {
|
||||
let buf = await openMirror("nochanges");
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_livemarks() {
|
||||
let { site, stopServer } = makeLivemarkServer();
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_value_structure_conflict() {
|
||||
let buf = await openMirror("value_structure_conflict");
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function test_value_combo() {
|
||||
let buf = await openMirror("value_combo");
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ support-files =
|
|||
[test_bookmark_corruption.js]
|
||||
[test_bookmark_deduping.js]
|
||||
[test_bookmark_deletion.js]
|
||||
[test_bookmark_explicit_weakupload.js]
|
||||
[test_bookmark_haschanges.js]
|
||||
[test_bookmark_kinds.js]
|
||||
[test_bookmark_structure_changes.js]
|
||||
|
|
|
@ -647,7 +647,7 @@ var AddonRepository = {
|
|||
|
||||
if (typeof aEntry.ratings == "object") {
|
||||
addon.averageRating = Math.min(5, aEntry.ratings.average);
|
||||
addon.reviewCount = aEntry.ratings.count;
|
||||
addon.reviewCount = aEntry.ratings.text_count;
|
||||
}
|
||||
|
||||
addon.reviewURL = aEntry.ratings_url;
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
"32": "http://localhost/repo/1/icon.png"
|
||||
},
|
||||
"ratings": {
|
||||
"count": 1111,
|
||||
"count": 1234,
|
||||
"text_count": 1111,
|
||||
"average": 1
|
||||
},
|
||||
"homepage": "http://localhost/repo/1/homepage.html",
|
||||
|
@ -95,7 +96,8 @@
|
|||
}
|
||||
],
|
||||
"ratings": {
|
||||
"count": 1112,
|
||||
"count": 2223,
|
||||
"text_count": 1112,
|
||||
"average": 2
|
||||
},
|
||||
"homepage": "http://localhost/repo/2/homepage.html",
|
||||
|
|
|
@ -49,7 +49,8 @@
|
|||
}
|
||||
],
|
||||
"ratings": {
|
||||
"count": 1111,
|
||||
"count": 1234,
|
||||
"text_count": 1111,
|
||||
"average": 4
|
||||
},
|
||||
"ratings_url": "http://localhost:%PORT%/review1.html",
|
||||
|
|
|
@ -66,7 +66,6 @@ toolbarbutton[checked="true"]:not([disabled="true"]) {
|
|||
padding-bottom: 2px;
|
||||
padding-inline-start: 4px;
|
||||
padding-inline-end: 2px;
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
|
|
|
@ -16,31 +16,26 @@
|
|||
var path = require("path");
|
||||
var helpers = require("../helpers");
|
||||
var globals = require("../globals");
|
||||
var modules = helpers.modulesGlobalData;
|
||||
|
||||
const placesOverlayFiles = [
|
||||
"toolkit/content/globalOverlay.js",
|
||||
"browser/base/content/utilityOverlay.js",
|
||||
"browser/components/places/content/controller.js",
|
||||
"browser/components/places/content/treeView.js"
|
||||
"browser/base/content/utilityOverlay.js"
|
||||
];
|
||||
|
||||
const extraPlacesDefinitions = [
|
||||
// Straight definitions.
|
||||
{name: "Cc", writable: false},
|
||||
{name: "Ci", writable: false},
|
||||
{name: "Cr", writable: false},
|
||||
{name: "Cu", writable: false},
|
||||
// Via Components.utils / XPCOMUtils.defineLazyModuleGetter (and map to
|
||||
// Via Components.utils, defineModuleGetter, defineLazyModuleGetters or
|
||||
// defineLazyScriptGetter (and map to
|
||||
// single) variable.
|
||||
{name: "XPCOMUtils", writable: false},
|
||||
{name: "Task", writable: false},
|
||||
{name: "PlacesUtils", writable: false},
|
||||
{name: "PlacesUIUtils", writable: false},
|
||||
{name: "PlacesTransactions", writable: false}
|
||||
];
|
||||
|
||||
const placesOverlayModules = [
|
||||
"PlacesUtils.jsm"
|
||||
{name: "PlacesTransactions", writable: false},
|
||||
{name: "ForgetAboutSite", writable: false},
|
||||
{name: "PlacesTreeView", writable: false},
|
||||
{name: "PlacesInsertionPoint", writable: false},
|
||||
{name: "PlacesController", writable: false},
|
||||
{name: "PlacesControllerDragHelper", writable: false}
|
||||
];
|
||||
|
||||
function getScriptGlobals() {
|
||||
|
@ -54,14 +49,6 @@ function getScriptGlobals() {
|
|||
}
|
||||
}
|
||||
|
||||
for (let file of placesOverlayModules) {
|
||||
if (file in modules) {
|
||||
for (let globalVar of modules[file]) {
|
||||
fileGlobals.push({name: globalVar, writable: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileGlobals.concat(extraPlacesDefinitions);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче