mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge m-c to m-i, a=release to defeat a buggy hook
This commit is contained in:
commit
34d760eb72
@ -166,7 +166,8 @@ ProcessGlobal.prototype = {
|
||||
let args = message.arguments;
|
||||
let stackTrace = '';
|
||||
|
||||
if (message.level == 'assert' || message.level == 'error' || message.level == 'trace') {
|
||||
if (message.stacktrace &&
|
||||
(message.level == 'assert' || message.level == 'error' || message.level == 'trace')) {
|
||||
stackTrace = Array.map(message.stacktrace, formatStackFrame).join('\n');
|
||||
} else {
|
||||
stackTrace = formatStackFrame(message);
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "16383ec2bf3ed46f893b15b3fab2892e9fadc4e7",
|
||||
"git_revision": "e370e6beecd28785beef8c7ff299cf788693f0cc",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "2b1fea55c45ae4b59eb077840bfe5361ecd48d54",
|
||||
"revision": "e4abf3a2e6a68bafbeec52cdc2a388ff7b9adf3d",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -2982,6 +2982,14 @@
|
||||
<gfxBlacklistEntry blockID="g511"> <os>WINNT 5.1</os> <vendor>0x8086</vendor> <feature>DIRECT3D_9_LAYERS, WEBGL_ANGLE</feature> <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus> <driverVersion>6.14.10.5218</driverVersion> <driverVersionComparator>LESS_THAN</driverVersionComparator> </gfxBlacklistEntry>
|
||||
</gfxItems>
|
||||
|
||||
<certItems>
|
||||
<certItem issuerName="MIGQMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDE2MDQGA1UEAxMtQ09NT0RPIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB">
|
||||
<serialNumber>D9UltDPl4XVfSSqQOvdiwQ==</serialNumber>
|
||||
</certItem>
|
||||
<certItem issuerName="MDIxCzAJBgNVBAYTAkNOMQ4wDAYDVQQKEwVDTk5JQzETMBEGA1UEAxMKQ05OSUMgUk9PVA==">
|
||||
<serialNumber>STMAjg==</serialNumber>
|
||||
</certItem>
|
||||
</certItems>
|
||||
|
||||
|
||||
</blocklist>
|
@ -258,7 +258,7 @@ const gXPInstallObserver = {
|
||||
label: gNavigatorBundle.getString("addonInstallRestartButton"),
|
||||
accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
|
||||
callback: function() {
|
||||
Application.restart();
|
||||
BrowserUtils.restartApplication();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -374,7 +374,7 @@ var LightWeightThemeWebInstaller = {
|
||||
label: gNavigatorBundle.getString("lwthemeNeedsRestart.button"),
|
||||
accessKey: gNavigatorBundle.getString("lwthemeNeedsRestart.accesskey"),
|
||||
callback: function () {
|
||||
Application.restart();
|
||||
BrowserUtils.restartApplication();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -104,6 +104,7 @@ let ReadingListUI = {
|
||||
}
|
||||
|
||||
document.getElementById(READINGLIST_COMMAND_ID).setAttribute("hidden", !enabled);
|
||||
document.getElementById(READINGLIST_COMMAND_ID).setAttribute("disabled", !enabled);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -149,7 +149,7 @@
|
||||
sidebarurl="chrome://browser/content/history/history-panel.xul"
|
||||
oncommand="SidebarUI.toggle('viewHistorySidebar');"/>
|
||||
|
||||
<broadcaster id="readingListSidebar" hidden="true" autoCheck="false"
|
||||
<broadcaster id="readingListSidebar" hidden="true" autoCheck="false" disabled="true"
|
||||
sidebartitle="&readingList.label;" type="checkbox" group="sidebar"
|
||||
sidebarurl="chrome://browser/content/readinglist/sidebar.xhtml"
|
||||
oncommand="SidebarUI.toggle('readingListSidebar');"/>
|
||||
|
@ -2558,11 +2558,7 @@ let gMenuButtonUpdateBadge = {
|
||||
// If the update is successfully applied, or if the updater has fallen back
|
||||
// to non-staged updates, add a badge to the hamburger menu to indicate an
|
||||
// update will be applied once the browser restarts.
|
||||
let badge = document.getAnonymousElementByAttribute(PanelUI.menuButton,
|
||||
"class",
|
||||
"toolbarbutton-badge");
|
||||
badge.style.backgroundColor = '#74BF43';
|
||||
PanelUI.menuButton.setAttribute("badge", "\u2B06");
|
||||
PanelUI.menuButton.setAttribute("update-status", "succeeded");
|
||||
|
||||
let brandBundle = document.getElementById("bundle_brand");
|
||||
let brandShortName = brandBundle.getString("brandShortName");
|
||||
@ -2580,6 +2576,7 @@ let gMenuButtonUpdateBadge = {
|
||||
case STATE_FAILED:
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
PanelUI.menuButton.setAttribute("update-status", "failed");
|
||||
PanelUI.menuButton.setAttribute("badge", "!");
|
||||
|
||||
stringId = "appmenu.updateFailed.description";
|
||||
|
@ -3924,8 +3924,8 @@
|
||||
<!-- Deprecated stuff, implemented for backwards compatibility. -->
|
||||
<method name="enterTabbedMode">
|
||||
<body>
|
||||
Application.console.log("enterTabbedMode is an obsolete method and " +
|
||||
"will be removed in a future release.");
|
||||
Services.console.logStringMessage("enterTabbedMode is an obsolete method and " +
|
||||
"will be removed in a future release.");
|
||||
</body>
|
||||
</method>
|
||||
<field name="mTabbedMode" readonly="true">true</field>
|
||||
|
@ -68,11 +68,6 @@ ServerClient.prototype = {
|
||||
},
|
||||
|
||||
_removeToken(token) {
|
||||
// XXX - remove this check once tokencaching landsin FxA.
|
||||
if (!this.fxa.removeCachedOAuthToken) {
|
||||
dump("XXX - token caching support is yet to land - can't remove token!");
|
||||
return;
|
||||
}
|
||||
return this.fxa.removeCachedOAuthToken({token});
|
||||
},
|
||||
|
||||
|
@ -106,9 +106,12 @@ let AnimationsController = {
|
||||
"setCurrentTime");
|
||||
this.hasMutationEvents = yield target.actorHasMethod("animations",
|
||||
"stopAnimationPlayerUpdates");
|
||||
this.hasSetPlaybackRate = yield target.actorHasMethod("animationplayer",
|
||||
"setPlaybackRate");
|
||||
|
||||
this.onPanelVisibilityChange = this.onPanelVisibilityChange.bind(this);
|
||||
this.onNewNodeFront = this.onNewNodeFront.bind(this);
|
||||
this.onAnimationMutations = this.onAnimationMutations.bind(this);
|
||||
|
||||
this.startListeners();
|
||||
|
||||
@ -151,6 +154,9 @@ let AnimationsController = {
|
||||
gInspector.selection.off("new-node-front", this.onNewNodeFront);
|
||||
gInspector.sidebar.off("select", this.onPanelVisibilityChange);
|
||||
gToolbox.off("select", this.onPanelVisibilityChange);
|
||||
if (this.isListeningToMutations) {
|
||||
this.animationsFront.off("mutations", this.onAnimationMutations);
|
||||
}
|
||||
},
|
||||
|
||||
isPanelVisible: function() {
|
||||
@ -213,6 +219,34 @@ let AnimationsController = {
|
||||
|
||||
this.animationPlayers = yield this.animationsFront.getAnimationPlayersForNode(nodeFront);
|
||||
this.startAllAutoRefresh();
|
||||
|
||||
// Start listening for animation mutations only after the first method call
|
||||
// otherwise events won't be sent.
|
||||
if (!this.isListeningToMutations && this.hasMutationEvents) {
|
||||
this.animationsFront.on("mutations", this.onAnimationMutations);
|
||||
this.isListeningToMutations = true;
|
||||
}
|
||||
}),
|
||||
|
||||
onAnimationMutations: Task.async(function*(changes) {
|
||||
// Insert new players into this.animationPlayers when new animations are
|
||||
// added.
|
||||
for (let {type, player} of changes) {
|
||||
if (type === "added") {
|
||||
this.animationPlayers.push(player);
|
||||
player.startAutoRefresh();
|
||||
}
|
||||
|
||||
if (type === "removed") {
|
||||
player.stopAutoRefresh();
|
||||
yield player.release();
|
||||
let index = this.animationPlayers.indexOf(player);
|
||||
this.animationPlayers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Let the UI know the list has been updated.
|
||||
this.emit(this.PLAYERS_UPDATED_EVENT, this.animationPlayers);
|
||||
}),
|
||||
|
||||
startAllAutoRefresh: function() {
|
||||
|
@ -19,7 +19,7 @@
|
||||
<span class="label">&allAnimations;</span>
|
||||
<button id="toggle-all" standalone="true" class="devtools-button"></button>
|
||||
</div>
|
||||
<div id="players" class="theme-toolbar"></div>
|
||||
<div id="players"></div>
|
||||
<div id="error-message">
|
||||
<p>&invalidElement;</p>
|
||||
<p>&selectElement;</p>
|
||||
|
@ -187,8 +187,12 @@ function PlayerWidget(player, containerEl) {
|
||||
this.onRewindBtnClick = this.onRewindBtnClick.bind(this);
|
||||
this.onFastForwardBtnClick = this.onFastForwardBtnClick.bind(this);
|
||||
this.onCurrentTimeChanged = this.onCurrentTimeChanged.bind(this);
|
||||
this.onPlaybackRateChanged = this.onPlaybackRateChanged.bind(this);
|
||||
|
||||
this.metaDataComponent = new PlayerMetaDataHeader();
|
||||
if (AnimationsController.hasSetPlaybackRate) {
|
||||
this.rateComponent = new PlaybackRateSelector();
|
||||
}
|
||||
}
|
||||
|
||||
PlayerWidget.prototype = {
|
||||
@ -211,6 +215,9 @@ PlayerWidget.prototype = {
|
||||
this.stopTimelineAnimation();
|
||||
this.stopListeners();
|
||||
this.metaDataComponent.destroy();
|
||||
if (this.rateComponent) {
|
||||
this.rateComponent.destroy();
|
||||
}
|
||||
|
||||
this.el.remove();
|
||||
this.playPauseBtnEl = this.rewindBtnEl = this.fastForwardBtnEl = null;
|
||||
@ -226,6 +233,9 @@ PlayerWidget.prototype = {
|
||||
this.fastForwardBtnEl.addEventListener("click", this.onFastForwardBtnClick);
|
||||
this.currentTimeEl.addEventListener("input", this.onCurrentTimeChanged);
|
||||
}
|
||||
if (this.rateComponent) {
|
||||
this.rateComponent.on("rate-changed", this.onPlaybackRateChanged);
|
||||
}
|
||||
},
|
||||
|
||||
stopListeners: function() {
|
||||
@ -236,6 +246,9 @@ PlayerWidget.prototype = {
|
||||
this.fastForwardBtnEl.removeEventListener("click", this.onFastForwardBtnClick);
|
||||
this.currentTimeEl.removeEventListener("input", this.onCurrentTimeChanged);
|
||||
}
|
||||
if (this.rateComponent) {
|
||||
this.rateComponent.off("rate-changed", this.onPlaybackRateChanged);
|
||||
}
|
||||
},
|
||||
|
||||
createMarkup: function() {
|
||||
@ -247,7 +260,7 @@ PlayerWidget.prototype = {
|
||||
}
|
||||
});
|
||||
|
||||
this.metaDataComponent.createMarkup(this.el);
|
||||
this.metaDataComponent.init(this.el);
|
||||
this.metaDataComponent.render(state);
|
||||
|
||||
// Timeline widget.
|
||||
@ -293,6 +306,11 @@ PlayerWidget.prototype = {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.rateComponent) {
|
||||
this.rateComponent.init(playbackControlsEl);
|
||||
this.rateComponent.render(state);
|
||||
}
|
||||
|
||||
// Sliders container.
|
||||
let slidersContainerEl = createNode({
|
||||
parent: timelineEl,
|
||||
@ -378,19 +396,30 @@ PlayerWidget.prototype = {
|
||||
this.setCurrentTime(parseFloat(time), true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Executed when the playback rate dropdown value changes in the playbackrate
|
||||
* component.
|
||||
*/
|
||||
onPlaybackRateChanged: function(e, rate) {
|
||||
this.setPlaybackRate(rate);
|
||||
},
|
||||
|
||||
/**
|
||||
* Whenever a player state update is received.
|
||||
*/
|
||||
onStateChanged: function() {
|
||||
let state = this.player.state;
|
||||
|
||||
this.updateWidgetState(state);
|
||||
this.metaDataComponent.render(state);
|
||||
if (this.rateComponent) {
|
||||
this.rateComponent.render(state);
|
||||
}
|
||||
|
||||
switch (state.playState) {
|
||||
case "finished":
|
||||
this.stopTimelineAnimation();
|
||||
this.displayTime(this.player.state.duration);
|
||||
this.stopListeners();
|
||||
this.displayTime(this.player.state.currentTime);
|
||||
break;
|
||||
case "running":
|
||||
this.startTimelineAnimation();
|
||||
@ -399,6 +428,10 @@ PlayerWidget.prototype = {
|
||||
this.stopTimelineAnimation();
|
||||
this.displayTime(this.player.state.currentTime);
|
||||
break;
|
||||
case "idle":
|
||||
this.stopTimelineAnimation();
|
||||
this.displayTime(0);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -429,16 +462,25 @@ PlayerWidget.prototype = {
|
||||
yield this.player.setCurrentTime(time);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Set the playback rate of the animation.
|
||||
* @param {Number} rate.
|
||||
* @return {Promise} Resolves when the rate has been set.
|
||||
*/
|
||||
setPlaybackRate: function(rate) {
|
||||
if (!AnimationsController.hasSetPlaybackRate) {
|
||||
throw new Error("This server version doesn't support setting animations' playbackRate");
|
||||
}
|
||||
|
||||
return this.player.setPlaybackRate(rate);
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause the animation player via this widget.
|
||||
* @return {Promise} Resolves when the player is paused, the button is
|
||||
* switched to the right state, and the timeline animation is stopped.
|
||||
*/
|
||||
pause: function() {
|
||||
if (this.player.state.playState === "finished") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch to the right className on the element right away to avoid waiting
|
||||
// for the next state update to change the playPause icon.
|
||||
this.updateWidgetState({playState: "paused"});
|
||||
@ -452,10 +494,6 @@ PlayerWidget.prototype = {
|
||||
* switched to the right state, and the timeline animation is started.
|
||||
*/
|
||||
play: function() {
|
||||
if (this.player.state.playState === "finished") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch to the right className on the element right away to avoid waiting
|
||||
// for the next state update to change the playPause icon.
|
||||
this.updateWidgetState({playState: "running"});
|
||||
@ -479,7 +517,8 @@ PlayerWidget.prototype = {
|
||||
let start = performance.now();
|
||||
let loop = () => {
|
||||
this.rafID = requestAnimationFrame(loop);
|
||||
let now = state.currentTime + performance.now() - start;
|
||||
let delta = (performance.now() - start) * state.playbackRate;
|
||||
let now = state.currentTime + delta;
|
||||
this.displayTime(now);
|
||||
};
|
||||
|
||||
@ -540,7 +579,7 @@ function PlayerMetaDataHeader() {
|
||||
}
|
||||
|
||||
PlayerMetaDataHeader.prototype = {
|
||||
createMarkup: function(containerEl) {
|
||||
init: function(containerEl) {
|
||||
// The main title element.
|
||||
this.el = createNode({
|
||||
parent: containerEl,
|
||||
@ -683,6 +722,87 @@ PlayerMetaDataHeader.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* UI component responsible for displaying the playback rate drop-down in each
|
||||
* player widget, updating it when the state changes, and emitting events when
|
||||
* the user selects a new value.
|
||||
* The parent UI component for this should drive its updates by calling
|
||||
* render(state) whenever it wants the component to update.
|
||||
*/
|
||||
function PlaybackRateSelector() {
|
||||
this.currentRate = null;
|
||||
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
PlaybackRateSelector.prototype = {
|
||||
PRESETS: [.1, .5, 1, 2, 5, 10],
|
||||
|
||||
init: function(containerEl) {
|
||||
// This component is simple enough that we can re-create the markup every
|
||||
// time it's rendered. So here we only store the parentEl.
|
||||
this.parentEl = containerEl;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.removeSelect();
|
||||
this.parentEl = this.el = null;
|
||||
},
|
||||
|
||||
removeSelect: function() {
|
||||
if (this.el) {
|
||||
this.el.removeEventListener("change", this.onSelectionChanged);
|
||||
this.el.remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the ordered list of presets, including the current playbackRate if
|
||||
* different from the existing presets.
|
||||
*/
|
||||
getCurrentPresets: function({playbackRate}) {
|
||||
return [...new Set([...this.PRESETS, playbackRate])].sort((a,b) => a > b);
|
||||
},
|
||||
|
||||
render: function(state) {
|
||||
if (state.playbackRate === this.currentRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeSelect();
|
||||
|
||||
this.el = createNode({
|
||||
parent: this.parentEl,
|
||||
nodeType: "select",
|
||||
attributes: {
|
||||
"class": "rate devtools-button"
|
||||
}
|
||||
});
|
||||
|
||||
for (let preset of this.getCurrentPresets(state)) {
|
||||
let option = createNode({
|
||||
parent: this.el,
|
||||
nodeType: "option",
|
||||
attributes: {
|
||||
value: preset,
|
||||
}
|
||||
});
|
||||
option.textContent = L10N.getFormatStr("player.playbackRateLabel", preset);
|
||||
if (preset === state.playbackRate) {
|
||||
option.setAttribute("selected", "");
|
||||
}
|
||||
}
|
||||
|
||||
this.el.addEventListener("change", this.onSelectionChanged);
|
||||
|
||||
this.currentRate = state.playbackRate;
|
||||
},
|
||||
|
||||
onSelectionChanged: function(e) {
|
||||
this.emit("rate-changed", parseFloat(this.el.value));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DOM node creation helper function.
|
||||
* @param {Object} Options to customize the node to be created.
|
||||
|
@ -18,9 +18,13 @@ support-files =
|
||||
[browser_animation_playerWidgets_have_control_buttons.js]
|
||||
[browser_animation_playerWidgets_meta_data.js]
|
||||
[browser_animation_playerWidgets_state_after_pause.js]
|
||||
[browser_animation_rate_select_shows_presets.js]
|
||||
[browser_animation_refresh_on_added_animation.js]
|
||||
[browser_animation_refresh_on_removed_animation.js]
|
||||
[browser_animation_refresh_when_active.js]
|
||||
[browser_animation_same_nb_of_playerWidgets_and_playerFronts.js]
|
||||
[browser_animation_setting_currentTime_works_and_pauses.js]
|
||||
[browser_animation_setting_playbackRate_works.js]
|
||||
[browser_animation_shows_player_on_valid_node.js]
|
||||
[browser_animation_timeline_animates.js]
|
||||
[browser_animation_timeline_is_enabled.js]
|
||||
@ -31,4 +35,5 @@ support-files =
|
||||
[browser_animation_toolbar_exists.js]
|
||||
[browser_animation_ui_updates_when_animation_changes.js]
|
||||
[browser_animation_ui_updates_when_animation_data_changes.js]
|
||||
[browser_animation_ui_updates_when_animation_rate_changes.js]
|
||||
[browser_animation_ui_updates_when_animation_time_changes.js]
|
||||
|
@ -25,15 +25,7 @@ add_task(function*() {
|
||||
info("Wait for both animations to end");
|
||||
|
||||
let promises = controller.animationPlayers.map(front => {
|
||||
let def = promise.defer();
|
||||
let onStateChanged = () => {
|
||||
if (front.state.playState === "finished") {
|
||||
front.off(front.AUTO_REFRESH_EVENT, onStateChanged);
|
||||
def.resolve();
|
||||
}
|
||||
};
|
||||
front.on(front.AUTO_REFRESH_EVENT, onStateChanged);
|
||||
return def.promise;
|
||||
return waitForPlayState(front, "finished");
|
||||
});
|
||||
|
||||
yield promise.all(promises);
|
||||
|
@ -28,15 +28,7 @@ add_task(function*() {
|
||||
let widget = panel.playerWidgets[0];
|
||||
let front = widget.player;
|
||||
|
||||
let def = promise.defer();
|
||||
let onStateChanged = () => {
|
||||
if (front.state.playState === "finished") {
|
||||
front.off(front.AUTO_REFRESH_EVENT, onStateChanged);
|
||||
def.resolve();
|
||||
}
|
||||
};
|
||||
front.on(front.AUTO_REFRESH_EVENT, onStateChanged);
|
||||
yield def.promise;
|
||||
yield waitForPlayState(front, "finished");
|
||||
|
||||
is(widget.currentTimeEl.value, front.state.duration,
|
||||
"The timeline slider has the right value");
|
||||
|
@ -25,6 +25,8 @@ add_task(function*() {
|
||||
"The second button is the rewind button");
|
||||
ok(container.children[2].classList.contains("ff"),
|
||||
"The third button is the fast-forward button");
|
||||
ok(container.querySelector("select"),
|
||||
"The container contains the playback rate select");
|
||||
|
||||
info("Faking an older server version by setting " +
|
||||
"AnimationsController.hasSetCurrentTime to false");
|
||||
@ -46,4 +48,23 @@ add_task(function*() {
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
controller.hasSetCurrentTime = true;
|
||||
|
||||
info("Faking an older server version by setting " +
|
||||
"AnimationsController.hasSetPlaybackRate to false");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
controller.hasSetPlaybackRate = false;
|
||||
|
||||
info("Selecting the animated node again");
|
||||
yield selectNode(".animated", inspector);
|
||||
|
||||
widget = panel.playerWidgets[0];
|
||||
container = widget.el.querySelector(".playback-controls");
|
||||
|
||||
ok(container, "The control buttons container still exists");
|
||||
ok(!container.querySelector("select"),
|
||||
"The playback rate select does not exist");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
controller.hasSetPlaybackRate = true;
|
||||
});
|
||||
|
@ -0,0 +1,49 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the playbackRate select element contains a list of presets and
|
||||
// and that if the animation has a current rate that is not part of this list,
|
||||
// it is added.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {inspector, panel} = yield openAnimationInspector();
|
||||
|
||||
info("Selecting the test node");
|
||||
yield selectNode(".animated", inspector);
|
||||
|
||||
info("Get the playback rate UI component");
|
||||
let widget = panel.playerWidgets[0];
|
||||
let rateComponent = widget.rateComponent;
|
||||
|
||||
let options = rateComponent.el.querySelectorAll("option");
|
||||
is(options.length, rateComponent.PRESETS.length,
|
||||
"The playback rate select contains the right number of options");
|
||||
|
||||
for (let i = 0; i < rateComponent.PRESETS.length; i ++) {
|
||||
is(options[i].value, rateComponent.PRESETS[i] + "",
|
||||
"The playback rate option " + i + " has the right preset value " +
|
||||
rateComponent.PRESETS[i]);
|
||||
}
|
||||
|
||||
info("Set a custom rate (not part of the presets) via the DOM");
|
||||
let onRateChanged = waitForStateCondition(widget.player, state => {
|
||||
return state.playbackRate === 3.6
|
||||
});
|
||||
yield executeInContent("Test:SetAnimationPlayerPlaybackRate", {
|
||||
selector: ".animated",
|
||||
animationIndex: 0,
|
||||
playbackRate: 3.6
|
||||
});
|
||||
yield onRateChanged;
|
||||
|
||||
options = rateComponent.el.querySelectorAll("option");
|
||||
is(options.length, rateComponent.PRESETS.length + 1,
|
||||
"The playback rate select contains the right number of options (presets + 1)");
|
||||
|
||||
ok([...options].find(option => option.value === "3.6"),
|
||||
"The custom rate is part of the select");
|
||||
});
|
@ -0,0 +1,34 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the panel content refreshes when new animations are added.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {toolbox, inspector, panel} = yield openAnimationInspector();
|
||||
|
||||
info("Select a non animated node");
|
||||
yield selectNode(".still", inspector);
|
||||
|
||||
is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
|
||||
"There are no player widgets in the panel");
|
||||
|
||||
info("Listen to the next UI update event");
|
||||
let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
|
||||
info("Start an animation on the node");
|
||||
yield executeInContent("devtools:test:setAttribute", {
|
||||
selector: ".still",
|
||||
attributeName: "class",
|
||||
attributeValue: "ball animated"
|
||||
});
|
||||
|
||||
yield onPanelUpdated;
|
||||
ok(true, "The panel update event was fired");
|
||||
|
||||
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
|
||||
"There is one player widget in the panel");
|
||||
});
|
@ -0,0 +1,62 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the panel content refreshes when animations are removed.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {toolbox, inspector, panel} = yield openAnimationInspector();
|
||||
|
||||
info("Select a animated node");
|
||||
yield selectNode(".animated", inspector);
|
||||
|
||||
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
|
||||
"There is one player widget in the panel");
|
||||
|
||||
info("Listen to the next UI update event");
|
||||
let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
|
||||
info("Remove the animation on the node by removing the class");
|
||||
yield executeInContent("devtools:test:setAttribute", {
|
||||
selector: ".animated",
|
||||
attributeName: "class",
|
||||
attributeValue: "ball still test-node"
|
||||
});
|
||||
|
||||
yield onPanelUpdated;
|
||||
ok(true, "The panel update event was fired");
|
||||
|
||||
is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
|
||||
"There are no player widgets in the panel anymore");
|
||||
|
||||
info("Add an finite animation on the node again, and wait for it to appear");
|
||||
onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
|
||||
yield executeInContent("devtools:test:setAttribute", {
|
||||
selector: ".test-node",
|
||||
attributeName: "class",
|
||||
attributeValue: "ball short"
|
||||
});
|
||||
yield onPanelUpdated;
|
||||
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
|
||||
"There is one player widget in the panel again");
|
||||
|
||||
info("Now wait until the animation finishes");
|
||||
let widget = panel.playerWidgets[0];
|
||||
yield waitForPlayState(widget.player, "finished")
|
||||
|
||||
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
|
||||
"There is still a player widget in the panel after the animation finished");
|
||||
|
||||
info("Checking that the animation's currentTime can still be set");
|
||||
info("Click at the center of the slider input");
|
||||
|
||||
let onPaused = waitForPlayState(widget.player, "paused");
|
||||
let input = widget.currentTimeEl;
|
||||
let win = input.ownerDocument.defaultView;
|
||||
EventUtils.synthesizeMouseAtCenter(input, {type: "mousedown"}, win);
|
||||
yield onPaused;
|
||||
ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
|
||||
});
|
@ -41,23 +41,3 @@ add_task(function*() {
|
||||
|
||||
yield checkPausedAt(widget, 2000);
|
||||
});
|
||||
|
||||
function* checkPausedAt(widget, time) {
|
||||
info("Wait for the next auto-update");
|
||||
|
||||
let onPaused = promise.defer();
|
||||
widget.player.on(widget.player.AUTO_REFRESH_EVENT, function onRefresh() {
|
||||
info("Still waiting for the player to pause");
|
||||
if (widget.player.state.playState === "paused") {
|
||||
ok(true, "The player's playState is paused");
|
||||
widget.player.off(widget.player.AUTO_REFRESH_EVENT, onRefresh);
|
||||
onPaused.resolve();
|
||||
}
|
||||
});
|
||||
yield onPaused.promise;
|
||||
|
||||
ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
|
||||
is(widget.player.state.currentTime, time,
|
||||
"The player front's currentTime was set to " + time);
|
||||
is(widget.currentTimeEl.value, time, "The input's value was set to " + time);
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that setting an animation's playback rate by selecting a rate in the
|
||||
// presets drop-down sets the rate accordingly.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {toolbox, inspector, panel} = yield openAnimationInspector();
|
||||
|
||||
info("Select an animated node");
|
||||
yield selectNode(".animated", inspector);
|
||||
|
||||
info("Get the player widget for this node");
|
||||
let widget = panel.playerWidgets[0];
|
||||
let select = widget.rateComponent.el;
|
||||
let win = select.ownerDocument.defaultView;
|
||||
|
||||
info("Click on the rate drop-down");
|
||||
EventUtils.synthesizeMouseAtCenter(select, {type: "mousedown"}, win);
|
||||
|
||||
info("Click on a rate option");
|
||||
let option = select.options[select.options.length - 1];
|
||||
EventUtils.synthesizeMouseAtCenter(option, {type: "mouseup"}, win);
|
||||
let selectedRate = parseFloat(option.value);
|
||||
|
||||
info("Check that the rate was changed on the player at the next update");
|
||||
yield waitForStateCondition(widget.player, ({playbackRate}) => playbackRate === selectedRate);
|
||||
is(widget.player.state.playbackRate, selectedRate,
|
||||
"The rate was changed successfully");
|
||||
});
|
@ -14,22 +14,25 @@ add_task(function*() {
|
||||
info("Select an animated node");
|
||||
yield selectNode(".animated", inspector);
|
||||
let widget = panel.playerWidgets[0];
|
||||
let player = widget.player;
|
||||
|
||||
info("Click the toggle button to pause all animations");
|
||||
let onRefresh = onceNextPlayerRefresh(widget.player);
|
||||
info("Listen to animation state changes and click the toggle button to " +
|
||||
"pause all animations");
|
||||
let onPaused = waitForPlayState(player, "paused");
|
||||
yield panel.toggleAll();
|
||||
yield onRefresh;
|
||||
yield onPaused;
|
||||
|
||||
info("Checking the selected node's animation player widget's state");
|
||||
is(widget.player.state.playState, "paused", "The player front's state is paused");
|
||||
is(player.state.playState, "paused", "The player front's state is paused");
|
||||
ok(widget.el.classList.contains("paused"), "The widget's UI is in paused state");
|
||||
|
||||
info("Click the toggle button to play all animations");
|
||||
onRefresh = onceNextPlayerRefresh(widget.player);
|
||||
info("Listen to animation state changes and click the toggle button to " +
|
||||
"play all animations");
|
||||
let onRunning = waitForPlayState(player, "running");
|
||||
yield panel.toggleAll();
|
||||
yield onRefresh;
|
||||
yield onRunning;
|
||||
|
||||
info("Checking the selected node's animation player widget's state again");
|
||||
is(widget.player.state.playState, "running", "The player front's state is running");
|
||||
is(player.state.playState, "running", "The player front's state is running");
|
||||
ok(widget.el.classList.contains("running"), "The widget's UI is in running state");
|
||||
});
|
||||
|
@ -16,6 +16,10 @@ add_task(function*() {
|
||||
|
||||
info("Get the player widget");
|
||||
let widget = panel.playerWidgets[0];
|
||||
let player = widget.player;
|
||||
|
||||
info("Wait for paused playState");
|
||||
let onPaused = waitForPlayState(player, "paused");
|
||||
|
||||
info("Pause the animation via the content DOM");
|
||||
yield executeInContent("Test:ToggleAnimationPlayer", {
|
||||
@ -24,13 +28,15 @@ add_task(function*() {
|
||||
pause: true
|
||||
});
|
||||
|
||||
info("Wait for the next state update");
|
||||
yield onceNextPlayerRefresh(widget.player);
|
||||
yield onPaused;
|
||||
|
||||
is(widget.player.state.playState, "paused", "The AnimationPlayerFront is paused");
|
||||
is(player.state.playState, "paused", "The AnimationPlayerFront is paused");
|
||||
ok(widget.el.classList.contains("paused"), "The button's state has changed");
|
||||
ok(!widget.rafID, "The smooth timeline animation has been stopped");
|
||||
|
||||
info("Wait for running playState");
|
||||
let onRunning = waitForPlayState(player, "running");
|
||||
|
||||
info("Play the animation via the content DOM");
|
||||
yield executeInContent("Test:ToggleAnimationPlayer", {
|
||||
selector: ".animated",
|
||||
@ -38,10 +44,9 @@ add_task(function*() {
|
||||
pause: false
|
||||
});
|
||||
|
||||
info("Wait for the next state update");
|
||||
yield onceNextPlayerRefresh(widget.player);
|
||||
yield onRunning;
|
||||
|
||||
is(widget.player.state.playState, "running", "The AnimationPlayerFront is running");
|
||||
is(player.state.playState, "running", "The AnimationPlayerFront is running");
|
||||
ok(widget.el.classList.contains("running"), "The button's state has changed");
|
||||
ok(widget.rafID, "The smooth timeline animation has been started");
|
||||
});
|
||||
|
@ -0,0 +1,47 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that setting an animation's playbackRate via the WebAnimations API (from
|
||||
// content), actually changes the rate in the corresponding widget too.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {inspector, panel} = yield openAnimationInspector();
|
||||
|
||||
info("Selecting the test node");
|
||||
yield selectNode(".animated", inspector);
|
||||
|
||||
info("Get the player widget");
|
||||
let widget = panel.playerWidgets[0];
|
||||
|
||||
info("Change the animation's playbackRate via the content DOM");
|
||||
let onRateChanged = waitForStateCondition(widget.player, state => {
|
||||
return state.playbackRate === 2;
|
||||
}, "playbackRate === 2");
|
||||
yield executeInContent("Test:SetAnimationPlayerPlaybackRate", {
|
||||
selector: ".animated",
|
||||
animationIndex: 0,
|
||||
playbackRate: 2
|
||||
});
|
||||
yield onRateChanged;
|
||||
|
||||
is(widget.rateComponent.el.value, "2",
|
||||
"The playbackRate select value was changed");
|
||||
|
||||
info("Change the animation's playbackRate again via the content DOM");
|
||||
onRateChanged = waitForStateCondition(widget.player, state => {
|
||||
return state.playbackRate === 0.3;
|
||||
}, "playbackRate === 0.3");
|
||||
yield executeInContent("Test:SetAnimationPlayerPlaybackRate", {
|
||||
selector: ".animated",
|
||||
animationIndex: 0,
|
||||
playbackRate: 0.3
|
||||
});
|
||||
yield onRateChanged;
|
||||
|
||||
is(widget.rateComponent.el.value, "0.3",
|
||||
"The playbackRate select value was changed again");
|
||||
});
|
@ -52,6 +52,27 @@ addMessageListener("Test:SetAnimationPlayerCurrentTime", function(msg) {
|
||||
sendAsyncMessage("Test:SetAnimationPlayerCurrentTime");
|
||||
});
|
||||
|
||||
/**
|
||||
* Change the playbackRate of one of the animation players of a given node.
|
||||
* @param {Object} data
|
||||
* - {String} selector The CSS selector to get the node (can be a "super"
|
||||
* selector).
|
||||
* - {Number} animationIndex The index of the node's animationPlayers to change.
|
||||
* - {Number} playbackRate The rate to set.
|
||||
*/
|
||||
addMessageListener("Test:SetAnimationPlayerPlaybackRate", function(msg) {
|
||||
let {selector, animationIndex, playbackRate} = msg.data;
|
||||
let node = superQuerySelector(selector);
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
let player = node.getAnimations()[animationIndex];
|
||||
player.playbackRate = playbackRate;
|
||||
|
||||
sendAsyncMessage("Test:SetAnimationPlayerPlaybackRate");
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the current playState of an animation player on a given node.
|
||||
* @param {Object} data
|
||||
|
@ -284,10 +284,8 @@ let togglePlayPauseButton = Task.async(function*(widget) {
|
||||
|
||||
yield onClicked;
|
||||
|
||||
// Wait for the next sate change event to make sure the state is updated
|
||||
yield waitForStateCondition(widget.player, state => {
|
||||
return state.playState === nextState;
|
||||
}, "after clicking the toggle button");
|
||||
// Wait until the state changes.
|
||||
yield waitForPlayState(widget.player, nextState);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -317,6 +315,37 @@ let waitForStateCondition = Task.async(function*(player, conditionCheck, desc=""
|
||||
return def.promise;
|
||||
});
|
||||
|
||||
/**
|
||||
* Wait for a player's auto-refresh events and stop when the playState is the
|
||||
* provided string.
|
||||
* @param {AnimationPlayerFront} player
|
||||
* @param {String} playState The playState to expect.
|
||||
* @return {Promise} Resolves when the playState has changed to the expected value.
|
||||
*/
|
||||
function waitForPlayState(player, playState) {
|
||||
return waitForStateCondition(player, state => {
|
||||
return state.playState === playState;
|
||||
}, "Waiting for animation to be " + playState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the player's auto-refresh events until the animation is paused.
|
||||
* When done, check its currentTime.
|
||||
* @param {PlayerWidget} widget.
|
||||
* @param {Numer} time.
|
||||
* @return {Promise} Resolves when the animation is paused and tests have ran.
|
||||
*/
|
||||
let checkPausedAt = Task.async(function*(widget, time) {
|
||||
info("Wait for the next auto-refresh");
|
||||
|
||||
yield waitForPlayState(widget.player, "paused");
|
||||
|
||||
ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
|
||||
is(widget.player.state.currentTime, time,
|
||||
"The player front's currentTime was set to " + time);
|
||||
is(widget.currentTimeEl.value, time, "The input's value was set to " + time);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the current playState of an animation player on a given node.
|
||||
*/
|
||||
|
@ -83,7 +83,7 @@ function testSetBreakpointBlankLine() {
|
||||
ok(!aResponse.error,
|
||||
"Should be able to set a breakpoint in a coffee source file on a blank line.");
|
||||
ok(aResponse.actualLocation,
|
||||
"Because 3 is empty, we should have an actualLocation.");
|
||||
"Because 7 is empty, we should have an actualLocation.");
|
||||
is(aResponse.actualLocation.source.url, COFFEE_URL,
|
||||
"actualLocation.actor should be source mapped to the coffee file.");
|
||||
is(aResponse.actualLocation.line, 8,
|
||||
|
@ -8,5 +8,5 @@ support-files =
|
||||
templates.json
|
||||
|
||||
[browser_tabs.js]
|
||||
skip-if = os == 'win' || e10s # Bug 1149289 - Intermittent on Windows, Bug 1072167 - browser_tabs.js test fails under e10s
|
||||
skip-if = e10s # Bug 1072167 - browser_tabs.js test fails under e10s
|
||||
[browser_widget.js]
|
||||
|
@ -28,6 +28,9 @@ function test() {
|
||||
|
||||
yield selectTabProject(win);
|
||||
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
yield win.UI.toolboxPromise;
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, TEST_URI, "Location is correct");
|
||||
is(project.name, "example.com: Test Tab", "Name is correct");
|
||||
@ -61,6 +64,8 @@ function selectTabProject(win) {
|
||||
yield waitForUpdate(win, "runtime-targets");
|
||||
let tabsNode = win.document.querySelector("#project-panel-tabs");
|
||||
let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
|
||||
let project = waitForUpdate(win, "project");
|
||||
tabNode.click();
|
||||
yield project;
|
||||
});
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
||||
"resource://gre/modules/Deprecated.jsm");
|
||||
|
||||
const APPLICATION_CID = Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66");
|
||||
const APPLICATION_CONTRACTID = "@mozilla.org/fuel/application;1";
|
||||
@ -734,6 +736,9 @@ var ApplicationFactory = {
|
||||
//=================================================
|
||||
// Application constructor
|
||||
function Application() {
|
||||
Deprecated.warning("FUEL is deprecated, you should use the add-on SDK instead.",
|
||||
"https://developer.mozilla.org/Add-ons/SDK/");
|
||||
|
||||
this.initToolkitHelpers();
|
||||
}
|
||||
|
||||
|
@ -46,3 +46,9 @@ player.infiniteIterationCount=∞
|
||||
# how long (in seconds) the animation lasts, or what is the animation's current
|
||||
# time (in seconds too);
|
||||
player.timeLabel=%Ss
|
||||
|
||||
# LOCALIZATION NOTE (player.playbackRateLabel):
|
||||
# This string is displayed in each animation player widget, as the label of
|
||||
# drop-down list items that can be used to change the rate at which the
|
||||
# animation runs (1x being the default, 2x being twice as fast).
|
||||
player.playbackRateLabel=%Sx
|
||||
|
@ -1132,26 +1132,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-confirmation"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
%include ../shared/notification-icons.inc.css
|
||||
|
||||
.popup-notification-description[popupid="addon-progress"],
|
||||
.popup-notification-description[popupid="addon-install-confirmation"] {
|
||||
@ -1163,92 +1144,13 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install-progress"],
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-radius: 2.5px 0 0 2.5px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
margin-top: -1px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#notification-popup-box:not([hidden]) + #identity-box {
|
||||
-moz-padding-start: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:-moz-focusring {
|
||||
outline: 1px dotted -moz-DialogText;
|
||||
}
|
||||
@ -1258,123 +1160,11 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
list-style-image: url(moz-icon://stock/gtk-dialog-info?size=16);
|
||||
}
|
||||
|
||||
.identity-notification-icon,
|
||||
#identity-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(moz-icon://stock/gtk-dialog-question?size=16);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bad-content-blocked-notification-icon,
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.bad-content-unblocked-notification-icon,
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
#pointerLock-cancel {
|
||||
margin: 0px;
|
||||
}
|
||||
@ -1453,18 +1243,6 @@ notification[value="translation"] menulist > .menulist-dropmarker {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
/* Loop/ Hello browser styles */
|
||||
|
||||
notification[value="loop-sharing-notification"] .button-menubutton-button {
|
||||
@ -2106,12 +1884,6 @@ toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
|
||||
/* Social toolbar item */
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
||||
}
|
||||
#social-undoactivation-button {
|
||||
-moz-margin-start: 0; /* override default label margin to match description margin */
|
||||
}
|
||||
@ -2188,28 +1960,6 @@ chatbox {
|
||||
border-top-right-radius: 2.5px;
|
||||
}
|
||||
|
||||
/* EME notifications */
|
||||
|
||||
.popup-notification-icon[popupid="drmContentPlaying"],
|
||||
#eme-notification-icon {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
|
||||
}
|
||||
|
||||
#eme-notification-icon:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
|
||||
}
|
||||
|
||||
#eme-notification-icon[firstplay=true] {
|
||||
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
|
||||
}
|
||||
|
||||
@keyframes emeTeachingMoment {
|
||||
0% {transform: translateX(0); }
|
||||
25% {transform: translateX(3px) }
|
||||
75% {transform: translateX(-3px) }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* Customization mode */
|
||||
|
||||
%include ../shared/customizableui/customizeMode.inc.css
|
||||
|
@ -86,6 +86,7 @@ browser.jar:
|
||||
skin/classic/browser/Toolbar-inverted.png
|
||||
skin/classic/browser/Toolbar-small.png
|
||||
skin/classic/browser/undoCloseTab.png (../shared/undoCloseTab.png)
|
||||
skin/classic/browser/update-badge.svg (../shared/update-badge.svg)
|
||||
skin/classic/browser/urlbar-arrow.png
|
||||
skin/classic/browser/session-restore.svg (../shared/incontent-icons/session-restore.svg)
|
||||
skin/classic/browser/tab-crashed.svg (../shared/incontent-icons/tab-crashed.svg)
|
||||
|
@ -3657,37 +3657,10 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
%include ../shared/notification-icons.inc.css
|
||||
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-radius: 2px 0 0 2px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#notification-popup-box {
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow@2x.png") 0 16 0 0 fill;
|
||||
}
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:-moz-focusring {
|
||||
@ -3699,278 +3672,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-32.png);
|
||||
}
|
||||
}
|
||||
|
||||
.identity-notification-icon,
|
||||
#identity-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
|
||||
}
|
||||
/* XXX: need HiDPI version */
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-32.png);
|
||||
}
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
}
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px);
|
||||
}
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.pointerLock-notification-icon,
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.pointerLock-notification-icon,
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
/* Translation */
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
|
||||
-moz-image-region: rect(0px, 32px, 32px, 0px);
|
||||
}
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
|
||||
-moz-image-region: rect(0px, 64px, 32px, 32px);
|
||||
}
|
||||
}
|
||||
|
||||
%include ../shared/translation/infobar.inc.css
|
||||
|
||||
notification[value="translation"] {
|
||||
@ -4123,42 +3826,6 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-confirmation"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-description[popupid="addon-progress"],
|
||||
.popup-notification-description[popupid="addon-install-confirmation"] {
|
||||
width: 27em;
|
||||
@ -4177,91 +3844,10 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
-moz-margin-start: 0 !important; /* override default label margin to match description margin */
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install-progress"],
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64@2x.png);
|
||||
}
|
||||
}
|
||||
#pointerLock-cancel {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
/* Popup Buttons */
|
||||
#identity-popup-more-info-button {
|
||||
@hudButton@
|
||||
@ -4482,22 +4068,6 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
|
||||
}
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#social-undoactivation-button {
|
||||
-moz-margin-start: 0; /* override default label margin to match description margin */
|
||||
}
|
||||
@ -4619,28 +4189,6 @@ window > chatbox {
|
||||
border-bottom-right-radius: @toolbarbuttonCornerRadius@;
|
||||
}
|
||||
|
||||
/* EME notifications */
|
||||
|
||||
.popup-notification-icon[popupid="drmContentPlaying"],
|
||||
#eme-notification-icon {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
|
||||
}
|
||||
|
||||
#eme-notification-icon:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
|
||||
}
|
||||
|
||||
#eme-notification-icon[firstplay=true] {
|
||||
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
|
||||
}
|
||||
|
||||
@keyframes emeTeachingMoment {
|
||||
0% {transform: translateX(0); }
|
||||
25% {transform: translateX(3px) }
|
||||
75% {transform: translateX(-3px) }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* Customization mode */
|
||||
|
||||
%include ../shared/customizableui/customizeMode.inc.css
|
||||
|
@ -131,6 +131,7 @@ browser.jar:
|
||||
skin/classic/browser/toolbarbutton-dropmarker.png
|
||||
skin/classic/browser/undoCloseTab.png (../shared/undoCloseTab.png)
|
||||
skin/classic/browser/undoCloseTab@2x.png (../shared/undoCloseTab@2x.png)
|
||||
skin/classic/browser/update-badge.svg (../shared/update-badge.svg)
|
||||
skin/classic/browser/urlbar-history-dropmarker.png
|
||||
skin/classic/browser/urlbar-history-dropmarker@2x.png
|
||||
skin/classic/browser/urlbar-arrow.png
|
||||
|
@ -106,6 +106,12 @@
|
||||
background-position: 100% 0, calc(100% - 1px) 0, calc(100% - 2px) 0;
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[update-status="succeeded"] .toolbarbutton-badge::after {
|
||||
content: url(chrome://browser/skin/update-badge.svg);
|
||||
background-color: #74BF43;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.panel-subviews {
|
||||
padding: 4px;
|
||||
background-clip: padding-box;
|
||||
|
@ -28,7 +28,7 @@ body {
|
||||
}
|
||||
|
||||
#toggle-all {
|
||||
border-width: 0px 1px;
|
||||
border-width: 0 0 0 1px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
@ -99,13 +99,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/* Disabled playerWidget when the animation has ended */
|
||||
|
||||
.finished {
|
||||
pointer-events: none;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
/* Animation title gutter, contains the name, duration, iteration */
|
||||
|
||||
.animation-title {
|
||||
@ -182,6 +175,12 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.timeline .rate {
|
||||
-moz-appearance: none;
|
||||
text-align: center;
|
||||
border-right: 1px solid var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
/* Slider (input type range) container */
|
||||
|
||||
.timeline .sliders-container {
|
||||
|
439
browser/themes/shared/notification-icons.inc.css
Normal file
439
browser/themes/shared/notification-icons.inc.css
Normal file
@ -0,0 +1,439 @@
|
||||
%if 0
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
%endif
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-confirmation"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install-progress"],
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
.identity-notification-icon,
|
||||
#identity-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
|
||||
/* XXX: need HiDPI version */
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bad-content-blocked-notification-icon,
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.bad-content-unblocked-notification-icon,
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
.pointerLock-notification-icon,
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
||||
}
|
||||
|
||||
/* EME notifications */
|
||||
|
||||
.popup-notification-icon[popupid="drmContentPlaying"],
|
||||
#eme-notification-icon {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
|
||||
}
|
||||
|
||||
#eme-notification-icon:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
|
||||
}
|
||||
|
||||
#eme-notification-icon[firstplay=true] {
|
||||
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
|
||||
}
|
||||
|
||||
@keyframes emeTeachingMoment {
|
||||
0% {transform: translateX(0); }
|
||||
25% {transform: translateX(3px) }
|
||||
75% {transform: translateX(-3px) }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
/* HiDPI notification icons */
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#notification-popup-box {
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow@2x.png") 0 16 0 0 fill;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-32.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-32.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16@2x.png);
|
||||
}
|
||||
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px);
|
||||
}
|
||||
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16@2x.png);
|
||||
}
|
||||
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16@2x.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16@2x.png);
|
||||
}
|
||||
|
||||
.pointerLock-notification-icon,
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16@2x.png);
|
||||
}
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
|
||||
-moz-image-region: rect(0px, 32px, 32px, 0px);
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
|
||||
-moz-image-region: rect(0px, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
|
||||
}
|
||||
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
|
||||
}
|
||||
}
|
||||
%endif
|
3
browser/themes/shared/update-badge.svg
Normal file
3
browser/themes/shared/update-badge.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10px" height="10px">
|
||||
<polygon points="4,9 4,5 2,5 5,1 8,5 6,5 6,9" fill="#fff"/>
|
||||
</svg>
|
After Width: | Height: | Size: 138 B |
@ -2,15 +2,9 @@
|
||||
* 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/. */
|
||||
|
||||
%define WINDOWS_AERO
|
||||
%include browser.css
|
||||
%undef WINDOWS_AERO
|
||||
|
||||
%define glassActiveBorderColor rgb(37, 44, 51)
|
||||
%define glassInactiveBorderColor rgb(102, 102, 102)
|
||||
|
||||
%include downloads/indicator-aero.css
|
||||
|
||||
@media not all and (-moz-windows-classic) {
|
||||
#main-window[sizemode="normal"] > #tab-view-deck > #browser-panel > #navigator-toolbox > #toolbar-menubar {
|
||||
margin-top: 1px;
|
||||
|
@ -112,10 +112,8 @@
|
||||
transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media not all and (-moz-windows-compositor),
|
||||
not all and (-moz-windows-default-theme) {
|
||||
%endif
|
||||
#main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar:not(:-moz-lwtheme),
|
||||
#main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
|
||||
color: CaptionText;
|
||||
@ -129,13 +127,9 @@
|
||||
#main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) {
|
||||
color: inherit;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media not all and (-moz-windows-compositor) {
|
||||
%endif
|
||||
#main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
|
||||
visibility: hidden;
|
||||
}
|
||||
@ -144,9 +138,7 @@
|
||||
-moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
|
||||
visibility: visible;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
/**
|
||||
* In the classic themes, the titlebar has a horizontal gradient, which is
|
||||
@ -313,15 +305,11 @@
|
||||
box-shadow: 0 1px 0 @toolbarHighlight@ inset;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media not all and (-moz-windows-compositor) {
|
||||
%endif
|
||||
#TabsToolbar[collapsed="true"] + #nav-bar {
|
||||
border-top-style: none !important;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#personal-bookmarks {
|
||||
min-height: 24px;
|
||||
@ -335,13 +323,11 @@
|
||||
background-color: -moz-dialog;
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
@media (-moz-windows-default-theme) {
|
||||
@media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
|
||||
#main-window[tabsintitlebar][sizemode="normal"] #toolbar-menubar {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
/* ::::: titlebar ::::: */
|
||||
|
||||
@ -370,11 +356,13 @@
|
||||
}
|
||||
|
||||
.titlebar-placeholder[type="caption-buttons"] {
|
||||
%ifdef WINDOWS_AERO
|
||||
margin-left: 22px; /* additional space for Aero Snap */
|
||||
%else
|
||||
margin-left: 10px;
|
||||
%endif
|
||||
margin-left: 22px; /* space needed for Aero Snap */
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
.titlebar-placeholder[type="caption-buttons"] {
|
||||
margin-left: 10px; /* less space needed on XP because there's no Aero Snap */
|
||||
}
|
||||
}
|
||||
|
||||
/* titlebar command buttons */
|
||||
@ -589,7 +577,6 @@ menuitem.bookmark-item {
|
||||
%include ../shared/toolbarbuttons.inc.css
|
||||
%include ../shared/menupanel.inc.css
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
@media (-moz-windows-theme: luna-silver) {
|
||||
:-moz-any(@primaryToolbarButtons@),
|
||||
#bookmarks-menu-button.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
@ -600,7 +587,6 @@ menuitem.bookmark-item {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver.png)
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
|
||||
@ -682,10 +668,9 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
:root {
|
||||
--toolbarbutton-hover-background: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
@ -723,9 +708,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
|
||||
@ -803,10 +786,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
box-shadow: var(--toolbarbutton-hover-boxshadow);
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
#nav-bar .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
|
||||
#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled]) + .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled])::before {
|
||||
@ -834,9 +816,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
box-shadow: 0 0 1px hsla(210,54%,20%,.03),
|
||||
0 0 2px hsla(210,54%,20%,.1);
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
|
||||
@ -850,10 +830,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
transition-duration: 10ms;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
|
||||
@ -873,9 +852,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
background-color: var(--toolbarbutton-checkedhover-backgroundcolor);
|
||||
transition: background-color .4s;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#TabsToolbar .toolbarbutton-1,
|
||||
#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
@ -984,10 +961,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
0 1px 0 0 hsla(210,80%,20%,.1) inset !important;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
#back-button > .toolbarbutton-icon {
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)) !important;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
@ -1020,9 +996,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
0 1px 0 hsla(210,54%,20%,.65) !important;
|
||||
transition: none;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
@ -1140,18 +1114,14 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
||||
border: 1px solid ThreeDShadow;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
border-radius: 2px;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#urlbar {
|
||||
-moz-padding-end: 2px;
|
||||
@ -1421,17 +1391,14 @@ richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-si
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media not all and (-moz-windows-default-theme) {
|
||||
%endif
|
||||
@media (-moz-os-version: windows-xp),
|
||||
not all and (-moz-windows-default-theme) {
|
||||
.ac-result-type-keyword[selected="true"],
|
||||
.autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected),
|
||||
richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
.ac-result-type-tag,
|
||||
.autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
|
||||
@ -1454,14 +1421,12 @@ richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-si
|
||||
color: -moz-nativehyperlinktext;
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
@media (-moz-windows-default-theme) {
|
||||
@media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
|
||||
.ac-url-text:not([selected="true"]),
|
||||
.ac-action-text:not([selected="true"]) {
|
||||
color: #008800;
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
|
||||
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
|
||||
@ -1469,9 +1434,8 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media not all and (-moz-windows-default-theme) {
|
||||
%endif
|
||||
@media (-moz-os-version: windows-xp),
|
||||
not all and (-moz-windows-default-theme) {
|
||||
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
|
||||
-moz-image-region: rect(11px, 16px, 22px, 0);
|
||||
}
|
||||
@ -1481,9 +1445,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
.ac-action-text[selected="true"] {
|
||||
color: inherit !important;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
|
||||
color: GrayText;
|
||||
@ -1808,14 +1770,12 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
margin-bottom: calc(-1 * var(--tab-toolbar-navbar-overlap)); /* overlap the nav-bar's top border */
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
@media (-moz-windows-default-theme) {
|
||||
@media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
|
||||
#main-window[sizemode=normal] #TabsToolbar {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
%include ../shared/tabs.inc.css
|
||||
|
||||
@ -1852,7 +1812,6 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
}
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
/* Use lighter colors of buttons and text in the titlebar on luna-blue */
|
||||
@media (-moz-windows-theme: luna-blue) {
|
||||
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
|
||||
@ -1861,7 +1820,6 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
background-image: url("chrome://browser/skin/tabbrowser/tab-separator-luna-blue.png");
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
#TabsToolbar[brighttext] .tab-close-button:not(:hover):not([visuallyselected="true"]) {
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px) !important;
|
||||
@ -2146,26 +2104,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-confirmation"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
%include ../shared/notification-icons.inc.css
|
||||
|
||||
.popup-notification-description[popupid="addon-progress"],
|
||||
.popup-notification-description[popupid="addon-install-confirmation"] {
|
||||
@ -2177,212 +2116,15 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install-progress"],
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-radius: 2.5px 0 0 2.5px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:-moz-focusring {
|
||||
outline: 1px dotted -moz-DialogText;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
.identity-notification-icon,
|
||||
#identity-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bad-content-blocked-notification-icon,
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.bad-content-unblocked-notification-icon,
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
#pointerLock-cancel {
|
||||
margin: 0px;
|
||||
}
|
||||
@ -2464,18 +2206,6 @@ notification[value="translation"] {
|
||||
}
|
||||
}
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
.translation-menupopup {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
@ -2702,12 +2432,6 @@ toolbarpaletteitem[place="palette"] > #switch-to-metro-button {
|
||||
list-style-image: url(chrome://browser/skin/Metro_Glyph-menuPanel.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
||||
}
|
||||
#social-undoactivation-button {
|
||||
-moz-margin-start: 0; /* override default label margin to match description margin */
|
||||
}
|
||||
@ -2811,28 +2535,6 @@ chatbox {
|
||||
border-top-right-radius: 2.5px;
|
||||
}
|
||||
|
||||
/* EME notifications */
|
||||
|
||||
.popup-notification-icon[popupid="drmContentPlaying"],
|
||||
#eme-notification-icon {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
|
||||
}
|
||||
|
||||
#eme-notification-icon:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
|
||||
}
|
||||
|
||||
#eme-notification-icon[firstplay=true] {
|
||||
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
|
||||
}
|
||||
|
||||
@keyframes emeTeachingMoment {
|
||||
0% {transform: translateX(0); }
|
||||
25% {transform: translateX(3px) }
|
||||
75% {transform: translateX(-3px) }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* Customization mode */
|
||||
|
||||
%include ../shared/customizableui/customizeMode.inc.css
|
||||
@ -2936,32 +2638,32 @@ chatbox {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
#TabsToolbar > .private-browsing-indicator {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing-mask-tabstrip-XPVista7.png");
|
||||
}
|
||||
|
||||
@media not all and (-moz-windows-classic) {
|
||||
#private-browsing-indicator-titlebar > .private-browsing-indicator {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7-tall.png");
|
||||
height: 28px;
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
#TabsToolbar > .private-browsing-indicator {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing-mask-tabstrip-XPVista7.png");
|
||||
}
|
||||
|
||||
/* We're intentionally using the titlebar asset here for fullscreen mode.
|
||||
* See bug 1008183.
|
||||
*/
|
||||
#main-window[inFullscreen] #TabsToolbar > .private-browsing-indicator {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7.png");
|
||||
}
|
||||
@media not all and (-moz-windows-classic) {
|
||||
#private-browsing-indicator-titlebar > .private-browsing-indicator {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7-tall.png");
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
#main-window[sizemode="maximized"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
|
||||
top: -5px;
|
||||
}
|
||||
#main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
|
||||
top: -1px;
|
||||
/* We're intentionally using the titlebar asset here for fullscreen mode.
|
||||
* See bug 1008183.
|
||||
*/
|
||||
#main-window[inFullscreen] #TabsToolbar > .private-browsing-indicator {
|
||||
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7.png");
|
||||
}
|
||||
|
||||
#main-window[sizemode="maximized"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
|
||||
top: -5px;
|
||||
}
|
||||
#main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
@media (-moz-windows-classic) {
|
||||
/* We're intentionally using the titlebar asset here for fullscreen mode.
|
||||
@ -3000,3 +2702,8 @@ chatbox {
|
||||
-moz-margin-start: -28px;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
%include browser-aero.css
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%define WINDOWS_AERO
|
||||
%include panelUIOverlay.css
|
||||
%undef WINDOWS_AERO
|
@ -129,24 +129,24 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
/* Win8 and beyond. */
|
||||
@media not all and (-moz-os-version: windows-vista) {
|
||||
@media not all and (-moz-os-version: windows-win7) {
|
||||
panelview .toolbarbutton-1,
|
||||
.subviewbutton,
|
||||
.widget-overflow-list .toolbarbutton-1,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
#BMB_bookmarksPopup menupopup[placespopup=true] > hbox,
|
||||
#edit-controls@inAnyPanel@,
|
||||
#zoom-controls@inAnyPanel@,
|
||||
#edit-controls@inAnyPanel@ > toolbarbutton,
|
||||
#zoom-controls@inAnyPanel@ > toolbarbutton {
|
||||
border-radius: 0;
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
@media not all and (-moz-os-version: windows-vista) {
|
||||
@media not all and (-moz-os-version: windows-win7) {
|
||||
panelview .toolbarbutton-1,
|
||||
.subviewbutton,
|
||||
.widget-overflow-list .toolbarbutton-1,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
#BMB_bookmarksPopup menupopup[placespopup=true] > hbox,
|
||||
#edit-controls@inAnyPanel@,
|
||||
#zoom-controls@inAnyPanel@,
|
||||
#edit-controls@inAnyPanel@ > toolbarbutton,
|
||||
#zoom-controls@inAnyPanel@ > toolbarbutton {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
@media not all and (-moz-windows-default-theme) {
|
||||
#edit-controls@inAnyPanel@ > #copy-button,
|
||||
|
@ -1,7 +0,0 @@
|
||||
% This Source Code Form is subject to the terms of the Mozilla Public
|
||||
% License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
% file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
%define WINDOWS_AERO
|
||||
%include devedition.css
|
||||
%undef WINDOWS_AERO
|
@ -1,35 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%define WINDOWS_AERO
|
||||
%include allDownloadsViewOverlay.css
|
||||
%undef WINDOWS_AERO
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
/*
|
||||
-moz-appearance: menuitem is almost right, but the hover effect is not
|
||||
transparent and is lighter than desired.
|
||||
|
||||
Copied from the autocomplete richlistbox styling in
|
||||
toolkit/themes/windows/global/autocomplete.css
|
||||
|
||||
This styling should be kept in sync with the style from the above file.
|
||||
*/
|
||||
#downloadsRichListBox > richlistitem.download[selected] {
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
/* four gradients for the bevel highlights on each edge, one for blue background */
|
||||
background-image:
|
||||
linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px),
|
||||
linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px),
|
||||
linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px),
|
||||
linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px),
|
||||
linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
|
||||
background-clip: content-box;
|
||||
border-radius: 6px;
|
||||
outline: 1px solid rgb(124,163,206);
|
||||
-moz-outline-radius: 3px;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
}
|
@ -10,21 +10,27 @@
|
||||
|
||||
#downloadsRichListBox > richlistitem.download {
|
||||
height: 6em;
|
||||
%ifndef WINDOWS_AERO
|
||||
padding: 5px 8px;
|
||||
%endif
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
#downloadsRichListBox > richlistitem.download {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.downloadTypeIcon {
|
||||
-moz-margin-end: 8px;
|
||||
%ifdef WINDOWS_AERO
|
||||
-moz-margin-start: 8px;
|
||||
%endif
|
||||
/* explicitly size the icon, so size doesn't vary on hidpi systems */
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
.downloadTypeIcon {
|
||||
-moz-margin-start: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.blockedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/Error.png");
|
||||
}
|
||||
@ -105,56 +111,86 @@ richlistitem.download:hover > .downloadButton.downloadRetry:active {
|
||||
-moz-image-region: rect(32px, 64px, 48px, 48px);
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
richlistitem.download[selected] > .downloadButton.downloadConfirmBlock,
|
||||
richlistitem.download[selected] > .downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 80px, 16px, 64px);
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
richlistitem.download[selected] > .downloadButton.downloadConfirmBlock,
|
||||
richlistitem.download[selected] > .downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 80px, 16px, 64px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock,
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:hover,
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:hover {
|
||||
-moz-image-region: rect(0px, 112px, 16px, 96px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:active,
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 16px, 112px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected] > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 80px, 32px, 64px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected] > .downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(32px, 80px, 48px, 64px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(32px, 96px, 48px, 80px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:hover {
|
||||
-moz-image-region: rect(32px, 112px, 48px, 96px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:active {
|
||||
-moz-image-region: rect(32px, 128px, 48px, 112px);
|
||||
}
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock,
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadCancel {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
/*
|
||||
-moz-appearance: menuitem is almost right, but the hover effect is not
|
||||
transparent and is lighter than desired.
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:hover,
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:hover {
|
||||
-moz-image-region: rect(0px, 112px, 16px, 96px);
|
||||
}
|
||||
Copied from the autocomplete richlistbox styling in
|
||||
toolkit/themes/windows/global/autocomplete.css
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:active,
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:active {
|
||||
-moz-image-region: rect(0px, 128px, 16px, 112px);
|
||||
This styling should be kept in sync with the style from the above file.
|
||||
*/
|
||||
#downloadsRichListBox > richlistitem.download[selected] {
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
/* four gradients for the bevel highlights on each edge, one for blue background */
|
||||
background-image:
|
||||
linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px),
|
||||
linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px),
|
||||
linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px),
|
||||
linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px),
|
||||
linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
|
||||
background-clip: content-box;
|
||||
border-radius: 6px;
|
||||
outline: 1px solid rgb(124,163,206);
|
||||
-moz-outline-radius: 3px;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
richlistitem.download[selected] > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 80px, 32px, 64px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected] > .downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(32px, 80px, 48px, 64px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(32px, 96px, 48px, 80px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:hover {
|
||||
-moz-image-region: rect(32px, 112px, 48px, 96px);
|
||||
}
|
||||
|
||||
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:active {
|
||||
-moz-image-region: rect(32px, 128px, 48px, 112px);
|
||||
}
|
||||
%endif
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%define WINDOWS_AERO
|
||||
%include downloads.css
|
||||
%undef WINDOWS_AERO
|
||||
|
||||
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
|
||||
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
|
||||
richlistitem[type="download"] {
|
||||
border: 1px solid transparent;
|
||||
border-bottom: 1px solid hsl(213,40%,90%);
|
||||
}
|
||||
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
|
||||
border: 1px solid hsl(213,45%,65%);
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.3) inset;
|
||||
background-image: linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
|
||||
color: black;
|
||||
}
|
||||
}
|
@ -32,16 +32,13 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
#downloadsHistory {
|
||||
color: -moz-nativehyperlinktext;
|
||||
#downloadsHistory {
|
||||
color: -moz-nativehyperlinktext;
|
||||
}
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#downloadsPanel[keyfocus] > #downloadsFooter > #downloadsHistory:focus {
|
||||
outline: 1px -moz-dialogtext dotted;
|
||||
@ -69,31 +66,32 @@
|
||||
box-shadow: 0 2px 0 0 hsla(210,4%,10%,.1) inset;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
@media (-moz-windows-default-theme) {
|
||||
#downloadsFooter {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
transition-duration: 0s;
|
||||
}
|
||||
@media (-moz-windows-default-theme) {
|
||||
#downloadsFooter {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
transition-duration: 0s;
|
||||
}
|
||||
|
||||
#downloadsFooter,
|
||||
#downloadsFooter:hover,
|
||||
#downloadsFooter:hover:active {
|
||||
%ifdef WINDOWS_AERO
|
||||
background-color: #f1f5fb;
|
||||
%else
|
||||
background-color: hsla(216,45%,88%,.98);
|
||||
%endif
|
||||
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
|
||||
#downloadsFooter,
|
||||
#downloadsFooter:hover,
|
||||
#downloadsFooter:hover:active {
|
||||
background-color: #f1f5fb;
|
||||
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
#downloadsFooter,
|
||||
#downloadsFooter:hover,
|
||||
#downloadsFooter:hover:active {
|
||||
background-color: hsla(216,45%,88%,.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
/*** Downloads Summary and List items ***/
|
||||
|
||||
@ -131,6 +129,14 @@ richlistitem[type="download"] {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
|
||||
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
|
||||
richlistitem[type="download"] {
|
||||
border: 1px solid transparent;
|
||||
border-bottom: 1px solid hsl(213,40%,90%);
|
||||
}
|
||||
}
|
||||
|
||||
richlistitem[type="download"]:first-child {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
@ -227,27 +233,35 @@ richlistitem[type="download"]:first-child {
|
||||
box-shadow: 0 1px 0 0 hsla(210,4%,10%,.05) inset;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
|
||||
border-radius: 3px;
|
||||
outline: 0;
|
||||
border-top: 1px solid hsla(0,0%,100%,.2);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.2);
|
||||
background-color: Highlight;
|
||||
color: HighlightText;
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
|
||||
border-radius: 3px;
|
||||
outline: 0;
|
||||
border-top: 1px solid hsla(0,0%,100%,.2);
|
||||
border-bottom: 1px solid hsla(0,0%,0%,.2);
|
||||
background-color: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover:active {
|
||||
background-color: Highlight;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover:active {
|
||||
background-color: Highlight;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
|
||||
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
|
||||
border: 1px solid hsl(213,45%,65%);
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.3) inset;
|
||||
background-image: linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
/*** Button icons ***/
|
||||
|
||||
@ -280,26 +294,26 @@ richlistitem[type="download"]:hover > stack > .downloadButton.downloadShow:hover
|
||||
richlistitem[type="download"]:hover > stack > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
%ifndef WINDOWS_AERO
|
||||
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
@media (-moz-os-version: windows-xp) {
|
||||
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
}
|
||||
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 64px, 32px, 48px);
|
||||
}
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
|
||||
-moz-image-region: rect(16px, 96px, 32px, 80px);
|
||||
}
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
|
||||
-moz-image-region: rect(16px, 112px, 32px, 96px);
|
||||
}
|
||||
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
|
||||
-moz-image-region: rect(16px, 128px, 32px, 112px);
|
||||
}
|
||||
%endif
|
||||
|
||||
.downloadButton.downloadRetry {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0px);
|
||||
|
@ -1,8 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#downloads-indicator-counter {
|
||||
/* Bug 812345 added this... */
|
||||
margin-bottom: -1px;
|
||||
}
|
@ -133,6 +133,13 @@ toolbar[brighttext] #downloads-button:not([counter])[attention] > #downloads-ind
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
#downloads-indicator-counter {
|
||||
/* Bug 812345 added this... */
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
toolbar[brighttext] #downloads-indicator-counter {
|
||||
color: white;
|
||||
text-shadow: 0 0 1px rgba(0,0,0,.7),
|
||||
|
@ -23,9 +23,7 @@ browser.jar:
|
||||
skin/classic/browser/aboutTabCrashed.css (../shared/aboutTabCrashed.css)
|
||||
skin/classic/browser/actionicon-tab.png
|
||||
* skin/classic/browser/browser.css
|
||||
* skin/classic/browser/browser-aero.css
|
||||
* skin/classic/browser/devedition.css
|
||||
* skin/classic/browser/devedition-aero.css
|
||||
* skin/classic/browser/browser-lightweightTheme.css
|
||||
skin/classic/browser/click-to-play-warning-stripes.png
|
||||
skin/classic/browser/content-contextmenu.svg
|
||||
@ -119,6 +117,7 @@ browser.jar:
|
||||
skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
|
||||
skin/classic/browser/undoCloseTab.png (../shared/undoCloseTab.png)
|
||||
skin/classic/browser/undoCloseTab@2x.png (../shared/undoCloseTab@2x.png)
|
||||
skin/classic/browser/update-badge.svg (../shared/update-badge.svg)
|
||||
skin/classic/browser/urlbar-arrow.png
|
||||
skin/classic/browser/urlbar-popup-blocked.png
|
||||
skin/classic/browser/urlbar-history-dropmarker.png
|
||||
@ -165,15 +164,13 @@ browser.jar:
|
||||
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
|
||||
skin/classic/browser/customizableui/panelarrow-customizeTip.png (../shared/customizableui/panelarrow-customizeTip.png)
|
||||
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
|
||||
* skin/classic/browser/customizableui/panelUIOverlay-aero.css (customizableui/panelUIOverlay-aero.css)
|
||||
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
|
||||
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
|
||||
skin/classic/browser/customizableui/whimsy.png (../shared/customizableui/whimsy.png)
|
||||
skin/classic/browser/customizableui/whimsy@2x.png (../shared/customizableui/whimsy@2x.png)
|
||||
skin/classic/browser/customizableui/whimsy-bw.png (../shared/customizableui/whimsy-bw.png)
|
||||
skin/classic/browser/customizableui/whimsy-bw@2x.png (../shared/customizableui/whimsy-bw@2x.png)
|
||||
* skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
|
||||
* skin/classic/browser/downloads/allDownloadsViewOverlay-aero.css (downloads/allDownloadsViewOverlay-aero.css)
|
||||
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
|
||||
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
|
||||
skin/classic/browser/downloads/buttons-aero.png (downloads/buttons-aero.png)
|
||||
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
|
||||
@ -181,8 +178,7 @@ browser.jar:
|
||||
skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png)
|
||||
skin/classic/browser/downloads/download-notification-start.png (downloads/download-notification-start.png)
|
||||
skin/classic/browser/downloads/download-summary.png (downloads/download-summary.png)
|
||||
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
* skin/classic/browser/downloads/downloads-aero.css (downloads/downloads-aero.css)
|
||||
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/feedIcon-aero.png (feeds/feedIcon-aero.png)
|
||||
@ -195,9 +191,7 @@ browser.jar:
|
||||
skin/classic/browser/panic-panel/header-small.png (../shared/panic-panel/header-small.png)
|
||||
skin/classic/browser/panic-panel/icons.png (../shared/panic-panel/icons.png)
|
||||
skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/places-aero.css (places/places-aero.css)
|
||||
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
* skin/classic/browser/places/organizer-aero.css (places/organizer-aero.css)
|
||||
skin/classic/browser/places/bookmark.png (places/bookmark.png)
|
||||
skin/classic/browser/places/bookmark-aero.png (places/bookmark-aero.png)
|
||||
skin/classic/browser/places/query.png (places/query.png)
|
||||
@ -529,8 +523,6 @@ browser.jar:
|
||||
% override chrome://browser/skin/aboutSessionRestore-window-icon.png chrome://browser/skin/preferences/application.png os=WINNT osversion<6
|
||||
% override chrome://browser/skin/aboutSessionRestore-window-icon.png chrome://browser/skin/aboutSessionRestore-window-icon-aero.png os=WINNT osversion>=6
|
||||
|
||||
% override chrome://browser/skin/browser.css chrome://browser/skin/browser-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/devedition.css chrome://browser/skin/devedition-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/Info.png chrome://browser/skin/Info-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/identity.png chrome://browser/skin/identity-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/livemark-folder.png chrome://browser/skin/livemark-folder-aero.png os=WINNT osversion>=6
|
||||
@ -541,14 +533,9 @@ browser.jar:
|
||||
% override chrome://browser/skin/Privacy-32.png chrome://browser/skin/Privacy-32-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/searchbar-dropdown-arrow.png chrome://browser/skin/searchbar-dropdown-arrow-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/Secure24.png chrome://browser/skin/Secure24-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/customizableui/panelUIOverlay.css chrome://browser/skin/customizableui/panelUIOverlay-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/downloads/allDownloadsViewOverlay.css chrome://browser/skin/downloads/allDownloadsViewOverlay-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/downloads/buttons.png chrome://browser/skin/downloads/buttons-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/downloads/downloads.css chrome://browser/skin/downloads/downloads-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/feeds/feedIcon.png chrome://browser/skin/feeds/feedIcon-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/feeds/feedIcon16.png chrome://browser/skin/feeds/feedIcon16-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/places/places.css chrome://browser/skin/places/places-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/places/organizer.css chrome://browser/skin/places/organizer-aero.css os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/places/bookmark.png chrome://browser/skin/places/bookmark-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/places/query.png chrome://browser/skin/places/query-aero.png os=WINNT osversion>=6
|
||||
% override chrome://browser/skin/places/bookmarksMenu.png chrome://browser/skin/places/bookmarksMenu-aero.png os=WINNT osversion>=6
|
||||
|
@ -1,77 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%define WINDOWS_AERO
|
||||
%include ../windowsShared.inc
|
||||
%include organizer.css
|
||||
%undef WINDOWS_AERO
|
||||
|
||||
%filter substitution
|
||||
|
||||
#placesView {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media not all and (-moz-windows-classic) {
|
||||
#placesToolbox {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#placesToolbar {
|
||||
-moz-appearance: none;
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-dialogText;
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-compositor) {
|
||||
#placesToolbox {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#placesToolbar {
|
||||
background-image: linear-gradient(@toolbarHighlight@, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
#placesView > splitter {
|
||||
border: 0;
|
||||
-moz-border-end: 1px solid #A9B7C9;
|
||||
min-width: 0;
|
||||
width: 3px;
|
||||
background-color: transparent;
|
||||
-moz-margin-start: -3px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
|
||||
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
|
||||
#placesView,
|
||||
#infoPane,
|
||||
#placesList,
|
||||
#placeContent {
|
||||
background-color: #EEF3FA;
|
||||
}
|
||||
|
||||
#placesToolbar {
|
||||
background-color: @customToolbarColor@;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#detailsDeck {
|
||||
border-top-color: #A9B7C9;
|
||||
}
|
||||
|
||||
#searchFilter {
|
||||
-moz-appearance: none;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0,0,0,.32);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
@ -2,6 +2,9 @@
|
||||
* 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/. */
|
||||
|
||||
%include ../windowsShared.inc
|
||||
%filter substitution
|
||||
|
||||
/* Toolbar */
|
||||
#placesToolbar {
|
||||
padding: 3px;
|
||||
@ -17,14 +20,12 @@
|
||||
list-style-image: url("chrome://browser/skin/Toolbar.png");
|
||||
}
|
||||
|
||||
%ifndef WINDOWS_AERO
|
||||
@media (-moz-windows-theme: luna-silver) {
|
||||
#back-button,
|
||||
#forward-button {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
#back-button {
|
||||
-moz-image-region: rect(0, 54px, 18px, 36px);
|
||||
@ -149,3 +150,73 @@
|
||||
-moz-padding-start: 9px;
|
||||
-moz-padding-end: 9px;
|
||||
}
|
||||
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
#placesView {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media not all and (-moz-windows-classic) {
|
||||
#placesToolbox {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#placesToolbar {
|
||||
-moz-appearance: none;
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-dialogText;
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) {
|
||||
#placesView > splitter {
|
||||
border: 0;
|
||||
-moz-border-end: 1px solid #A9B7C9;
|
||||
min-width: 0;
|
||||
width: 3px;
|
||||
background-color: transparent;
|
||||
-moz-margin-start: -3px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-compositor) {
|
||||
#placesToolbox {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#placesToolbar {
|
||||
background-image: linear-gradient(@toolbarHighlight@, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
|
||||
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
|
||||
#placesView,
|
||||
#infoPane,
|
||||
#placesList,
|
||||
#placeContent {
|
||||
background-color: #EEF3FA;
|
||||
}
|
||||
|
||||
#placesToolbar {
|
||||
background-color: @customToolbarColor@;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#detailsDeck {
|
||||
border-top-color: #A9B7C9;
|
||||
}
|
||||
|
||||
#searchFilter {
|
||||
-moz-appearance: none;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid rgba(0,0,0,.32);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%include places.css
|
||||
|
||||
/* Style Places sidebars as Vista media collection */
|
||||
@media (-moz-windows-default-theme) {
|
||||
#bookmarksPanel,
|
||||
#history-panel {
|
||||
background-color: #EEF3FA;
|
||||
}
|
||||
|
||||
.sidebar-placesTree {
|
||||
background-color: transparent;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.sidebar-placesTreechildren::-moz-tree-cell-text(leaf, hover) {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
@ -24,6 +24,25 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Style Places sidebars as Vista media collection */
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
@media (-moz-windows-default-theme) {
|
||||
#bookmarksPanel,
|
||||
#history-panel {
|
||||
background-color: #EEF3FA;
|
||||
}
|
||||
|
||||
.sidebar-placesTree {
|
||||
background-color: transparent;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.sidebar-placesTreechildren::-moz-tree-cell-text(leaf, hover) {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Trees */
|
||||
treechildren::-moz-tree-image(title) {
|
||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
|
||||
|
@ -54,6 +54,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_signed_pkg_install.html]
|
||||
[test_uninstall_errors.html]
|
||||
[test_theme_role.html]
|
||||
[test_third_party_homescreen.html]
|
||||
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
[test_web_app_install.html]
|
||||
[test_widget.html]
|
||||
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
|
||||
|
203
dom/apps/tests/test_third_party_homescreen.html
Normal file
203
dom/apps/tests/test_third_party_homescreen.html
Normal file
@ -0,0 +1,203 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug {1097468}</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}">Mozilla Bug {1097468}</a>
|
||||
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
|
||||
var gManifestURL = "http://test/tests/dom/apps/tests/file_app.sjs?apptype=hosted&getmanifest=true";
|
||||
var gGenerator = runTest();
|
||||
|
||||
const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm', {});
|
||||
|
||||
function runApp(aApp, aCallback) {
|
||||
var ifr = document.createElement('iframe');
|
||||
ifr.setAttribute('mozbrowser', 'true');
|
||||
ifr.setAttribute('mozapp', aApp.manifestURL);
|
||||
ifr.src = Services.io.newURI(aApp.manifestURL, null, null)
|
||||
.resolve(aApp.manifest.launch_path);
|
||||
|
||||
ifr.addEventListener('mozbrowsershowmodalprompt', function onAlert(e) {
|
||||
var message = e.detail.message;
|
||||
info("Got message " + message);
|
||||
|
||||
if (message.startsWith("OK: ")) {
|
||||
ok(true, message.substring(4, message.length));
|
||||
} else if (message.startsWith("ERROR: ")) {
|
||||
ok(false, message.substring(7, message.length));
|
||||
} else if (message == "DONE") {
|
||||
ifr.removeEventListener('mozbrowsershowmodalprompt', onAlert, false);
|
||||
loadFrameScript(mm);
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
var mm = SpecialPowers.getBrowserFrameMessageManager(ifr);
|
||||
ok(mm, "mm is not null");
|
||||
mm.addMessageListener('OK', function(msg) {
|
||||
ok(true, "Message from app: " + SpecialPowers.wrap(msg).json);
|
||||
});
|
||||
mm.addMessageListener('KO', function(msg) {
|
||||
ok(false, "Message from app: " + SpecialPowers.wrap(msg).json);
|
||||
});
|
||||
mm.addMessageListener('DONE', function() {
|
||||
ok(true, "Message from app: complete");
|
||||
document.body.removeChild(ifr);
|
||||
aCallback();
|
||||
});
|
||||
|
||||
// Test permission |homescreen-webapps-manage|
|
||||
function frameScript()
|
||||
{
|
||||
function ok(p, msg) {
|
||||
if (p) {
|
||||
sendAsyncMessage("OK", msg);
|
||||
} else {
|
||||
sendAsyncMessage("KO", msg);
|
||||
}
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
if (a == b) {
|
||||
sendAsyncMessage("OK", a + " == " + b + " - " + msg);
|
||||
} else {
|
||||
sendAsyncMessage("KO", a + " != " + b + " - " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
function finish() {
|
||||
sendAsyncMessage("DONE", "");
|
||||
}
|
||||
|
||||
if ('mgmt' in content.window.navigator.mozApps) {
|
||||
ok(true, "get mgmt");
|
||||
var mgmt = content.window.navigator.mozApps.mgmt;
|
||||
is(typeof mgmt.getAll, "function", "get getAll");
|
||||
is(typeof mgmt.uninstall, "function", "get uninstall");
|
||||
is(typeof mgmt.oninstall, "object", "get oninstall");
|
||||
is(typeof mgmt.onuninstall, "object", "get onuninstall");
|
||||
is(typeof mgmt.onenabledstatechange, "object", "get onenabledstatechange");
|
||||
|
||||
[
|
||||
"getNotInstalled",
|
||||
"applyDownload",
|
||||
"import",
|
||||
"extractManifest",
|
||||
"setEnabled"
|
||||
].forEach(function(func) {
|
||||
is(typeof mgmt[func], "undefined", "shouldn't get" + func);
|
||||
});
|
||||
} else {
|
||||
ok(false, "can not get mgmt");
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
function loadFrameScript(mm) {
|
||||
var script = "data:,(" + frameScript.toString() + ")();";
|
||||
mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
function go() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "webapps-manage", "allow": 1, "context": document },
|
||||
{ "type": "browser", "allow": 1, "context": document },
|
||||
{ "type": "embed-apps", "allow": 1, "context": document }],
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.mozApps.homescreenURL",
|
||||
gManifestURL]]}, continueTest)});
|
||||
}
|
||||
|
||||
function continueTest() {
|
||||
try {
|
||||
gGenerator.next();
|
||||
} catch (e if e instanceof StopIteration) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function cbError(aEvent) {
|
||||
ok(false, "Error callback invoked " +
|
||||
aEvent.target.error.name + " " + aEvent.target.error.message);
|
||||
finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/**
|
||||
* Test third-party homescreen (permission |homescreen-webapps-manage|)
|
||||
*/
|
||||
function runTest() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.autoConfirmAppUninstall(continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Install a app.
|
||||
var request = navigator.mozApps.install(gManifestURL, { });
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
yield undefined;
|
||||
|
||||
var app = request.result;
|
||||
ok(app, "App is non-null");
|
||||
is(app.manifestURL, gManifestURL, "App manifest url is correct.");
|
||||
|
||||
var context = {"manifestURL": app.manifestURL, "isInBrowserElement": false};
|
||||
|
||||
SpecialPowers.pushPermissions([{"type": "homescreen-webapps-manage",
|
||||
"allow": 1,
|
||||
"context": context}], continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Launch the app.
|
||||
info("Running " + app.manifestURL);
|
||||
runApp(app, continueTest);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.popPermissions(continueTest);
|
||||
yield undefined;
|
||||
|
||||
// Uninstall the app to cleanup after ourself.
|
||||
navigator.mozApps.mgmt.onuninstall = function(event) {
|
||||
var app = event.application;
|
||||
is(app.manifestURL, gManifestURL, "App uninstall event ok.");
|
||||
is(app.manifest.name, "Really Rapid Release (hosted)",
|
||||
"App uninstall manifest ok.");
|
||||
continueTest();
|
||||
}
|
||||
request = navigator.mozApps.mgmt.uninstall(app);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = continueTest;
|
||||
yield undefined;
|
||||
yield undefined;
|
||||
is(request.result, gManifestURL, "App uninstalled.");
|
||||
navigator.mozApps.mgmt.onuninstall = null;
|
||||
}
|
||||
|
||||
addLoadEvent(go);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -176,6 +176,16 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
|
||||
bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
|
||||
bool isKeyboard = IS_KEYBOARD(mTarget.cod);
|
||||
bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
|
||||
bool isInvalid = IS_INVALID_COD(mTarget.cod);
|
||||
|
||||
// The value of CoD is invalid. Since the device didn't declare its class of
|
||||
// device properly, we assume the device may support all of these profiles.
|
||||
if (isInvalid) {
|
||||
AddProfile(BluetoothHfpManager::Get());
|
||||
AddProfile(BluetoothA2dpManager::Get());
|
||||
AddProfile(BluetoothHidManager::Get());
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);
|
||||
|
||||
|
@ -53,6 +53,17 @@ BEGIN_BLUETOOTH_NAMESPACE
|
||||
// Pointing device: sub-field of minor device class (Bit 7)
|
||||
#define IS_POINTING_DEVICE(cod) ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
|
||||
|
||||
/**
|
||||
* Check whether the value of CoD is invalid. (i.e. Bit 31 ~ Bit 24 != 0x0)
|
||||
*
|
||||
* According to Bluetooth core spec v4.1. Vol 2, Sec. 7.3, the data length of
|
||||
* CoD (class of device) is 3 bytes. The two least significant bits are used to
|
||||
* indicate 'format type'. The following 22 bits are used to indicate category
|
||||
* of service class and device type. The remaining 8 bits (Bit 31 ~ Bit 24)
|
||||
* should be unassigned bits, since BlueDroid uses uint32_t to store CoD.
|
||||
*/
|
||||
#define IS_INVALID_COD(cod) (cod >> 24)
|
||||
|
||||
class BluetoothProfileManagerBase;
|
||||
class BluetoothReplyRunnable;
|
||||
typedef void (*BluetoothProfileControllerCallback)();
|
||||
|
@ -173,6 +173,16 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
|
||||
bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
|
||||
bool isKeyboard = IS_KEYBOARD(mTarget.cod);
|
||||
bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
|
||||
bool isInvalid = IS_INVALID_COD(mTarget.cod);
|
||||
|
||||
// The value of CoD is invalid. Since the device didn't declare its class of
|
||||
// device properly, we assume the device may support all of these profiles.
|
||||
if (isInvalid) {
|
||||
AddProfile(BluetoothHfpManager::Get());
|
||||
AddProfile(BluetoothA2dpManager::Get());
|
||||
AddProfile(BluetoothHidManager::Get());
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);
|
||||
|
||||
|
@ -53,6 +53,17 @@ BEGIN_BLUETOOTH_NAMESPACE
|
||||
// Pointing device: sub-field of minor device class (Bit 7)
|
||||
#define IS_POINTING_DEVICE(cod) ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
|
||||
|
||||
/**
|
||||
* Check whether the value of CoD is invalid. (i.e. Bit 31 ~ Bit 24 != 0x0)
|
||||
*
|
||||
* According to Bluetooth core spec v4.1. Vol 2, Sec. 7.3, the data length of
|
||||
* CoD (class of device) is 3 bytes. The two least significant bits are used to
|
||||
* indicate 'format type'. The following 22 bits are used to indicate category
|
||||
* of service class and device type. The remaining 8 bits (Bit 31 ~ Bit 24)
|
||||
* should be unassigned bits, since BlueDroid uses uint32_t to store CoD.
|
||||
*/
|
||||
#define IS_INVALID_COD(cod) (cod >> 24)
|
||||
|
||||
class BluetoothProfileManagerBase;
|
||||
class BluetoothReplyRunnable;
|
||||
typedef void (*BluetoothProfileControllerCallback)();
|
||||
|
@ -172,6 +172,11 @@ BrowserElementChild.prototype = {
|
||||
/* useCapture = */ true,
|
||||
/* wantsUntrusted = */ false);
|
||||
|
||||
addEventListener('click',
|
||||
this._ClickHandler.bind(this),
|
||||
/* useCapture = */ false,
|
||||
/* wantsUntrusted = */ false);
|
||||
|
||||
// This listens to unload events from our message manager, but /not/ from
|
||||
// the |content| window. That's because the window's unload event doesn't
|
||||
// bubble, and we're not using a capturing listener. If we'd used
|
||||
@ -579,6 +584,18 @@ BrowserElementChild.prototype = {
|
||||
sendAsyncMsg('scrollviewchange', detail);
|
||||
},
|
||||
|
||||
_ClickHandler: function(e) {
|
||||
let elem = e.target;
|
||||
if (elem instanceof Ci.nsIDOMHTMLAnchorElement && elem.href) {
|
||||
// Open in a new tab if middle click or ctrl/cmd-click.
|
||||
if ((Services.appinfo.OS == 'Darwin' && e.metaKey) ||
|
||||
(Services.appinfo.OS != 'Darwin' && e.ctrlKey) ||
|
||||
e.button == 1) {
|
||||
sendAsyncMsg('opentab', {url: elem.href});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_selectionStateChangedHandler: function(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
@ -1085,7 +1102,7 @@ BrowserElementChild.prototype = {
|
||||
|
||||
_updateVisibility: function() {
|
||||
var visible = this._forcedVisible && this._ownerVisible;
|
||||
if (docShell.isActive !== visible) {
|
||||
if (docShell && docShell.isActive !== visible) {
|
||||
docShell.isActive = visible;
|
||||
sendAsyncMsg('visibilitychange', {visible: visible});
|
||||
}
|
||||
|
@ -214,7 +214,8 @@ BrowserElementParent.prototype = {
|
||||
"metachange": this._fireEventFromMsg,
|
||||
"resize": this._fireEventFromMsg,
|
||||
"activitydone": this._fireEventFromMsg,
|
||||
"scroll": this._fireEventFromMsg
|
||||
"scroll": this._fireEventFromMsg,
|
||||
"opentab": this._fireEventFromMsg
|
||||
};
|
||||
|
||||
this._mm.addMessageListener('browser-element-api:call', function(aMsg) {
|
||||
|
69
dom/browser-element/mochitest/browserElement_OpenTab.js
Normal file
69
dom/browser-element/mochitest/browserElement_OpenTab.js
Normal file
@ -0,0 +1,69 @@
|
||||
/* Any copyright is dedicated to the public domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Bug 1144015 - test middle/ctrl/cmd-click on a link.
|
||||
|
||||
"use strict";
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
browserElementTestHelpers.setEnabledPref(true);
|
||||
browserElementTestHelpers.addPermission();
|
||||
|
||||
function runTest() {
|
||||
let iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('mozbrowser', 'true');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
let x = 2;
|
||||
let y = 2;
|
||||
// First we force a reflow so that getChildProcessOffset actually returns
|
||||
// meaningful data.
|
||||
iframe.getBoundingClientRect();
|
||||
// We need to make sure the event coordinates are actually inside the iframe,
|
||||
// relative to the chome window.
|
||||
let tabParent = SpecialPowers.wrap(iframe)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader.tabParent;
|
||||
if (tabParent) {
|
||||
let offsetX = {};
|
||||
let offsetY = {};
|
||||
tabParent.getChildProcessOffset(offsetX, offsetY);
|
||||
x -= offsetX.value;
|
||||
y -= offsetY.value;
|
||||
}
|
||||
|
||||
let sendCtrlClick = () => {
|
||||
let nsIDOMWindowUtils = SpecialPowers.Ci.nsIDOMWindowUtils;
|
||||
let mod = nsIDOMWindowUtils.MODIFIER_META |
|
||||
nsIDOMWindowUtils.MODIFIER_CONTROL;
|
||||
iframe.sendMouseEvent('mousedown', x, y, 0, 1, mod);
|
||||
iframe.sendMouseEvent('mouseup', x, y, 0, 1, mod);
|
||||
}
|
||||
|
||||
let onCtrlClick = e => {
|
||||
is(e.detail.url, 'http://example.com/', 'URL matches');
|
||||
iframe.removeEventListener('mozbrowseropentab', onCtrlClick);
|
||||
iframe.addEventListener('mozbrowseropentab', onMiddleClick);
|
||||
sendMiddleClick();
|
||||
}
|
||||
|
||||
let sendMiddleClick = () => {
|
||||
iframe.sendMouseEvent('mousedown', x, y, 1, 1, 0);
|
||||
iframe.sendMouseEvent('mouseup', x, y, 1, 1, 0);
|
||||
}
|
||||
|
||||
let onMiddleClick= e => {
|
||||
is(e.detail.url, 'http://example.com/', 'URL matches');
|
||||
iframe.removeEventListener('mozbrowseropentab', onMiddleClick);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', e => {
|
||||
iframe.addEventListener('mozbrowseropentab', onCtrlClick);
|
||||
sendCtrlClick();
|
||||
});
|
||||
|
||||
|
||||
iframe.src = 'data:text/html,<body style="margin:0"><a href="http://example.com">click here</a></body>';
|
||||
}
|
||||
|
||||
addEventListener('testready', runTest);
|
@ -7,6 +7,7 @@ skip-if = os == "android" || (toolkit == "cocoa" && debug) || buildapp == 'mulet
|
||||
support-files =
|
||||
browserElement_OpenMixedProcess.js
|
||||
file_browserElement_OpenMixedProcess.html
|
||||
browserElement_OpenTab.js
|
||||
|
||||
[test_browserElement_oop_ThemeColor.html]
|
||||
[test_browserElement_inproc_ErrorSecurity.html]
|
||||
@ -60,6 +61,8 @@ skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_OpenWindowRejected.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_Opensearch.html]
|
||||
[test_browserElement_oop_OpenTab.html]
|
||||
skip-if = (toolkit == 'gonk') # Disabled on emulator. See bug 1144015 comment 8
|
||||
[test_browserElement_oop_PrivateBrowsing.html]
|
||||
[test_browserElement_oop_PromptCheck.html]
|
||||
[test_browserElement_oop_PromptConfirm.html]
|
||||
|
@ -38,6 +38,7 @@ support-files =
|
||||
browserElement_Metachange.js
|
||||
browserElement_NextPaint.js
|
||||
browserElement_OpenNamed.js
|
||||
browserElement_OpenTab.js
|
||||
browserElement_OpenWindow.js
|
||||
browserElement_OpenWindowDifferentOrigin.js
|
||||
browserElement_OpenWindowInFrame.js
|
||||
@ -168,6 +169,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_browserElement_inproc_NextPaint.html]
|
||||
[test_browserElement_inproc_OpenNamed.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_inproc_OpenTab.html]
|
||||
disabled = won't work as Firefox desktop will intercept ctrl-click
|
||||
[test_browserElement_inproc_OpenWindow.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_inproc_OpenWindowDifferentOrigin.html]
|
||||
|
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1144015
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1144015</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1144015">Mozilla Bug 1144015</a>
|
||||
|
||||
<script type="application/javascript;version=1.7" src="browserElement_OpenTab.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1144015
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1144015</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1144015">Mozilla Bug 1144015</a>
|
||||
|
||||
<script type="application/javascript;version=1.7" src="browserElement_OpenTab.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -39,7 +39,7 @@ skip-if(Android||B2G) == 649134-2.html 649134-2-ref.html
|
||||
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
|
||||
# The vast majority of the fuzziness comes from Linux and WinXP.)
|
||||
fuzzy(1,149) == bug917595-iframe-1.html bug917595-1-ref.html
|
||||
skip-if(B2G) fuzzy-if(!B2G,3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
|
||||
skip-if(B2G||Mulet) fuzzy-if((!B2G&&!Mulet),3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869 # Bug 1150490 disabling on Mulet as on B2G
|
||||
|
||||
# Test support for SVG-as-image in <picture> elements.
|
||||
pref(dom.image.picture.enabled,true) pref(dom.image.srcset.enabled,true) == bug1106522-1.html bug1106522-ref.html
|
||||
|
@ -992,14 +992,39 @@ void NetworkUtils::removeDefaultRoute(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
// FIXME: (Bug 1121795) We only remove the first gateway to the default route.
|
||||
// For dual stack (ipv4/ipv6) device, one of the gateway would
|
||||
// not be added to the default route.
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s 0.0.0.0/0 %s",
|
||||
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
|
||||
if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) {
|
||||
aCallback(aChain, false, aResult);
|
||||
return;
|
||||
}
|
||||
|
||||
doCommand(command, aChain, aCallback);
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
nsTArray<nsString>& gateways = GET_FIELD(mGateways);
|
||||
NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]);
|
||||
|
||||
int type = getIpType(autoGateway.get());
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s %s/0 %s",
|
||||
GET_FIELD(mNetId), GET_CHAR(mIfname),
|
||||
type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get());
|
||||
|
||||
struct MyCallback {
|
||||
static void callback(CommandCallback::CallbackType aOriginalCallback,
|
||||
CommandChain* aChain,
|
||||
bool aError,
|
||||
mozilla::dom::NetworkResultOptions& aResult)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
|
||||
NU_DBG("removeDefaultRoute's reason: %s", reason.get());
|
||||
if (aError && !reason.EqualsASCII("removeRoute() failed (No such process)")) {
|
||||
return aOriginalCallback(aChain, aError, aResult);
|
||||
}
|
||||
|
||||
GET_FIELD(mLoopIndex)++;
|
||||
return removeDefaultRoute(aChain, aOriginalCallback, aResult);
|
||||
}
|
||||
};
|
||||
|
||||
CommandCallback wrappedCallback(MyCallback::callback, aCallback);
|
||||
doCommand(command, aChain, wrappedCallback);
|
||||
}
|
||||
|
||||
void NetworkUtils::setInterfaceDns(CommandChain* aChain,
|
||||
@ -1147,13 +1172,19 @@ void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) {
|
||||
aCallback(aChain, false, aResult);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: (Bug 1121795) We only add the first gateway to the default route.
|
||||
// For dual stack (ipv4/ipv6) device, one of the gateway would
|
||||
// not be added to the default route.
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s 0.0.0.0/0 %s",
|
||||
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
nsTArray<nsString>& gateways = GET_FIELD(mGateways);
|
||||
NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]);
|
||||
|
||||
int type = getIpType(autoGateway.get());
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s %s/0 %s",
|
||||
GET_FIELD(mNetId), GET_CHAR(mIfname),
|
||||
type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get());
|
||||
|
||||
struct MyCallback {
|
||||
static void callback(CommandCallback::CallbackType aOriginalCallback,
|
||||
@ -1163,11 +1194,12 @@ void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
|
||||
NU_DBG("addDefaultRouteToNetwork's reason: %s", reason.get());
|
||||
if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) {
|
||||
NU_DBG("Ignore \"File exists\" error when adding host route.");
|
||||
return aOriginalCallback(aChain, false, aResult);
|
||||
if (aError && !reason.EqualsASCII("addRoute() failed (File exists)")) {
|
||||
return aOriginalCallback(aChain, aError, aResult);
|
||||
}
|
||||
aOriginalCallback(aChain, aError, aResult);
|
||||
|
||||
GET_FIELD(mLoopIndex)++;
|
||||
return addDefaultRouteToNetwork(aChain, aOriginalCallback, aResult);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1810,8 +1842,9 @@ CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
|
||||
}
|
||||
|
||||
aOptions.mNetId = netIdInfo.mNetId;
|
||||
|
||||
aOptions.mLoopIndex = 0;
|
||||
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
|
||||
|
||||
return CommandResult::Pending();
|
||||
}
|
||||
|
||||
@ -1893,6 +1926,7 @@ CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
|
||||
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
|
||||
|
||||
aOptions.mNetId = netIdInfo.mNetId;
|
||||
aOptions.mLoopIndex = 0;
|
||||
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
|
||||
|
||||
return CommandResult::Pending();
|
||||
|
@ -146,6 +146,8 @@ public:
|
||||
COPY_OPT_FIELD(mDns1_long, 0)
|
||||
COPY_OPT_FIELD(mDns2_long, 0)
|
||||
|
||||
mLoopIndex = 0;
|
||||
|
||||
#undef COPY_SEQUENCE_FIELD
|
||||
#undef COPY_OPT_STRING_FIELD
|
||||
#undef COPY_OPT_FIELD
|
||||
@ -198,7 +200,8 @@ public:
|
||||
long mDns2_long;
|
||||
|
||||
// Auxiliary information required to carry accros command chain.
|
||||
int mNetId; // A locally defined id per interface.
|
||||
int mNetId; // A locally defined id per interface.
|
||||
uint32_t mLoopIndex; // Loop index for adding/removing multiple gateways.
|
||||
};
|
||||
|
||||
// CommandChain store the necessary information to execute command one by one.
|
||||
|
@ -24,7 +24,7 @@ enum LocaleResourceType {
|
||||
[NoInterfaceObject, NavigatorProperty="mozApps",
|
||||
JSImplementation="@mozilla.org/webapps;1"]
|
||||
interface DOMApplicationsRegistry {
|
||||
[CheckPermissions="webapps-manage"]
|
||||
[CheckPermissions="webapps-manage homescreen-webapps-manage"]
|
||||
readonly attribute DOMApplicationsManager mgmt;
|
||||
DOMRequest install(DOMString url, optional InstallParameters params);
|
||||
DOMRequest installPackage(DOMString url, optional InstallParameters params);
|
||||
@ -116,16 +116,22 @@ interface DOMApplication : EventTarget {
|
||||
|
||||
[JSImplementation="@mozilla.org/webapps/manager;1",
|
||||
ChromeOnly,
|
||||
CheckPermissions="webapps-manage"]
|
||||
CheckPermissions="webapps-manage homescreen-webapps-manage"]
|
||||
interface DOMApplicationsManager : EventTarget {
|
||||
DOMRequest getAll();
|
||||
|
||||
[CheckPermissions="webapps-manage"]
|
||||
DOMRequest getNotInstalled();
|
||||
[CheckPermissions="webapps-manage"]
|
||||
void applyDownload(DOMApplication app);
|
||||
DOMRequest uninstall(DOMApplication app);
|
||||
|
||||
[CheckPermissions="webapps-manage"]
|
||||
Promise<DOMApplication> import(Blob blob);
|
||||
[CheckPermissions="webapps-manage"]
|
||||
Promise<any> extractManifest(Blob blob);
|
||||
|
||||
[CheckPermissions="webapps-manage"]
|
||||
void setEnabled(DOMApplication app, boolean state);
|
||||
Promise<Blob> getIcon(DOMApplication app, DOMString iconID,
|
||||
optional DOMString entryPoint);
|
||||
|
@ -156,6 +156,12 @@ public:
|
||||
SetLayer(aLayer);
|
||||
mAttached = true;
|
||||
mKeepAttached = aFlags & KEEP_ATTACHED;
|
||||
|
||||
// If we already have a textureHost before, use that in this moment.
|
||||
RefPtr<TextureHost> frontBuffer = GetAsTextureHost();
|
||||
if (frontBuffer) {
|
||||
UseTextureHost(frontBuffer);
|
||||
}
|
||||
}
|
||||
// Detach this compositable host from its layer.
|
||||
// If we are used for async video, then it is not safe to blindly detach since
|
||||
|
@ -567,11 +567,14 @@ struct AutoStopwatch final
|
||||
ULARGE_INTEGER userTimeInt;
|
||||
kernelTimeInt.LowPart = kernelFileTime.dwLowDateTime;
|
||||
kernelTimeInt.HighPart = kernelFileTime.dwHighDateTime;
|
||||
*systemTime = kernelTimeInt.QuadPart / 10; // 100 ns to 1 us
|
||||
// Convert 100 ns to 1 us, make sure that the result is monotonic
|
||||
*systemTime = runtime_-> stopwatch.systemTimeFix.monotonize(kernelTimeInt.QuadPart / 10);
|
||||
|
||||
userTimeInt.LowPart = userFileTime.dwLowDateTime;
|
||||
userTimeInt.HighPart = userFileTime.dwHighDateTime;
|
||||
*userTime = userTimeInt.QuadPart / 10; // 100 ns to 1 us
|
||||
// Convert 100 ns to 1 us, make sure that the result is monotonic
|
||||
*userTime = runtime_-> stopwatch.userTimeFix.monotonize(userTimeInt.QuadPart / 10);
|
||||
|
||||
#endif // defined(XP_UNIX) || defined(XP_WIN)
|
||||
|
||||
return true;
|
||||
|
@ -1532,6 +1532,28 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
return isActive_;
|
||||
}
|
||||
|
||||
// Some systems have non-monotonic clocks. While we cannot
|
||||
// improve the precision, we can make sure that our measures
|
||||
// are monotonic nevertheless. We do this by storing the
|
||||
// result of the latest call to the clock and making sure
|
||||
// that the next timestamp is greater or equal.
|
||||
struct MonotonicTimeStamp {
|
||||
MonotonicTimeStamp()
|
||||
: latestGood_(0)
|
||||
{}
|
||||
inline uint64_t monotonize(uint64_t stamp)
|
||||
{
|
||||
if (stamp <= latestGood_)
|
||||
return latestGood_;
|
||||
latestGood_ = stamp;
|
||||
return stamp;
|
||||
}
|
||||
private:
|
||||
uint64_t latestGood_;
|
||||
};
|
||||
MonotonicTimeStamp systemTimeFix;
|
||||
MonotonicTimeStamp userTimeFix;
|
||||
|
||||
private:
|
||||
/**
|
||||
* A map used to collapse compartments belonging to the same
|
||||
|
@ -28,14 +28,14 @@ fails-if(Android||B2G||Mulet) == disabled-1.html disabled-1-ref.html # Initial m
|
||||
!= disabled-5.html disabled-5-notref.html
|
||||
!= disabled-6.html disabled-6-notref.html
|
||||
|
||||
fails-if(B2G) == width-auto-size-em-ltr.html width-auto-size-em-ltr-ref.html # Bug 1145672
|
||||
fails-if(B2G) == width-auto-size-ltr.html width-auto-size-ltr-ref.html # Bug 1145672
|
||||
fails-if(B2G||Mulet) == width-auto-size-em-ltr.html width-auto-size-em-ltr-ref.html # Bug 1145672 # Bug 1150486
|
||||
fails-if(B2G||Mulet) == width-auto-size-ltr.html width-auto-size-ltr-ref.html # Bug 1145672 # Bug 1150486
|
||||
== width-exact-fit-ltr.html width-auto-size-ltr-ref.html
|
||||
== width-erode-part-focuspadding-ltr.html width-erode-part-focuspadding-ltr-ref.html
|
||||
== width-erode-all-focuspadding-ltr.html width-erode-all-focuspadding-ltr-ref.html
|
||||
== width-erode-overflow-focuspadding-ltr.html width-erode-overflow-focuspadding-ltr-ref.html
|
||||
fails-if(B2G) == width-auto-size-em-rtl.html width-auto-size-em-rtl-ref.html # Bug 1145672
|
||||
fails-if(B2G) == width-auto-size-rtl.html width-auto-size-rtl-ref.html # Bug 1145672
|
||||
fails-if(B2G||Mulet) == width-auto-size-em-rtl.html width-auto-size-em-rtl-ref.html # Bug 1145672 # Bug 1150486
|
||||
fails-if(B2G||Mulet) == width-auto-size-rtl.html width-auto-size-rtl-ref.html # Bug 1145672 # Bug 1150486
|
||||
== width-exact-fit-rtl.html width-auto-size-rtl-ref.html
|
||||
== width-erode-part-focuspadding-rtl.html width-erode-part-focuspadding-rtl-ref.html
|
||||
== width-erode-all-focuspadding-rtl.html width-erode-all-focuspadding-rtl-ref.html
|
||||
|
@ -173,9 +173,9 @@ skip-if(B2G) == object-fit-scale-down-svg-002o.html object-fit-scale-down-svg-00
|
||||
== object-fit-scale-down-svg-006o.html object-fit-scale-down-svg-006-ref.html
|
||||
== object-fit-scale-down-svg-006p.html object-fit-scale-down-svg-006-ref.html
|
||||
fails == object-position-png-001c.html object-position-png-001-ref.html # bug 1105150
|
||||
== object-position-png-001e.html object-position-png-001-ref.html
|
||||
fuzzy-if(Mulet,2,20) == object-position-png-001e.html object-position-png-001-ref.html # Bug 1150536
|
||||
== object-position-png-001i.html object-position-png-001-ref.html
|
||||
== object-position-png-001o.html object-position-png-001-ref.html
|
||||
fuzzy-if(Mulet,2,20) == object-position-png-001o.html object-position-png-001-ref.html # Bug 1150492
|
||||
== object-position-png-001p.html object-position-png-001-ref.html
|
||||
fails == object-position-png-002c.html object-position-png-002-ref.html # bug 1105150
|
||||
== object-position-png-002e.html object-position-png-002-ref.html
|
||||
|
@ -58,11 +58,16 @@ public class AndroidFxAccount {
|
||||
public static final String ACCOUNT_KEY_PROFILE = "profile";
|
||||
public static final String ACCOUNT_KEY_IDP_SERVER = "idpServerURI";
|
||||
|
||||
// The audience should always be a prefix of the token server URI.
|
||||
public static final String ACCOUNT_KEY_AUDIENCE = "audience"; // Sync-specific.
|
||||
public static final String ACCOUNT_KEY_TOKEN_SERVER = "tokenServerURI"; // Sync-specific.
|
||||
public static final String ACCOUNT_KEY_DESCRIPTOR = "descriptor";
|
||||
|
||||
// The set of authorities to sync automatically changes over time. The first
|
||||
// new authority is the Reading List. This tracks if we've enabled syncing,
|
||||
// and opted in (or out) of syncing automatically, for the new Reading List
|
||||
// authority. This happens either on when the account is created or when
|
||||
// upgrading.
|
||||
public static final String ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED = "readingListAuthorityInitialized";
|
||||
|
||||
public static final int CURRENT_BUNDLE_VERSION = 2;
|
||||
public static final String BUNDLE_KEY_BUNDLE_VERSION = "version";
|
||||
public static final String BUNDLE_KEY_STATE_LABEL = "stateLabel";
|
||||
@ -401,6 +406,10 @@ public class AndroidFxAccount {
|
||||
userdata.putString(ACCOUNT_KEY_IDP_SERVER, idpServerURI);
|
||||
userdata.putString(ACCOUNT_KEY_TOKEN_SERVER, tokenServerURI);
|
||||
userdata.putString(ACCOUNT_KEY_PROFILE, profile);
|
||||
if (DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.containsKey(BrowserContract.READING_LIST_AUTHORITY)) {
|
||||
// Have we initialized the Reading List authority?
|
||||
userdata.putString(ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED, "1");
|
||||
}
|
||||
|
||||
if (bundle == null) {
|
||||
bundle = new ExtendedJSONObject();
|
||||
|
@ -11,6 +11,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
@ -19,7 +20,9 @@ import org.mozilla.gecko.fxa.login.State.StateLabel;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
@ -45,6 +48,7 @@ public class FxAccountUpgradeReceiver extends BroadcastReceiver {
|
||||
// Recovering accounts that are in the Doghouse should happen *after* we
|
||||
// unpickle any accounts saved to disk.
|
||||
runnables.add(new AdvanceFromDoghouseRunnable(context));
|
||||
runnables.add(new MaybeInitializeReadingListAuthority(context));
|
||||
return runnables;
|
||||
}
|
||||
|
||||
@ -130,4 +134,68 @@ public class FxAccountUpgradeReceiver extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Runnable that initializes the Reading List authority (specifically, set
|
||||
* the sync automatically flag) for existing Firefox Accounts that have not
|
||||
* yet seen the authority. That is, if a new authority (Reading List) is added
|
||||
* to the set of defaults, existing Firefox Accounts won't be syncing it
|
||||
* automatically. This tries to set the sync automatically flag for such
|
||||
* existing accounts.
|
||||
*
|
||||
* Public for testing only.
|
||||
*/
|
||||
public static class MaybeInitializeReadingListAuthority implements Runnable {
|
||||
protected final Context context;
|
||||
|
||||
public MaybeInitializeReadingListAuthority(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final String authority = BrowserContract.READING_LIST_AUTHORITY;
|
||||
Boolean enabledByDefault = AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.get(authority);
|
||||
if (enabledByDefault == null || !enabledByDefault.booleanValue()) {
|
||||
Logger.info(LOG_TAG, "Reading List authority is not enabled by default; not trying to initialize Reading List authority for any accounts.");
|
||||
}
|
||||
|
||||
final AccountManager accountManager = AccountManager.get(context);
|
||||
final Account[] accounts = FirefoxAccounts.getFirefoxAccounts(context);
|
||||
Logger.info(LOG_TAG, "Trying to initialize Reading List authority for " + accounts.length + " existing Firefox Accounts (if necessary).");
|
||||
|
||||
for (Account account : accounts) {
|
||||
try {
|
||||
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
|
||||
// For great debugging.
|
||||
if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
|
||||
fxAccount.dump();
|
||||
}
|
||||
|
||||
final boolean readingListAuthorityInitialized =
|
||||
"1".equals(accountManager.getUserData(account, AndroidFxAccount.ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED));
|
||||
if (readingListAuthorityInitialized) {
|
||||
Logger.debug(LOG_TAG, "Reading List authority has already been initialized.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// The Reading List authority has not been seen. This happens when an
|
||||
// authority is added after the Firefox Account has been added (and
|
||||
// the package last upgraded). If Firefox Sync is not syncing
|
||||
// automatically, Reading List should not start syncing
|
||||
// automatically: the user has elected not to upload data to Mozilla
|
||||
// servers; we shouldn't opt them in.
|
||||
final boolean syncAutomatically = ContentResolver.getSyncAutomatically(account, BrowserContract.AUTHORITY);
|
||||
Logger.debug(LOG_TAG, "Setting Reading List authority " +
|
||||
(syncAutomatically ? " to " : " to not ") + "sync automatically.");
|
||||
ContentResolver.setSyncAutomatically(account, BrowserContract.READING_LIST_AUTHORITY, syncAutomatically);
|
||||
// Update the account record.
|
||||
accountManager.setUserData(account, AndroidFxAccount.ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED, "1");
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception trying to set authoritities to sync automatically for account named like " +
|
||||
Utils.obfuscateEmail(account.name) + "; ignoring.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,6 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getWindow().setWindowAnimations(0);
|
||||
setContentView(R.layout.overlay_share_dialog);
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(uiEventListener,
|
||||
@ -254,6 +253,11 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
||||
serviceStartupIntent.setAction(OverlayConstants.ACTION_PREPARE_SHARE);
|
||||
startService(serviceStartupIntent);
|
||||
|
||||
// Start the slide-up animation.
|
||||
getWindow().setWindowAnimations(0);
|
||||
final Animation anim = AnimationUtils.loadAnimation(this, R.anim.overlay_slide_up);
|
||||
findViewById(R.id.sharedialog).startAnimation(anim);
|
||||
|
||||
// If provided, we use the subject text to give us something nice to display.
|
||||
// If not, we wing it with the URL.
|
||||
|
||||
@ -306,10 +310,6 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
||||
|
||||
final LocalBrowserDB browserDB = new LocalBrowserDB(getCurrentProfile());
|
||||
setButtonState(url, browserDB);
|
||||
|
||||
// Start the slide-up animation.
|
||||
final Animation anim = AnimationUtils.loadAnimation(this, R.anim.overlay_slide_up);
|
||||
findViewById(R.id.sharedialog).startAnimation(anim);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
@ -10,7 +10,7 @@
|
||||
android:paddingLeft="4dip"
|
||||
android:background="@drawable/new_tablet_tabs_count_foreground"
|
||||
android:textAppearance="@style/TextAppearance.Micro"
|
||||
android:textColor="@color/text_color_primary_inverse"
|
||||
android:textColor="@color/toolbar_grey"
|
||||
android:textStyle="bold"
|
||||
android:duplicateParentState="true"
|
||||
android:gravity="center"/>
|
||||
|
@ -11,7 +11,7 @@
|
||||
android:paddingLeft="4dip"
|
||||
android:background="@drawable/tabs_count_foreground"
|
||||
android:textAppearance="@style/TextAppearance.Micro"
|
||||
android:textColor="#FF43484E"
|
||||
android:textColor="@color/text_and_tabs_tray_grey"
|
||||
android:textStyle="bold"
|
||||
android:duplicateParentState="true"
|
||||
android:gravity="center"/>
|
||||
|
@ -5,9 +5,6 @@
|
||||
|
||||
package org.mozilla.gecko.toolbar;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.TouchDelegate;
|
||||
import android.view.ViewTreeObserver;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
@ -53,27 +50,6 @@ class BrowserToolbarTablet extends BrowserToolbarTabletBase {
|
||||
setButtonEnabled(forwardButton, true);
|
||||
|
||||
updateForwardButtonState(ForwardButtonState.HIDDEN);
|
||||
|
||||
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
// We do this in an onPreDrawListener because we need the Views
|
||||
// to be laid out before we can make size calculations.
|
||||
getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
|
||||
final Rect r = new Rect();
|
||||
r.left = menuButton.getLeft();
|
||||
r.right = getWidth();
|
||||
r.top = 0;
|
||||
r.bottom = getHeight();
|
||||
|
||||
// Redirect touch events between the 3-dot menu button
|
||||
// and the edge of the screen to the right of the button.
|
||||
setTouchDelegate(new TouchDelegate(r, menuButton));
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateForwardButtonState(final ForwardButtonState state) {
|
||||
|
@ -1082,4 +1082,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
||||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1436005136747000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1436609916936000);
|
||||
|
@ -6,6 +6,7 @@ airbnb.com: did not receive HSTS header
|
||||
aiticon.de: did not receive HSTS header
|
||||
altmv.com: max-age too low: 7776000
|
||||
amigogeek.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134" data: no]
|
||||
ankakaak.com: could not connect to host
|
||||
api.mega.co.nz: could not connect to host
|
||||
api.recurly.com: did not receive HSTS header
|
||||
apis.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
@ -14,8 +15,8 @@ appengine.google.com: did not receive HSTS header (error ignored - included rega
|
||||
appseccalifornia.org: did not receive HSTS header
|
||||
astaxi.net: did not receive HSTS header
|
||||
at.search.yahoo.com: did not receive HSTS header
|
||||
atavio.at: could not connect to host
|
||||
atavio.ch: could not connect to host
|
||||
atavio.at: did not receive HSTS header
|
||||
atavio.ch: did not receive HSTS header
|
||||
atavio.de: did not receive HSTS header
|
||||
au.search.yahoo.com: did not receive HSTS header
|
||||
auth.mail.ru: did not receive HSTS header
|
||||
@ -24,6 +25,7 @@ az.search.yahoo.com: did not receive HSTS header
|
||||
azprep.us: could not connect to host
|
||||
baldwinkoo.com: did not receive HSTS header
|
||||
barcodeberlin.com: did not receive HSTS header
|
||||
bassh.net: could not connect to host
|
||||
bccx.com: could not connect to host
|
||||
bcm.com.au: max-age too low: 0
|
||||
be.search.yahoo.com: did not receive HSTS header
|
||||
@ -38,11 +40,14 @@ bizon.sk: did not receive HSTS header
|
||||
blog.lookout.com: did not receive HSTS header
|
||||
br.search.yahoo.com: did not receive HSTS header
|
||||
brainfork.ml: did not receive HSTS header
|
||||
braintreegateway.com: did not receive HSTS header
|
||||
braintreepayments.com: did not receive HSTS header
|
||||
brainvation.de: did not receive HSTS header
|
||||
browserid.org: did not receive HSTS header
|
||||
business.medbank.com.mt: could not connect to host
|
||||
bzv-fr.eu: could not connect to host
|
||||
ca.search.yahoo.com: did not receive HSTS header
|
||||
cake.care: could not connect to host
|
||||
calibreapp.com: did not receive HSTS header
|
||||
calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134" data: no]
|
||||
carlolly.co.uk: could not connect to host
|
||||
@ -58,10 +63,12 @@ checkout.google.com: did not receive HSTS header (error ignored - included regar
|
||||
chfr.search.yahoo.com: did not receive HSTS header
|
||||
chit.search.yahoo.com: did not receive HSTS header
|
||||
chm.vn: did not receive HSTS header
|
||||
chontalpa.pw: did not receive HSTS header
|
||||
chrome-devtools-frontend.appspot.com: did not receive HSTS header (error ignored - included regardless)
|
||||
chrome.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
cimballa.com: did not receive HSTS header
|
||||
cl.search.yahoo.com: did not receive HSTS header
|
||||
climaprecio.es: did not receive HSTS header
|
||||
cn.search.yahoo.com: did not receive HSTS header
|
||||
co.search.yahoo.com: did not receive HSTS header
|
||||
code.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
@ -113,7 +120,6 @@ espanol.search.yahoo.com: did not receive HSTS header
|
||||
espra.com: could not connect to host
|
||||
ethitter.com: did not receive HSTS header
|
||||
etsysecure.com: could not connect to host
|
||||
ezequiel-garzon.com: could not connect to host
|
||||
fabianfischer.de: did not receive HSTS header
|
||||
fatzebra.com.au: did not receive HSTS header
|
||||
fi.search.yahoo.com: did not receive HSTS header
|
||||
@ -149,6 +155,7 @@ hn.search.yahoo.com: did not receive HSTS header
|
||||
hoerbuecher-und-hoerspiele.de: did not receive HSTS header
|
||||
honeytracks.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134" data: no]
|
||||
horosho.in: could not connect to host
|
||||
horseboners.xxx: could not connect to host
|
||||
hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
howrandom.org: could not connect to host
|
||||
hstspreload.appspot.com: did not receive HSTS header
|
||||
@ -164,14 +171,16 @@ iniiter.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERRO
|
||||
intercom.io: did not receive HSTS header
|
||||
interserved.com: did not receive HSTS header
|
||||
iop.intuit.com: max-age too low: 86400
|
||||
iranianlawschool.com: could not connect to host
|
||||
irccloud.com: did not receive HSTS header
|
||||
it.search.yahoo.com: did not receive HSTS header
|
||||
itshost.ru: could not connect to host
|
||||
j0s.at: did not receive HSTS header
|
||||
janoberst.com: did not receive HSTS header
|
||||
jelmer.co.uk: could not connect to host
|
||||
jonathan.ir: could not connect to host
|
||||
jottit.com: could not connect to host
|
||||
k-dev.de: could not connect to host
|
||||
kdex.de: did not receive HSTS header
|
||||
keepclean.me: could not connect to host
|
||||
keymaster.lookout.com: did not receive HSTS header
|
||||
kirkforcongress.com: could not connect to host
|
||||
@ -209,14 +218,15 @@ market.android.com: did not receive HSTS header (error ignored - included regard
|
||||
marshut.net: could not connect to host
|
||||
matatall.com: could not connect to host
|
||||
mattmccutchen.net: could not connect to host
|
||||
mccrypto.de: could not connect to host
|
||||
mediacru.sh: could not connect to host
|
||||
megashur.se: did not receive HSTS header
|
||||
megaxchange.com: did not receive HSTS header
|
||||
meinebo.it: could not connect to host
|
||||
minikneet.nl: did not receive HSTS header
|
||||
micropple.net: did not receive HSTS header
|
||||
minikneet.nl: could not connect to host
|
||||
mirindadomo.ru: did not receive HSTS header
|
||||
mnemotiv.com: could not connect to host
|
||||
mnsure.org: could not connect to host
|
||||
mobilethreat.net: could not connect to host
|
||||
mobilethreatnetwork.net: could not connect to host
|
||||
mocloud.eu: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134" data: no]
|
||||
@ -224,7 +234,6 @@ mqas.net: could not connect to host
|
||||
mt.search.yahoo.com: did not receive HSTS header
|
||||
mu.search.yahoo.com: did not receive HSTS header
|
||||
mujadin.se: max-age too low: 86400
|
||||
munuc.org: could not connect to host
|
||||
mw.search.yahoo.com: did not receive HSTS header
|
||||
mx.search.yahoo.com: did not receive HSTS header
|
||||
my.alfresco.com: did not receive HSTS header
|
||||
@ -259,6 +268,7 @@ pe.search.yahoo.com: did not receive HSTS header
|
||||
ph.search.yahoo.com: did not receive HSTS header
|
||||
piratenlogin.de: could not connect to host
|
||||
pisidia.de: did not receive HSTS header
|
||||
pixi.me: could not connect to host
|
||||
pk.search.yahoo.com: did not receive HSTS header
|
||||
pl.search.yahoo.com: did not receive HSTS header
|
||||
platform.lookout.com: could not connect to host
|
||||
@ -270,6 +280,7 @@ pressfreedomfoundation.org: did not receive HSTS header
|
||||
prodpad.com: did not receive HSTS header
|
||||
promecon-gmbh.de: did not receive HSTS header
|
||||
proximato.com: could not connect to host
|
||||
pult.co: could not connect to host
|
||||
py.search.yahoo.com: did not receive HSTS header
|
||||
qc.search.yahoo.com: did not receive HSTS header
|
||||
rapidresearch.me: could not connect to host
|
||||
@ -277,7 +288,6 @@ redlatam.org: did not receive HSTS header
|
||||
redports.org: did not receive HSTS header
|
||||
regar42.fr: could not connect to host
|
||||
reserve-online.net: did not receive HSTS header
|
||||
richiemail.net: could not connect to host
|
||||
riseup.net: did not receive HSTS header
|
||||
rme.li: did not receive HSTS header
|
||||
ro.search.yahoo.com: did not receive HSTS header
|
||||
@ -301,9 +311,9 @@ silentcircle.org: could not connect to host
|
||||
simon.butcher.name: max-age too low: 2629743
|
||||
simplyfixit.co.uk: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134" data: no]
|
||||
sites.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
smartcleaningcenter.nl: could not connect to host
|
||||
smartlend.se: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134" data: no]
|
||||
sol.io: could not connect to host
|
||||
soulogic.com: could not connect to host
|
||||
souyar.de: could not connect to host
|
||||
souyar.net: could not connect to host
|
||||
souyar.us: could not connect to host
|
||||
@ -332,9 +342,13 @@ temehu.com: did not receive HSTS header
|
||||
terrax.berlin: could not connect to host
|
||||
th.search.yahoo.com: did not receive HSTS header
|
||||
the-sky-of-valkyries.com: could not connect to host
|
||||
thetomharling.com: did not receive HSTS header
|
||||
thomasgriffin.io: did not receive HSTS header
|
||||
thorncreek.net: did not receive HSTS header
|
||||
tomharling.co.uk: did not receive HSTS header
|
||||
tomharling.uk: could not connect to host
|
||||
toptexture.com: did not receive HSTS header
|
||||
tor2web.org: could not connect to host
|
||||
tr.search.yahoo.com: did not receive HSTS header
|
||||
translate.googleapis.com: did not receive HSTS header (error ignored - included regardless)
|
||||
translatoruk.co.uk: did not receive HSTS header
|
||||
@ -349,7 +363,7 @@ uy.search.yahoo.com: did not receive HSTS header
|
||||
uz.search.yahoo.com: did not receive HSTS header
|
||||
ve.search.yahoo.com: did not receive HSTS header
|
||||
vhost.co.id: could not connect to host
|
||||
viennan.net: did not receive HSTS header
|
||||
viennan.net: could not connect to host
|
||||
vn.search.yahoo.com: did not receive HSTS header
|
||||
vyncke.org: did not receive HSTS header
|
||||
wallet.google.com: did not receive HSTS header (error ignored - included regardless)
|
||||
|
@ -8,7 +8,7 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
const PRTime gPreloadListExpirationTime = INT64_C(1438424329809000);
|
||||
const PRTime gPreloadListExpirationTime = INT64_C(1439029112102000);
|
||||
|
||||
class nsSTSPreload
|
||||
{
|
||||
@ -29,6 +29,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "2600hq.com", true },
|
||||
{ "301.website", true },
|
||||
{ "302.nyc", true },
|
||||
{ "47ronin.com", false },
|
||||
{ "5apps.com", false },
|
||||
{ "7183.org", true },
|
||||
{ "8ack.de", true },
|
||||
@ -37,6 +38,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "accounts.google.com", true },
|
||||
{ "aclu.org", false },
|
||||
{ "activiti.alfresco.com", false },
|
||||
{ "acuica.co.uk", false },
|
||||
{ "acus.gov", true },
|
||||
{ "adamkostecki.de", true },
|
||||
{ "adamstas.com", true },
|
||||
@ -47,6 +49,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "admin.stg.fedoraproject.org", true },
|
||||
{ "adorai.tk", true },
|
||||
{ "adsfund.org", true },
|
||||
{ "advanced-online.eu", true },
|
||||
{ "afp548.com", true },
|
||||
{ "agrimap.com", true },
|
||||
{ "ahoyconference.com", true },
|
||||
@ -102,6 +105,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "apps.fedoraproject.org", true },
|
||||
{ "apps.stg.fedoraproject.org", true },
|
||||
{ "aprz.de", true },
|
||||
{ "arbitrary.ch", true },
|
||||
{ "archlinux.de", true },
|
||||
{ "areafiftylan.nl", true },
|
||||
{ "arendburgers.nl", true },
|
||||
@ -114,8 +118,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "arty.name", true },
|
||||
{ "ask.fedoraproject.org", true },
|
||||
{ "ask.stg.fedoraproject.org", true },
|
||||
{ "atavio.at", true },
|
||||
{ "atavio.ch", true },
|
||||
{ "atc.io", true },
|
||||
{ "athenelive.com", true },
|
||||
{ "atishchenko.com", true },
|
||||
@ -160,6 +162,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "bgneuesheim.de", true },
|
||||
{ "bhatia.at", true },
|
||||
{ "biathloncup.ru", true },
|
||||
{ "bidon.ca", true },
|
||||
{ "big-andy.co.uk", true },
|
||||
{ "bigbrownpromotions.com.au", true },
|
||||
{ "billigssl.dk", true },
|
||||
@ -190,6 +193,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "blubbablasen.de", true },
|
||||
{ "bodo-wolff.de", true },
|
||||
{ "bohramt.de", true },
|
||||
{ "boiseonlinemall.com", true },
|
||||
{ "bonigo.de", true },
|
||||
{ "bonitabrazilian.co.nz", true },
|
||||
{ "bookingapp.nl", true },
|
||||
@ -197,7 +201,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "boypoint.de", true },
|
||||
{ "bradkovach.com", true },
|
||||
{ "brage.info", true },
|
||||
{ "braintreegateway.com", true },
|
||||
{ "brakemanpro.com", true },
|
||||
{ "bran.cc", true },
|
||||
{ "brandbuilderwebsites.com", true },
|
||||
@ -232,6 +235,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "cartucce24.it", true },
|
||||
{ "casa-su.casa", true },
|
||||
{ "cbhq.net", true },
|
||||
{ "cdlcenter.com", true },
|
||||
{ "cdnb.co", true },
|
||||
{ "certible.com", true },
|
||||
{ "certly.io", true },
|
||||
@ -242,7 +246,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "chatbot.me", true },
|
||||
{ "check.torproject.org", false },
|
||||
{ "checkout.google.com", true },
|
||||
{ "chontalpa.pw", true },
|
||||
{ "chrisirwin.ca", true },
|
||||
{ "chrisjean.com", true },
|
||||
{ "chrome-devtools-frontend.appspot.com", true },
|
||||
@ -271,6 +274,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "codepx.com", true },
|
||||
{ "codereview.appspot.com", false },
|
||||
{ "codereview.chromium.org", true },
|
||||
{ "coding.net", false },
|
||||
{ "coffeeetc.co.uk", true },
|
||||
{ "coinapult.com", true },
|
||||
{ "coinbase.com", true },
|
||||
@ -286,6 +290,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "cordial-restaurant.com", true },
|
||||
{ "cotonea.de", true },
|
||||
{ "courtlistener.com", true },
|
||||
{ "covenantoftheriver.org", true },
|
||||
{ "crm.onlime.ch", false },
|
||||
{ "crowdjuris.com", true },
|
||||
{ "crypto.cat", false },
|
||||
@ -313,6 +318,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "danielalvarez.net", true },
|
||||
{ "danonsecurity.com", true },
|
||||
{ "danskoferie.dk", true },
|
||||
{ "danw.io", true },
|
||||
{ "daphne.informatik.uni-freiburg.de", true },
|
||||
{ "darchoods.net", false },
|
||||
{ "darknode.in", true },
|
||||
@ -336,6 +342,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "debtkit.co.uk", true },
|
||||
{ "dedimax.de", true },
|
||||
{ "dee.pe", true },
|
||||
{ "defcon.org", true },
|
||||
{ "deliverance.co.uk", true },
|
||||
{ "denh.am", true },
|
||||
{ "depechemode-live.com", true },
|
||||
@ -348,11 +355,12 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "diamante.ro", true },
|
||||
{ "die-besten-weisheiten.de", true },
|
||||
{ "diedrich.co", true },
|
||||
{ "digital1st.co.uk", true },
|
||||
{ "dillonkorman.com", true },
|
||||
{ "dinamoelektrik.com", true },
|
||||
{ "disking.co.uk", true },
|
||||
{ "dist.torproject.org", false },
|
||||
{ "dixmag.com", true },
|
||||
{ "dixmag.com", false },
|
||||
{ "dl.google.com", true },
|
||||
{ "dlc.viasinc.com", true },
|
||||
{ "dm.lookout.com", false },
|
||||
@ -364,8 +372,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "docs.python.org", true },
|
||||
{ "domainkauf.de", true },
|
||||
{ "domains.google.com", true },
|
||||
{ "donmez.ws", false },
|
||||
{ "donmez.ws", true },
|
||||
{ "donotcall.gov", true },
|
||||
{ "dragons-of-highlands.cz", true },
|
||||
{ "dreadbyte.com", true },
|
||||
{ "dreamsforabetterworld.com.au", true },
|
||||
{ "drive.google.com", true },
|
||||
@ -404,6 +413,8 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "encrypted.google.com", true },
|
||||
{ "energy-drink-magazin.de", true },
|
||||
{ "enorekcah.com", true },
|
||||
{ "enskat.de", true },
|
||||
{ "enskatson-sippe.de", true },
|
||||
{ "entropia.de", false },
|
||||
{ "eromixx.com", true },
|
||||
{ "erotische-aanbiedingen.nl", true },
|
||||
@ -415,6 +426,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "eva.cz", true },
|
||||
{ "evalesc.com", true },
|
||||
{ "everhome.de", true },
|
||||
{ "eveshamglass.co.uk", true },
|
||||
{ "evstatus.com", true },
|
||||
{ "exiahost.com", false },
|
||||
{ "exon.io", true },
|
||||
@ -447,11 +459,13 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "finn.io", true },
|
||||
{ "firebaseio-demo.com", true },
|
||||
{ "firebaseio.com", true },
|
||||
{ "firebirdrangecookers.com", true },
|
||||
{ "firefart.at", true },
|
||||
{ "firemail.io", true },
|
||||
{ "firma-offshore.com", true },
|
||||
{ "firstlook.org", true },
|
||||
{ "fischer-its.com", true },
|
||||
{ "fitkram.cz", true },
|
||||
{ "fj.simple.com", false },
|
||||
{ "flagspot.net", true },
|
||||
{ "flamer-scene.com", true },
|
||||
@ -480,12 +494,15 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "futos.de", true },
|
||||
{ "fx5.de", true },
|
||||
{ "gallery44.org", true },
|
||||
{ "gambit.pro", true },
|
||||
{ "gambitnash.co.uk", true },
|
||||
{ "gambitnash.com", true },
|
||||
{ "gamercredo.com", true },
|
||||
{ "garron.net", true },
|
||||
{ "gavick.com", true },
|
||||
{ "gaytorrent.ru", true },
|
||||
{ "gc.net", true },
|
||||
{ "ge3k.net", true },
|
||||
{ "gemeinfreie-lieder.de", true },
|
||||
{ "geoip.fedoraproject.org", true },
|
||||
{ "geoip.stg.fedoraproject.org", true },
|
||||
@ -543,6 +560,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "haste.ch", true },
|
||||
{ "haufschild.de", true },
|
||||
{ "hausverbrauch.de", true },
|
||||
{ "hboeck.de", true },
|
||||
{ "hda.me", true },
|
||||
{ "healthcare.gov", false },
|
||||
{ "heartlandrentals.com", true },
|
||||
@ -574,6 +592,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "howrandom.org", true },
|
||||
{ "howsmyssl.com", true },
|
||||
{ "howsmytls.com", true },
|
||||
{ "hozana.si", true },
|
||||
{ "hpac-portal.com", true },
|
||||
{ "hrackydomino.cz", true },
|
||||
{ "hsmr.cc", true },
|
||||
@ -603,6 +622,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "inb4.us", true },
|
||||
{ "inbox.google.com", true },
|
||||
{ "indiecert.net", true },
|
||||
{ "indovinabank.com.vn", true },
|
||||
{ "iniiter.com", true },
|
||||
{ "inkbunny.net", true },
|
||||
{ "inleaked.com", true },
|
||||
@ -614,6 +634,8 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "interasistmen.se", true },
|
||||
{ "ionas-law.ro", true },
|
||||
{ "ipmimagazine.com", true },
|
||||
{ "ipomue.com", false },
|
||||
{ "ipsec.pl", true },
|
||||
{ "iranianlawschool.com", true },
|
||||
{ "iridiumbrowser.de", true },
|
||||
{ "irische-segenswuensche.info", true },
|
||||
@ -627,9 +649,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "itsamurai.ru", true },
|
||||
{ "itshost.ru", true },
|
||||
{ "izdiwho.com", true },
|
||||
{ "j0s.at", true },
|
||||
{ "jackyyf.com", false },
|
||||
{ "jakub-boucek.cz", true },
|
||||
{ "jamesdoylephoto.com", true },
|
||||
{ "janus-engineering.de", true },
|
||||
{ "jbn.mx", true },
|
||||
{ "jelmer.co.uk", true },
|
||||
@ -652,6 +674,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "jonathan.ir", true },
|
||||
{ "jonnybarnes.uk", true },
|
||||
{ "jonpads.com", true },
|
||||
{ "jpbike.cz", true },
|
||||
{ "jrc9.ca", true },
|
||||
{ "julian-kipka.de", true },
|
||||
{ "jwilsson.com", true },
|
||||
@ -660,13 +683,14 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "kaheim.de", true },
|
||||
{ "kalmar.com", true },
|
||||
{ "kamikano.com", true },
|
||||
{ "kaneo-gmbh.de", true },
|
||||
{ "kanzashi.com", true },
|
||||
{ "kardize24.pl", true },
|
||||
{ "karmaspa.se", true },
|
||||
{ "kartonmodellbau.org", true },
|
||||
{ "kaufberatung.community", true },
|
||||
{ "kdex.de", true },
|
||||
{ "kdyby.org", true },
|
||||
{ "kedarastudios.com", true },
|
||||
{ "keeleysam.com", true },
|
||||
{ "keeleysam.me", true },
|
||||
{ "keepa.com", true },
|
||||
@ -745,6 +769,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "lists.mayfirst.org", false },
|
||||
{ "lists.stg.fedoraproject.org", true },
|
||||
{ "livej.am", true },
|
||||
{ "livekaarten.nl", true },
|
||||
{ "ljs.io", true },
|
||||
{ "lnx.li", true },
|
||||
{ "lobste.rs", true },
|
||||
@ -762,6 +787,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "login.yahoo.com", false },
|
||||
{ "lolicore.ch", true },
|
||||
{ "lookout.com", false },
|
||||
{ "lookzook.com", true },
|
||||
{ "ludwig.im", true },
|
||||
{ "luelistan.net", true },
|
||||
{ "lukonet.com", true },
|
||||
@ -802,6 +828,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "markusueberallassetmanagement.de", true },
|
||||
{ "marshut.net", true },
|
||||
{ "massivum.de", true },
|
||||
{ "masters.black", true },
|
||||
{ "matatall.com", true },
|
||||
{ "mathiasbynens.be", true },
|
||||
{ "matteomarescotti.it", true },
|
||||
@ -817,6 +844,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "md5file.com", true },
|
||||
{ "mdfnet.se", false },
|
||||
{ "meamod.com", true },
|
||||
{ "medallia.io", true },
|
||||
{ "mediacru.sh", true },
|
||||
{ "medium.com", true },
|
||||
{ "meetfinch.com", true },
|
||||
@ -832,22 +860,25 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "miasarafina.de", true },
|
||||
{ "michalspacek.cz", true },
|
||||
{ "miconcinemas.com", true },
|
||||
{ "micropple.net", true },
|
||||
{ "mig5.net", true },
|
||||
{ "mijn-email.org", true },
|
||||
{ "mike-bland.com", true },
|
||||
{ "miketabor.com", true },
|
||||
{ "mikewest.org", true },
|
||||
{ "miku.hatsune.my", false },
|
||||
{ "mimeit.de", true },
|
||||
{ "mimovrste.com", true },
|
||||
{ "mindcoding.ro", true },
|
||||
{ "mindoktor.se", true },
|
||||
{ "minecraftvoter.com", true },
|
||||
{ "mineover.es", true },
|
||||
{ "minez-nightswatch.com", true },
|
||||
{ "minikneet.com", true },
|
||||
{ "minnesotadata.com", true },
|
||||
{ "mironet.cz", true },
|
||||
{ "mirrorx.com", true },
|
||||
{ "miskatonic.org", true },
|
||||
{ "miss-inventory.co.uk", true },
|
||||
{ "mister.hosting", true },
|
||||
{ "mitell.jp", false },
|
||||
{ "mittenhacks.com", true },
|
||||
@ -902,6 +933,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "nan.zone", true },
|
||||
{ "narodniki.com", true },
|
||||
{ "nationalpriorities.org", true },
|
||||
{ "nayahe.ru", true },
|
||||
{ "nbl.org.tw", true },
|
||||
{ "nctx.co.uk", true },
|
||||
{ "nectarleaf.com", true },
|
||||
@ -918,12 +950,14 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "newstarnootropics.com", true },
|
||||
{ "ng-security.com", true },
|
||||
{ "nginxnudes.com", true },
|
||||
{ "nicolaw.uk", true },
|
||||
{ "nieselregen.com", true },
|
||||
{ "niloxy.com", true },
|
||||
{ "nmctest.net", true },
|
||||
{ "nodari.com.ar", true },
|
||||
{ "noemax.com", true },
|
||||
{ "noobs-r-us.co.uk", true },
|
||||
{ "nopex.no", true },
|
||||
{ "nos-oignons.net", true },
|
||||
{ "notalone.gov", true },
|
||||
{ "nouvelle-vague-saint-cast.fr", true },
|
||||
@ -978,6 +1012,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "partyvan.it", true },
|
||||
{ "partyvan.nl", true },
|
||||
{ "partyvan.se", true },
|
||||
{ "passphrase.today", true },
|
||||
{ "passport.yandex.by", true },
|
||||
{ "passport.yandex.com", true },
|
||||
{ "passport.yandex.com.tr", true },
|
||||
@ -1029,6 +1064,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "pmg-offshore-company.com", true },
|
||||
{ "pmg-purchase.com", true },
|
||||
{ "pmg-purchase.net", true },
|
||||
{ "pollpodium.nl", true },
|
||||
{ "polymathematician.com", true },
|
||||
{ "polypho.nyc", true },
|
||||
{ "ponythread.com", true },
|
||||
@ -1090,10 +1126,12 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "riccy.org", true },
|
||||
{ "richiemail.net", true },
|
||||
{ "ricochet.im", true },
|
||||
{ "rid-wan.com", true },
|
||||
{ "riesenmagnete.de", true },
|
||||
{ "rika.me", true },
|
||||
{ "rippleunion.com", true },
|
||||
{ "rlalique.com", true },
|
||||
{ "roan24.pl", true },
|
||||
{ "robinadr.com", true },
|
||||
{ "robteix.com", true },
|
||||
{ "rodosto.com", true },
|
||||
@ -1113,6 +1151,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "rubecodeberg.com", true },
|
||||
{ "rubendv.be", true },
|
||||
{ "rudloff.pro", true },
|
||||
{ "rusadmin.biz", false },
|
||||
{ "ruudkoot.nl", true },
|
||||
{ "rws-vertriebsportal.de", true },
|
||||
{ "s-c.se", true },
|
||||
@ -1140,6 +1179,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "schreiber-netzwerk.eu", true },
|
||||
{ "schwarzer.it", true },
|
||||
{ "sciencex.com", true },
|
||||
{ "scotthel.me", true },
|
||||
{ "scotthelme.co.uk", true },
|
||||
{ "scoutdb.ch", true },
|
||||
{ "scrambl.is", true },
|
||||
@ -1200,7 +1240,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "smartcoin.com.br", true },
|
||||
{ "smartlend.se", true },
|
||||
{ "smartship.co.jp", true },
|
||||
{ "smith.is", true },
|
||||
{ "snakehosting.dk", true },
|
||||
{ "sneezry.com", true },
|
||||
{ "snowflake.ch", false },
|
||||
{ "sockeye.cc", true },
|
||||
{ "soia.ca", true },
|
||||
@ -1244,6 +1286,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "studienportal.eu", true },
|
||||
{ "studydrive.net", true },
|
||||
{ "stulda.cz", true },
|
||||
{ "subeesu.com", true },
|
||||
{ "subrosa.io", true },
|
||||
{ "suite73.org", true },
|
||||
{ "sunjaydhama.com", true },
|
||||
@ -1282,11 +1325,14 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "techloaner.com", true },
|
||||
{ "tegelsensanitaironline.nl", true },
|
||||
{ "tekshrek.com", true },
|
||||
{ "tempus-aquilae.de", true },
|
||||
{ "tent.io", true },
|
||||
{ "terraelectronica.ru", true },
|
||||
{ "terraweb.net", true },
|
||||
{ "terrty.net", true },
|
||||
{ "testsuite.org", true },
|
||||
{ "texte-zur-taufe.de", true },
|
||||
{ "theamp.com", true },
|
||||
{ "thebimhub.com", true },
|
||||
{ "thecustomizewindows.com", true },
|
||||
{ "theescapistswiki.com", true },
|
||||
@ -1295,7 +1341,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "therapynotes.com", true },
|
||||
{ "therapyportal.com", true },
|
||||
{ "theshadestore.com", true },
|
||||
{ "thetomharling.com", true },
|
||||
{ "theunitedstates.io", true },
|
||||
{ "thomastimepieces.com.au", true },
|
||||
{ "thusoy.com", true },
|
||||
{ "thyngster.com", false },
|
||||
@ -1317,8 +1363,8 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "todoist.com", true },
|
||||
{ "tollmanz.com", true },
|
||||
{ "tomfisher.eu", true },
|
||||
{ "tomharling.co.uk", true },
|
||||
{ "tomharling.uk", true },
|
||||
{ "tomrichards.net", true },
|
||||
{ "tomvote.com", true },
|
||||
{ "toner24.at", true },
|
||||
{ "toner24.co.uk", true },
|
||||
@ -1355,8 +1401,10 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "tresorit.com", true },
|
||||
{ "tribut.de", true },
|
||||
{ "tucuxi.org", true },
|
||||
{ "tuitle.com", true },
|
||||
{ "tunebitfm.de", true },
|
||||
{ "tuturulianda.com", true },
|
||||
{ "tuxplace.nl", true },
|
||||
{ "twentymilliseconds.com", true },
|
||||
{ "twisto.cz", true },
|
||||
{ "twitter.com", false },
|
||||
@ -1383,6 +1431,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "utilityapi.com", true },
|
||||
{ "utleieplassen.no", true },
|
||||
{ "vaddder.com", true },
|
||||
{ "vechkasov.ru", true },
|
||||
{ "vhost.co.id", true },
|
||||
{ "viasinc.com", false },
|
||||
{ "vijos.org", true },
|
||||
@ -1396,6 +1445,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "vrobert.fr", false },
|
||||
{ "w-spotlight.appspot.com", true },
|
||||
{ "wallet.google.com", true },
|
||||
{ "walnutgaming.co.uk", true },
|
||||
{ "walnutgaming.com", true },
|
||||
{ "warrencreative.com", false },
|
||||
{ "watsonhall.uk", true },
|
||||
@ -1515,6 +1565,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "xps2pdf.co.uk", true },
|
||||
{ "xuntier.ch", true },
|
||||
{ "y-o-w.com", true },
|
||||
{ "yafuoku.ru", true },
|
||||
{ "yahvehyireh.com", true },
|
||||
{ "yanovich.net", true },
|
||||
{ "yaporn.tv", false },
|
||||
@ -1522,6 +1573,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
|
||||
{ "yksityisyydensuoja.fi", true },
|
||||
{ "yokeepo.com", true },
|
||||
{ "yorcom.nl", true },
|
||||
{ "youdowell.com", true },
|
||||
{ "yoursecondphone.co", true },
|
||||
{ "ypart.eu", true },
|
||||
{ "z.ai", true },
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/ClientID.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
@ -65,13 +66,6 @@ this.DataReportingService = function () {
|
||||
this._os = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
|
||||
this._clientID = null;
|
||||
this._loadClientIdTask = null;
|
||||
this._saveClientIdTask = null;
|
||||
|
||||
this._stateDir = null;
|
||||
this._stateFilePath = null;
|
||||
|
||||
// Used for testing only, when true results in getSessionRecorder() returning
|
||||
// undefined. Controlled via simulate* methods.
|
||||
this._simulateNoSessionRecorder = false;
|
||||
@ -140,9 +134,6 @@ DataReportingService.prototype = Object.freeze({
|
||||
let policyPrefs = new Preferences(POLICY_BRANCH);
|
||||
this.policy = new DataReportingPolicy(policyPrefs, this._prefs, this);
|
||||
|
||||
this._stateDir = OS.Path.join(OS.Constants.Path.profileDir, "datareporting");
|
||||
this._stateFilePath = OS.Path.join(this._stateDir, "state.json");
|
||||
|
||||
this._os.addObserver(this, "sessionstore-windows-restored", true);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Exception when initializing data reporting service: " +
|
||||
@ -302,68 +293,6 @@ DataReportingService.prototype = Object.freeze({
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_loadClientID: function () {
|
||||
if (this._loadClientIdTask) {
|
||||
return this._loadClientIdTask;
|
||||
}
|
||||
|
||||
this._loadClientIdTask = Task.spawn(function* () {
|
||||
// Previously we had the stable client ID managed in FHR.
|
||||
// As we want to start correlating FHR and telemetry data (and moving towards
|
||||
// unifying the two), we moved the ID management to the datareporting
|
||||
// service. Consequently, we try to import the FHR ID first, so we can keep
|
||||
// using it.
|
||||
|
||||
// Try to load the client id from the DRS state file first.
|
||||
try {
|
||||
let state = yield CommonUtils.readJSON(this._stateFilePath);
|
||||
if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
|
||||
this._clientID = state.clientID;
|
||||
this._loadClientIdTask = null;
|
||||
return this._clientID;
|
||||
}
|
||||
} catch (e) {
|
||||
// fall through to next option
|
||||
}
|
||||
|
||||
// If we dont have DRS state yet, try to import from the FHR state.
|
||||
try {
|
||||
let fhrStatePath = OS.Path.join(OS.Constants.Path.profileDir, "healthreport", "state.json");
|
||||
let state = yield CommonUtils.readJSON(fhrStatePath);
|
||||
if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
|
||||
this._clientID = state.clientID;
|
||||
this._loadClientIdTask = null;
|
||||
this._saveClientID();
|
||||
return this._clientID;
|
||||
}
|
||||
} catch (e) {
|
||||
// fall through to next option
|
||||
}
|
||||
|
||||
// We dont have an id from FHR yet, generate a new ID.
|
||||
this._clientID = CommonUtils.generateUUID();
|
||||
this._loadClientIdTask = null;
|
||||
this._saveClientIdTask = this._saveClientID();
|
||||
|
||||
// Wait on persisting the id. Otherwise failure to save the ID would result in
|
||||
// the client creating and subsequently sending multiple IDs to the server.
|
||||
// This would appear as multiple clients submitting similar data, which would
|
||||
// result in orphaning.
|
||||
yield this._saveClientIdTask;
|
||||
|
||||
return this._clientID;
|
||||
}.bind(this));
|
||||
|
||||
return this._loadClientIdTask;
|
||||
},
|
||||
|
||||
_saveClientID: Task.async(function* () {
|
||||
let obj = { clientID: this._clientID };
|
||||
yield OS.File.makeDir(this._stateDir);
|
||||
yield CommonUtils.writeJSON(obj, this._stateFilePath);
|
||||
this._saveClientIdTask = null;
|
||||
}),
|
||||
|
||||
/**
|
||||
* This returns a promise resolving to the the stable client ID we use for
|
||||
* data reporting (FHR & Telemetry). Previously exising FHR client IDs are
|
||||
@ -372,11 +301,7 @@ DataReportingService.prototype = Object.freeze({
|
||||
* @return Promise<string> The stable client ID.
|
||||
*/
|
||||
getClientID: function() {
|
||||
if (!this._clientID) {
|
||||
return this._loadClientID();
|
||||
}
|
||||
|
||||
return Promise.resolve(this._clientID);
|
||||
return ClientID.getClientID();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -385,14 +310,7 @@ DataReportingService.prototype = Object.freeze({
|
||||
* @return Promise<string> The new client ID.
|
||||
*/
|
||||
resetClientID: Task.async(function* () {
|
||||
yield this._loadClientIdTask;
|
||||
yield this._saveClientIdTask;
|
||||
|
||||
this._clientID = CommonUtils.generateUUID();
|
||||
this._saveClientIdTask = this._saveClientID();
|
||||
yield this._saveClientIdTask;
|
||||
|
||||
return this._clientID;
|
||||
return ClientID.resetClientID();
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -413,15 +331,6 @@ DataReportingService.prototype = Object.freeze({
|
||||
simulateRestoreSessionRecorder() {
|
||||
this._simulateNoSessionRecorder = false;
|
||||
},
|
||||
|
||||
/*
|
||||
* Simulate a restart of the service. This is for testing only.
|
||||
*/
|
||||
_reset: Task.async(function* () {
|
||||
yield this._loadClientIdTask;
|
||||
yield this._saveClientIdTask;
|
||||
this._clientID = null;
|
||||
}),
|
||||
});
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataReportingService]);
|
||||
|
@ -5,4 +5,3 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
|
||||
[test_policy.js]
|
||||
[test_session_recorder.js]
|
||||
[test_client_id.js]
|
||||
|
@ -45,6 +45,7 @@ let publicProperties = [
|
||||
"now",
|
||||
"promiseAccountsForceSigninURI",
|
||||
"promiseAccountsChangeProfileURI",
|
||||
"removeCachedOAuthToken",
|
||||
"resendVerificationEmail",
|
||||
"setSignedInUser",
|
||||
"signOut",
|
||||
@ -70,17 +71,24 @@ let publicProperties = [
|
||||
// }
|
||||
// If the state has changed between the function being called and the promise
|
||||
// being resolved, the .resolve() call will actually be rejected.
|
||||
let AccountState = function(fxaInternal) {
|
||||
let AccountState = function(fxaInternal, signedInUserStorage, accountData = null) {
|
||||
this.fxaInternal = fxaInternal;
|
||||
this.signedInUserStorage = signedInUserStorage;
|
||||
this.signedInUser = accountData ? {version: DATA_FORMAT_VERSION, accountData} : null;
|
||||
this.uid = accountData ? accountData.uid : null;
|
||||
this.oauthTokens = {};
|
||||
};
|
||||
|
||||
AccountState.prototype = {
|
||||
cert: null,
|
||||
keyPair: null,
|
||||
signedInUser: null,
|
||||
oauthTokens: null,
|
||||
whenVerifiedDeferred: null,
|
||||
whenKeysReadyDeferred: null,
|
||||
profile: null,
|
||||
promiseInitialAccountData: null,
|
||||
uid: null,
|
||||
|
||||
get isCurrent() this.fxaInternal && this.fxaInternal.currentAccountState === this,
|
||||
|
||||
@ -100,6 +108,7 @@ AccountState.prototype = {
|
||||
this.cert = null;
|
||||
this.keyPair = null;
|
||||
this.signedInUser = null;
|
||||
this.uid = null;
|
||||
this.fxaInternal = null;
|
||||
this.initProfilePromise = null;
|
||||
|
||||
@ -109,46 +118,113 @@ AccountState.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
getUserAccountData: function() {
|
||||
// Skip disk if user is cached.
|
||||
// Clobber all cached data and write that empty data to storage.
|
||||
signOut() {
|
||||
this.cert = null;
|
||||
this.keyPair = null;
|
||||
this.signedInUser = null;
|
||||
this.oauthTokens = {};
|
||||
this.uid = null;
|
||||
return this.persistUserData();
|
||||
},
|
||||
|
||||
getUserAccountData() {
|
||||
if (!this.isCurrent) {
|
||||
return this.reject(new Error("Another user has signed in"));
|
||||
}
|
||||
if (this.promiseInitialAccountData) {
|
||||
// We are still reading the data for the first and only time.
|
||||
return this.promiseInitialAccountData;
|
||||
}
|
||||
// We've previously read it successfully (and possibly updated it since)
|
||||
if (this.signedInUser) {
|
||||
return this.resolve(this.signedInUser.accountData);
|
||||
}
|
||||
|
||||
return this.fxaInternal.signedInUserStorage.get().then(
|
||||
user => {
|
||||
// We fetch the signedInUser data first, then fetch the token store and
|
||||
// ensure the uid in the tokens matches our user.
|
||||
let accountData = null;
|
||||
let oauthTokens = {};
|
||||
return this.promiseInitialAccountData = this.signedInUserStorage.get()
|
||||
.then(user => {
|
||||
if (logPII) {
|
||||
// don't stringify unless it will be written. We should replace this
|
||||
// check with param substitutions added in bug 966674
|
||||
log.debug("getUserAccountData -> " + JSON.stringify(user));
|
||||
log.debug("getUserAccountData", user);
|
||||
}
|
||||
if (user && user.version == this.version) {
|
||||
log.debug("setting signed in user");
|
||||
this.signedInUser = user;
|
||||
}
|
||||
return this.resolve(user ? user.accountData : null);
|
||||
},
|
||||
err => {
|
||||
// In an ideal world we could cache the data in this.signedInUser, but
|
||||
// if we do, the interaction with the login manager breaks when the
|
||||
// password is locked as this read may only have obtained partial data.
|
||||
// Therefore every read *must* really read incase the login manager is
|
||||
// now unlocked. We could fix this with a refactor...
|
||||
accountData = user ? user.accountData : null;
|
||||
}, err => {
|
||||
// Error reading signed in user account data.
|
||||
this.promiseInitialAccountData = null;
|
||||
if (err instanceof OS.File.Error && err.becauseNoSuchFile) {
|
||||
// File hasn't been created yet. That will be done
|
||||
// on the first call to getSignedInUser
|
||||
return this.resolve(null);
|
||||
// on the first call to setSignedInUser
|
||||
return;
|
||||
}
|
||||
return this.reject(err);
|
||||
}
|
||||
);
|
||||
// something else went wrong - report the error but continue without
|
||||
// user data.
|
||||
log.error("Failed to read signed in user data", err);
|
||||
}).then(() => {
|
||||
if (!accountData) {
|
||||
return null;
|
||||
}
|
||||
return this.signedInUserStorage.getOAuthTokens();
|
||||
}).then(tokenData => {
|
||||
if (tokenData && tokenData.tokens &&
|
||||
tokenData.version == DATA_FORMAT_VERSION &&
|
||||
tokenData.uid == accountData.uid ) {
|
||||
oauthTokens = tokenData.tokens;
|
||||
}
|
||||
}, err => {
|
||||
// Error reading the OAuth tokens file.
|
||||
if (err instanceof OS.File.Error && err.becauseNoSuchFile) {
|
||||
// File hasn't been created yet, but will be when tokens are saved.
|
||||
return;
|
||||
}
|
||||
log.error("Failed to read oauth tokens", err)
|
||||
}).then(() => {
|
||||
// We are done - clear our promise and save the data if we are still
|
||||
// current.
|
||||
this.promiseInitialAccountData = null;
|
||||
if (this.isCurrent) {
|
||||
// As above, we can not cache the data to this.signedInUser as we
|
||||
// may only have partial data due to a locked MP, so the next
|
||||
// request must re-read incase it is now unlocked.
|
||||
// But we do save the tokens and the uid
|
||||
this.oauthTokens = oauthTokens;
|
||||
this.uid = accountData ? accountData.uid : null;
|
||||
}
|
||||
return accountData;
|
||||
});
|
||||
// phew!
|
||||
},
|
||||
|
||||
// XXX - this should really be called "updateCurrentUserData" or similar as
|
||||
// it is only ever used to add new fields to the *current* user, not to
|
||||
// set a new user as current.
|
||||
setUserAccountData: function(accountData) {
|
||||
return this.fxaInternal.signedInUserStorage.get().then(record => {
|
||||
if (!this.isCurrent) {
|
||||
return this.reject(new Error("Another user has signed in"));
|
||||
}
|
||||
record.accountData = accountData;
|
||||
this.signedInUser = record;
|
||||
return this.fxaInternal.signedInUserStorage.set(record)
|
||||
if (!this.isCurrent) {
|
||||
return this.reject(new Error("Another user has signed in"));
|
||||
}
|
||||
if (this.promiseInitialAccountData) {
|
||||
throw new Error("Can't set account data before it's been read.");
|
||||
}
|
||||
if (!accountData) {
|
||||
// see above - this should really be called "updateCurrentUserData" or similar.
|
||||
throw new Error("Attempt to use setUserAccountData with null user data.");
|
||||
}
|
||||
if (accountData.uid != this.uid) {
|
||||
// see above - this should really be called "updateCurrentUserData" or similar.
|
||||
throw new Error("Attempt to use setUserAccountData with a different user.");
|
||||
}
|
||||
// Set our signedInUser before we start the write, so any updates to the
|
||||
// data while the write completes are still captured.
|
||||
this.signedInUser = {version: DATA_FORMAT_VERSION, accountData: accountData};
|
||||
return this.signedInUserStorage.set(this.signedInUser)
|
||||
.then(() => this.resolve(accountData));
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -276,7 +352,107 @@ AccountState.prototype = {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
|
||||
};
|
||||
// Abstractions for storage of cached tokens - these are all sync, and don't
|
||||
// handle revocation etc - it's just storage.
|
||||
|
||||
// A preamble for the cache helpers...
|
||||
_cachePreamble() {
|
||||
if (!this.isCurrent) {
|
||||
throw new Error("Another user has signed in");
|
||||
}
|
||||
},
|
||||
|
||||
// Set a cached token. |tokenData| must have a 'token' element, but may also
|
||||
// have additional fields (eg, it probably specifies the server to revoke
|
||||
// from). The 'get' functions below return the entire |tokenData| value.
|
||||
setCachedToken(scopeArray, tokenData) {
|
||||
this._cachePreamble();
|
||||
if (!tokenData.token) {
|
||||
throw new Error("No token");
|
||||
}
|
||||
let key = getScopeKey(scopeArray);
|
||||
this.oauthTokens[key] = tokenData;
|
||||
// And a background save...
|
||||
this._persistCachedTokens();
|
||||
},
|
||||
|
||||
// Return data for a cached token or null (or throws on bad state etc)
|
||||
getCachedToken(scopeArray) {
|
||||
this._cachePreamble();
|
||||
let key = getScopeKey(scopeArray);
|
||||
if (this.oauthTokens[key]) {
|
||||
// later we might want to check an expiry date - but we currently
|
||||
// have no such concept, so just return it.
|
||||
log.trace("getCachedToken returning cached token");
|
||||
return this.oauthTokens[key];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// Get an array of tokenData for all cached tokens.
|
||||
getAllCachedTokens() {
|
||||
this._cachePreamble();
|
||||
let result = [];
|
||||
for (let [key, tokenValue] in Iterator(this.oauthTokens)) {
|
||||
result.push(tokenValue);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
// Remove a cached token from the cache. Does *not* revoke it from anywhere.
|
||||
// Returns the entire token entry if found, null otherwise.
|
||||
removeCachedToken(token) {
|
||||
this._cachePreamble();
|
||||
let data = this.oauthTokens;
|
||||
for (let [key, tokenValue] in Iterator(data)) {
|
||||
if (tokenValue.token == token) {
|
||||
delete data[key];
|
||||
// And a background save...
|
||||
this._persistCachedTokens();
|
||||
return tokenValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// A hook-point for tests. Returns a promise that's ignored in most cases
|
||||
// (notable exceptions are tests and when we explicitly are saving the entire
|
||||
// set of user data.)
|
||||
_persistCachedTokens() {
|
||||
this._cachePreamble();
|
||||
let record;
|
||||
if (this.uid) {
|
||||
record = {
|
||||
version: DATA_FORMAT_VERSION,
|
||||
uid: this.uid,
|
||||
tokens: this.oauthTokens,
|
||||
};
|
||||
} else {
|
||||
record = null;
|
||||
}
|
||||
return this.signedInUserStorage.setOAuthTokens(record).catch(
|
||||
err => {
|
||||
log.error("Failed to save account data for token cache", err);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
persistUserData() {
|
||||
return this._persistCachedTokens().catch(err => {
|
||||
log.error("Failed to persist cached tokens", err);
|
||||
}).then(() => {
|
||||
return this.signedInUserStorage.set(this.signedInUser);
|
||||
}).catch(err => {
|
||||
log.error("Failed to persist account data", err);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/* Given an array of scopes, make a string key by normalizing. */
|
||||
function getScopeKey(scopeArray) {
|
||||
let normalizedScopes = scopeArray.map(item => item.toLowerCase());
|
||||
return normalizedScopes.sort().join("|");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies properties from a given object to another object.
|
||||
@ -336,6 +512,11 @@ this.FxAccounts = function (mockInternal) {
|
||||
}
|
||||
|
||||
if (mockInternal) {
|
||||
// A little work-around to ensure the initial currentAccountState has
|
||||
// the same mock storage the test passed in.
|
||||
if (mockInternal.signedInUserStorage) {
|
||||
internal.currentAccountState.signedInUserStorage = mockInternal.signedInUserStorage;
|
||||
}
|
||||
// Exposes the internal object for testing only.
|
||||
external.internal = internal;
|
||||
}
|
||||
@ -352,6 +533,28 @@ function FxAccountsInternal() {
|
||||
// Make a local copy of this constant so we can mock it in testing
|
||||
this.POLL_SESSION = POLL_SESSION;
|
||||
|
||||
// The one and only "storage" object. While this is created here, the
|
||||
// FxAccountsInternal object does *not* use it directly, but instead passes
|
||||
// it to AccountState objects which has sole responsibility for storage.
|
||||
// Ideally we would create it in the AccountState objects, but that makes
|
||||
// testing hard as AccountState objects are regularly created and thrown
|
||||
// away. Doing it this way means tests can mock/replace this storage object
|
||||
// and have it used by all AccountState objects, even those created before
|
||||
// and after the mock has been setup.
|
||||
|
||||
// We only want the fancy LoginManagerStorage on desktop.
|
||||
#if defined(MOZ_B2G)
|
||||
this.signedInUserStorage = new JSONStorage({
|
||||
#else
|
||||
this.signedInUserStorage = new LoginManagerStorage({
|
||||
#endif
|
||||
// We don't reference |profileDir| in the top-level module scope
|
||||
// as we may be imported before we know where it is.
|
||||
filename: DEFAULT_STORAGE_FILENAME,
|
||||
oauthTokensFilename: DEFAULT_OAUTH_TOKENS_FILENAME,
|
||||
baseDir: OS.Constants.Path.profileDir,
|
||||
});
|
||||
|
||||
// We interact with the Firefox Accounts auth server in order to confirm that
|
||||
// a user's email has been verified and also to fetch the user's keys from
|
||||
// the server. We manage these processes in possibly long-lived promises
|
||||
@ -363,19 +566,7 @@ function FxAccountsInternal() {
|
||||
// currentAccountState are used for this purpose.
|
||||
// (XXX - should the timer be directly on the currentAccountState?)
|
||||
this.currentTimer = null;
|
||||
this.currentAccountState = new AccountState(this);
|
||||
|
||||
// We don't reference |profileDir| in the top-level module scope
|
||||
// as we may be imported before we know where it is.
|
||||
// We only want the fancy new LoginManagerStorage on desktop.
|
||||
#if defined(MOZ_B2G)
|
||||
this.signedInUserStorage = new JSONStorage({
|
||||
#else
|
||||
this.signedInUserStorage = new LoginManagerStorage({
|
||||
#endif
|
||||
filename: DEFAULT_STORAGE_FILENAME,
|
||||
baseDir: OS.Constants.Path.profileDir,
|
||||
});
|
||||
this.currentAccountState = new AccountState(this, this.signedInUserStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -509,19 +700,22 @@ FxAccountsInternal.prototype = {
|
||||
log.debug("setSignedInUser - aborting any existing flows");
|
||||
this.abortExistingFlow();
|
||||
|
||||
let record = {version: this.version, accountData: credentials};
|
||||
let currentState = this.currentAccountState;
|
||||
// Cache a clone of the credentials object.
|
||||
currentState.signedInUser = JSON.parse(JSON.stringify(record));
|
||||
let currentAccountState = this.currentAccountState = new AccountState(
|
||||
this,
|
||||
this.signedInUserStorage,
|
||||
JSON.parse(JSON.stringify(credentials)) // Pass a clone of the credentials object.
|
||||
);
|
||||
|
||||
// This promise waits for storage, but not for verification.
|
||||
// We're telling the caller that this is durable now.
|
||||
return this.signedInUserStorage.set(record).then(() => {
|
||||
return currentAccountState.persistUserData().then(() => {
|
||||
this.notifyObservers(ONLOGIN_NOTIFICATION);
|
||||
if (!this.isUserEmailVerified(credentials)) {
|
||||
this.startVerifiedCheck(credentials);
|
||||
}
|
||||
}).then(result => currentState.resolve(result));
|
||||
}).then(() => {
|
||||
return currentAccountState.resolve();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -578,7 +772,7 @@ FxAccountsInternal.prototype = {
|
||||
this.currentTimer = 0;
|
||||
}
|
||||
this.currentAccountState.abort();
|
||||
this.currentAccountState = new AccountState(this);
|
||||
this.currentAccountState = new AccountState(this, this.signedInUserStorage);
|
||||
},
|
||||
|
||||
accountStatus: function accountStatus() {
|
||||
@ -590,12 +784,31 @@ FxAccountsInternal.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
_destroyOAuthToken: function(tokenData) {
|
||||
let client = new FxAccountsOAuthGrantClient({
|
||||
serverURL: tokenData.server,
|
||||
client_id: FX_OAUTH_CLIENT_ID
|
||||
});
|
||||
return client.destroyToken(tokenData.token)
|
||||
},
|
||||
|
||||
_destroyAllOAuthTokens: function(tokenInfos) {
|
||||
// let's just destroy them all in parallel...
|
||||
let promises = [];
|
||||
for (let tokenInfo of tokenInfos) {
|
||||
promises.push(this._destroyOAuthToken(tokenInfo));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
signOut: function signOut(localOnly) {
|
||||
let currentState = this.currentAccountState;
|
||||
let sessionToken;
|
||||
let tokensToRevoke;
|
||||
return currentState.getUserAccountData().then(data => {
|
||||
// Save the session token for use in the call to signOut below.
|
||||
sessionToken = data && data.sessionToken;
|
||||
tokensToRevoke = currentState.getAllCachedTokens();
|
||||
return this._signOutLocal();
|
||||
}).then(() => {
|
||||
// FxAccountsManager calls here, then does its own call
|
||||
@ -608,8 +821,15 @@ FxAccountsInternal.prototype = {
|
||||
// the user from signing out. The server must tolerate
|
||||
// clients just disappearing, so this call should be best effort.
|
||||
return this._signOutServer(sessionToken);
|
||||
}).then(null, err => {
|
||||
log.error("Error during remote sign out of Firefox Accounts: " + err);
|
||||
}).catch(err => {
|
||||
log.error("Error during remote sign out of Firefox Accounts", err);
|
||||
}).then(() => {
|
||||
return this._destroyAllOAuthTokens(tokensToRevoke);
|
||||
}).catch(err => {
|
||||
log.error("Error during destruction of oauth tokens during signout", err);
|
||||
}).then(() => {
|
||||
// just for testing - notifications are cheap when no observers.
|
||||
this.notifyObservers("testhelper-fxa-signout-complete");
|
||||
});
|
||||
}
|
||||
}).then(() => {
|
||||
@ -622,9 +842,10 @@ FxAccountsInternal.prototype = {
|
||||
* signOut via FxAccountsClient.
|
||||
*/
|
||||
_signOutLocal: function signOutLocal() {
|
||||
this.abortExistingFlow();
|
||||
this.currentAccountState.signedInUser = null; // clear in-memory cache
|
||||
return this.signedInUserStorage.set(null);
|
||||
let currentAccountState = this.currentAccountState;
|
||||
return currentAccountState.signOut().then(() => {
|
||||
this.abortExistingFlow(); // this resets this.currentAccountState.
|
||||
});
|
||||
},
|
||||
|
||||
_signOutServer: function signOutServer(sessionToken) {
|
||||
@ -995,7 +1216,9 @@ FxAccountsInternal.prototype = {
|
||||
*
|
||||
* @param options
|
||||
* {
|
||||
* scope: (string) the oauth scope being requested
|
||||
* scope: (string/array) the oauth scope(s) being requested. As a
|
||||
* convenience, you may pass a string if only one scope is
|
||||
* required, or an array of strings if multiple are needed.
|
||||
* }
|
||||
*
|
||||
* @return Promise.<string | Error>
|
||||
@ -1008,46 +1231,107 @@ FxAccountsInternal.prototype = {
|
||||
* AUTH_ERROR
|
||||
* UNKNOWN_ERROR
|
||||
*/
|
||||
getOAuthToken: function (options = {}) {
|
||||
getOAuthToken: Task.async(function* (options = {}) {
|
||||
log.debug("getOAuthToken enter");
|
||||
|
||||
if (!options.scope) {
|
||||
return this._error(ERROR_INVALID_PARAMETER, "Missing 'scope' option");
|
||||
let scope = options.scope;
|
||||
if (typeof scope === "string") {
|
||||
scope = [scope];
|
||||
}
|
||||
|
||||
let oAuthURL = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.oauth.uri");
|
||||
if (!scope || !scope.length) {
|
||||
throw this._error(ERROR_INVALID_PARAMETER, "Missing or invalid 'scope' option");
|
||||
}
|
||||
|
||||
yield this._getVerifiedAccountOrReject();
|
||||
|
||||
// Early exit for a cached token.
|
||||
let currentState = this.currentAccountState;
|
||||
let cached = currentState.getCachedToken(scope);
|
||||
if (cached) {
|
||||
log.debug("getOAuthToken returning a cached token");
|
||||
return cached.token;
|
||||
}
|
||||
|
||||
// We are going to hit the server - this is the string we pass to it.
|
||||
let scopeString = scope.join(" ");
|
||||
let client = options.client;
|
||||
|
||||
if (!client) {
|
||||
try {
|
||||
let defaultURL = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.oauth.uri");
|
||||
client = new FxAccountsOAuthGrantClient({
|
||||
serverURL: oAuthURL,
|
||||
serverURL: defaultURL,
|
||||
client_id: FX_OAUTH_CLIENT_ID
|
||||
});
|
||||
} catch (e) {
|
||||
return this._error(ERROR_INVALID_PARAMETER, e);
|
||||
throw this._error(ERROR_INVALID_PARAMETER, e);
|
||||
}
|
||||
}
|
||||
let oAuthURL = client.serverURL.href;
|
||||
|
||||
return this._getVerifiedAccountOrReject()
|
||||
.then(() => this.getAssertion(oAuthURL))
|
||||
.then(assertion => client.getTokenFromAssertion(assertion, options.scope))
|
||||
.then(result => result.access_token)
|
||||
.then(null, err => this._errorToErrorClass(err));
|
||||
},
|
||||
try {
|
||||
log.debug("getOAuthToken fetching new token from", oAuthURL);
|
||||
let assertion = yield this.getAssertion(oAuthURL);
|
||||
let result = yield client.getTokenFromAssertion(assertion, scopeString);
|
||||
let token = result.access_token;
|
||||
// If we got one, cache it.
|
||||
if (token) {
|
||||
let entry = {token: token, server: oAuthURL};
|
||||
// But before we do, check the cache again - if we find one now, it
|
||||
// means someone else concurrently requested the same scope and beat
|
||||
// us to the cache write. To be nice to the server, we revoke the one
|
||||
// we just got and return the newly cached value.
|
||||
let cached = currentState.getCachedToken(scope);
|
||||
if (cached) {
|
||||
log.debug("Detected a race for this token - revoking the new one.");
|
||||
this._destroyOAuthToken(entry);
|
||||
return cached.token;
|
||||
}
|
||||
currentState.setCachedToken(scope, entry);
|
||||
}
|
||||
return token;
|
||||
} catch (err) {
|
||||
throw this._errorToErrorClass(err);
|
||||
}
|
||||
}),
|
||||
|
||||
_getVerifiedAccountOrReject: function () {
|
||||
return this.currentAccountState.getUserAccountData().then(data => {
|
||||
if (!data) {
|
||||
// No signed-in user
|
||||
return this._error(ERROR_NO_ACCOUNT);
|
||||
}
|
||||
if (!this.isUserEmailVerified(data)) {
|
||||
// Signed-in user has not verified email
|
||||
return this._error(ERROR_UNVERIFIED_ACCOUNT);
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Remove an OAuth token from the token cache. Callers should call this
|
||||
* after they determine a token is invalid, so a new token will be fetched
|
||||
* on the next call to getOAuthToken().
|
||||
*
|
||||
* @param options
|
||||
* {
|
||||
* token: (string) A previously fetched token.
|
||||
* }
|
||||
* @return Promise.<undefined> This function will always resolve, even if
|
||||
* an unknown token is passed.
|
||||
*/
|
||||
removeCachedOAuthToken: Task.async(function* (options) {
|
||||
if (!options.token || typeof options.token !== "string") {
|
||||
throw this._error(ERROR_INVALID_PARAMETER, "Missing or invalid 'token' option");
|
||||
}
|
||||
let currentState = this.currentAccountState;
|
||||
let existing = currentState.removeCachedToken(options.token);
|
||||
if (existing) {
|
||||
// background destroy.
|
||||
this._destroyOAuthToken(existing).catch(err => {
|
||||
log.warn("FxA failed to revoke a cached token", err);
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
_getVerifiedAccountOrReject: Task.async(function* () {
|
||||
let data = yield this.currentAccountState.getUserAccountData();
|
||||
if (!data) {
|
||||
// No signed-in user
|
||||
throw this._error(ERROR_NO_ACCOUNT);
|
||||
}
|
||||
if (!this.isUserEmailVerified(data)) {
|
||||
// Signed-in user has not verified email
|
||||
throw this._error(ERROR_UNVERIFIED_ACCOUNT);
|
||||
}
|
||||
}),
|
||||
|
||||
/*
|
||||
* Coerce an error into one of the general error cases:
|
||||
@ -1068,7 +1352,7 @@ FxAccountsInternal.prototype = {
|
||||
(aError.message === "INVALID_PARAMETER" ||
|
||||
aError.message === "NO_ACCOUNT" ||
|
||||
aError.message === "UNVERIFIED_ACCOUNT")) {
|
||||
return Promise.reject(aError);
|
||||
return aError;
|
||||
}
|
||||
return this._error(ERROR_UNKNOWN, aError);
|
||||
},
|
||||
@ -1079,7 +1363,7 @@ FxAccountsInternal.prototype = {
|
||||
if (aDetails) {
|
||||
reason.details = aDetails;
|
||||
}
|
||||
return Promise.reject(reason);
|
||||
return reason;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1115,7 +1399,7 @@ FxAccountsInternal.prototype = {
|
||||
log.error("Could not retrieve profile data", error);
|
||||
return accountState.reject(error);
|
||||
})
|
||||
.then(null, err => this._errorToErrorClass(err));
|
||||
.then(null, err => Promise.reject(this._errorToErrorClass(err)));
|
||||
},
|
||||
};
|
||||
|
||||
@ -1133,6 +1417,7 @@ FxAccountsInternal.prototype = {
|
||||
function JSONStorage(options) {
|
||||
this.baseDir = options.baseDir;
|
||||
this.path = OS.Path.join(options.baseDir, options.filename);
|
||||
this.oauthTokensPath = OS.Path.join(options.baseDir, options.oauthTokensFilename);
|
||||
};
|
||||
|
||||
JSONStorage.prototype = {
|
||||
@ -1143,7 +1428,17 @@ JSONStorage.prototype = {
|
||||
|
||||
get: function() {
|
||||
return CommonUtils.readJSON(this.path);
|
||||
}
|
||||
},
|
||||
|
||||
setOAuthTokens: function(contents) {
|
||||
return OS.File.makeDir(this.baseDir, {ignoreExisting: true})
|
||||
.then(CommonUtils.writeJSON.bind(null, contents, this.oauthTokensPath));
|
||||
},
|
||||
|
||||
getOAuthTokens: function(contents) {
|
||||
return CommonUtils.readJSON(this.oauthTokensPath);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1332,6 +1627,16 @@ LoginManagerStorage.prototype = {
|
||||
return data;
|
||||
}),
|
||||
|
||||
// OAuth tokens are always written to disk, so delegate to our JSON storage.
|
||||
// (Bug 1013064 comments 23-25 explain why we save the sessionToken into the
|
||||
// plain JSON file, and the same logic applies for oauthTokens being in JSON)
|
||||
getOAuthTokens() {
|
||||
return this.jsonStorage.getOAuthTokens();
|
||||
},
|
||||
|
||||
setOAuthTokens(contents) {
|
||||
return this.jsonStorage.setOAuthTokens(contents);
|
||||
},
|
||||
}
|
||||
|
||||
// A getter for the instance to export
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user