diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index 891e0d6c4dd7..c0c2b93f78ee 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -129,7 +129,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index f6bc70db111e..06c2b8b92bc3 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,13 +19,13 @@
-
+
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index a7607d964b3e..1602eb6a9a24 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index e83d03f6fef3..f1aab48a4798 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index f6bc70db111e..06c2b8b92bc3 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,13 +19,13 @@
-
+
-
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index 15d4f75d40c5..d5675726df09 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index 6a3a4f8dab1b..7b26522340c4 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index 5332e79b2bf2..15616f7d710e 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
- "revision": "03effd58034893d2a12907faa6a8a41d3e923b50",
+ "revision": "1764121939b82f4ded4ca30761df48c3841028b0",
"repo_path": "integration/gaia-central"
}
diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml
index 2e45fb7271b2..3195f9b97113 100644
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -17,11 +17,11 @@
-
+
-
+
diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml
index c82bbe571909..91571de3f13f 100644
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index f0b7c3e74cff..d7fe4e2722d7 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml
index 948ec2e310f8..917e60da9aad 100644
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -17,12 +17,12 @@
-
+
-
+
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 3b29ba7cd78a..ca9db831b348 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2562,7 +2562,7 @@ let BrowserOnClick = {
let mm = window.messageManager;
mm.addMessageListener("Browser:CertExceptionError", this);
mm.addMessageListener("Browser:SiteBlockedError", this);
- mm.addMessageListener("Browser:NetworkError", this);
+ mm.addMessageListener("Browser:EnableOnlineMode", this);
mm.addMessageListener("Browser:SendSSLErrorReport", this);
mm.addMessageListener("Browser:SetSSLErrorReportAuto", this);
},
@@ -2571,7 +2571,7 @@ let BrowserOnClick = {
let mm = window.messageManager;
mm.removeMessageListener("Browser:CertExceptionError", this);
mm.removeMessageListener("Browser:SiteBlockedError", this);
- mm.removeMessageListener("Browser:NetworkError", this);
+ mm.removeMessageListener("Browser:EnableOnlineMode", this);
mm.removeMessageListener("Browser:SendSSLErrorReport", this);
mm.removeMessageListener("Browser:SetSSLErrorReportAuto", this);
},
@@ -2605,9 +2605,12 @@ let BrowserOnClick = {
this.onAboutBlocked(msg.data.elementId, msg.data.isMalware,
msg.data.isTopFrame, msg.data.location);
break;
- case "Browser:NetworkError":
- // Reset network state, the error page will refresh on its own.
- Services.io.offline = false;
+ case "Browser:EnableOnlineMode":
+ if (Services.io.offline) {
+ // Reset network state and refresh the page.
+ Services.io.offline = false;
+ msg.target.reload();
+ }
break;
case "Browser:SendSSLErrorReport":
this.onSSLErrorReport(msg.target, msg.data.elementId,
diff --git a/browser/base/content/content.js b/browser/base/content/content.js
index 9fc0fd64847e..941242cf4bec 100644
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -568,7 +568,8 @@ let ClickEventHandler = {
this.onAboutBlocked(originalTarget, ownerDoc);
return;
} else if (ownerDoc.documentURI.startsWith("about:neterror")) {
- this.onAboutNetError(originalTarget, ownerDoc);
+ this.onAboutNetError(event, ownerDoc.documentURI);
+ return;
}
let [href, node] = this._hrefAndLinkNodeForClickEvent(event);
@@ -635,12 +636,18 @@ let ClickEventHandler = {
});
},
- onAboutNetError: function (targetElement, ownerDoc) {
- let elmId = targetElement.getAttribute("id");
- if (elmId != "errorTryAgain" || !/e=netOffline/.test(ownerDoc.documentURI)) {
+ onAboutNetError: function (event, documentURI) {
+ let elmId = event.originalTarget.getAttribute("id");
+ if (elmId != "errorTryAgain" || !/e=netOffline/.test(documentURI)) {
return;
}
- sendSyncMessage("Browser:NetworkError", {});
+ // browser front end will handle clearing offline mode and refreshing
+ // the page *if* we're in offline mode now. Otherwise let the error page
+ // handle the click.
+ if (Services.io.offline) {
+ event.preventDefault();
+ sendAsyncMessage("Browser:EnableOnlineMode", {});
+ }
},
/**
diff --git a/browser/base/content/test/general/browser_bug435325.js b/browser/base/content/test/general/browser_bug435325.js
index fe05c757a12d..4b70503a7a01 100644
--- a/browser/base/content/test/general/browser_bug435325.js
+++ b/browser/base/content/test/general/browser_bug435325.js
@@ -56,12 +56,12 @@ function checkPage() {
// the actual example.com.
Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
+ Services.obs.addObserver(function observer(aSubject, aTopic) {
+ ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
+ "online.");
+ finish();
+ }, "network:offline-status-changed", false);
gBrowser.contentDocument.getElementById("errorTryAgain").click();
-
- ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
- "online.");
-
- finish();
}
registerCleanupFunction(function() {
diff --git a/browser/base/content/test/newtab/browser_newtab_enhanced.js b/browser/base/content/test/newtab/browser_newtab_enhanced.js
index 6e48a5772b57..c45f155811ca 100644
--- a/browser/base/content/test/newtab/browser_newtab_enhanced.js
+++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js
@@ -37,8 +37,8 @@ function runTests() {
yield setLinks("-1");
// Test with enhanced = false
- NewTabUtils.allPages.enhanced = false;
yield addNewTabPageTab();
+ yield customizeNewTabPage("classic");
let {type, enhanced, title} = getData(0);
is(type, "organic", "directory link is organic");
isnot(enhanced, "", "directory link has enhanced image");
@@ -47,8 +47,8 @@ function runTests() {
is(getData(1), null, "history link pushed out by directory link");
// Test with enhanced = true
- NewTabUtils.allPages.enhanced = true;
yield addNewTabPageTab();
+ yield customizeNewTabPage("enhanced");
({type, enhanced, title} = getData(0));
is(type, "organic", "directory link is still organic");
isnot(enhanced, "", "directory link still has enhanced image");
@@ -67,12 +67,15 @@ function runTests() {
is(getData(1), null, "directory link pushed out by pinned history link");
// Test pinned link with enhanced = false
- NewTabUtils.allPages.enhanced = false;
yield addNewTabPageTab();
+ yield customizeNewTabPage("classic");
({type, enhanced, title} = getData(0));
isnot(type, "enhanced", "history link is not enhanced");
is(enhanced, "", "history link has no enhanced image");
is(title, "site#-1");
is(getData(1), null, "directory link still pushed out by pinned history link");
+
+ ok(getContentDocument().getElementById("newtab-intro-what"),
+ "'What is this page?' link exists");
}
diff --git a/browser/base/content/test/newtab/head.js b/browser/base/content/test/newtab/head.js
index d823085242b9..890939847dc8 100644
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -684,3 +684,34 @@ function whenSearchInitDone() {
});
return deferred.promise;
}
+
+/**
+ * Changes the newtab customization option and waits for the panel to open and close
+ *
+ * @param {string} aTheme
+ * Can be any of("blank"|"classic"|"enhanced")
+ */
+function customizeNewTabPage(aTheme) {
+ let document = getContentDocument();
+ let panel = document.getElementById("newtab-customize-panel");
+ let customizeButton = document.getElementById("newtab-customize-button");
+
+ // Attache onShown the listener on panel
+ panel.addEventListener("popupshown", function onShown() {
+ panel.removeEventListener("popupshown", onShown);
+
+ // Get the element for the specific option and click on it,
+ // then trigger an escape to close the panel
+ document.getElementById("newtab-customize-" + aTheme).click();
+ executeSoon(() => { panel.hidePopup(); });
+ });
+
+ // Attache the listener for panel closing, this will resolve the promise
+ panel.addEventListener("popuphidden", function onHidden() {
+ panel.removeEventListener("popuphidden", onHidden);
+ executeSoon(TestRunner.next);
+ });
+
+ // Click on the customize button to display the panel
+ customizeButton.click();
+}
diff --git a/browser/devtools/animationinspector/animation-panel.js b/browser/devtools/animationinspector/animation-panel.js
index d6a5825b169b..1fd762a7e6fc 100644
--- a/browser/devtools/animationinspector/animation-panel.js
+++ b/browser/devtools/animationinspector/animation-panel.js
@@ -193,21 +193,26 @@ PlayerWidget.prototype = {
});
let titleHTML = "";
- // Name
+ // Name.
if (state.name) {
- // Css animations have names
+ // Css animations have names.
titleHTML += L10N.getStr("player.animationNameLabel");
titleHTML += "" + state.name + "";
} else {
- // Css transitions don't
+ // Css transitions don't.
titleHTML += L10N.getStr("player.transitionNameLabel");
}
- // Duration and iteration count
+ // Duration, delay and iteration count.
titleHTML += "";
titleHTML += L10N.getStr("player.animationDurationLabel");
titleHTML += "" + L10N.getFormatStr("player.timeLabel",
this.getFormattedTime(state.duration)) + "";
+ if (state.delay) {
+ titleHTML += L10N.getStr("player.animationDelayLabel");
+ titleHTML += "" + L10N.getFormatStr("player.timeLabel",
+ this.getFormattedTime(state.delay)) + "";
+ }
titleHTML += L10N.getStr("player.animationIterationCountLabel");
let count = state.iterationCount || L10N.getStr("player.infiniteIterationCount");
titleHTML += "" + count + "";
@@ -215,7 +220,7 @@ PlayerWidget.prototype = {
titleEl.innerHTML = titleHTML;
- // Timeline widget
+ // Timeline widget.
let timelineEl = createNode({
parent: this.el,
attributes: {
@@ -223,7 +228,7 @@ PlayerWidget.prototype = {
}
});
- // Playback control buttons container
+ // Playback control buttons container.
let playbackControlsEl = createNode({
parent: timelineEl,
attributes: {
@@ -241,7 +246,7 @@ PlayerWidget.prototype = {
}
});
- // Sliders container
+ // Sliders container.
let slidersContainerEl = createNode({
parent: timelineEl,
attributes: {
@@ -249,9 +254,9 @@ PlayerWidget.prototype = {
}
});
- let max = state.duration; // Infinite iterations
+ let max = state.duration; // Infinite iterations.
if (state.iterationCount) {
- // Finite iterations
+ // Finite iterations.
max = state.iterationCount * state.duration;
}
@@ -267,6 +272,7 @@ PlayerWidget.prototype = {
"min": "0",
"max": max,
"step": "10",
+ "value": "0",
// The currentTime isn't settable yet, so disable the timeline slider
"disabled": "true"
}
@@ -280,7 +286,7 @@ PlayerWidget.prototype = {
}
});
this.timeDisplayEl.textContent = L10N.getFormatStr("player.timeLabel",
- this.getFormattedTime());
+ this.getFormattedTime(0));
this.containerEl.appendChild(this.el);
},
@@ -290,14 +296,11 @@ PlayerWidget.prototype = {
* @param {Number} time Defaults to the player's currentTime.
* @return {String} The formatted time, e.g. "10.55"
*/
- getFormattedTime: function(time=this.player.state.currentTime) {
- let str = time/1000 + "";
- str = str.split(".");
- if (str.length === 1) {
- return str[0] + ".00";
- } else {
- return str[0] + "." + str[1].substring(0, 2);
- }
+ getFormattedTime: function(time) {
+ return (time/1000).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2
+ });
},
/**
@@ -390,6 +393,12 @@ PlayerWidget.prototype = {
displayTime: function(time) {
let state = this.player.state;
+ // If the animation is delayed, don't start displaying the time until the
+ // delay has passed.
+ if (state.delay) {
+ time = Math.max(0, time - state.delay);
+ }
+
this.timeDisplayEl.textContent = L10N.getFormatStr("player.timeLabel",
this.getFormattedTime(time));
if (!state.iterationCount && time !== state.duration) {
diff --git a/browser/devtools/animationinspector/test/browser.ini b/browser/devtools/animationinspector/test/browser.ini
index 9a8cd21659af..6d528f7ef961 100644
--- a/browser/devtools/animationinspector/test/browser.ini
+++ b/browser/devtools/animationinspector/test/browser.ini
@@ -11,8 +11,10 @@ support-files =
[browser_animation_play_pause_button.js]
[browser_animation_playerFronts_are_refreshed.js]
[browser_animation_playerWidgets_destroy.js]
+[browser_animation_playerWidgets_meta_data.js]
[browser_animation_refresh_when_active.js]
[browser_animation_same_nb_of_playerWidgets_and_playerFronts.js]
[browser_animation_shows_player_on_valid_node.js]
[browser_animation_timeline_animates.js]
-[browser_animation_ui_updates_when_animation_changes.js]
+[browser_animation_timeline_waits_for_delay.js]
+[browser_animation_ui_updates_when_animation_changes.js]
\ No newline at end of file
diff --git a/browser/devtools/animationinspector/test/browser_animation_playerWidgets_meta_data.js b/browser/devtools/animationinspector/test/browser_animation_playerWidgets_meta_data.js
new file mode 100644
index 000000000000..69d5a3ba0e83
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_playerWidgets_meta_data.js
@@ -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 player widgets show the right player meta-data (name, duration,
+// iteration count, delay).
+
+add_task(function*() {
+ yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+ let {inspector, panel} = yield openAnimationInspector();
+
+ info("Select the simple animated node");
+ yield selectNode(".animated", inspector);
+
+ let titleEl = panel.playerWidgets[0].el.querySelector(".animation-title");
+ ok(titleEl,
+ "The player widget has a title element, where meta-data should be displayed");
+
+ let nameEl = titleEl.querySelector("strong");
+ ok(nameEl, "The first tag was retrieved, it should contain the name");
+ is(nameEl.textContent, "simple-animation", "The animation name is correct");
+
+ let metaDataEl = titleEl.querySelector(".meta-data");
+ ok(metaDataEl, "The meta-data element exists");
+
+ let metaDataEls = metaDataEl.querySelectorAll("strong");
+ is(metaDataEls.length, 2, "2 meta-data elements were found");
+ is(metaDataEls[0].textContent, "2.00s",
+ "The first meta-data is the duration, and is correct");
+
+ info("Select the node with the delayed animation");
+ yield selectNode(".delayed", inspector);
+
+ titleEl = panel.playerWidgets[0].el.querySelector(".animation-title");
+ nameEl = titleEl.querySelector("strong");
+ is(nameEl.textContent, "simple-animation", "The animation name is correct");
+
+ metaDataEls = titleEl.querySelectorAll(".meta-data strong");
+ is(metaDataEls.length, 3,
+ "3 meta-data elements were found for the delayed animation");
+ is(metaDataEls[0].textContent, "3.00s",
+ "The first meta-data is the duration, and is correct");
+ is(metaDataEls[1].textContent, "60.00s",
+ "The second meta-data is the delay, and is correct");
+ is(metaDataEls[2].textContent, "10",
+ "The third meta-data is the iteration count, and is correct");
+});
diff --git a/browser/devtools/animationinspector/test/browser_animation_timeline_waits_for_delay.js b/browser/devtools/animationinspector/test/browser_animation_timeline_waits_for_delay.js
new file mode 100644
index 000000000000..65d688e98ffa
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_timeline_waits_for_delay.js
@@ -0,0 +1,24 @@
+/* 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 currentTime timeline doesn't move if the animation is currently
+// waiting for an animation-delay.
+
+add_task(function*() {
+ yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+ let {inspector, panel} = yield openAnimationInspector();
+
+ info("Select the delayed animation node");
+ yield selectNode(".delayed", inspector);
+
+ let widget = panel.playerWidgets[0];
+
+ let timeline = widget.currentTimeEl;
+ is(timeline.value, 0, "The timeline is at 0 since the animation hasn't started");
+
+ let timeLabel = widget.timeDisplayEl;
+ is(timeLabel.textContent, "0.00s", "The current time is 0");
+});
diff --git a/browser/devtools/animationinspector/test/doc_simple_animation.html b/browser/devtools/animationinspector/test/doc_simple_animation.html
index 3582cef3432d..945f7bd7847f 100644
--- a/browser/devtools/animationinspector/test/doc_simple_animation.html
+++ b/browser/devtools/animationinspector/test/doc_simple_animation.html
@@ -4,8 +4,8 @@