Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-11-05 15:22:01 -05:00
commit d25d42ef82
381 changed files with 6024 additions and 2070 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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
}
};

View File

@ -2594,6 +2594,7 @@
]]>
</body>
</method>
#endif
<method name="moveTabTo">
<parameter name="aTab"/>

View File

@ -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]

View File

@ -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()

View File

@ -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) {

View File

@ -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() {

View File

@ -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/");

View File

@ -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();

View File

@ -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;
}

View File

@ -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'):

View File

@ -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;
}

View File

@ -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

View File

@ -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>

View File

@ -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));
},

View File

@ -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,

View File

@ -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}

View File

@ -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"));

View File

@ -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"));

View File

@ -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);

View File

@ -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);

View File

@ -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>

View File

@ -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
})
};
})();

View File

@ -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;
})();

View File

@ -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);
},

View File

@ -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;
})();

View File

@ -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)

View File

@ -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>

View File

@ -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;
})();

View File

@ -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
};
})();

View File

@ -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
};
})();

View File

@ -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 {

View File

@ -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 {

View File

@ -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) {

View File

@ -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();

View File

@ -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>

View File

@ -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();

View File

@ -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");
});
});
});
});

View File

@ -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 () {

View File

@ -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>");

View File

@ -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
});

View File

@ -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>

View File

@ -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"
}));
});
});
});

View File

@ -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,

View File

@ -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>

View File

@ -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"})
)
),

View File

@ -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>

View File

@ -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)

View File

@ -43,8 +43,6 @@ EXTRA_JS_MODULES += [
'distribution.js',
]
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
BROWSER_CHROME_MANIFESTS += [
'test/browser.ini'
]

View File

@ -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--;

View File

@ -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);

View File

@ -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'):

View File

@ -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

View File

@ -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 */
}

View File

@ -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>

View File

@ -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" });
}
};

View File

@ -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)

View File

@ -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 = {

View 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;
}

View File

@ -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',

View File

@ -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;
},

View File

@ -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

View File

@ -123,7 +123,7 @@ LoginManagerPrompter.prototype = {
},
setE10sData : function (aBrowser) {
setE10sData : function (aBrowser, aOpener) {
// XXX Implement me!
throw new Error("Not Yet Implemented");
},

View File

@ -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)

View File

@ -6,6 +6,4 @@
DIRS += ['communicator']
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
JAR_MANIFESTS += ['jar.mn']

View File

@ -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)

View File

@ -6,6 +6,4 @@
DIRS += ['communicator']
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
JAR_MANIFESTS += ['jar.mn']

View File

@ -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 {

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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)

View File

@ -6,6 +6,4 @@
DIRS += ['communicator']
DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
JAR_MANIFESTS += ['jar.mn']

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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;

View File

@ -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,

View File

@ -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();

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -73,7 +73,6 @@ class IDBFactory MOZ_FINAL
PRThread* mOwningThread;
#endif
bool mRootedOwningObject;
bool mBackgroundActorFailed;
bool mPrivateBrowsingMode;

View File

@ -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) {

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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*

View File

@ -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)

View File

@ -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