mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound. a=merge
This commit is contained in:
commit
d25d42ef82
@ -31,15 +31,15 @@ function log(...aMessageArgs) {
|
||||
log("\n\n======================= identity.js =======================\n\n");
|
||||
|
||||
// This script may be injected more than once into an iframe.
|
||||
// Ensure we don't redefine contstants
|
||||
// It's hard to do this with |const| like we should, so use var instead.
|
||||
if (typeof kIdentityJSLoaded === 'undefined') {
|
||||
const kIdentityDelegateWatch = "identity-delegate-watch";
|
||||
const kIdentityDelegateRequest = "identity-delegate-request";
|
||||
const kIdentityDelegateLogout = "identity-delegate-logout";
|
||||
const kIdentityDelegateReady = "identity-delegate-ready";
|
||||
const kIdentityDelegateFinished = "identity-delegate-finished";
|
||||
const kIdentityControllerDoMethod = "identity-controller-doMethod";
|
||||
const kIdentktyJSLoaded = true;
|
||||
var kIdentityDelegateWatch = "identity-delegate-watch";
|
||||
var kIdentityDelegateRequest = "identity-delegate-request";
|
||||
var kIdentityDelegateLogout = "identity-delegate-logout";
|
||||
var kIdentityDelegateReady = "identity-delegate-ready";
|
||||
var kIdentityDelegateFinished = "identity-delegate-finished";
|
||||
var kIdentityControllerDoMethod = "identity-controller-doMethod";
|
||||
var kIdentktyJSLoaded = true;
|
||||
}
|
||||
|
||||
var showUI = false;
|
||||
|
@ -1306,6 +1306,17 @@ pref("browser.devedition.theme.enabled", false);
|
||||
pref("browser.devedition.theme.showCustomizeButton", false);
|
||||
#endif
|
||||
|
||||
// Developer edition promo preferences
|
||||
pref("devtools.devedition.promo.shown", false);
|
||||
pref("devtools.devedition.promo.url", "https://mozilla.org/firefox/developer");
|
||||
|
||||
// Only potentially show in beta release
|
||||
#ifdef MOZ_UPDATE_CHANNEL == beta
|
||||
pref("devtools.devedition.promo.enabled", true);
|
||||
#else
|
||||
pref("devtools.devedition.promo.enabled", false);
|
||||
#endif
|
||||
|
||||
// Disable the error console
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
|
@ -18,6 +18,8 @@ Cu.import("resource://services-sync/util.js");
|
||||
const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
|
||||
const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync.ui.showCustomizationDialog";
|
||||
|
||||
const ACTION_URL_PARAM = "action";
|
||||
|
||||
const OBSERVER_TOPICS = [
|
||||
fxAccountsCommon.ONVERIFIED_NOTIFICATION,
|
||||
fxAccountsCommon.ONLOGOUT_NOTIFICATION,
|
||||
@ -96,7 +98,7 @@ function shouldAllowRelink(acctName) {
|
||||
let wrapper = {
|
||||
iframe: null,
|
||||
|
||||
init: function (url, entryPoint) {
|
||||
init: function (url, urlParams) {
|
||||
let weave = Cc["@mozilla.org/weave/service;1"]
|
||||
.getService(Ci.nsISupports)
|
||||
.wrappedJSObject;
|
||||
@ -116,14 +118,14 @@ let wrapper = {
|
||||
let iframe = document.getElementById("remote");
|
||||
this.iframe = iframe;
|
||||
iframe.addEventListener("load", this);
|
||||
try {
|
||||
if (entryPoint) {
|
||||
url += (url.indexOf("?") >= 0 ? "&" : "?") + entryPoint;
|
||||
}
|
||||
iframe.src = url;
|
||||
} catch (e) {
|
||||
error("Couldn't init Firefox Account wrapper: " + e.message);
|
||||
|
||||
// Ideally we'd just merge urlParams with new URL(url).searchParams, but our
|
||||
// URLSearchParams implementation doesn't support iteration (bug 1085284).
|
||||
let urlParamStr = urlParams.toString();
|
||||
if (urlParamStr) {
|
||||
url += (url.contains("?") ? "&" : "?") + urlParamStr;
|
||||
}
|
||||
iframe.src = url;
|
||||
},
|
||||
|
||||
handleEvent: function (evt) {
|
||||
@ -295,46 +297,49 @@ function init() {
|
||||
if (window.closed) {
|
||||
return;
|
||||
}
|
||||
// If the url contains an entrypoint query parameter, extract it into a variable
|
||||
// to append it to the accounts URI resource.
|
||||
// Works for the following cases:
|
||||
// - about:accounts?entrypoint="abouthome"
|
||||
// - about:accounts?entrypoint=abouthome&action=signup
|
||||
let entryPointQParam = "entrypoint=";
|
||||
let entryPointPos = window.location.href.indexOf(entryPointQParam);
|
||||
let entryPoint = "";
|
||||
if (entryPointPos >= 0) {
|
||||
entryPoint = window.location.href.substring(entryPointPos).split("&")[0];
|
||||
}
|
||||
if (window.location.href.contains("action=signin")) {
|
||||
|
||||
// Ideally we'd use new URL(document.URL).searchParams, but for about: URIs,
|
||||
// searchParams is empty.
|
||||
let urlParams = new URLSearchParams(document.URL.split("?")[1] || "");
|
||||
let action = urlParams.get(ACTION_URL_PARAM);
|
||||
urlParams.delete(ACTION_URL_PARAM);
|
||||
|
||||
switch (action) {
|
||||
case "signin":
|
||||
if (user) {
|
||||
// asking to sign-in when already signed in just shows manage.
|
||||
show("stage", "manage");
|
||||
} else {
|
||||
show("remote");
|
||||
wrapper.init(fxAccounts.getAccountsSignInURI(), entryPoint);
|
||||
wrapper.init(fxAccounts.getAccountsSignInURI(), urlParams);
|
||||
}
|
||||
} else if (window.location.href.contains("action=signup")) {
|
||||
break;
|
||||
case "signup":
|
||||
if (user) {
|
||||
// asking to sign-up when already signed in just shows manage.
|
||||
show("stage", "manage");
|
||||
} else {
|
||||
show("remote");
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), entryPoint);
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), urlParams);
|
||||
}
|
||||
} else if (window.location.href.contains("action=reauth")) {
|
||||
break;
|
||||
case "reauth":
|
||||
// ideally we would only show this when we know the user is in a
|
||||
// "must reauthenticate" state - but we don't.
|
||||
// As the email address will be included in the URL returned from
|
||||
// promiseAccountsForceSigninURI, just always show it.
|
||||
fxAccounts.promiseAccountsForceSigninURI().then(url => {
|
||||
show("remote");
|
||||
wrapper.init(url, entryPoint);
|
||||
wrapper.init(url, urlParams);
|
||||
});
|
||||
} else if (window.location.href.contains("action=migrateToDevEdition") &&
|
||||
user == null) {
|
||||
migrateToDevEdition(user, entryPoint);
|
||||
} else {
|
||||
break;
|
||||
case "migrateToDevEdition":
|
||||
if (user == null) {
|
||||
migrateToDevEdition(user, urlParams);
|
||||
break;
|
||||
}
|
||||
// else, fall through
|
||||
default:
|
||||
// No action specified, or migration request when we already have a user.
|
||||
if (user) {
|
||||
show("stage", "manage");
|
||||
@ -343,8 +348,9 @@ function init() {
|
||||
} else {
|
||||
show("stage", "intro");
|
||||
// load the remote frame in the background
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), entryPoint);
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), urlParams);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -376,7 +382,7 @@ function show(id, childId) {
|
||||
}
|
||||
|
||||
// Migrate sync data from the default profile to the dev-edition profile.
|
||||
function migrateToDevEdition(user, entryPoint) {
|
||||
function migrateToDevEdition(user, urlParams) {
|
||||
let migrateSyncCreds = false;
|
||||
try {
|
||||
migrateSyncCreds = Services.prefs.getBoolPref("identity.fxaccounts.migrateToDevEdition");
|
||||
@ -390,13 +396,13 @@ function migrateToDevEdition(user, entryPoint) {
|
||||
}).then(() => {
|
||||
return fxAccounts.promiseAccountsForceSigninURI().then(url => {
|
||||
show("remote");
|
||||
wrapper.init(url, entryPoint);
|
||||
wrapper.init(url, urlParams);
|
||||
});
|
||||
}).then(null, error => {
|
||||
log("Failed to migrate FX Account: " + error);
|
||||
show("stage", "intro");
|
||||
// load the remote frame in the background
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), entryPoint);
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), urlParams);
|
||||
}).then(() => {
|
||||
// Reset the pref after migration.
|
||||
Services.prefs.setBoolPref("identity.fxaccounts.migrateToDevEdition", false);
|
||||
@ -404,7 +410,7 @@ function migrateToDevEdition(user, entryPoint) {
|
||||
} else {
|
||||
show("stage", "intro");
|
||||
// load the remote frame in the background
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), entryPoint);
|
||||
wrapper.init(fxAccounts.getAccountsSignUpURI(), urlParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,20 +32,9 @@ const gXPInstallObserver = {
|
||||
{
|
||||
var brandBundle = document.getElementById("bundle_brand");
|
||||
var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
|
||||
var winOrBrowser = installInfo.originator;
|
||||
var browser = installInfo.browser;
|
||||
|
||||
var browser;
|
||||
try {
|
||||
var shell = winOrBrowser.QueryInterface(Components.interfaces.nsIDOMWindow)
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocShell);
|
||||
browser = this._getBrowser(shell);
|
||||
} catch (e) {
|
||||
browser = winOrBrowser;
|
||||
}
|
||||
// Note that the above try/catch will pass through dead object proxies and
|
||||
// other degenerate objects. Make sure the browser is bonafide.
|
||||
// Make sure the browser is still alive.
|
||||
if (!browser || gBrowser.browsers.indexOf(browser) == -1)
|
||||
return;
|
||||
|
||||
|
@ -1194,7 +1194,9 @@ var gBrowserInit = {
|
||||
BrowserOffline.init();
|
||||
OfflineApps.init();
|
||||
IndexedDBPromptHelper.init();
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
gRemoteTabsUI.init();
|
||||
#endif
|
||||
|
||||
// Initialize the full zoom setting.
|
||||
// We do this before the session restore service gets initialized so we can
|
||||
@ -1616,7 +1618,9 @@ var gBrowserInit = {
|
||||
gSyncUI.init();
|
||||
#endif
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
gRemoteTabsUI.init();
|
||||
#endif
|
||||
},
|
||||
|
||||
nonBrowserWindowShutdown: function() {
|
||||
@ -7315,14 +7319,9 @@ let gRemoteTabsUI = {
|
||||
|
||||
let newRemoteWindow = document.getElementById("menu_newRemoteWindow");
|
||||
let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow");
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
let autostart = Services.appinfo.browserTabsRemoteAutostart;
|
||||
newRemoteWindow.hidden = autostart;
|
||||
newNonRemoteWindow.hidden = !autostart;
|
||||
#else
|
||||
newRemoteWindow.hidden = true;
|
||||
newNonRemoteWindow.hidden = true;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2594,6 +2594,7 @@
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
#endif
|
||||
|
||||
<method name="moveTabTo">
|
||||
<parameter name="aTab"/>
|
||||
|
@ -128,7 +128,7 @@ skip-if = e10s # Bug ????? - no e10s switch-to-tab support yet
|
||||
skip-if = os != "win" || e10s # The Fitts Law back button is only supported on Windows (bug 571454) / e10s - Bug ?????? test touches content (attempts to add an event listener directly to the contentWindow)
|
||||
[browser_blob-channelname.js]
|
||||
[browser_bookmark_titles.js]
|
||||
skip-if = buildapp == 'mulet' || toolkit == "windows" || e10s # Disabled on Windows due to frequent failures (bugs 825739, 841341) / e10s - Bug ?????? test checks event.target on load event, which our e10s utils don't support
|
||||
skip-if = buildapp == 'mulet' || toolkit == "windows" || e10s # Disabled on Windows due to frequent failures (bugs 825739, 841341) / e10s - Bug 1094205 - places doesn't return the right thing in e10s mode, for some reason
|
||||
[browser_bug304198.js]
|
||||
skip-if = e10s
|
||||
[browser_bug321000.js]
|
||||
@ -202,7 +202,8 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1093206 - need to re-enable tests re
|
||||
skip-if = e10s # Bug ?????? - test doesn't wait for document to be created before it checks it
|
||||
[browser_bug550565.js]
|
||||
[browser_bug553455.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet? ; for e10s, indefinite waiting halfway through the test, tracked in bug 1093586
|
||||
skip-if = true # Bug 1094312
|
||||
#skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet? ; for e10s, indefinite waiting halfway through the test, tracked in bug 1093586
|
||||
[browser_bug555224.js]
|
||||
skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
||||
[browser_bug555767.js]
|
||||
@ -212,7 +213,7 @@ skip-if = e10s # Bug 1093373 - relies on browser.sessionHistory
|
||||
[browser_bug561623.js]
|
||||
skip-if = e10s
|
||||
[browser_bug561636.js]
|
||||
skip-if = e10s # Bug 691601 - no form submit observers
|
||||
skip-if = e10s # Bug 1093677 - automated form submission from the test doesn't seem to quite work yet
|
||||
[browser_bug562649.js]
|
||||
skip-if = e10s # Bug 940195 - XULBrowserWindow.isBusy is false as a remote tab starts loading
|
||||
[browser_bug563588.js]
|
||||
@ -232,9 +233,8 @@ skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
[browser_bug580638.js]
|
||||
[browser_bug580956.js]
|
||||
[browser_bug581242.js]
|
||||
skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
|
||||
[browser_bug581253.js]
|
||||
skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
|
||||
skip-if = e10s # Bug 1093756 - can't bookmark the data: url in e10s somehow
|
||||
[browser_bug581947.js]
|
||||
skip-if = e10s
|
||||
[browser_bug585558.js]
|
||||
@ -245,7 +245,7 @@ skip-if = e10s
|
||||
skip-if = e10s # Bug 653065 - Make the lightweight theme web installer ready for e10s
|
||||
[browser_bug594131.js]
|
||||
[browser_bug595507.js]
|
||||
skip-if = e10s # Bug 691601 - no form submit observers
|
||||
skip-if = e10s # Bug 1093677 - automated form submission from the test doesn't seem to quite work yet
|
||||
[browser_bug596687.js]
|
||||
[browser_bug597218.js]
|
||||
[browser_bug609700.js]
|
||||
@ -270,7 +270,6 @@ skip-if = e10s # Bug ?????? - test directly manipulates content (doc.querySelect
|
||||
[browser_bug719271.js]
|
||||
skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
|
||||
[browser_bug724239.js]
|
||||
skip-if = e10s # Bug 1077738
|
||||
[browser_bug734076.js]
|
||||
skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
|
||||
[browser_bug735471.js]
|
||||
@ -292,7 +291,6 @@ skip-if = e10s # Bug 1093373 - relies on browser.sessionHistory
|
||||
[browser_bug880101.js]
|
||||
[browser_bug882977.js]
|
||||
[browser_bug902156.js]
|
||||
skip-if = e10s
|
||||
[browser_bug906190.js]
|
||||
skip-if = buildapp == "mulet" || e10s # Bug 1093642 - test manipulates content and relies on content focus
|
||||
[browser_bug970746.js]
|
||||
@ -309,7 +307,6 @@ skip-if = os == "mac" || e10s # bug 967013, bug 926729
|
||||
[browser_ctrlTab.js]
|
||||
skip-if = e10s # Bug ????? - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
|
||||
[browser_customize_popupNotification.js]
|
||||
skip-if = e10s
|
||||
[browser_datareporting_notification.js]
|
||||
run-if = datareporting
|
||||
[browser_devedition.js]
|
||||
@ -343,13 +340,13 @@ skip-if = e10s # Bug ?????? - this test fails for obscure reasons on non-windows
|
||||
[browser_keywordBookmarklets.js]
|
||||
skip-if = e10s # Bug ?????? - this test fails for obscure reasons on non-windows builds only.
|
||||
[browser_keywordSearch.js]
|
||||
skip-if = e10s # Bug 921957 - remote webprogress doesn't supply originalURI attribute on the request object
|
||||
skip-if = e10s # Bug 921957 - remote webprogress doesn't supply cancel method on the request object
|
||||
[browser_keywordSearch_postData.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.contentDocument.body.textContent)
|
||||
[browser_lastAccessedTab.js]
|
||||
skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
|
||||
[browser_locationBarCommand.js]
|
||||
skip-if = os == "linux" || e10s # Linux: Intermittent failures, bug 917535; e10s: Bug ?????? - Focus issues (There should be no focused element - Got [object XULElement], expected null)
|
||||
skip-if = os == "linux" || e10s # Linux: Intermittent failures, bug 917535; e10s: Bug 1094252 - Focus issues (There should be no focused element - Got [object XULElement], expected null)
|
||||
[browser_locationBarExternalLoad.js]
|
||||
skip-if = e10s
|
||||
[browser_menuButtonFitts.js]
|
||||
@ -359,7 +356,6 @@ skip-if = e10s # Bug 921952 - Content:Click event issues
|
||||
[browser_minimize.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: gBrowser.docShell is null)
|
||||
[browser_mixedcontent_securityflags.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content ("cannot ipc non-cpow object")
|
||||
[browser_notification_tab_switching.js]
|
||||
skip-if = buildapp == 'mulet' || e10s # Bug ?????? - uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32
|
||||
[browser_offlineQuotaNotification.js]
|
||||
@ -454,26 +450,22 @@ skip-if = buildapp == 'mulet' || e10s # Bug 921935 - focusmanager issues with e1
|
||||
[browser_unloaddialogs.js]
|
||||
skip-if = e10s # Bug ?????? - test uses chrome windowMediator to try and see alert() from content
|
||||
[browser_urlHighlight.js]
|
||||
skip-if = e10s
|
||||
[browser_urlbarAutoFillTrimURLs.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s # Bug 1093941 - Waits indefinitely for onSearchComplete
|
||||
[browser_urlbarCopying.js]
|
||||
skip-if = e10s # Bug 1069757 - browser_urlbarCopying.js needs e10s love.
|
||||
[browser_urlbarEnter.js]
|
||||
skip-if = e10s # Bug ?????? - obscure non-windows child process crashes on try
|
||||
skip-if = e10s # Bug 1093941 - used to cause obscure non-windows child process crashes on try
|
||||
[browser_urlbarRevert.js]
|
||||
skip-if = e10s # Bug ?????? - ESC reverted the location bar value - Got foobar, expected example.com
|
||||
skip-if = e10s # Bug 1093941 - ESC reverted the location bar value - Got foobar, expected example.com
|
||||
[browser_urlbarSearchSingleWordNotification.js]
|
||||
skip-if = e10s
|
||||
skip-if = e10s # Bug 1093997 - intermittent failures in e10s-mode only
|
||||
[browser_urlbarStop.js]
|
||||
skip-if = e10s # Bug ????? - test calls gBrowser.contentWindow.stop
|
||||
skip-if = e10s # Bug 1093941 - test calls gBrowser.contentWindow.stop
|
||||
[browser_urlbarTrimURLs.js]
|
||||
skip-if = e10s
|
||||
[browser_urlbar_search_healthreport.js]
|
||||
skip-if = e10s # Bug ?????? - FHR tests failing (either with "no data for today" or "2 records for today")
|
||||
[browser_utilityOverlay.js]
|
||||
[browser_visibleFindSelection.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
skip-if = e10s # Bug 921935 - focusmanager issues with e10s (test calls waitForFocus)
|
||||
[browser_visibleLabel.js]
|
||||
[browser_visibleTabs.js]
|
||||
[browser_visibleTabs_bookmarkAllPages.js]
|
||||
@ -488,7 +480,7 @@ skip-if = buildapp == 'mulet'
|
||||
[browser_wyciwyg_urlbarCopying.js]
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
|
||||
[browser_zbug569342.js]
|
||||
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
|
||||
skip-if = e10s # Bug 1094240 - has findbar-related failures
|
||||
[browser_registerProtocolHandler_notification.js]
|
||||
skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
|
||||
[browser_no_mcb_on_http_site.js]
|
||||
|
@ -331,6 +331,38 @@ let gTests = [
|
||||
is(url, sign_up_url + "&entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "about:accounts URL params should be copied to remote URL params " +
|
||||
"when remote URL has no URL params, except for 'action'",
|
||||
teardown() {
|
||||
gBrowser.removeCurrentTab();
|
||||
},
|
||||
run: function* () {
|
||||
let signupURL = "https://example.com/";
|
||||
setPref("identity.fxaccounts.remote.signup.uri", signupURL);
|
||||
let queryStr = "email=foo%40example.com&foo=bar&baz=quux";
|
||||
let [tab, url] =
|
||||
yield promiseNewTabWithIframeLoadEvent("about:accounts?" + queryStr +
|
||||
"&action=action");
|
||||
is(url, signupURL + "?" + queryStr, "URL params are copied to signup URL");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "about:accounts URL params should be copied to remote URL params " +
|
||||
"when remote URL already has some URL params, except for 'action'",
|
||||
teardown() {
|
||||
gBrowser.removeCurrentTab();
|
||||
},
|
||||
run: function* () {
|
||||
let signupURL = "https://example.com/?param";
|
||||
setPref("identity.fxaccounts.remote.signup.uri", signupURL);
|
||||
let queryStr = "email=foo%40example.com&foo=bar&baz=quux";
|
||||
let [tab, url] =
|
||||
yield promiseNewTabWithIframeLoadEvent("about:accounts?" + queryStr +
|
||||
"&action=action");
|
||||
is(url, signupURL + "&" + queryStr, "URL params are copied to signup URL");
|
||||
},
|
||||
},
|
||||
]; // gTests
|
||||
|
||||
function test()
|
||||
|
@ -102,7 +102,7 @@ let gTests = [
|
||||
desc: "Check that performing a search fires a search event and records to " +
|
||||
"Firefox Health Report.",
|
||||
setup: function () { },
|
||||
run: function () {
|
||||
run: function* () {
|
||||
// Skip this test on Linux.
|
||||
if (navigator.platform.indexOf("Linux") == 0) {
|
||||
return Promise.resolve();
|
||||
@ -116,10 +116,19 @@ let gTests = [
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let engine = yield promiseNewEngine("searchSuggestionEngine.xml");
|
||||
// Make this actually work in healthreport by giving it an ID:
|
||||
engine.wrappedJSObject._identifier = 'org.mozilla.testsearchsuggestions';
|
||||
|
||||
let promise = promiseBrowserAttributes(gBrowser.selectedTab);
|
||||
Services.search.currentEngine = engine;
|
||||
yield promise;
|
||||
|
||||
let numSearchesBefore = 0;
|
||||
let searchEventDeferred = Promise.defer();
|
||||
let doc = gBrowser.contentDocument;
|
||||
let engineName = doc.documentElement.getAttribute("searchEngineName");
|
||||
is(engine.name, engineName, "Engine name in DOM should match engine we just added");
|
||||
let mm = gBrowser.selectedTab.linkedBrowser.messageManager;
|
||||
|
||||
mm.loadFrameScript(TEST_CONTENT_HELPER, false);
|
||||
@ -149,7 +158,16 @@ let gTests = [
|
||||
uri.spec;
|
||||
let loadPromise = waitForDocLoadAndStopIt(expectedURL);
|
||||
|
||||
return Promise.all([searchEventDeferred.promise, loadPromise]);
|
||||
try {
|
||||
yield Promise.all([searchEventDeferred.promise, loadPromise]);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "An error occurred waiting for the search to be performed: " + ex);
|
||||
} finally {
|
||||
try {
|
||||
Services.search.removeEngine(engine);
|
||||
} catch (ex) {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -656,7 +674,11 @@ function promiseNewEngine(basename) {
|
||||
Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
|
||||
onSuccess: function (engine) {
|
||||
info("Search engine added: " + basename);
|
||||
registerCleanupFunction(() => Services.search.removeEngine(engine));
|
||||
registerCleanupFunction(() => {
|
||||
try {
|
||||
Services.search.removeEngine(engine);
|
||||
} catch (ex) { /* Can't remove the engine more than once */ }
|
||||
});
|
||||
addDeferred.resolve(engine);
|
||||
},
|
||||
onError: function (errCode) {
|
||||
|
@ -16,7 +16,7 @@ function testVal(aExpected) {
|
||||
value = value.substring(pos + range.length);
|
||||
}
|
||||
result += value;
|
||||
is(result, aExpected);
|
||||
is(result, aExpected, "Correct part of the urlbar contents is highlighted");
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
@ -55,6 +55,9 @@ function test() {
|
||||
testVal("jar:http://mozilla.org/example.jar!/");
|
||||
testVal("view-source:http://mozilla.org/");
|
||||
|
||||
testVal("http://localhost");
|
||||
testVal("http://someotherhostwithnodots");
|
||||
|
||||
Services.prefs.setBoolPref(prefname, false);
|
||||
|
||||
testVal("http://mozilla.org/");
|
||||
|
@ -1180,7 +1180,6 @@
|
||||
// Cache these as cancelling the installs will remove this
|
||||
// notification which will drop these references
|
||||
let browser = this.notification.browser;
|
||||
let contentWindow = this.notification.options.contentWindow;
|
||||
let sourceURI = this.notification.options.sourceURI;
|
||||
|
||||
let installs = this.notification.options.installs;
|
||||
@ -1206,7 +1205,7 @@
|
||||
callback: function() {
|
||||
let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"].
|
||||
getService(Ci.amIWebInstallListener);
|
||||
if (weblistener.onWebInstallRequested(contentWindow, sourceURI,
|
||||
if (weblistener.onWebInstallRequested(browser, sourceURI,
|
||||
installs, installs.length)) {
|
||||
installs.forEach(function(aInstall) {
|
||||
aInstall.install();
|
||||
|
@ -712,8 +712,17 @@ function openPrefsHelp() {
|
||||
function trimURL(aURL) {
|
||||
// This function must not modify the given URL such that calling
|
||||
// nsIURIFixup::createFixupURI with the result will produce a different URI.
|
||||
return aURL /* remove single trailing slash for http/https/ftp URLs */
|
||||
.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1")
|
||||
/* remove http:// unless the host starts with "ftp\d*\." or contains "@" */
|
||||
.replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1");
|
||||
|
||||
// remove single trailing slash for http/https/ftp URLs
|
||||
let rv = aURL.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1");
|
||||
|
||||
// Strip the leading http:// only if the host has at least one '.' or
|
||||
// looks like an ipv6 ip:
|
||||
let hostMatch = rv.match(/^http:\/\/([^\/]*)/);
|
||||
let ipv6Regex = /\[[\da-f:]*\]/;
|
||||
if (hostMatch && (hostMatch[1].contains(".") || ipv6Regex.test(hostMatch[1]))) {
|
||||
/* remove http:// unless the host starts with "ftp\d*\." or contains "@" */
|
||||
rv = rv.replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
]
|
||||
|
||||
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
||||
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
|
||||
|
||||
DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
|
||||
|
@ -5,7 +5,7 @@
|
||||
#aboutDialogContainer {
|
||||
background-image: url("chrome://branding/content/about-background.png");
|
||||
background-repeat: no-repeat;
|
||||
background-color: rgb(19,8,36);
|
||||
background-color: rgb(26,58,99);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,6 @@ EXTRA_JS_MODULES += [
|
||||
'ScrollbarSampler.jsm',
|
||||
]
|
||||
|
||||
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
|
||||
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
|
||||
|
||||
|
@ -35,7 +35,8 @@
|
||||
<script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/otSdkDriver.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/conversationStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/localRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/js/conversationViews.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/websocket.js"></script>
|
||||
<script type="text/javascript" src="loop/js/conversationAppStore.js"></script>
|
||||
|
@ -151,23 +151,25 @@ loop.Client = (function($) {
|
||||
* Block call URL based on the token identifier
|
||||
*
|
||||
* @param {string} token Conversation identifier used to block the URL
|
||||
* @param {mozLoop.LOOP_SESSION_TYPE} sessionType The type of session which
|
||||
* the url belongs to.
|
||||
* @param {function} cb Callback function used for handling an error
|
||||
* response. XXX The incoming call panel does not
|
||||
* exist after the block button is clicked therefore
|
||||
* it does not make sense to display an error.
|
||||
**/
|
||||
deleteCallUrl: function(token, cb) {
|
||||
deleteCallUrl: function(token, sessionType, cb) {
|
||||
this._ensureRegistered(function(err) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this._deleteCallUrlInternal(token, cb);
|
||||
this._deleteCallUrlInternal(token, sessionType, cb);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_deleteCallUrlInternal: function(token, cb) {
|
||||
_deleteCallUrlInternal: function(token, sessionType, cb) {
|
||||
function deleteRequestCallback(error, responseText) {
|
||||
if (error) {
|
||||
this._failureHandler(cb, error);
|
||||
@ -182,8 +184,7 @@ loop.Client = (function($) {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX hard-coding of GUEST to be removed by 1065155
|
||||
this.mozLoop.hawkRequest(this.mozLoop.LOOP_SESSION_TYPE.GUEST,
|
||||
this.mozLoop.hawkRequest(sessionType,
|
||||
"/call-url/" + token, "DELETE", null,
|
||||
deleteRequestCallback.bind(this));
|
||||
},
|
||||
|
@ -287,7 +287,7 @@ loop.conversation = (function(mozL10n) {
|
||||
if (this.state.callFailed) {
|
||||
return GenericFailureView({
|
||||
cancelCall: this.closeWindow.bind(this)}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
document.title = mozL10n.get("conversation_has_ended");
|
||||
@ -499,12 +499,14 @@ loop.conversation = (function(mozL10n) {
|
||||
declineAndBlock: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
var token = this.props.conversation.get("callToken");
|
||||
this.props.client.deleteCallUrl(token, function(error) {
|
||||
// XXX The conversation window will be closed when this cb is triggered
|
||||
// figure out if there is a better way to report the error to the user
|
||||
// (bug 1048909).
|
||||
console.log(error);
|
||||
});
|
||||
this.props.client.deleteCallUrl(token,
|
||||
this.props.conversation.get("sessionType"),
|
||||
function(error) {
|
||||
// XXX The conversation window will be closed when this cb is triggered
|
||||
// figure out if there is a better way to report the error to the user
|
||||
// (bug 1048909).
|
||||
console.log(error);
|
||||
});
|
||||
this._declineCall();
|
||||
},
|
||||
|
||||
@ -538,7 +540,7 @@ loop.conversation = (function(mozL10n) {
|
||||
conversationStore: React.PropTypes.instanceOf(loop.store.ConversationStore)
|
||||
.isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
localRoomStore: React.PropTypes.instanceOf(loop.store.LocalRoomStore)
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore)
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -578,7 +580,7 @@ loop.conversation = (function(mozL10n) {
|
||||
case "room": {
|
||||
return (DesktopRoomView({
|
||||
mozLoop: navigator.mozLoop,
|
||||
localRoomStore: this.props.localRoomStore}
|
||||
roomStore: this.props.roomStore}
|
||||
));
|
||||
}
|
||||
case "failed": {
|
||||
@ -632,10 +634,15 @@ loop.conversation = (function(mozL10n) {
|
||||
dispatcher: dispatcher,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
var localRoomStore = new loop.store.LocalRoomStore({
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop
|
||||
});;
|
||||
});
|
||||
var roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: activeRoomStore
|
||||
});
|
||||
|
||||
// XXX Old class creation for the incoming conversation view, whilst
|
||||
// we transition across (bug 1072323).
|
||||
@ -663,7 +670,7 @@ loop.conversation = (function(mozL10n) {
|
||||
|
||||
React.renderComponent(AppControllerView({
|
||||
conversationAppStore: conversationAppStore,
|
||||
localRoomStore: localRoomStore,
|
||||
roomStore: roomStore,
|
||||
conversationStore: conversationStore,
|
||||
client: client,
|
||||
conversation: conversation,
|
||||
|
@ -287,7 +287,7 @@ loop.conversation = (function(mozL10n) {
|
||||
if (this.state.callFailed) {
|
||||
return <GenericFailureView
|
||||
cancelCall={this.closeWindow.bind(this)}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
|
||||
document.title = mozL10n.get("conversation_has_ended");
|
||||
@ -499,12 +499,14 @@ loop.conversation = (function(mozL10n) {
|
||||
declineAndBlock: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
var token = this.props.conversation.get("callToken");
|
||||
this.props.client.deleteCallUrl(token, function(error) {
|
||||
// XXX The conversation window will be closed when this cb is triggered
|
||||
// figure out if there is a better way to report the error to the user
|
||||
// (bug 1048909).
|
||||
console.log(error);
|
||||
});
|
||||
this.props.client.deleteCallUrl(token,
|
||||
this.props.conversation.get("sessionType"),
|
||||
function(error) {
|
||||
// XXX The conversation window will be closed when this cb is triggered
|
||||
// figure out if there is a better way to report the error to the user
|
||||
// (bug 1048909).
|
||||
console.log(error);
|
||||
});
|
||||
this._declineCall();
|
||||
},
|
||||
|
||||
@ -538,7 +540,7 @@ loop.conversation = (function(mozL10n) {
|
||||
conversationStore: React.PropTypes.instanceOf(loop.store.ConversationStore)
|
||||
.isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
localRoomStore: React.PropTypes.instanceOf(loop.store.LocalRoomStore)
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore)
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -578,7 +580,7 @@ loop.conversation = (function(mozL10n) {
|
||||
case "room": {
|
||||
return (<DesktopRoomView
|
||||
mozLoop={navigator.mozLoop}
|
||||
localRoomStore={this.props.localRoomStore}
|
||||
roomStore={this.props.roomStore}
|
||||
/>);
|
||||
}
|
||||
case "failed": {
|
||||
@ -632,10 +634,15 @@ loop.conversation = (function(mozL10n) {
|
||||
dispatcher: dispatcher,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
var localRoomStore = new loop.store.LocalRoomStore({
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop
|
||||
});;
|
||||
});
|
||||
var roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop,
|
||||
activeRoomStore: activeRoomStore
|
||||
});
|
||||
|
||||
// XXX Old class creation for the incoming conversation view, whilst
|
||||
// we transition across (bug 1072323).
|
||||
@ -663,7 +670,7 @@ loop.conversation = (function(mozL10n) {
|
||||
|
||||
React.renderComponent(<AppControllerView
|
||||
conversationAppStore={conversationAppStore}
|
||||
localRoomStore={localRoomStore}
|
||||
roomStore={roomStore}
|
||||
conversationStore={conversationStore}
|
||||
client={client}
|
||||
conversation={conversation}
|
||||
|
@ -489,7 +489,9 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
handleCopyButtonClick: function(event) {
|
||||
event.preventDefault();
|
||||
navigator.mozLoop.copyString(this.props.room.roomUrl);
|
||||
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
|
||||
roomUrl: this.props.room.roomUrl
|
||||
}));
|
||||
this.setState({urlCopied: true});
|
||||
},
|
||||
|
||||
@ -506,7 +508,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
_isActive: function() {
|
||||
// XXX bug 1074679 will implement this properly
|
||||
return this.props.room.participants.length > 0;
|
||||
},
|
||||
|
||||
@ -548,7 +549,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
store: React.PropTypes.instanceOf(loop.store.RoomListStore).isRequired,
|
||||
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
||||
},
|
||||
@ -636,8 +637,8 @@ loop.panel = (function(_, mozL10n) {
|
||||
showTabButtons: React.PropTypes.bool,
|
||||
selectedTab: React.PropTypes.string,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
roomListStore:
|
||||
React.PropTypes.instanceOf(loop.store.RoomListStore).isRequired
|
||||
roomStore:
|
||||
React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -696,7 +697,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
return (
|
||||
Tab({name: "rooms"},
|
||||
RoomList({dispatcher: this.props.dispatcher,
|
||||
store: this.props.roomListStore,
|
||||
store: this.props.roomStore,
|
||||
userDisplayName: this._getUserDisplayName()})
|
||||
)
|
||||
);
|
||||
@ -789,7 +790,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
var client = new loop.Client();
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var roomListStore = new loop.store.RoomListStore({
|
||||
var roomStore = new loop.store.RoomStore({
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher
|
||||
});
|
||||
@ -797,7 +798,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
React.renderComponent(PanelView({
|
||||
client: client,
|
||||
notifications: notifications,
|
||||
roomListStore: roomListStore,
|
||||
roomStore: roomStore,
|
||||
dispatcher: dispatcher}
|
||||
), document.querySelector("#main"));
|
||||
|
||||
|
@ -489,7 +489,9 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
handleCopyButtonClick: function(event) {
|
||||
event.preventDefault();
|
||||
navigator.mozLoop.copyString(this.props.room.roomUrl);
|
||||
this.props.dispatcher.dispatch(new sharedActions.CopyRoomUrl({
|
||||
roomUrl: this.props.room.roomUrl
|
||||
}));
|
||||
this.setState({urlCopied: true});
|
||||
},
|
||||
|
||||
@ -506,7 +508,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
_isActive: function() {
|
||||
// XXX bug 1074679 will implement this properly
|
||||
return this.props.room.participants.length > 0;
|
||||
},
|
||||
|
||||
@ -548,7 +549,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
store: React.PropTypes.instanceOf(loop.store.RoomListStore).isRequired,
|
||||
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
||||
},
|
||||
@ -636,8 +637,8 @@ loop.panel = (function(_, mozL10n) {
|
||||
showTabButtons: React.PropTypes.bool,
|
||||
selectedTab: React.PropTypes.string,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
roomListStore:
|
||||
React.PropTypes.instanceOf(loop.store.RoomListStore).isRequired
|
||||
roomStore:
|
||||
React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -696,7 +697,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
return (
|
||||
<Tab name="rooms">
|
||||
<RoomList dispatcher={this.props.dispatcher}
|
||||
store={this.props.roomListStore}
|
||||
store={this.props.roomStore}
|
||||
userDisplayName={this._getUserDisplayName()}/>
|
||||
</Tab>
|
||||
);
|
||||
@ -789,7 +790,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
var client = new loop.Client();
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var roomListStore = new loop.store.RoomListStore({
|
||||
var roomStore = new loop.store.RoomStore({
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher
|
||||
});
|
||||
@ -797,7 +798,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
React.renderComponent(<PanelView
|
||||
client={client}
|
||||
notifications={notifications}
|
||||
roomListStore={roomListStore}
|
||||
roomStore={roomStore}
|
||||
dispatcher={dispatcher}
|
||||
/>, document.querySelector("#main"));
|
||||
|
||||
|
@ -14,33 +14,31 @@ loop.roomViews = (function(mozL10n) {
|
||||
mixins: [Backbone.Events, loop.shared.mixins.DocumentTitleMixin],
|
||||
|
||||
propTypes: {
|
||||
mozLoop:
|
||||
React.PropTypes.object.isRequired,
|
||||
localRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.LocalRoomStore).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.localRoomStore.getStoreState();
|
||||
return this.props.roomStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.localRoomStore, "change",
|
||||
this._onLocalRoomStoreChanged);
|
||||
this.listenTo(this.props.roomStore, "change:activeRoom",
|
||||
this._onActiveRoomStateChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a "change" event on the localRoomStore, and updates this.state
|
||||
* Handles a "change" event on the roomStore, and updates this.state
|
||||
* to match the store.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onLocalRoomStoreChanged: function() {
|
||||
this.setState(this.props.localRoomStore.getStoreState());
|
||||
_onActiveRoomStateChanged: function() {
|
||||
this.setState(this.props.roomStore.getStoreState("activeRoom"));
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.localRoomStore);
|
||||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@ -58,4 +56,4 @@ loop.roomViews = (function(mozL10n) {
|
||||
DesktopRoomView: DesktopRoomView
|
||||
};
|
||||
|
||||
})(document.mozL10n || navigator.mozL10n);;
|
||||
})(document.mozL10n || navigator.mozL10n);
|
||||
|
@ -14,33 +14,31 @@ loop.roomViews = (function(mozL10n) {
|
||||
mixins: [Backbone.Events, loop.shared.mixins.DocumentTitleMixin],
|
||||
|
||||
propTypes: {
|
||||
mozLoop:
|
||||
React.PropTypes.object.isRequired,
|
||||
localRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.LocalRoomStore).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return this.props.localRoomStore.getStoreState();
|
||||
return this.props.roomStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.localRoomStore, "change",
|
||||
this._onLocalRoomStoreChanged);
|
||||
this.listenTo(this.props.roomStore, "change:activeRoom",
|
||||
this._onActiveRoomStateChanged);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a "change" event on the localRoomStore, and updates this.state
|
||||
* Handles a "change" event on the roomStore, and updates this.state
|
||||
* to match the store.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onLocalRoomStoreChanged: function() {
|
||||
this.setState(this.props.localRoomStore.getStoreState());
|
||||
_onActiveRoomStateChanged: function() {
|
||||
this.setState(this.props.roomStore.getStoreState("activeRoom"));
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.localRoomStore);
|
||||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@ -58,4 +56,4 @@ loop.roomViews = (function(mozL10n) {
|
||||
DesktopRoomView: DesktopRoomView
|
||||
};
|
||||
|
||||
})(document.mozL10n || navigator.mozL10n);;
|
||||
})(document.mozL10n || navigator.mozL10n);
|
||||
|
@ -27,7 +27,8 @@
|
||||
<script type="text/javascript" src="loop/shared/js/validate.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/actions.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomListStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/js/client.js"></script>
|
||||
<script type="text/javascript;version=1.8" src="loop/js/contacts.js"></script>
|
||||
<script type="text/javascript" src="loop/js/panel.js"></script>
|
||||
|
@ -37,6 +37,13 @@ loop.shared.actions = (function() {
|
||||
windowId: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Extract the token information and type for the standalone window
|
||||
*/
|
||||
ExtractTokenInfo: Action.define("extractTokenInfo", {
|
||||
windowPath: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Used to pass round the window data so that stores can
|
||||
* record the appropriate data.
|
||||
@ -51,6 +58,15 @@ loop.shared.actions = (function() {
|
||||
// data.
|
||||
}),
|
||||
|
||||
/**
|
||||
* Used to fetch the data from the server for a room or call for the
|
||||
* token.
|
||||
*/
|
||||
FetchServerData: Action.define("fetchServerData", {
|
||||
token: String,
|
||||
windowType: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Fetch a new call url from the server, intended to be sent over email when
|
||||
* a contact can't be reached.
|
||||
@ -203,6 +219,14 @@ loop.shared.actions = (function() {
|
||||
*/
|
||||
OpenRoom: Action.define("openRoom", {
|
||||
roomToken: String
|
||||
}),
|
||||
|
||||
/**
|
||||
* Copy a room url in the user's clipboard.
|
||||
* XXX: should move to some roomActions module - refs bug 1079284
|
||||
*/
|
||||
CopyRoomUrl: Action.define("copyRoomUrl", {
|
||||
roomUrl: String
|
||||
})
|
||||
};
|
||||
})();
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
loop.store.LocalRoomStore = (function() {
|
||||
loop.store.ActiveRoomStore = (function() {
|
||||
"use strict";
|
||||
|
||||
var sharedActions = loop.shared.actions;
|
||||
@ -23,7 +23,7 @@ loop.store.LocalRoomStore = (function() {
|
||||
* actions and registering to consume them.
|
||||
* @param {MozLoop} options.mozLoop - MozLoop API provider object
|
||||
*/
|
||||
function LocalRoomStore(options) {
|
||||
function ActiveRoomStore(options) {
|
||||
options = options || {};
|
||||
|
||||
if (!options.dispatcher) {
|
||||
@ -41,7 +41,7 @@ loop.store.LocalRoomStore = (function() {
|
||||
]);
|
||||
}
|
||||
|
||||
LocalRoomStore.prototype = _.extend({
|
||||
ActiveRoomStore.prototype = _.extend({
|
||||
|
||||
/**
|
||||
* Stored data reflecting the local state of a given room, used to drive
|
||||
@ -54,9 +54,6 @@ loop.store.LocalRoomStore = (function() {
|
||||
* @property {Error=} error - if the room is an error state, this will be
|
||||
* set to an Error object reflecting the problem;
|
||||
* otherwise it will be unset.
|
||||
*
|
||||
* @property {String} localRoomId - profile-local identifier used with
|
||||
* the MozLoop API.
|
||||
*/
|
||||
_storeState: {
|
||||
},
|
||||
@ -100,6 +97,6 @@ loop.store.LocalRoomStore = (function() {
|
||||
|
||||
}, Backbone.Events);
|
||||
|
||||
return LocalRoomStore;
|
||||
return ActiveRoomStore;
|
||||
|
||||
})();
|
@ -33,10 +33,6 @@ loop.shared.mixins = (function() {
|
||||
* @type {Object}
|
||||
*/
|
||||
var UrlHashChangeMixin = {
|
||||
propTypes: {
|
||||
onUrlHashChange: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
rootObject.addEventListener("hashchange", this.onUrlHashChange, false);
|
||||
},
|
||||
|
@ -48,14 +48,16 @@ loop.store = loop.store || {};
|
||||
* Room store.
|
||||
*
|
||||
* Options:
|
||||
* - {loop.Dispatcher} dispatcher The dispatcher for dispatching actions and
|
||||
* registering to consume actions.
|
||||
* - {mozLoop} mozLoop The MozLoop API object.
|
||||
* - {loop.Dispatcher} dispatcher The dispatcher for dispatching actions
|
||||
* and registering to consume actions.
|
||||
* - {mozLoop} mozLoop The MozLoop API object.
|
||||
* - {ActiveRoomStore} activeRoomStore An optional substore for active room
|
||||
* state.
|
||||
*
|
||||
* @extends {Backbone.Events}
|
||||
* @param {Object} options Options object.
|
||||
*/
|
||||
function RoomListStore(options) {
|
||||
function RoomStore(options) {
|
||||
options = options || {};
|
||||
|
||||
if (!options.dispatcher) {
|
||||
@ -68,9 +70,16 @@ loop.store = loop.store || {};
|
||||
}
|
||||
this._mozLoop = options.mozLoop;
|
||||
|
||||
if (options.activeRoomStore) {
|
||||
this.activeRoomStore = options.activeRoomStore;
|
||||
this.activeRoomStore.on("change",
|
||||
this._onActiveRoomStoreChange.bind(this));
|
||||
}
|
||||
|
||||
this._dispatcher.register(this, [
|
||||
"createRoom",
|
||||
"createRoomError",
|
||||
"copyRoomUrl",
|
||||
"deleteRoom",
|
||||
"deleteRoomError",
|
||||
"getAllRooms",
|
||||
@ -80,7 +89,7 @@ loop.store = loop.store || {};
|
||||
]);
|
||||
}
|
||||
|
||||
RoomListStore.prototype = _.extend({
|
||||
RoomStore.prototype = _.extend({
|
||||
/**
|
||||
* Maximum size given to createRoom; only 2 is supported (and is
|
||||
* always passed) because that's what the user-experience is currently
|
||||
@ -101,6 +110,7 @@ loop.store = loop.store || {};
|
||||
* @see #getStoreState
|
||||
*/
|
||||
_storeState: {
|
||||
activeRoom: {},
|
||||
error: null,
|
||||
pendingCreation: false,
|
||||
pendingInitialRetrieval: false,
|
||||
@ -115,21 +125,36 @@ loop.store = loop.store || {};
|
||||
* - {Boolean} pendingInitialRetrieval Pending initial list retrieval flag.
|
||||
* - {Array} rooms The current room list.
|
||||
* - {Error} error Latest error encountered, if any.
|
||||
* - {Object} activeRoom Active room data, if any.
|
||||
*
|
||||
* You can request a given state property by providing the `key` argument.
|
||||
*
|
||||
* @param {String|undefined} key An optional state property name.
|
||||
* @return {Object}
|
||||
*/
|
||||
getStoreState: function() {
|
||||
getStoreState: function(key) {
|
||||
if (key) {
|
||||
return this._storeState[key];
|
||||
}
|
||||
return this._storeState;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates store state and trigger a "change" event.
|
||||
* Updates store state and trigger a global "change" event, plus one for
|
||||
* each provided newState property:
|
||||
*
|
||||
* @param {Object} newState The new store state.
|
||||
* - change:rooms
|
||||
* - change:pendingInitialRetrieval
|
||||
* - change:pendingCreation
|
||||
* - change:error
|
||||
* - change:activeRoom
|
||||
*
|
||||
* @param {Object} newState The new store state object.
|
||||
*/
|
||||
setStoreState: function(newState) {
|
||||
for (var key in newState) {
|
||||
this._storeState[key] = newState[key];
|
||||
this.trigger("change:" + key);
|
||||
}
|
||||
this.trigger("change");
|
||||
},
|
||||
@ -144,6 +169,13 @@ loop.store = loop.store || {};
|
||||
this._mozLoop.rooms.on("delete", this._onRoomRemoved.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates active room store state.
|
||||
*/
|
||||
_onActiveRoomStoreChange: function() {
|
||||
this.setStoreState({activeRoom: this.activeRoomStore.getStoreState()});
|
||||
},
|
||||
|
||||
/**
|
||||
* Local proxy helper to dispatch an action.
|
||||
*
|
||||
@ -285,6 +317,15 @@ loop.store = loop.store || {};
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy a room url.
|
||||
*
|
||||
* @param {sharedActions.CopyRoomUrl} actionData The action data.
|
||||
*/
|
||||
copyRoomUrl: function(actionData) {
|
||||
this._mozLoop.copyString(actionData.roomUrl);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new room.
|
||||
*
|
||||
@ -362,5 +403,5 @@ loop.store = loop.store || {};
|
||||
}
|
||||
}, Backbone.Events);
|
||||
|
||||
loop.store.RoomListStore = RoomListStore;
|
||||
loop.store.RoomStore = RoomStore;
|
||||
})();
|
@ -58,8 +58,8 @@ browser.jar:
|
||||
# Shared scripts
|
||||
content/browser/loop/shared/js/actions.js (content/shared/js/actions.js)
|
||||
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
|
||||
content/browser/loop/shared/js/roomListStore.js (content/shared/js/roomListStore.js)
|
||||
content/browser/loop/shared/js/localRoomStore.js (content/shared/js/localRoomStore.js)
|
||||
content/browser/loop/shared/js/roomStore.js (content/shared/js/roomStore.js)
|
||||
content/browser/loop/shared/js/activeRoomStore.js (content/shared/js/activeRoomStore.js)
|
||||
content/browser/loop/shared/js/dispatcher.js (content/shared/js/dispatcher.js)
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
content/browser/loop/shared/js/models.js (content/shared/js/models.js)
|
||||
|
@ -42,8 +42,13 @@
|
||||
<script type="text/javascript" src="shared/js/mixins.js"></script>
|
||||
<script type="text/javascript" src="shared/js/views.js"></script>
|
||||
<script type="text/javascript" src="shared/js/feedbackApiClient.js"></script>
|
||||
<script type="text/javascript" src="shared/js/actions.js"></script>
|
||||
<script type="text/javascript" src="shared/js/validate.js"></script>
|
||||
<script type="text/javascript" src="shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="shared/js/websocket.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneAppStore.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneClient.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneRoomViews.js"></script>
|
||||
<script type="text/javascript" src="js/webapp.js"></script>
|
||||
|
||||
<script>
|
||||
|
@ -0,0 +1,148 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
|
||||
/**
|
||||
* Manages the conversation window app controller view. Used to get
|
||||
* the window data and store the window type.
|
||||
*/
|
||||
loop.store.StandaloneAppStore = (function() {
|
||||
"use strict";
|
||||
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
|
||||
var OLD_STYLE_CALL_REGEXP = /\#call\/(.*)/;
|
||||
var NEW_STYLE_CALL_REGEXP = /\/c\/([\w\-]+)$/;
|
||||
var ROOM_REGEXP = /\/([\w\-]+)$/;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param {Object} options Options for the store. Should contain the dispatcher.
|
||||
*/
|
||||
var StandaloneAppStore = function(options) {
|
||||
if (!options.dispatcher) {
|
||||
throw new Error("Missing option dispatcher");
|
||||
}
|
||||
if (!options.sdk) {
|
||||
throw new Error("Missing option sdk");
|
||||
}
|
||||
if (!options.helper) {
|
||||
throw new Error("Missing option helper");
|
||||
}
|
||||
if (!options.conversation) {
|
||||
throw new Error("Missing option conversation");
|
||||
}
|
||||
|
||||
this._dispatcher = options.dispatcher;
|
||||
this._storeState = {};
|
||||
this._sdk = options.sdk;
|
||||
this._helper = options.helper;
|
||||
this._conversation = options.conversation;
|
||||
|
||||
this._dispatcher.register(this, [
|
||||
"extractTokenInfo"
|
||||
]);
|
||||
};
|
||||
|
||||
StandaloneAppStore.prototype = _.extend({
|
||||
/**
|
||||
* Retrieves current store state.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
getStoreState: function() {
|
||||
return this._storeState;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates store states and trigger a "change" event.
|
||||
*
|
||||
* @param {Object} state The new store state.
|
||||
*/
|
||||
setStoreState: function(state) {
|
||||
this._storeState = state;
|
||||
this.trigger("change");
|
||||
},
|
||||
|
||||
_extractWindowDataFromPath: function(windowPath) {
|
||||
var match;
|
||||
var windowType = "home";
|
||||
|
||||
function extractId(path, regexp) {
|
||||
var match = path.match(regexp);
|
||||
if (match && match[1]) {
|
||||
return match;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (windowPath) {
|
||||
// Is this a call url (the hash is a backwards-compatible url)?
|
||||
match = extractId(windowPath, OLD_STYLE_CALL_REGEXP) ||
|
||||
extractId(windowPath, NEW_STYLE_CALL_REGEXP);
|
||||
|
||||
if (match) {
|
||||
windowType = "outgoing";
|
||||
} else {
|
||||
// Is this a room url?
|
||||
match = extractId(windowPath, ROOM_REGEXP);
|
||||
|
||||
if (match) {
|
||||
windowType = "room";
|
||||
}
|
||||
}
|
||||
}
|
||||
return [windowType, match && match[1] ? match[1] : null];
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the extract token info action - obtains the token information
|
||||
* and its type; updates the store and notifies interested components.
|
||||
*
|
||||
* @param {sharedActions.GetWindowData} actionData The action data
|
||||
*/
|
||||
extractTokenInfo: function(actionData) {
|
||||
var windowType = "home";
|
||||
var token;
|
||||
|
||||
// Check if we're on a supported device/platform.
|
||||
if (this._helper.isIOS(navigator.platform)) {
|
||||
windowType = "unsupportedDevice";
|
||||
} else if (!this._sdk.checkSystemRequirements()) {
|
||||
windowType = "unsupportedBrowser";
|
||||
} else if (actionData.windowPath) {
|
||||
// ES6 not used in standalone yet.
|
||||
var result = this._extractWindowDataFromPath(actionData.windowPath);
|
||||
windowType = result[0];
|
||||
token = result[1];
|
||||
}
|
||||
// Else type is home.
|
||||
|
||||
if (token) {
|
||||
this._conversation.set({loopToken: token});
|
||||
}
|
||||
|
||||
this.setStoreState({
|
||||
windowType: windowType
|
||||
});
|
||||
|
||||
// If we've not got a window ID, don't dispatch the action, as we don't need
|
||||
// it.
|
||||
if (token) {
|
||||
this._dispatcher.dispatch(new loop.shared.actions.FetchServerData({
|
||||
token: token,
|
||||
windowType: windowType
|
||||
}));
|
||||
}
|
||||
}
|
||||
}, Backbone.Events);
|
||||
|
||||
return StandaloneAppStore;
|
||||
})();
|
@ -0,0 +1,22 @@
|
||||
/** @jsx React.DOM */
|
||||
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true, React */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.standaloneRoomViews = (function() {
|
||||
"use strict";
|
||||
|
||||
var StandaloneRoomView = React.createClass({displayName: 'StandaloneRoomView',
|
||||
render: function() {
|
||||
return (React.DOM.div(null, "Room"));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
StandaloneRoomView: StandaloneRoomView
|
||||
};
|
||||
})();
|
@ -0,0 +1,22 @@
|
||||
/** @jsx React.DOM */
|
||||
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true, React */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.standaloneRoomViews = (function() {
|
||||
"use strict";
|
||||
|
||||
var StandaloneRoomView = React.createClass({
|
||||
render: function() {
|
||||
return (<div>Room</div>);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
StandaloneRoomView: StandaloneRoomView
|
||||
};
|
||||
})();
|
@ -14,6 +14,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
loop.config = loop.config || {};
|
||||
loop.config.serverUrl = loop.config.serverUrl || "http://localhost:5000";
|
||||
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedMixins = loop.shared.mixins;
|
||||
var sharedModels = loop.shared.models;
|
||||
var sharedViews = loop.shared.views;
|
||||
@ -877,7 +878,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
var WebappRootView = React.createClass({displayName: 'WebappRootView',
|
||||
|
||||
mixins: [sharedMixins.UrlHashChangeMixin,
|
||||
sharedMixins.DocumentLocationMixin],
|
||||
sharedMixins.DocumentLocationMixin,
|
||||
Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
client: React.PropTypes.instanceOf(loop.StandaloneClient).isRequired,
|
||||
@ -889,14 +891,25 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection)
|
||||
.isRequired,
|
||||
sdk: React.PropTypes.object.isRequired,
|
||||
feedbackApiClient: React.PropTypes.object.isRequired
|
||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
unsupportedDevice: this.props.helper.isIOS(navigator.platform),
|
||||
unsupportedBrowser: !this.props.sdk.checkSystemRequirements(),
|
||||
};
|
||||
return this.props.standaloneAppStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.standaloneAppStore, "change", function() {
|
||||
this.setState(this.props.standaloneAppStore.getStoreState());
|
||||
}, this);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.standaloneAppStore);
|
||||
},
|
||||
|
||||
onUrlHashChange: function() {
|
||||
@ -904,23 +917,36 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.unsupportedDevice) {
|
||||
return UnsupportedDeviceView(null);
|
||||
} else if (this.state.unsupportedBrowser) {
|
||||
return UnsupportedBrowserView(null);
|
||||
} else if (this.props.conversation.get("loopToken")) {
|
||||
return (
|
||||
OutgoingConversationView({
|
||||
client: this.props.client,
|
||||
conversation: this.props.conversation,
|
||||
helper: this.props.helper,
|
||||
notifications: this.props.notifications,
|
||||
sdk: this.props.sdk,
|
||||
feedbackApiClient: this.props.feedbackApiClient}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return HomeView(null);
|
||||
switch (this.state.windowType) {
|
||||
case "unsupportedDevice": {
|
||||
return UnsupportedDeviceView(null);
|
||||
}
|
||||
case "unsupportedBrowser": {
|
||||
return UnsupportedBrowserView(null);
|
||||
}
|
||||
case "outgoing": {
|
||||
return (
|
||||
OutgoingConversationView({
|
||||
client: this.props.client,
|
||||
conversation: this.props.conversation,
|
||||
helper: this.props.helper,
|
||||
notifications: this.props.notifications,
|
||||
sdk: this.props.sdk,
|
||||
feedbackApiClient: this.props.feedbackApiClient}
|
||||
)
|
||||
);
|
||||
}
|
||||
case "room": {
|
||||
return loop.standaloneRoomViews.StandaloneRoomView(null);
|
||||
}
|
||||
case "home": {
|
||||
return HomeView(null);
|
||||
}
|
||||
default: {
|
||||
// The state hasn't been initialised yet, so don't display
|
||||
// anything to avoid flicker.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -930,9 +956,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
*/
|
||||
function init() {
|
||||
var helper = new sharedUtils.Helper();
|
||||
var client = new loop.StandaloneClient({
|
||||
baseServerUrl: loop.config.serverUrl
|
||||
});
|
||||
|
||||
// Older non-flux based items.
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var conversation
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
@ -950,24 +975,18 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
url: document.location.origin
|
||||
});
|
||||
|
||||
// Obtain the loopToken
|
||||
// New flux items.
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var client = new loop.StandaloneClient({
|
||||
baseServerUrl: loop.config.serverUrl
|
||||
});
|
||||
|
||||
var match;
|
||||
|
||||
// locationHash supports the old format urls.
|
||||
var locationData = helper.locationData();
|
||||
if (locationData.hash) {
|
||||
match = locationData.hash.match(/\#call\/(.*)/);
|
||||
} else if (locationData.pathname) {
|
||||
// Otherwise, we're expecting a url such as /c/<token> for calls.
|
||||
match = locationData.pathname.match(/\/c\/([\w\-]+)/);
|
||||
}
|
||||
// XXX Supporting '/\/([\w\-]+)/' is for rooms which are to be implemented
|
||||
// in bug 1074701.
|
||||
|
||||
if (match && match[1]) {
|
||||
conversation.set({loopToken: match[1]});
|
||||
}
|
||||
var standaloneAppStore = new loop.store.StandaloneAppStore({
|
||||
conversation: conversation,
|
||||
dispatcher: dispatcher,
|
||||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
|
||||
React.renderComponent(WebappRootView({
|
||||
client: client,
|
||||
@ -975,13 +994,20 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
helper: helper,
|
||||
notifications: notifications,
|
||||
sdk: OT,
|
||||
feedbackApiClient: feedbackApiClient}
|
||||
feedbackApiClient: feedbackApiClient,
|
||||
standaloneAppStore: standaloneAppStore}
|
||||
), document.querySelector("#main"));
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
document.documentElement.lang = mozL10n.language.code;
|
||||
document.documentElement.dir = mozL10n.language.direction;
|
||||
document.title = mozL10n.get("clientShortname2");
|
||||
|
||||
dispatcher.dispatch(new sharedActions.ExtractTokenInfo({
|
||||
// We pass the hash or the pathname - the hash was used for the original
|
||||
// urls, the pathname for later ones.
|
||||
windowPath: helper.locationData().hash || helper.locationData().pathname
|
||||
}));
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -14,6 +14,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
loop.config = loop.config || {};
|
||||
loop.config.serverUrl = loop.config.serverUrl || "http://localhost:5000";
|
||||
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedMixins = loop.shared.mixins;
|
||||
var sharedModels = loop.shared.models;
|
||||
var sharedViews = loop.shared.views;
|
||||
@ -877,7 +878,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
var WebappRootView = React.createClass({
|
||||
|
||||
mixins: [sharedMixins.UrlHashChangeMixin,
|
||||
sharedMixins.DocumentLocationMixin],
|
||||
sharedMixins.DocumentLocationMixin,
|
||||
Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
client: React.PropTypes.instanceOf(loop.StandaloneClient).isRequired,
|
||||
@ -889,14 +891,25 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
notifications: React.PropTypes.instanceOf(sharedModels.NotificationCollection)
|
||||
.isRequired,
|
||||
sdk: React.PropTypes.object.isRequired,
|
||||
feedbackApiClient: React.PropTypes.object.isRequired
|
||||
feedbackApiClient: React.PropTypes.object.isRequired,
|
||||
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
unsupportedDevice: this.props.helper.isIOS(navigator.platform),
|
||||
unsupportedBrowser: !this.props.sdk.checkSystemRequirements(),
|
||||
};
|
||||
return this.props.standaloneAppStore.getStoreState();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.standaloneAppStore, "change", function() {
|
||||
this.setState(this.props.standaloneAppStore.getStoreState());
|
||||
}, this);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.stopListening(this.props.standaloneAppStore);
|
||||
},
|
||||
|
||||
onUrlHashChange: function() {
|
||||
@ -904,23 +917,36 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.unsupportedDevice) {
|
||||
return <UnsupportedDeviceView />;
|
||||
} else if (this.state.unsupportedBrowser) {
|
||||
return <UnsupportedBrowserView />;
|
||||
} else if (this.props.conversation.get("loopToken")) {
|
||||
return (
|
||||
<OutgoingConversationView
|
||||
client={this.props.client}
|
||||
conversation={this.props.conversation}
|
||||
helper={this.props.helper}
|
||||
notifications={this.props.notifications}
|
||||
sdk={this.props.sdk}
|
||||
feedbackApiClient={this.props.feedbackApiClient}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <HomeView />;
|
||||
switch (this.state.windowType) {
|
||||
case "unsupportedDevice": {
|
||||
return <UnsupportedDeviceView />;
|
||||
}
|
||||
case "unsupportedBrowser": {
|
||||
return <UnsupportedBrowserView />;
|
||||
}
|
||||
case "outgoing": {
|
||||
return (
|
||||
<OutgoingConversationView
|
||||
client={this.props.client}
|
||||
conversation={this.props.conversation}
|
||||
helper={this.props.helper}
|
||||
notifications={this.props.notifications}
|
||||
sdk={this.props.sdk}
|
||||
feedbackApiClient={this.props.feedbackApiClient}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "room": {
|
||||
return <loop.standaloneRoomViews.StandaloneRoomView/>;
|
||||
}
|
||||
case "home": {
|
||||
return <HomeView />;
|
||||
}
|
||||
default: {
|
||||
// The state hasn't been initialised yet, so don't display
|
||||
// anything to avoid flicker.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -930,9 +956,8 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
*/
|
||||
function init() {
|
||||
var helper = new sharedUtils.Helper();
|
||||
var client = new loop.StandaloneClient({
|
||||
baseServerUrl: loop.config.serverUrl
|
||||
});
|
||||
|
||||
// Older non-flux based items.
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var conversation
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
@ -950,24 +975,18 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
url: document.location.origin
|
||||
});
|
||||
|
||||
// Obtain the loopToken
|
||||
// New flux items.
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var client = new loop.StandaloneClient({
|
||||
baseServerUrl: loop.config.serverUrl
|
||||
});
|
||||
|
||||
var match;
|
||||
|
||||
// locationHash supports the old format urls.
|
||||
var locationData = helper.locationData();
|
||||
if (locationData.hash) {
|
||||
match = locationData.hash.match(/\#call\/(.*)/);
|
||||
} else if (locationData.pathname) {
|
||||
// Otherwise, we're expecting a url such as /c/<token> for calls.
|
||||
match = locationData.pathname.match(/\/c\/([\w\-]+)/);
|
||||
}
|
||||
// XXX Supporting '/\/([\w\-]+)/' is for rooms which are to be implemented
|
||||
// in bug 1074701.
|
||||
|
||||
if (match && match[1]) {
|
||||
conversation.set({loopToken: match[1]});
|
||||
}
|
||||
var standaloneAppStore = new loop.store.StandaloneAppStore({
|
||||
conversation: conversation,
|
||||
dispatcher: dispatcher,
|
||||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
|
||||
React.renderComponent(<WebappRootView
|
||||
client={client}
|
||||
@ -976,12 +995,19 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
notifications={notifications}
|
||||
sdk={OT}
|
||||
feedbackApiClient={feedbackApiClient}
|
||||
standaloneAppStore={standaloneAppStore}
|
||||
/>, document.querySelector("#main"));
|
||||
|
||||
// Set the 'lang' and 'dir' attributes to <html> when the page is translated
|
||||
document.documentElement.lang = mozL10n.language.code;
|
||||
document.documentElement.dir = mozL10n.language.direction;
|
||||
document.title = mozL10n.get("clientShortname2");
|
||||
|
||||
dispatcher.dispatch(new sharedActions.ExtractTokenInfo({
|
||||
// We pass the hash or the pathname - the hash was used for the original
|
||||
// urls, the pathname for later ones.
|
||||
windowPath: helper.locationData().hash || helper.locationData().pathname
|
||||
}));
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -56,7 +56,7 @@ describe("loop.Client", function() {
|
||||
describe("loop.Client", function() {
|
||||
describe("#deleteCallUrl", function() {
|
||||
it("should ensure loop is registered", function() {
|
||||
client.deleteCallUrl("fakeToken", callback);
|
||||
client.deleteCallUrl("fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, callback);
|
||||
|
||||
sinon.assert.calledOnce(mozLoop.ensureRegistered);
|
||||
});
|
||||
@ -64,14 +64,14 @@ describe("loop.Client", function() {
|
||||
it("should send an error when registration fails", function() {
|
||||
mozLoop.ensureRegistered.callsArgWith(0, "offline");
|
||||
|
||||
client.deleteCallUrl("fakeToken", callback);
|
||||
client.deleteCallUrl("fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, callback);
|
||||
|
||||
sinon.assert.calledOnce(callback);
|
||||
sinon.assert.calledWithExactly(callback, "offline");
|
||||
});
|
||||
|
||||
it("should make a delete call to /call-url/{fakeToken}", function() {
|
||||
client.deleteCallUrl(fakeToken, callback);
|
||||
client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.GUEST, callback);
|
||||
|
||||
sinon.assert.calledOnce(hawkRequestStub);
|
||||
sinon.assert.calledWith(hawkRequestStub,
|
||||
@ -86,7 +86,7 @@ describe("loop.Client", function() {
|
||||
// and the url.
|
||||
hawkRequestStub.callsArgWith(4, null);
|
||||
|
||||
client.deleteCallUrl(fakeToken, callback);
|
||||
client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.FXA, callback);
|
||||
|
||||
sinon.assert.calledWithExactly(callback, null);
|
||||
});
|
||||
@ -96,7 +96,7 @@ describe("loop.Client", function() {
|
||||
// an error
|
||||
hawkRequestStub.callsArgWith(4, fakeErrorRes);
|
||||
|
||||
client.deleteCallUrl(fakeToken, callback);
|
||||
client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.FXA, callback);
|
||||
|
||||
sinon.assert.calledOnce(callback);
|
||||
sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
|
||||
|
@ -126,14 +126,14 @@ describe("loop.conversation", function() {
|
||||
|
||||
describe("AppControllerView", function() {
|
||||
var conversationStore, conversation, client, ccView, oldTitle, dispatcher;
|
||||
var conversationAppStore, localRoomStore;
|
||||
var conversationAppStore, roomStore;
|
||||
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
loop.conversation.AppControllerView({
|
||||
client: client,
|
||||
conversation: conversation,
|
||||
localRoomStore: localRoomStore,
|
||||
roomStore: roomStore,
|
||||
sdk: {},
|
||||
conversationStore: conversationStore,
|
||||
conversationAppStore: conversationAppStore
|
||||
@ -161,7 +161,7 @@ describe("loop.conversation", function() {
|
||||
dispatcher: dispatcher,
|
||||
sdkDriver: {}
|
||||
});
|
||||
localRoomStore = new loop.store.LocalRoomStore({
|
||||
roomStore = new loop.store.RoomStore({
|
||||
mozLoop: navigator.mozLoop,
|
||||
dispatcher: dispatcher
|
||||
});
|
||||
@ -539,6 +539,8 @@ describe("loop.conversation", function() {
|
||||
});
|
||||
|
||||
describe("#blocked", function() {
|
||||
var mozLoop;
|
||||
|
||||
beforeEach(function() {
|
||||
icView = mountTestComponent();
|
||||
|
||||
@ -547,6 +549,13 @@ describe("loop.conversation", function() {
|
||||
close: sinon.stub()
|
||||
};
|
||||
sandbox.stub(window, "close");
|
||||
|
||||
mozLoop = {
|
||||
LOOP_SESSION_TYPE: {
|
||||
GUEST: 1,
|
||||
FXA: 2
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it("should call mozLoop.stopAlerting", function() {
|
||||
@ -557,21 +566,24 @@ describe("loop.conversation", function() {
|
||||
|
||||
it("should call delete call", function() {
|
||||
sandbox.stub(conversation, "get").withArgs("callToken")
|
||||
.returns("fakeToken");
|
||||
.returns("fakeToken")
|
||||
.withArgs("sessionType")
|
||||
.returns(mozLoop.LOOP_SESSION_TYPE.FXA);
|
||||
|
||||
var deleteCallUrl = sandbox.stub(loop.Client.prototype,
|
||||
"deleteCallUrl");
|
||||
icView.declineAndBlock();
|
||||
|
||||
sinon.assert.calledOnce(deleteCallUrl);
|
||||
sinon.assert.calledWithExactly(deleteCallUrl, "fakeToken",
|
||||
sinon.match.func);
|
||||
sinon.assert.calledWithExactly(deleteCallUrl,
|
||||
"fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, sinon.match.func);
|
||||
});
|
||||
|
||||
it("should get callToken from conversation model", function() {
|
||||
sandbox.stub(conversation, "get");
|
||||
icView.declineAndBlock();
|
||||
|
||||
sinon.assert.calledTwice(conversation.get);
|
||||
sinon.assert.called(conversation.get);
|
||||
sinon.assert.calledWithExactly(conversation.get, "callToken");
|
||||
sinon.assert.calledWithExactly(conversation.get, "windowId");
|
||||
});
|
||||
@ -582,7 +594,7 @@ describe("loop.conversation", function() {
|
||||
var fakeError = {
|
||||
error: true
|
||||
};
|
||||
sandbox.stub(loop.Client.prototype, "deleteCallUrl", function(_, cb) {
|
||||
sandbox.stub(loop.Client.prototype, "deleteCallUrl", function(_, __, cb) {
|
||||
cb(fakeError);
|
||||
});
|
||||
icView.declineAndBlock();
|
||||
|
@ -43,9 +43,9 @@
|
||||
<script src="../../content/shared/js/validate.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/otSdkDriver.js"></script>
|
||||
<script src="../../content/shared/js/roomListStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/js/client.js"></script>
|
||||
<script src="../../content/shared/js/localRoomStore.js"></script>
|
||||
<script src="../../content/js/conversationAppStore.js"></script>
|
||||
<script src="../../content/js/roomViews.js"></script>
|
||||
<script src="../../content/js/conversationViews.js"></script>
|
||||
|
@ -140,7 +140,7 @@ describe("loop.panel", function() {
|
||||
});
|
||||
|
||||
describe("loop.panel.PanelView", function() {
|
||||
var fakeClient, dispatcher, roomListStore, callUrlData;
|
||||
var fakeClient, dispatcher, roomStore, callUrlData;
|
||||
|
||||
beforeEach(function() {
|
||||
callUrlData = {
|
||||
@ -155,7 +155,7 @@ describe("loop.panel", function() {
|
||||
};
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
roomListStore = new loop.store.RoomListStore({
|
||||
roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop
|
||||
});
|
||||
@ -167,7 +167,7 @@ describe("loop.panel", function() {
|
||||
client: fakeClient,
|
||||
showTabButtons: true,
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore
|
||||
roomStore: roomStore
|
||||
}));
|
||||
}
|
||||
|
||||
@ -679,11 +679,13 @@ describe("loop.panel", function() {
|
||||
});
|
||||
|
||||
it("should copy the URL when the click event fires", function() {
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
TestUtils.Simulate.click(copyButton);
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.copyString);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.copyString,
|
||||
roomData.roomUrl);
|
||||
sinon.assert.called(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.CopyRoomUrl({roomUrl: roomData.roomUrl}));
|
||||
});
|
||||
|
||||
it("should set state.urlCopied when the click event fires", function() {
|
||||
@ -757,16 +759,16 @@ describe("loop.panel", function() {
|
||||
});
|
||||
|
||||
describe("loop.panel.RoomList", function() {
|
||||
var roomListStore, dispatcher, fakeEmail;
|
||||
var roomStore, dispatcher, fakeEmail;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeEmail = "fakeEmail@example.com";
|
||||
dispatcher = new loop.Dispatcher();
|
||||
roomListStore = new loop.store.RoomListStore({
|
||||
roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop
|
||||
});
|
||||
roomListStore.setStoreState({
|
||||
roomStore.setStoreState({
|
||||
pendingCreation: false,
|
||||
pendingInitialRetrieval: false,
|
||||
rooms: [],
|
||||
@ -776,7 +778,7 @@ describe("loop.panel", function() {
|
||||
|
||||
function createTestComponent() {
|
||||
return TestUtils.renderIntoDocument(loop.panel.RoomList({
|
||||
store: roomListStore,
|
||||
store: roomStore,
|
||||
dispatcher: dispatcher,
|
||||
userDisplayName: fakeEmail
|
||||
}));
|
||||
@ -809,7 +811,7 @@ describe("loop.panel", function() {
|
||||
it("should disable the create button when a creation operation is ongoing",
|
||||
function() {
|
||||
var dispatch = sandbox.stub(dispatcher, "dispatch");
|
||||
roomListStore.setStoreState({pendingCreation: true});
|
||||
roomStore.setStoreState({pendingCreation: true});
|
||||
|
||||
var view = createTestComponent();
|
||||
|
||||
@ -820,7 +822,7 @@ describe("loop.panel", function() {
|
||||
it("should disable the create button when a list retrieval operation is pending",
|
||||
function() {
|
||||
var dispatch = sandbox.stub(dispatcher, "dispatch");
|
||||
roomListStore.setStoreState({pendingInitialRetrieval: true});
|
||||
roomStore.setStoreState({pendingInitialRetrieval: true});
|
||||
|
||||
var view = createTestComponent();
|
||||
|
||||
|
@ -3,28 +3,26 @@ var expect = chai.expect;
|
||||
describe("loop.roomViews", function () {
|
||||
"use strict";
|
||||
|
||||
var store, fakeWindow, sandbox, fakeAddCallback, fakeMozLoop,
|
||||
fakeRemoveCallback, fakeRoomId, fakeWindow;
|
||||
var sandbox, dispatcher, roomStore, activeRoomStore, fakeWindow, fakeMozLoop,
|
||||
fakeRoomId;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
fakeRoomId = "fakeRoomId";
|
||||
fakeAddCallback =
|
||||
sandbox.stub().withArgs(fakeRoomId, "RoomCreationError");
|
||||
fakeRemoveCallback =
|
||||
sandbox.stub().withArgs(fakeRoomId, "RoomCreationError");
|
||||
fakeMozLoop = { rooms: { addCallback: fakeAddCallback,
|
||||
removeCallback: fakeRemoveCallback } };
|
||||
dispatcher = new loop.Dispatcher();
|
||||
|
||||
fakeWindow = { document: {} };
|
||||
loop.shared.mixins.setRootObject(fakeWindow);
|
||||
|
||||
store = new loop.store.LocalRoomStore({
|
||||
dispatcher: { register: function() {} },
|
||||
mozLoop: fakeMozLoop
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {}
|
||||
});
|
||||
roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: {},
|
||||
activeRoomStore: activeRoomStore
|
||||
});
|
||||
store.setStoreState({localRoomId: fakeRoomId});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
@ -36,23 +34,19 @@ describe("loop.roomViews", function () {
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
new loop.roomViews.DesktopRoomView({
|
||||
mozLoop: fakeMozLoop,
|
||||
localRoomStore: store
|
||||
mozLoop: {},
|
||||
roomStore: roomStore
|
||||
}));
|
||||
}
|
||||
|
||||
describe("#render", function() {
|
||||
it("should set document.title to store.serverData.roomName",
|
||||
function() {
|
||||
var fakeRoomName = "Monkey";
|
||||
store.setStoreState({serverData: {roomName: fakeRoomName},
|
||||
localRoomId: fakeRoomId});
|
||||
it("should set document.title to store.serverData.roomName", function() {
|
||||
mountTestComponent();
|
||||
|
||||
mountTestComponent();
|
||||
activeRoomStore.setStoreState({serverData: {roomName: "fakeName"}});
|
||||
|
||||
expect(fakeWindow.document.title).to.equal(fakeRoomName);
|
||||
});
|
||||
expect(fakeWindow.document.title).to.equal("fakeName");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -3,7 +3,7 @@
|
||||
var expect = chai.expect;
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
describe("loop.store.LocalRoomStore", function () {
|
||||
describe("loop.store.ActiveRoomStore", function () {
|
||||
"use strict";
|
||||
|
||||
var sandbox, dispatcher;
|
||||
@ -20,13 +20,13 @@ describe("loop.store.LocalRoomStore", function () {
|
||||
describe("#constructor", function() {
|
||||
it("should throw an error if the dispatcher is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.LocalRoomStore({mozLoop: {}});
|
||||
new loop.store.ActiveRoomStore({mozLoop: {}});
|
||||
}).to.Throw(/dispatcher/);
|
||||
});
|
||||
|
||||
it("should throw an error if mozLoop is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.LocalRoomStore({dispatcher: dispatcher});
|
||||
new loop.store.ActiveRoomStore({dispatcher: dispatcher});
|
||||
}).to.Throw(/mozLoop/);
|
||||
});
|
||||
});
|
||||
@ -41,7 +41,7 @@ describe("loop.store.LocalRoomStore", function () {
|
||||
rooms: { get: sandbox.stub() }
|
||||
};
|
||||
|
||||
store = new loop.store.LocalRoomStore(
|
||||
store = new loop.store.ActiveRoomStore(
|
||||
{mozLoop: fakeMozLoop, dispatcher: dispatcher});
|
||||
fakeMozLoop.rooms.get.
|
||||
withArgs(fakeToken).
|
||||
@ -64,7 +64,7 @@ describe("loop.store.LocalRoomStore", function () {
|
||||
}));
|
||||
});
|
||||
|
||||
it("should set localRoomId on the store from the action data",
|
||||
it("should set roomToken on the store from the action data",
|
||||
function(done) {
|
||||
|
||||
store.once("change", function () {
|
@ -43,9 +43,9 @@
|
||||
<script src="../../content/shared/js/actions.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/otSdkDriver.js"></script>
|
||||
<script src="../../content/shared/js/localRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/conversationStore.js"></script>
|
||||
<script src="../../content/shared/js/roomListStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStore.js"></script>
|
||||
|
||||
<!-- Test scripts -->
|
||||
<script src="models_test.js"></script>
|
||||
@ -56,10 +56,10 @@
|
||||
<script src="feedbackApiClient_test.js"></script>
|
||||
<script src="validate_test.js"></script>
|
||||
<script src="dispatcher_test.js"></script>
|
||||
<script src="localRoomStore_test.js"></script>
|
||||
<script src="activeRoomStore_test.js"></script>
|
||||
<script src="conversationStore_test.js"></script>
|
||||
<script src="otSdkDriver_test.js"></script>
|
||||
<script src="roomListStore_test.js"></script>
|
||||
<script src="roomStore_test.js"></script>
|
||||
<script>
|
||||
mocha.run(function () {
|
||||
$("#mocha").append("<p id='complete'>Complete.</p>");
|
||||
|
@ -15,7 +15,7 @@ describe("loop.store.Room", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("loop.store.RoomListStore", function () {
|
||||
describe("loop.store.RoomStore", function () {
|
||||
"use strict";
|
||||
|
||||
var sharedActions = loop.shared.actions;
|
||||
@ -57,13 +57,13 @@ describe("loop.store.RoomListStore", function () {
|
||||
describe("#constructor", function() {
|
||||
it("should throw an error if the dispatcher is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.RoomListStore({mozLoop: {}});
|
||||
new loop.store.RoomStore({mozLoop: {}});
|
||||
}).to.Throw(/dispatcher/);
|
||||
});
|
||||
|
||||
it("should throw an error if mozLoop is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.RoomListStore({dispatcher: dispatcher});
|
||||
new loop.store.RoomStore({dispatcher: dispatcher});
|
||||
}).to.Throw(/mozLoop/);
|
||||
});
|
||||
});
|
||||
@ -71,24 +71,28 @@ describe("loop.store.RoomListStore", function () {
|
||||
describe("constructed", function() {
|
||||
var fakeMozLoop, store;
|
||||
|
||||
var defaultStoreState = {
|
||||
error: undefined,
|
||||
pendingCreation: false,
|
||||
pendingInitialRetrieval: false,
|
||||
rooms: [],
|
||||
activeRoom: {}
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
fakeMozLoop = {
|
||||
copyString: function() {},
|
||||
rooms: {
|
||||
create: function() {},
|
||||
getAll: function() {},
|
||||
on: sandbox.stub()
|
||||
}
|
||||
};
|
||||
store = new loop.store.RoomListStore({
|
||||
store = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: fakeMozLoop
|
||||
});
|
||||
store.setStoreState({
|
||||
error: undefined,
|
||||
pendingCreation: false,
|
||||
pendingInitialRetrieval: false,
|
||||
rooms: []
|
||||
});
|
||||
store.setStoreState(defaultStoreState);
|
||||
});
|
||||
|
||||
describe("MozLoop rooms event listeners", function() {
|
||||
@ -149,6 +153,19 @@ describe("loop.store.RoomListStore", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#getStoreState", function() {
|
||||
it("should retrieve the whole state by default", function() {
|
||||
expect(store.getStoreState()).eql(defaultStoreState);
|
||||
});
|
||||
|
||||
it("should retrieve a given property state", function() {
|
||||
var fakeActiveRoom = {fake: true};
|
||||
store.setStoreState({activeRoom: fakeActiveRoom});
|
||||
|
||||
expect(store.getStoreState().activeRoom).eql(fakeActiveRoom);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#findNextAvailableRoomNumber", function() {
|
||||
var fakeNameTemplate = "RoomWord {{conversationLabel}}";
|
||||
|
||||
@ -243,6 +260,19 @@ describe("loop.store.RoomListStore", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#copyRoomUrl", function() {
|
||||
it("should copy the room URL", function() {
|
||||
var copyString = sandbox.stub(fakeMozLoop, "copyString");
|
||||
|
||||
store.copyRoomUrl(new sharedActions.CopyRoomUrl({
|
||||
roomUrl: "http://invalid"
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(copyString);
|
||||
sinon.assert.calledWithExactly(copyString, "http://invalid");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#setStoreState", function() {
|
||||
it("should update store state data", function() {
|
||||
store.setStoreState({pendingCreation: true});
|
||||
@ -257,6 +287,14 @@ describe("loop.store.RoomListStore", function () {
|
||||
|
||||
store.setStoreState({pendingCreation: true});
|
||||
});
|
||||
|
||||
it("should trigger a `change:<prop>` event", function(done) {
|
||||
store.once("change:pendingCreation", function() {
|
||||
done();
|
||||
});
|
||||
|
||||
store.setStoreState({pendingCreation: true});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#getAllRooms", function() {
|
||||
@ -325,6 +363,40 @@ describe("loop.store.RoomListStore", function () {
|
||||
expect(store.getStoreState().pendingInitialRetrieval).eql(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ActiveRoomStore substore", function() {
|
||||
var store, activeRoomStore;
|
||||
|
||||
beforeEach(function() {
|
||||
activeRoomStore = new loop.store.ActiveRoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: fakeMozLoop
|
||||
});
|
||||
store = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: fakeMozLoop,
|
||||
activeRoomStore: activeRoomStore
|
||||
});
|
||||
});
|
||||
|
||||
it("should subscribe to substore changes", function() {
|
||||
var fakeServerData = {fake: true};
|
||||
|
||||
activeRoomStore.setStoreState({serverData: fakeServerData});
|
||||
|
||||
expect(store.getStoreState().activeRoom.serverData)
|
||||
.eql(fakeServerData);
|
||||
});
|
||||
|
||||
it("should trigger a change event when the substore is updated",
|
||||
function(done) {
|
||||
store.once("change:activeRoom", function() {
|
||||
done();
|
||||
});
|
||||
|
||||
activeRoomStore.setStoreState({serverData: {}});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#openRoom", function() {
|
||||
@ -336,7 +408,7 @@ describe("loop.store.RoomListStore", function () {
|
||||
open: sinon.spy()
|
||||
}
|
||||
};
|
||||
store = new loop.store.RoomListStore({
|
||||
store = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: fakeMozLoop
|
||||
});
|
@ -37,11 +37,17 @@
|
||||
<script src="../../content/shared/js/views.js"></script>
|
||||
<script src="../../content/shared/js/websocket.js"></script>
|
||||
<script src="../../content/shared/js/feedbackApiClient.js"></script>
|
||||
<script src="../../content/shared/js/actions.js"></script>
|
||||
<script src="../../content/shared/js/validate.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../standalone/content/js/multiplexGum.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneAppStore.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneClient.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneRoomViews.js"></script>
|
||||
<script src="../../standalone/content/js/webapp.js"></script>
|
||||
<!-- Test scripts -->
|
||||
<script src="standalone_client_test.js"></script>
|
||||
<script src="standaloneAppStore_test.js"></script>
|
||||
<script src="webapp_test.js"></script>
|
||||
<script src="multiplexGum_test.js"></script>
|
||||
<script>
|
||||
|
@ -0,0 +1,246 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var expect = chai.expect;
|
||||
|
||||
describe("loop.store.StandaloneAppStore", function () {
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
var sandbox, dispatcher;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
dispatcher = new loop.Dispatcher();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("#constructor", function() {
|
||||
it("should throw an error if the dispatcher is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.StandaloneAppStore({
|
||||
sdk: {},
|
||||
helper: {},
|
||||
conversation: {}
|
||||
});
|
||||
}).to.Throw(/dispatcher/);
|
||||
});
|
||||
|
||||
it("should throw an error if sdk is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
helper: {},
|
||||
conversation: {}
|
||||
});
|
||||
}).to.Throw(/sdk/);
|
||||
});
|
||||
|
||||
it("should throw an error if helper is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
sdk: {},
|
||||
conversation: {}
|
||||
});
|
||||
}).to.Throw(/helper/);
|
||||
});
|
||||
|
||||
it("should throw an error if conversation is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
sdk: {},
|
||||
helper: {}
|
||||
});
|
||||
}).to.Throw(/conversation/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#extractTokenInfo", function() {
|
||||
var store, fakeGetWindowData, fakeSdk, fakeConversation, helper;
|
||||
|
||||
beforeEach(function() {
|
||||
fakeGetWindowData = {
|
||||
windowPath: ""
|
||||
};
|
||||
|
||||
helper = new sharedUtils.Helper();
|
||||
sandbox.stub(helper, "isIOS").returns(false);
|
||||
|
||||
fakeSdk = {
|
||||
checkSystemRequirements: sinon.stub().returns(true)
|
||||
};
|
||||
|
||||
fakeConversation = {
|
||||
set: sinon.spy()
|
||||
};
|
||||
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
store = new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
sdk: fakeSdk,
|
||||
helper: helper,
|
||||
conversation: fakeConversation
|
||||
});
|
||||
});
|
||||
|
||||
it("should set windowType to `unsupportedDevice` for IOS", function() {
|
||||
// The stub should return true for this test.
|
||||
helper.isIOS.returns(true);
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
expect(store.getStoreState()).eql({
|
||||
windowType: "unsupportedDevice"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set windowType to `unsupportedBrowser` for browsers the sdk does not support",
|
||||
function() {
|
||||
// The stub should return false for this test.
|
||||
fakeSdk.checkSystemRequirements.returns(false);
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
expect(store.getStoreState()).eql({
|
||||
windowType: "unsupportedBrowser"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set windowType to `outgoing` for old style call hashes", function() {
|
||||
fakeGetWindowData.windowPath = "#call/faketoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
expect(store.getStoreState()).eql({
|
||||
windowType: "outgoing"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set windowType to `outgoing` for new style call paths", function() {
|
||||
fakeGetWindowData.windowPath = "/c/fakecalltoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
expect(store.getStoreState()).eql({
|
||||
windowType: "outgoing"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set windowType to `room` for room paths", function() {
|
||||
fakeGetWindowData.windowPath = "/fakeroomtoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
expect(store.getStoreState()).eql({
|
||||
windowType: "room"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set windowType to `home` for unknown paths", function() {
|
||||
fakeGetWindowData.windowPath = "/";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
expect(store.getStoreState()).eql({
|
||||
windowType: "home"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for old style call hashes",
|
||||
function() {
|
||||
fakeGetWindowData.windowPath = "#call/faketoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
sinon.assert.calledOnce(fakeConversation.set);
|
||||
sinon.assert.calledWithExactly(fakeConversation.set, {
|
||||
loopToken: "faketoken"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for new style call paths",
|
||||
function() {
|
||||
fakeGetWindowData.windowPath = "/c/fakecalltoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
sinon.assert.calledOnce(fakeConversation.set);
|
||||
sinon.assert.calledWithExactly(fakeConversation.set, {
|
||||
loopToken: "fakecalltoken"
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for room paths",
|
||||
function() {
|
||||
fakeGetWindowData.windowPath = "/c/fakeroomtoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
sinon.assert.calledOnce(fakeConversation.set);
|
||||
sinon.assert.calledWithExactly(fakeConversation.set, {
|
||||
loopToken: "fakeroomtoken"
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch a SetupWindowData action for old style call hashes",
|
||||
function() {
|
||||
fakeGetWindowData.windowPath = "#call/faketoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.FetchServerData({
|
||||
windowType: "outgoing",
|
||||
token: "faketoken"
|
||||
}));
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for new style call paths",
|
||||
function() {
|
||||
fakeGetWindowData.windowPath = "/c/fakecalltoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.FetchServerData({
|
||||
windowType: "outgoing",
|
||||
token: "fakecalltoken"
|
||||
}));
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for room paths",
|
||||
function() {
|
||||
fakeGetWindowData.windowPath = "/c/fakeroomtoken";
|
||||
|
||||
store.extractTokenInfo(
|
||||
new sharedActions.ExtractTokenInfo(fakeGetWindowData));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
new sharedActions.FetchServerData({
|
||||
windowType: "outgoing",
|
||||
token: "fakeroomtoken"
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -10,6 +10,7 @@ var TestUtils = React.addons.TestUtils;
|
||||
describe("loop.webapp", function() {
|
||||
"use strict";
|
||||
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedModels = loop.shared.models,
|
||||
sharedViews = loop.shared.views,
|
||||
sharedUtils = loop.shared.utils,
|
||||
@ -35,13 +36,10 @@ describe("loop.webapp", function() {
|
||||
});
|
||||
|
||||
describe("#init", function() {
|
||||
var conversationSetStub;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(React, "renderComponent");
|
||||
loop.config.feedbackApiUrl = "http://fake.invalid";
|
||||
conversationSetStub =
|
||||
sandbox.stub(sharedModels.ConversationModel.prototype, "set");
|
||||
sandbox.stub(loop.Dispatcher.prototype, "dispatch");
|
||||
});
|
||||
|
||||
it("should create the WebappRootView", function() {
|
||||
@ -55,33 +53,36 @@ describe("loop.webapp", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for old-style call urls",
|
||||
function() {
|
||||
sandbox.stub(sharedUtils.Helper.prototype,
|
||||
"locationData").returns({
|
||||
hash: "#call/fake-Token",
|
||||
pathname: "/"
|
||||
});
|
||||
|
||||
loop.webapp.init();
|
||||
|
||||
sinon.assert.called(conversationSetStub);
|
||||
sinon.assert.calledWithExactly(conversationSetStub, {loopToken: "fake-Token"});
|
||||
it("should dispatch a ExtractTokenInfo action with the hash", function() {
|
||||
sandbox.stub(loop.shared.utils.Helper.prototype, "locationData").returns({
|
||||
hash: "#call/faketoken",
|
||||
pathname: "invalid"
|
||||
});
|
||||
|
||||
it("should set the loopToken on the conversation for new-style call urls",
|
||||
loop.webapp.init();
|
||||
|
||||
sinon.assert.calledOnce(loop.Dispatcher.prototype.dispatch);
|
||||
sinon.assert.calledWithExactly(loop.Dispatcher.prototype.dispatch,
|
||||
new sharedActions.ExtractTokenInfo({
|
||||
windowPath: "#call/faketoken"
|
||||
}));
|
||||
});
|
||||
|
||||
it("should dispatch a ExtractTokenInfo action with the path if there is no hash",
|
||||
function() {
|
||||
sandbox.stub(sharedUtils.Helper.prototype,
|
||||
"locationData").returns({
|
||||
hash: "",
|
||||
pathname: "/c/abc123-_Tes"
|
||||
});
|
||||
sandbox.stub(loop.shared.utils.Helper.prototype, "locationData").returns({
|
||||
hash: "",
|
||||
pathname: "/c/faketoken"
|
||||
});
|
||||
|
||||
loop.webapp.init();
|
||||
loop.webapp.init();
|
||||
|
||||
sinon.assert.called(conversationSetStub);
|
||||
sinon.assert.calledWithExactly(conversationSetStub, {loopToken: "abc123-_Tes"});
|
||||
});
|
||||
sinon.assert.calledOnce(loop.Dispatcher.prototype.dispatch);
|
||||
sinon.assert.calledWithExactly(loop.Dispatcher.prototype.dispatch,
|
||||
new sharedActions.ExtractTokenInfo({
|
||||
windowPath: "/c/faketoken"
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("OutgoingConversationView", function() {
|
||||
@ -544,7 +545,8 @@ describe("loop.webapp", function() {
|
||||
});
|
||||
|
||||
describe("WebappRootView", function() {
|
||||
var helper, sdk, conversationModel, client, props;
|
||||
var helper, sdk, conversationModel, client, props, standaloneAppStore;
|
||||
var dispatcher;
|
||||
|
||||
function mountTestComponent() {
|
||||
return TestUtils.renderIntoDocument(
|
||||
@ -555,7 +557,7 @@ describe("loop.webapp", function() {
|
||||
sdk: sdk,
|
||||
conversation: conversationModel,
|
||||
feedbackApiClient: feedbackApiClient,
|
||||
onUrlHashChange: sandbox.stub()
|
||||
standaloneAppStore: standaloneAppStore
|
||||
}));
|
||||
}
|
||||
|
||||
@ -570,14 +572,21 @@ describe("loop.webapp", function() {
|
||||
client = new loop.StandaloneClient({
|
||||
baseServerUrl: "fakeUrl"
|
||||
});
|
||||
dispatcher = new loop.Dispatcher();
|
||||
standaloneAppStore = new loop.store.StandaloneAppStore({
|
||||
dispatcher: dispatcher,
|
||||
sdk: sdk,
|
||||
helper: helper,
|
||||
conversation: conversationModel
|
||||
});
|
||||
// Stub this to stop the StartConversationView kicking in the request and
|
||||
// follow-ups.
|
||||
sandbox.stub(client, "requestCallUrlInfo");
|
||||
});
|
||||
|
||||
it("should mount the unsupportedDevice view if the device is running iOS",
|
||||
it("should display the UnsupportedDeviceView for `unsupportedDevice` window type",
|
||||
function() {
|
||||
sandbox.stub(helper, "isIOS").returns(true);
|
||||
standaloneAppStore.setStoreState({windowType: "unsupportedDevice"});
|
||||
|
||||
var webappRootView = mountTestComponent();
|
||||
|
||||
@ -585,11 +594,9 @@ describe("loop.webapp", function() {
|
||||
loop.webapp.UnsupportedDeviceView);
|
||||
});
|
||||
|
||||
it("should mount the unsupportedBrowser view if the sdk detects " +
|
||||
"the browser is unsupported", function() {
|
||||
sdk.checkSystemRequirements = function() {
|
||||
return false;
|
||||
};
|
||||
it("should display the UnsupportedBrowserView for `unsupportedBrowser` window type",
|
||||
function() {
|
||||
standaloneAppStore.setStoreState({windowType: "unsupportedBrowser"});
|
||||
|
||||
var webappRootView = mountTestComponent();
|
||||
|
||||
@ -597,9 +604,9 @@ describe("loop.webapp", function() {
|
||||
loop.webapp.UnsupportedBrowserView);
|
||||
});
|
||||
|
||||
it("should mount the OutgoingConversationView view if there is a loopToken",
|
||||
it("should display the OutgoingConversationView for `outgoing` window type",
|
||||
function() {
|
||||
conversationModel.set("loopToken", "fakeToken");
|
||||
standaloneAppStore.setStoreState({windowType: "outgoing"});
|
||||
|
||||
var webappRootView = mountTestComponent();
|
||||
|
||||
@ -607,7 +614,19 @@ describe("loop.webapp", function() {
|
||||
loop.webapp.OutgoingConversationView);
|
||||
});
|
||||
|
||||
it("should mount the Home view there is no loopToken", function() {
|
||||
it("should display the StandaloneRoomView for `room` window type",
|
||||
function() {
|
||||
standaloneAppStore.setStoreState({windowType: "room"});
|
||||
|
||||
var webappRootView = mountTestComponent();
|
||||
|
||||
TestUtils.findRenderedComponentWithType(webappRootView,
|
||||
loop.standaloneRoomViews.StandaloneRoomView);
|
||||
});
|
||||
|
||||
it("should display the HomeView for `home` window type", function() {
|
||||
standaloneAppStore.setStoreState({windowType: "home"});
|
||||
|
||||
var webappRootView = mountTestComponent();
|
||||
|
||||
TestUtils.findRenderedComponentWithType(webappRootView,
|
||||
|
@ -42,7 +42,8 @@
|
||||
<script src="../content/shared/js/validate.js"></script>
|
||||
<script src="../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../content/shared/js/conversationStore.js"></script>
|
||||
<script src="../content/shared/js/roomListStore.js"></script>
|
||||
<script src="../content/shared/js/roomStore.js"></script>
|
||||
<script src="../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../content/js/roomViews.js"></script>
|
||||
<script src="../content/js/conversationViews.js"></script>
|
||||
<script src="../content/js/client.js"></script>
|
||||
|
@ -57,7 +57,7 @@
|
||||
);
|
||||
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var roomListStore = new loop.store.RoomListStore({
|
||||
var roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop
|
||||
});
|
||||
@ -126,8 +126,8 @@
|
||||
return (
|
||||
React.DOM.div({className: "svg-icon-list"},
|
||||
this.shapes.map(function(shapeId, i) {
|
||||
return React.DOM.div({className: "svg-icon-entry"},
|
||||
React.DOM.p(null, SVGIcon({key: i, shapeId: shapeId})),
|
||||
return React.DOM.div({key: i, className: "svg-icon-entry"},
|
||||
React.DOM.p(null, SVGIcon({shapeId: shapeId})),
|
||||
React.DOM.p(null, shapeId)
|
||||
);
|
||||
}, this)
|
||||
@ -203,42 +203,42 @@
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
callUrl: "http://invalid.example.url/",
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Call URL retrieved - authenticated", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
callUrl: "http://invalid.example.url/",
|
||||
userProfile: {email: "test@example.com"},
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Pending call url retrieval", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Pending call url retrieval - authenticated", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
userProfile: {email: "test@example.com"},
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Error Notification", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: errNotifications,
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Error Notification - authenticated", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: errNotifications,
|
||||
userProfile: {email: "test@example.com"},
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
Example({summary: "Room list tab", dashed: "true", style: {width: "332px"}},
|
||||
PanelView({client: mockClient, notifications: notifications,
|
||||
userProfile: {email: "test@example.com"},
|
||||
dispatcher: dispatcher,
|
||||
roomListStore: roomListStore,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "rooms"})
|
||||
)
|
||||
),
|
||||
|
@ -57,7 +57,7 @@
|
||||
);
|
||||
|
||||
var dispatcher = new loop.Dispatcher();
|
||||
var roomListStore = new loop.store.RoomListStore({
|
||||
var roomStore = new loop.store.RoomStore({
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop
|
||||
});
|
||||
@ -126,8 +126,8 @@
|
||||
return (
|
||||
<div className="svg-icon-list">{
|
||||
this.shapes.map(function(shapeId, i) {
|
||||
return <div className="svg-icon-entry">
|
||||
<p><SVGIcon key={i} shapeId={shapeId} /></p>
|
||||
return <div key={i} className="svg-icon-entry">
|
||||
<p><SVGIcon shapeId={shapeId} /></p>
|
||||
<p>{shapeId}</p>
|
||||
</div>;
|
||||
}, this)
|
||||
@ -203,42 +203,42 @@
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
callUrl="http://invalid.example.url/"
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Call URL retrieved - authenticated" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
callUrl="http://invalid.example.url/"
|
||||
userProfile={{email: "test@example.com"}}
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Pending call url retrieval" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Pending call url retrieval - authenticated" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
userProfile={{email: "test@example.com"}}
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Error Notification" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={errNotifications}
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Error Notification - authenticated" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={errNotifications}
|
||||
userProfile={{email: "test@example.com"}}
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example summary="Room list tab" dashed="true" style={{width: "332px"}}>
|
||||
<PanelView client={mockClient} notifications={notifications}
|
||||
userProfile={{email: "test@example.com"}}
|
||||
dispatcher={dispatcher}
|
||||
roomListStore={roomListStore}
|
||||
roomStore={roomStore}
|
||||
selectedTab="rooms" />
|
||||
</Example>
|
||||
</Section>
|
||||
|
@ -5,4 +5,4 @@
|
||||
browser.jar:
|
||||
* content/browser/migration/migration.xul (content/migration.xul)
|
||||
content/browser/migration/migration.js (content/migration.js)
|
||||
* content/browser/aboutWelcomeBack.xhtml (content/aboutWelcomeBack.xhtml)
|
||||
content/browser/aboutWelcomeBack.xhtml (content/aboutWelcomeBack.xhtml)
|
||||
|
@ -43,8 +43,6 @@ EXTRA_JS_MODULES += [
|
||||
'distribution.js',
|
||||
]
|
||||
|
||||
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser.ini'
|
||||
]
|
||||
|
@ -636,7 +636,7 @@ PlacesController.prototype = {
|
||||
if (!openContainerInTabsItem.hidden) {
|
||||
var containerToUse = this._view.selectedNode || this._view.result.root;
|
||||
if (PlacesUtils.nodeIsContainer(containerToUse)) {
|
||||
if (!PlacesUtils.hasChildURIs(containerToUse, true)) {
|
||||
if (!PlacesUtils.hasChildURIs(containerToUse)) {
|
||||
openContainerInTabsItem.disabled = true;
|
||||
// Ensure that we don't display the menu if nothing is enabled:
|
||||
usableItemCount--;
|
||||
|
@ -40,7 +40,7 @@ var SidebarUtils = {
|
||||
var openInTabs = isContainer &&
|
||||
(aEvent.button == 1 ||
|
||||
(aEvent.button == 0 && modifKey)) &&
|
||||
PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row), true);
|
||||
PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row));
|
||||
|
||||
if (aEvent.button == 0 && isContainer && !openInTabs) {
|
||||
tbo.view.toggleOpenState(cell.row);
|
||||
|
@ -4,7 +4,7 @@
|
||||
# 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/.
|
||||
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME', 'E10S_TESTING_ONLY'):
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'cocoa'):
|
||||
|
@ -369,9 +369,7 @@
|
||||
tooltiptext="&debuggerUI.sources.blackBoxTooltip;"
|
||||
command="blackBoxCommand"/>
|
||||
<toolbarbutton id="pretty-print"
|
||||
class="devtools-toolbarbutton devtools-monospace"
|
||||
text-as-image="true"
|
||||
label="{}"
|
||||
class="devtools-toolbarbutton"
|
||||
tooltiptext="&debuggerUI.sources.prettyPrint;"
|
||||
command="prettyPrintCommand"
|
||||
hidden="true"/>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
@ -0,0 +1,74 @@
|
||||
/* 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/. */
|
||||
|
||||
#doorhanger-container {
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
#top-panel {
|
||||
padding: 20px;
|
||||
background: #343c45; /* toolbars */
|
||||
color: #8fa1b2; /* body text */
|
||||
font-size: 15px;
|
||||
line-height: 19px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
#top-panel h1 {
|
||||
font-weight: bold;
|
||||
font-family: Open Sans, sans-serif;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#top-panel p {
|
||||
font-family: Open Sans, sans-serif;
|
||||
font-size: 0.9em;
|
||||
width: 300px;
|
||||
display: block;
|
||||
margin: 5px 0px 0px 0px;
|
||||
}
|
||||
|
||||
#icon {
|
||||
background-image: url("chrome://browser/content/devtools/framework/dev-edition-logo.png");
|
||||
background-size: 64px 64px;
|
||||
background-repeat: no-repeat;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#lower-panel {
|
||||
padding: 20px;
|
||||
background-color: #252c33; /* tab toolbars */
|
||||
min-height: 75px;
|
||||
border-top: 1px solid #292e33; /* text high contrast (light) */
|
||||
}
|
||||
|
||||
#button-container {
|
||||
margin: auto 20px;
|
||||
}
|
||||
|
||||
#button-container button {
|
||||
font: message-box !important;
|
||||
font-size: 16px !important;
|
||||
cursor: pointer;
|
||||
width: 125px;
|
||||
opacity: 1;
|
||||
position: static;
|
||||
-moz-appearance: none;
|
||||
border-radius: 5px;
|
||||
height: 30px;
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
#close {
|
||||
background-color: transparent;
|
||||
color: #8fa1b2; /* body text */
|
||||
}
|
||||
|
||||
#go {
|
||||
margin-left: 100px;
|
||||
background-color: #70bf53; /* green */
|
||||
color: #f5f7fa; /* selection text color */
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % toolboxDTD SYSTEM "chrome://browser/locale/devtools/toolbox.dtd" >
|
||||
%toolboxDTD;
|
||||
]>
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<?xml-stylesheet rel="stylesheet" href="chrome://browser/content/devtools/framework/dev-edition-promo.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="dev-edition-promo">
|
||||
<vbox id="doorhanger-container">
|
||||
<hbox flex="1" id="top-panel">
|
||||
<image id="icon" />
|
||||
<vbox id="info">
|
||||
<h1>Using Developer Tools in your browser?</h1>
|
||||
<p>Download Firefox Developer Edition, our first browser made just for you.</p>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<hbox id="lower-panel" flex="1">
|
||||
<hbox id="button-container" flex="1">
|
||||
<button id="close"
|
||||
flex="1"
|
||||
standalone="true"
|
||||
label="No thanks">
|
||||
</button>
|
||||
<button id="go"
|
||||
flex="1"
|
||||
standalone="true"
|
||||
label="Learn more »">
|
||||
</button>
|
||||
</hbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</window>
|
@ -17,6 +17,7 @@ let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
let {getHighlighterUtils} = require("devtools/framework/toolbox-highlighter-utils");
|
||||
let HUDService = require("devtools/webconsole/hudservice");
|
||||
let {showDoorhanger} = require("devtools/shared/doorhanger");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -100,6 +101,7 @@ function Toolbox(target, selectedTool, hostType, hostOptions) {
|
||||
this._prefChanged = this._prefChanged.bind(this);
|
||||
this._saveSplitConsoleHeight = this._saveSplitConsoleHeight.bind(this);
|
||||
this._onFocus = this._onFocus.bind(this);
|
||||
this._showDevEditionPromo = this._showDevEditionPromo.bind(this);
|
||||
|
||||
this._target.on("close", this.destroy);
|
||||
|
||||
@ -124,6 +126,8 @@ function Toolbox(target, selectedTool, hostType, hostOptions) {
|
||||
this.on("host-changed", this._refreshHostTitle);
|
||||
this.on("select", this._refreshHostTitle);
|
||||
|
||||
this.on("ready", this._showDevEditionPromo);
|
||||
|
||||
gDevTools.on("tool-registered", this._toolRegistered);
|
||||
gDevTools.on("tool-unregistered", this._toolUnregistered);
|
||||
}
|
||||
@ -1649,5 +1653,18 @@ Toolbox.prototype = {
|
||||
|
||||
_highlighterHidden: function() {
|
||||
this.emit("highlighter-hide");
|
||||
},
|
||||
|
||||
/**
|
||||
* For displaying the promotional Doorhanger on first opening of
|
||||
* the developer tools, promoting the Developer Edition.
|
||||
*/
|
||||
_showDevEditionPromo: function() {
|
||||
// Do not display in browser toolbox
|
||||
if (this.target.chrome) {
|
||||
return;
|
||||
}
|
||||
let window = this.frame.contentWindow;
|
||||
showDoorhanger({ window, type: "deveditionpromo" });
|
||||
}
|
||||
};
|
||||
|
@ -103,6 +103,9 @@ browser.jar:
|
||||
content/browser/devtools/framework/options-panel.css (framework/options-panel.css)
|
||||
content/browser/devtools/framework/toolbox-process-window.xul (framework/toolbox-process-window.xul)
|
||||
content/browser/devtools/framework/toolbox-process-window.js (framework/toolbox-process-window.js)
|
||||
content/browser/devtools/framework/dev-edition-promo.xul (framework/dev-edition-promo/dev-edition-promo.xul)
|
||||
content/browser/devtools/framework/dev-edition-promo.css (framework/dev-edition-promo/dev-edition-promo.css)
|
||||
content/browser/devtools/framework/dev-edition-logo.png (framework/dev-edition-promo/dev-edition-logo.png)
|
||||
content/browser/devtools/inspector/inspector.xul (inspector/inspector.xul)
|
||||
content/browser/devtools/inspector/inspector.css (inspector/inspector.css)
|
||||
content/browser/devtools/connect.xhtml (framework/connect/connect.xhtml)
|
||||
|
@ -17,6 +17,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
|
||||
|
||||
var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
let Telemetry = require("devtools/shared/telemetry");
|
||||
let {showDoorhanger} = require("devtools/shared/doorhanger");
|
||||
let {TouchEventHandler} = require("devtools/touch-events");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
|
||||
@ -217,6 +218,13 @@ function ResponsiveUI(aWindow, aTab)
|
||||
|
||||
// E10S: We should be using target here. See bug 1028234
|
||||
ResponsiveUIManager.emit("on", { tab: this.tab });
|
||||
|
||||
// Hook to display promotional Developer Edition doorhanger. Only displayed once.
|
||||
showDoorhanger({
|
||||
window: this.mainWindow,
|
||||
type: "deveditionpromo",
|
||||
anchor: this.chromeDoc.querySelector("#content")
|
||||
});
|
||||
}
|
||||
|
||||
ResponsiveUI.prototype = {
|
||||
|
144
browser/devtools/shared/doorhanger.js
Normal file
144
browser/devtools/shared/doorhanger.js
Normal file
@ -0,0 +1,144 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Ci, Cc } = require("chrome");
|
||||
const { Services } = require("resource://gre/modules/Services.jsm");
|
||||
const { DOMHelpers } = require("resource:///modules/devtools/DOMHelpers.jsm");
|
||||
const { Task } = require("resource://gre/modules/Task.jsm");
|
||||
const { Promise } = require("resource://gre/modules/Promise.jsm");
|
||||
const { getMostRecentBrowserWindow } = require("sdk/window/utils");
|
||||
|
||||
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const DEV_EDITION_PROMO_URL = "chrome://browser/content/devtools/framework/dev-edition-promo.xul";
|
||||
const DEV_EDITION_PROMO_ENABLED_PREF = "devtools.devedition.promo.enabled";
|
||||
const DEV_EDITION_PROMO_SHOWN_PREF = "devtools.devedition.promo.shown";
|
||||
const DEV_EDITION_PROMO_URL_PREF = "devtools.devedition.promo.url";
|
||||
const LOCALE = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global");
|
||||
|
||||
/**
|
||||
* Only show Dev Edition promo if it's enabled (beta channel),
|
||||
* if it has not been shown before, and it's a locale build
|
||||
* for `en-US`
|
||||
*/
|
||||
function shouldDevEditionPromoShow () {
|
||||
return Services.prefs.getBoolPref(DEV_EDITION_PROMO_ENABLED_PREF) &&
|
||||
!Services.prefs.getBoolPref(DEV_EDITION_PROMO_SHOWN_PREF) &&
|
||||
LOCALE === "en-US";
|
||||
}
|
||||
|
||||
let TYPES = {
|
||||
// The Developer Edition promo doorhanger, called by
|
||||
// opening the toolbox, browser console, WebIDE, or responsive design mode
|
||||
// in Beta releases. Only displayed once per profile.
|
||||
deveditionpromo: {
|
||||
predicate: shouldDevEditionPromoShow,
|
||||
success: () => Services.prefs.setBoolPref(DEV_EDITION_PROMO_SHOWN_PREF, true),
|
||||
action: () => {
|
||||
let url = Services.prefs.getCharPref(DEV_EDITION_PROMO_URL_PREF);
|
||||
getGBrowser().selectedTab = getGBrowser().addTab(url);
|
||||
},
|
||||
url: DEV_EDITION_PROMO_URL
|
||||
}
|
||||
};
|
||||
|
||||
let panelAttrs = {
|
||||
orient: "vertical",
|
||||
hidden: "false",
|
||||
consumeoutsideclicks: "true",
|
||||
noautofocus: "true",
|
||||
align: "start",
|
||||
role: "alert"
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to call a doorhanger, defined in `TYPES`, with defined conditions,
|
||||
* success handlers and loads its own XUL in a frame. Takes an object with
|
||||
* several properties:
|
||||
*
|
||||
* @param {XULWindow} window
|
||||
* The window that should house the doorhanger.
|
||||
* @param {String} type
|
||||
* The type of doorhanger to be displayed is, using the `TYPES` definition.
|
||||
* @param {String} selector
|
||||
* The selector that the doorhanger should be appended to within `window`.
|
||||
* Defaults to a XUL Document's `window` element.
|
||||
*/
|
||||
exports.showDoorhanger = Task.async(function *({ window, type, anchor }) {
|
||||
let { predicate, success, url, action } = TYPES[type];
|
||||
// Abort if predicate fails
|
||||
if (!predicate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let document = window.document;
|
||||
|
||||
let panel = document.createElementNS(XULNS, "panel");
|
||||
let frame = document.createElementNS(XULNS, "iframe");
|
||||
let parentEl = document.querySelector("window");
|
||||
|
||||
frame.setAttribute("src", url);
|
||||
let close = () => parentEl.removeChild(panel);
|
||||
|
||||
setDoorhangerStyle(panel, frame);
|
||||
|
||||
panel.appendChild(frame);
|
||||
parentEl.appendChild(panel);
|
||||
|
||||
yield onFrameLoad(frame);
|
||||
|
||||
panel.openPopup(anchor);
|
||||
|
||||
let closeBtn = frame.contentDocument.querySelector("#close");
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener("click", close);
|
||||
}
|
||||
|
||||
let goBtn = frame.contentDocument.querySelector("#go");
|
||||
if (goBtn) {
|
||||
goBtn.addEventListener("click", () => {
|
||||
if (action) {
|
||||
action();
|
||||
}
|
||||
close();
|
||||
});
|
||||
}
|
||||
|
||||
// Call success function to set preferences, etc.
|
||||
success();
|
||||
});
|
||||
|
||||
function setDoorhangerStyle (panel, frame) {
|
||||
Object.keys(panelAttrs).forEach(prop => panel.setAttribute(prop, panelAttrs[prop]));
|
||||
panel.style.margin = "20px";
|
||||
panel.style.borderRadius = "5px";
|
||||
frame.style.borderRadius = "5px";
|
||||
frame.setAttribute("flex", "1");
|
||||
frame.setAttribute("width", "450");
|
||||
frame.setAttribute("height", "179");
|
||||
}
|
||||
|
||||
function onFrameLoad (frame) {
|
||||
let { resolve, promise } = Promise.defer();
|
||||
|
||||
if (frame.contentWindow) {
|
||||
let domHelper = new DOMHelpers(frame.contentWindow);
|
||||
domHelper.onceDOMReady(resolve);
|
||||
} else {
|
||||
let callback = () => {
|
||||
frame.removeEventListener("DOMContentLoaded", callback);
|
||||
resolve();
|
||||
}
|
||||
frame.addEventListener("DOMContentLoaded", callback);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function getGBrowser () {
|
||||
return getMostRecentBrowserWindow().gBrowser;
|
||||
}
|
@ -33,6 +33,7 @@ EXTRA_JS_MODULES.devtools += [
|
||||
EXTRA_JS_MODULES.devtools.shared += [
|
||||
'autocomplete-popup.js',
|
||||
'd3.js',
|
||||
'doorhanger.js',
|
||||
'frame-script-utils.js',
|
||||
'inplace-editor.js',
|
||||
'observable-object.js',
|
||||
|
@ -19,6 +19,7 @@ loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.js
|
||||
loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
|
||||
loader.lazyImporter(this, "DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
|
||||
loader.lazyImporter(this, "DebuggerClient", "resource://gre/modules/devtools/dbg-client.jsm");
|
||||
loader.lazyGetter(this, "showDoorhanger", () => require("devtools/shared/doorhanger").showDoorhanger);
|
||||
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
|
||||
let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
|
||||
@ -713,6 +714,9 @@ BrowserConsole.prototype = Heritage.extend(WebConsole.prototype,
|
||||
|
||||
this._telemetry.toolOpened("browserconsole");
|
||||
|
||||
// Hook to display promotional Developer Edition doorhanger. Only displayed once.
|
||||
showDoorhanger({ window, type: "deveditionpromo" });
|
||||
|
||||
this._bc_init = this.$init();
|
||||
return this._bc_init;
|
||||
},
|
||||
|
@ -23,6 +23,7 @@ const {GetTemplatesJSON, GetAddonsJSON} = require("devtools/webide/remote-resour
|
||||
const utils = require("devtools/webide/utils");
|
||||
const Telemetry = require("devtools/shared/telemetry");
|
||||
const {RuntimeScanners, WiFiScanner} = require("devtools/webide/runtimes");
|
||||
const {showDoorhanger} = require("devtools/shared/doorhanger");
|
||||
|
||||
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
|
||||
|
||||
@ -96,6 +97,9 @@ let UI = {
|
||||
}
|
||||
|
||||
this.setupDeck();
|
||||
|
||||
// Hook to display promotional Developer Edition doorhanger. Only displayed once.
|
||||
showDoorhanger({ window, type: "deveditionpromo", anchor: document.querySelector("#deck") });
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 25 KiB |
@ -123,7 +123,7 @@ LoginManagerPrompter.prototype = {
|
||||
},
|
||||
|
||||
|
||||
setE10sData : function (aBrowser) {
|
||||
setE10sData : function (aBrowser, aOpener) {
|
||||
// XXX Implement me!
|
||||
throw new Error("Not Yet Implemented");
|
||||
},
|
||||
|
@ -293,6 +293,8 @@ browser.jar:
|
||||
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/browser/devtools/debugger-prettyprint.png (../shared/devtools/images/debugger-prettyprint.png)
|
||||
skin/classic/browser/devtools/debugger-prettyprint@2x.png (../shared/devtools/images/debugger-prettyprint@2x.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
|
@ -6,6 +6,4 @@
|
||||
|
||||
DIRS += ['communicator']
|
||||
|
||||
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -415,6 +415,8 @@ browser.jar:
|
||||
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/browser/devtools/debugger-prettyprint.png (../shared/devtools/images/debugger-prettyprint.png)
|
||||
skin/classic/browser/devtools/debugger-prettyprint@2x.png (../shared/devtools/images/debugger-prettyprint@2x.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
|
@ -6,6 +6,4 @@
|
||||
|
||||
DIRS += ['communicator']
|
||||
|
||||
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -68,7 +68,13 @@
|
||||
}
|
||||
|
||||
#pretty-print {
|
||||
font-weight: bold;
|
||||
list-style-image: url(debugger-prettyprint.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#pretty-print {
|
||||
list-style-image: url(debugger-prettyprint@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#toggle-breakpoints {
|
||||
|
BIN
browser/themes/shared/devtools/images/debugger-prettyprint.png
Normal file
BIN
browser/themes/shared/devtools/images/debugger-prettyprint.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 639 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -329,6 +329,8 @@ browser.jar:
|
||||
skin/classic/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/browser/devtools/debugger-prettyprint.png (../shared/devtools/images/debugger-prettyprint.png)
|
||||
skin/classic/browser/devtools/debugger-prettyprint@2x.png (../shared/devtools/images/debugger-prettyprint@2x.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
@ -761,6 +763,8 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/debugger-step-over@2x.png (../shared/devtools/images/debugger-step-over@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-blackbox.png (../shared/devtools/images/debugger-blackbox.png)
|
||||
skin/classic/aero/browser/devtools/debugger-blackbox@2x.png (../shared/devtools/images/debugger-blackbox@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-prettyprint.png (../shared/devtools/images/debugger-prettyprint.png)
|
||||
skin/classic/aero/browser/devtools/debugger-prettyprint@2x.png (../shared/devtools/images/debugger-prettyprint@2x.png)
|
||||
skin/classic/aero/browser/devtools/debugger-toggleBreakpoints.png (../shared/devtools/images/debugger-toggleBreakpoints.png)
|
||||
skin/classic/aero/browser/devtools/debugger-toggleBreakpoints@2x.png (../shared/devtools/images/debugger-toggleBreakpoints@2x.png)
|
||||
skin/classic/aero/browser/devtools/tracer-icon.png (../shared/devtools/images/tracer-icon.png)
|
||||
|
@ -6,6 +6,4 @@
|
||||
|
||||
DIRS += ['communicator']
|
||||
|
||||
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
@ -13,7 +13,6 @@ import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from urlparse import urlparse
|
||||
import zipfile
|
||||
import mozinfo
|
||||
|
||||
@ -21,7 +20,6 @@ __all__ = [
|
||||
"ZipFileReader",
|
||||
"addCommonOptions",
|
||||
"dumpLeakLog",
|
||||
"isURL",
|
||||
"processLeakLog",
|
||||
'KeyValueParseError',
|
||||
'parseKeyValue',
|
||||
@ -107,11 +105,6 @@ class ZipFileReader(object):
|
||||
for name in self._zipfile.namelist():
|
||||
self._extractname(name, path)
|
||||
|
||||
def isURL(thing):
|
||||
"""Return True if |thing| looks like a URL."""
|
||||
# We want to download URLs like http://... but not Windows paths like c:\...
|
||||
return len(urlparse(thing).scheme) >= 2
|
||||
|
||||
# Python does not provide strsignal() even in the very latest 3.x.
|
||||
# This is a reasonable fake.
|
||||
def strsig(n):
|
||||
|
@ -806,7 +806,7 @@ ifdef DTRACE_PROBE_OBJ
|
||||
ifndef DTRACE_LIB_DEPENDENT
|
||||
NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS))
|
||||
$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS)
|
||||
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
|
||||
dtrace -x nolibs -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -824,7 +824,7 @@ ifndef INCREMENTAL_LINKER
|
||||
endif
|
||||
ifdef DTRACE_LIB_DEPENDENT
|
||||
ifndef XP_MACOSX
|
||||
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS))
|
||||
dtrace -x nolibs -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS))
|
||||
endif
|
||||
$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE)
|
||||
@$(RM) $(DTRACE_PROBE_OBJ)
|
||||
|
@ -3569,8 +3569,9 @@ dnl ========================================================
|
||||
dnl Multiprocess Firefox Nightly Testing UI
|
||||
dnl To be removed in Bug 1003313
|
||||
dnl ========================================================
|
||||
if test -z "$NIGHTLY_BUILD"; then
|
||||
if test -n "$NIGHTLY_BUILD"; then
|
||||
E10S_TESTING_ONLY=1
|
||||
AC_DEFINE(E10S_TESTING_ONLY)
|
||||
fi
|
||||
|
||||
AC_SUBST(E10S_TESTING_ONLY)
|
||||
|
@ -17,11 +17,13 @@ namespace mozilla {
|
||||
LoadInfo::LoadInfo(nsIPrincipal* aPrincipal,
|
||||
nsINode* aLoadingContext,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType)
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
nsIURI* aBaseURI)
|
||||
: mPrincipal(aPrincipal)
|
||||
, mLoadingContext(do_GetWeakReference(aLoadingContext))
|
||||
, mSecurityFlags(aSecurityFlags)
|
||||
, mContentPolicyType(aContentPolicyType)
|
||||
, mBaseURI(aBaseURI)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
// if the load is sandboxed, we can not also inherit the principal
|
||||
@ -95,4 +97,12 @@ LoadInfo::GetContentPolicyType(nsContentPolicyType* outContentPolicyType)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetBaseURI(nsIURI** aBaseURI)
|
||||
{
|
||||
*aBaseURI = mBaseURI;
|
||||
NS_IF_ADDREF(*aBaseURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
|
||||
#include "nsIURI.h"
|
||||
|
||||
class nsINode;
|
||||
|
||||
@ -29,7 +30,8 @@ public:
|
||||
LoadInfo(nsIPrincipal* aPrincipal,
|
||||
nsINode* aLoadingContext,
|
||||
nsSecurityFlags aSecurityFlags,
|
||||
nsContentPolicyType aContentPolicyType);
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
nsIURI* aBaseURI = nullptr);
|
||||
|
||||
private:
|
||||
~LoadInfo();
|
||||
@ -38,6 +40,7 @@ private:
|
||||
nsWeakPtr mLoadingContext;
|
||||
nsSecurityFlags mSecurityFlags;
|
||||
nsContentPolicyType mContentPolicyType;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -10268,12 +10268,15 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
}
|
||||
|
||||
if (!isSrcdoc) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
new mozilla::LoadInfo(requestingPrincipal,
|
||||
requestingNode,
|
||||
securityFlags,
|
||||
aContentPolicyType,
|
||||
aBaseURI);
|
||||
rv = NS_NewChannelInternal(getter_AddRefs(channel),
|
||||
aURI,
|
||||
requestingNode,
|
||||
requestingPrincipal,
|
||||
securityFlags,
|
||||
aContentPolicyType,
|
||||
loadInfo,
|
||||
nullptr, // loadGroup
|
||||
static_cast<nsIInterfaceRequestor*>(this),
|
||||
loadFlags);
|
||||
@ -10293,12 +10296,6 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
if (aBaseURI) {
|
||||
nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
|
||||
if (vsc) {
|
||||
vsc->SetBaseURI(aBaseURI);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsAutoCString scheme;
|
||||
@ -10311,14 +10308,14 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance();
|
||||
NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE);
|
||||
|
||||
rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, aBaseURI,
|
||||
getter_AddRefs(channel));
|
||||
rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, getter_AddRefs(channel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
new LoadInfo(requestingPrincipal,
|
||||
requestingNode,
|
||||
securityFlags,
|
||||
aContentPolicyType);
|
||||
aContentPolicyType,
|
||||
aBaseURI);
|
||||
channel->SetLoadInfo(loadInfo);
|
||||
}
|
||||
else {
|
||||
@ -10330,11 +10327,9 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
||||
requestingPrincipal,
|
||||
securityFlags,
|
||||
aContentPolicyType,
|
||||
true);
|
||||
true,
|
||||
aBaseURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
|
||||
MOZ_ASSERT(isc);
|
||||
isc->SetBaseURI(aBaseURI);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11590,8 +11585,10 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
|
||||
nsAutoString srcdoc;
|
||||
inStrmChan->GetSrcdocData(srcdoc);
|
||||
entry->SetSrcdocData(srcdoc);
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
|
||||
loadInfo->GetBaseURI(getter_AddRefs(baseURI));
|
||||
entry->SetBaseURI(baseURI);
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,14 @@
|
||||
interface nsIDOMDocument;
|
||||
interface nsINode;
|
||||
interface nsIPrincipal;
|
||||
interface nsIURI;
|
||||
|
||||
typedef unsigned long nsSecurityFlags;
|
||||
|
||||
/**
|
||||
* An nsILoadOwner represents per-load information about who started the load.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(046db047-a1c1-4519-8ec7-99f3054bc9ac)]
|
||||
[scriptable, builtinclass, uuid(b22b8ee7-047a-4351-a749-13c6d39f6b17)]
|
||||
interface nsILoadInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -148,4 +149,10 @@ interface nsILoadInfo : nsISupports
|
||||
}
|
||||
%}
|
||||
|
||||
/**
|
||||
* A base URI for use in situations where it cannot otherwise be inferred.
|
||||
* This attribute may be null. The value of this attribute may be
|
||||
* ignored if the base URI can be inferred by the channel's URI.
|
||||
*/
|
||||
readonly attribute nsIURI baseURI;
|
||||
};
|
||||
|
@ -271,6 +271,16 @@ nsDOMWindowUtils::Redraw(uint32_t aCount, uint32_t *aDurationOut)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::UpdateLayerTree()
|
||||
{
|
||||
if (nsIPresShell* presShell = GetPresShell()) {
|
||||
nsRefPtr<nsViewManager> vm = presShell->GetViewManager();
|
||||
vm->ProcessPendingUpdates();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SetCSSViewport(float aWidthPx, float aHeightPx)
|
||||
{
|
||||
|
@ -4016,7 +4016,7 @@ nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aKid->IsElement() && GetRootElement()) {
|
||||
NS_ERROR("Inserting element child when we already have one");
|
||||
NS_WARNING("Inserting root element when we already have one");
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
|
||||
@ -7728,32 +7728,6 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
/*allowZoom*/true,
|
||||
/*allowDoubleTapZoom*/false);
|
||||
}
|
||||
|
||||
// Bug 940036. This is bad. When FirefoxOS was built, apps installed
|
||||
// where not using the AsyncPanZoom code. As a result a lot of apps
|
||||
// in the marketplace does not use it yet and instead are built to
|
||||
// render correctly in FirefoxOS only. For a smooth transition the above
|
||||
// code force installed apps to render as if they have a viewport with
|
||||
// content="width=device-width, height=device-height, user-scalable=no".
|
||||
// This could be safely remove once it is known that most apps in the
|
||||
// marketplace use it and that users does not use an old version of the
|
||||
// app that does not use it.
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
if (docShell && docShell->GetIsApp()) {
|
||||
nsString uri;
|
||||
GetDocumentURI(uri);
|
||||
if (!uri.EqualsLiteral("about:blank")) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DOM"), this,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"ImplicitMetaViewportTagFallback");
|
||||
}
|
||||
mViewportType = DisplayWidthHeightNoZoom;
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/false,
|
||||
/*allowDoubleTapZoom*/false);
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString minScaleStr;
|
||||
|
@ -951,6 +951,16 @@ DOMInterfaces = {
|
||||
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorker.h',
|
||||
},
|
||||
|
||||
'ServiceWorkerClient': {
|
||||
'nativeType': 'mozilla::dom::workers::ServiceWorkerClient',
|
||||
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClient.h',
|
||||
},
|
||||
|
||||
'ServiceWorkerClients': {
|
||||
'nativeType': 'mozilla::dom::workers::ServiceWorkerClients',
|
||||
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorkerClients.h',
|
||||
},
|
||||
|
||||
'ServiceWorkerGlobalScope': {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
'workers': True,
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsITextControlElement.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -99,8 +98,11 @@ IMEContentObserver::IMEContentObserver()
|
||||
void
|
||||
IMEContentObserver::Init(nsIWidget* aWidget,
|
||||
nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor)
|
||||
{
|
||||
MOZ_ASSERT(aEditor, "aEditor must not be null");
|
||||
|
||||
mESM = aPresContext->EventStateManager();
|
||||
mESM->OnStartToObserveContent(this);
|
||||
|
||||
@ -110,27 +112,8 @@ IMEContentObserver::Init(nsIWidget* aWidget,
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITextControlElement> textControlElement =
|
||||
do_QueryInterface(mEditableNode);
|
||||
if (textControlElement) {
|
||||
// This may fail. For example, <input type="button" contenteditable>
|
||||
mEditor = textControlElement->GetTextEditor();
|
||||
if (!mEditor && mEditableNode->IsContent()) {
|
||||
// The element must be an editing host.
|
||||
nsIContent* editingHost = mEditableNode->AsContent()->GetEditingHost();
|
||||
MOZ_ASSERT(editingHost == mEditableNode,
|
||||
"found editing host should be mEditableNode");
|
||||
if (editingHost == mEditableNode) {
|
||||
mEditor = nsContentUtils::GetHTMLEditor(aPresContext);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mEditor = nsContentUtils::GetHTMLEditor(aPresContext);
|
||||
}
|
||||
MOZ_ASSERT(mEditor, "Failed to get editor");
|
||||
if (mEditor) {
|
||||
mEditor->AddEditorObserver(this);
|
||||
}
|
||||
mEditor = aEditor;
|
||||
mEditor->AddEditorObserver(this);
|
||||
|
||||
nsIPresShell* presShell = aPresContext->PresShell();
|
||||
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
WidgetMouseEvent* aMouseEvent);
|
||||
|
||||
void Init(nsIWidget* aWidget, nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
nsIContent* aContent, nsIEditor* aEditor);
|
||||
void Destroy();
|
||||
/**
|
||||
* IMEContentObserver is stored by EventStateManager during observing.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsINode.h"
|
||||
@ -559,12 +560,14 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
// static
|
||||
void
|
||||
IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
|
||||
aPresContext, aContent, sPresContext, sContent,
|
||||
("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p, "
|
||||
"aEditor=0x%p), sPresContext=0x%p, sContent=0x%p, "
|
||||
"sActiveIMEContentObserver=0x%p",
|
||||
aPresContext, aContent, aEditor, sPresContext, sContent,
|
||||
sActiveIMEContentObserver));
|
||||
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
@ -586,21 +589,22 @@ IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
|
||||
CreateIMEContentObserver();
|
||||
CreateIMEContentObserver(aEditor);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
nsIContent* aContent)
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::UpdateIMEState(aNewIMEState={ mEnabled=%s, "
|
||||
"mOpen=%s }, aContent=0x%p), "
|
||||
"mOpen=%s }, aContent=0x%p, aEditor=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
|
||||
"sIsGettingNewIMEState=%s",
|
||||
GetIMEStateEnabledName(aNewIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent,
|
||||
GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent, aEditor,
|
||||
sPresContext, sContent, sActiveIMEContentObserver,
|
||||
GetBoolName(sIsGettingNewIMEState)));
|
||||
|
||||
@ -651,7 +655,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
}
|
||||
|
||||
if (createTextStateManager) {
|
||||
CreateIMEContentObserver();
|
||||
CreateIMEContentObserver(aEditor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1145,13 +1149,13 @@ IMEStateManager::DestroyIMEContentObserver()
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::CreateIMEContentObserver()
|
||||
IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
|
||||
{
|
||||
PR_LOG(sISMLog, PR_LOG_ALWAYS,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver(), "
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver(aEditor=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
|
||||
"sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
|
||||
sPresContext, sContent, sActiveIMEContentObserver,
|
||||
aEditor, sPresContext, sContent, sActiveIMEContentObserver,
|
||||
GetBoolName(sActiveIMEContentObserver ?
|
||||
sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
|
||||
|
||||
@ -1195,7 +1199,7 @@ IMEStateManager::CreateIMEContentObserver()
|
||||
// instance. So, sActiveIMEContentObserver would be replaced with new one.
|
||||
// We should hold the current instance here.
|
||||
nsRefPtr<IMEContentObserver> kungFuDeathGrip(sActiveIMEContentObserver);
|
||||
sActiveIMEContentObserver->Init(widget, sPresContext, sContent);
|
||||
sActiveIMEContentObserver->Init(widget, sPresContext, sContent, aEditor);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
class nsIContent;
|
||||
class nsIDOMMouseEvent;
|
||||
class nsIEditor;
|
||||
class nsINode;
|
||||
class nsPIDOMWindow;
|
||||
class nsPresContext;
|
||||
@ -65,7 +66,8 @@ public:
|
||||
// Note that this method changes the IME state of the active element in the
|
||||
// widget. So, the caller must have focus.
|
||||
static void UpdateIMEState(const IMEState &aNewIMEState,
|
||||
nsIContent* aContent);
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor);
|
||||
|
||||
// This method is called when user operates mouse button in focused editor
|
||||
// and before the editor handles it.
|
||||
@ -89,7 +91,8 @@ public:
|
||||
// If the editor is for contenteditable, the active editinghost.
|
||||
// If the editor is for designMode, nullptr.
|
||||
static void OnFocusInEditor(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor);
|
||||
|
||||
/**
|
||||
* All composition events must be dispatched via DispatchCompositionEvent()
|
||||
@ -149,7 +152,7 @@ protected:
|
||||
nsIContent* aContent);
|
||||
|
||||
static void EnsureTextCompositionArray();
|
||||
static void CreateIMEContentObserver();
|
||||
static void CreateIMEContentObserver(nsIEditor* aEditor);
|
||||
static void DestroyIMEContentObserver();
|
||||
|
||||
static bool IsEditable(nsINode* node);
|
||||
|
@ -110,7 +110,6 @@ struct IDBFactory::PendingRequestInfo
|
||||
IDBFactory::IDBFactory()
|
||||
: mOwningObject(nullptr)
|
||||
, mBackgroundActor(nullptr)
|
||||
, mRootedOwningObject(false)
|
||||
, mBackgroundActorFailed(false)
|
||||
, mPrivateBrowsingMode(false)
|
||||
{
|
||||
@ -124,10 +123,8 @@ IDBFactory::~IDBFactory()
|
||||
{
|
||||
MOZ_ASSERT_IF(mBackgroundActorFailed, !mBackgroundActor);
|
||||
|
||||
if (mRootedOwningObject) {
|
||||
mOwningObject = nullptr;
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
mOwningObject = nullptr;
|
||||
mozilla::DropJSObjects(this);
|
||||
|
||||
if (mBackgroundActor) {
|
||||
mBackgroundActor->SendDeleteMeInternal();
|
||||
@ -271,9 +268,7 @@ IDBFactory::CreateForJSInternal(JSContext* aCx,
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mPrincipalInfo = aPrincipalInfo.forget();
|
||||
factory->mOwningObject = aOwningObject;
|
||||
|
||||
mozilla::HoldJSObjects(factory.get());
|
||||
factory->mRootedOwningObject = true;
|
||||
|
||||
factory.forget(aFactory);
|
||||
return NS_OK;
|
||||
@ -716,13 +711,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
if (tmp->mOwningObject) {
|
||||
tmp->mOwningObject = nullptr;
|
||||
}
|
||||
if (tmp->mRootedOwningObject) {
|
||||
mozilla::DropJSObjects(tmp);
|
||||
tmp->mRootedOwningObject = false;
|
||||
}
|
||||
tmp->mOwningObject = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -73,7 +73,6 @@ class IDBFactory MOZ_FINAL
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
|
||||
bool mRootedOwningObject;
|
||||
bool mBackgroundActorFailed;
|
||||
bool mPrivateBrowsingMode;
|
||||
|
||||
|
@ -321,6 +321,11 @@ IDBMutableFile::Open(FileMode aMode, ErrorResult& aError)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mInvalidated) {
|
||||
aError.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBFileHandle> fileHandle =
|
||||
IDBFileHandle::Create(aMode, FileHandleBase::NORMAL, this);
|
||||
if (!fileHandle) {
|
||||
|
@ -103,6 +103,11 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
unsigned long redraw([optional] in unsigned long aCount);
|
||||
|
||||
/**
|
||||
* Force a synchronous layer transaction for this window if necessary.
|
||||
*/
|
||||
void updateLayerTree();
|
||||
|
||||
/**
|
||||
* Set the CSS viewport to be |widthPx| x |heightPx| in units of CSS
|
||||
* pixels, regardless of the size of the enclosing widget/view.
|
||||
|
@ -2363,6 +2363,18 @@ ContentChild::RecvOnAppThemeChanged()
|
||||
return true;
|
||||
}
|
||||
|
||||
PBrowserOrId
|
||||
ContentChild::GetBrowserOrId(TabChild* aTabChild)
|
||||
{
|
||||
if (!aTabChild ||
|
||||
this == aTabChild->Manager()) {
|
||||
return PBrowserOrId(aTabChild);
|
||||
}
|
||||
else {
|
||||
return PBrowserOrId(aTabChild->GetTabId());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/ContentBridgeParent.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/dom/PBrowserOrId.h"
|
||||
#include "mozilla/dom/PContentChild.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIObserver.h"
|
||||
@ -48,6 +49,7 @@ class PrefObserver;
|
||||
class ConsoleListener;
|
||||
class PStorageChild;
|
||||
class ClonedMessageData;
|
||||
class TabChild;
|
||||
|
||||
class ContentChild : public PContentChild
|
||||
, public nsIContentChild
|
||||
@ -403,6 +405,9 @@ public:
|
||||
|
||||
void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
|
||||
|
||||
PBrowserOrId
|
||||
GetBrowserOrId(TabChild* aTabChild);
|
||||
|
||||
private:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "nsAuthInformationHolder.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsILoginManagerPrompter.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla::dom;
|
||||
@ -1880,8 +1881,18 @@ TabParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
|
||||
|
||||
// Get an auth prompter for our window so that the parenting
|
||||
// of the dialogs works as it should when using tabs.
|
||||
return wwatch->GetPrompt(window, iid,
|
||||
reinterpret_cast<void**>(aResult));
|
||||
nsCOMPtr<nsISupports> prompt;
|
||||
rv = wwatch->GetPrompt(window, iid, getter_AddRefs(prompt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILoginManagerPrompter> prompter = do_QueryInterface(prompt);
|
||||
if (prompter) {
|
||||
nsCOMPtr<nsIDOMElement> browser = do_QueryInterface(mFrameElement);
|
||||
prompter->SetE10sData(browser, nullptr);
|
||||
}
|
||||
|
||||
*aResult = prompt.forget().take();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PColorPickerParent*
|
||||
|
@ -1474,6 +1474,7 @@ void MediaDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int6
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
|
||||
}
|
||||
UpdateReadyStateForData();
|
||||
}
|
||||
|
||||
void MediaDecoder::UpdatePlaybackPosition(int64_t aTime)
|
||||
|
@ -59,7 +59,7 @@ GonkVideoDecoderManager::GonkVideoDecoderManager(
|
||||
mVideoWidth = aConfig.display_width;
|
||||
mVideoHeight = aConfig.display_height;
|
||||
mDisplayWidth = aConfig.display_width;
|
||||
mDisplayHeight = aConfig.display_width;
|
||||
mDisplayHeight = aConfig.display_height;
|
||||
mInfo.mVideo.mHasVideo = true;
|
||||
nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
|
||||
mInfo.mVideo.mDisplay = displaySize;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user