Merge fx-team to m-c a=merge

This commit is contained in:
Wes Kocher 2014-09-16 15:59:12 -07:00
commit 214c0e0ea2
76 changed files with 48677 additions and 142 deletions

View File

@ -81,3 +81,15 @@ GPATH
# Git clone directory for updating web-platform-tests
^testing/web-platform/sync/
# Loop web client build/deploy dependencies
^browser/components/loop/standalone/bower_components
# Loop legal content build/deploy artifacts
# XXX Once a grunt contrib-clean command has been added (bug 1066491), or
# once legal has centralized their ToS and PP hosting infrastructure,
# (expected Q4 2014) the legal doc build stuff for Loop can be removed,
# including the following three lines
^browser/components/loop/standalone/content/legal/styles/.*\.css$
^browser/components/loop/standalone/content/legal/terms/en_US\.html$

View File

@ -132,7 +132,4 @@ function closeConnection() {
return deferred.promise;
}
// bug 1042976 - temporary test disable
module.exports = {};
require('sdk/test/runner').runTestsFromModule(module);

View File

@ -292,7 +292,7 @@ pref("browser.slowStartup.maxSamples", 5);
// This url, if changed, MUST continue to point to an https url. Pulling arbitrary content to inject into
// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream
// repackager of this code using an alternate snippet url, please keep your users safe
pref("browser.aboutHomeSnippets.updateUrl", "https://snippets.mozilla.com/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
pref("browser.aboutHomeSnippets.updateUrl", "https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
pref("browser.enable_automatic_image_resizing", true);
pref("browser.chrome.site_icons", true);
@ -1598,7 +1598,7 @@ pref("loop.throttled", false);
pref("loop.enabled", true);
pref("loop.throttled", true);
pref("loop.soft_start_ticket_number", -1);
pref("loop.soft_start_hostname", "soft-start.loop-dev.stage.mozaws.net");
pref("loop.soft_start_hostname", "soft-start.loop.services.mozilla.com");
#endif
pref("loop.server", "https://loop.services.mozilla.com");

View File

@ -189,12 +189,12 @@ let gGestureSupport = {
let isVerticalSwipe = false;
if (aEvent.direction == aEvent.DIRECTION_UP) {
if (content.pageYOffset > 0) {
if (gMultiProcessBrowser || content.pageYOffset > 0) {
return false;
}
isVerticalSwipe = true;
} else if (aEvent.direction == aEvent.DIRECTION_DOWN) {
if (content.pageYOffset < content.scrollMaxY) {
if (gMultiProcessBrowser || content.pageYOffset < content.scrollMaxY) {
return false;
}
isVerticalSwipe = true;

View File

@ -393,7 +393,8 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
visibility: visible;
}
#urlbar:not([actiontype]) > #urlbar-display-box {
#urlbar:not([actiontype]) > #urlbar-display-box,
#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box > .urlbar-display-switchtab {
display: none;
}

View File

@ -756,7 +756,7 @@
</hbox>
</box>
<box id="urlbar-display-box" align="center">
<label id="urlbar-display" value="&urlbar.switchToTab.label;"/>
<label class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
</box>
<hbox id="urlbar-icons">
<image id="page-report-button"

View File

@ -65,7 +65,8 @@ add_task(function*() {
let tab = gBrowser.addTab("about:about");
yield promiseTabLoaded(tab);
yield check_a11y_label("% about", "about:about moz-action:switchtab,about:about Tab");
let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec;
yield check_a11y_label("% about", "about:about " + actionURL + " Tab");
yield promisePopupHidden(gURLBar.popup);
gBrowser.removeTab(tab);

View File

@ -34,7 +34,7 @@ function test() {
"The test tab doesn't have the busy attribute");
// Set the urlbar to include the moz-action
gURLBar.value = "moz-action:switchtab," + testURL;
gURLBar.value = "moz-action:switchtab," + JSON.stringify({url: testURL});
// Focus the urlbar so we can press enter
gURLBar.focus();

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
let testActionURL = "moz-action:switchtab," + testURL;
let testActionURL = "moz-action:switchtab," + JSON.stringify({url: testURL});
testURL = gURLBar.trimValue(testURL);
let testTab;

View File

@ -72,7 +72,7 @@ function test() {
"The test tab doesn't have the busy attribute");
// Set the urlbar to include the moz-action
aDestWindow.gURLBar.value = "moz-action:switchtab," + testURL;
aDestWindow.gURLBar.value = "moz-action:switchtab," + JSON.stringify({url: testURL});
// Focus the urlbar so we can press enter
aDestWindow.gURLBar.focus();

View File

@ -666,6 +666,11 @@ function assertWebRTCIndicatorStatus(expected) {
}
}
function makeActionURI(action, params) {
let url = "moz-action:" + action + "," + JSON.stringify(params);
return NetUtil.newURI(url);
}
function waitForNewTab(aTabBrowser) {
return promiseWaitForEvent(aTabBrowser.tabContainer, "TabOpen");
}

View File

@ -150,7 +150,12 @@
var action = this._parseActionUrl(aValue);
if (action) {
returnValue = action.param;
switch (action.type) {
case "switchtab": {
returnValue = action.params.url;
break;
}
}
}
// Set the actiontype only if the user is not overriding actions.
@ -300,9 +305,9 @@
let matchLastLocationChange = true;
if (action) {
url = action.param;
if (this.hasAttribute("actiontype")) {
if (action.type == "switchtab") {
url = action.params.url;
this.handleRevert();
let prevTab = gBrowser.selectedTab;
if (switchToTabHavingURI(url) &&
@ -739,9 +744,28 @@
if (!aUrl.startsWith("moz-action:"))
return null;
// url is in the format moz-action:ACTION,PARAM
let [, action, param] = aUrl.match(/^moz-action:([^,]+),(.*)$/);
return {type: action, param: param};
// URL is in the format moz-action:ACTION,PARAMS
// Where PARAMS is a JSON encoded object.
aUrl = decodeURI(aUrl);
let [, type, params] = aUrl.match(/^moz-action:([^,]+),(.*)$/);
let action = {
type: type,
};
try {
action.params = JSON.parse(params);
} catch (e) {
// If this failed, we assume that params is not a JSON object, and
// is instead just a flat string. This will happen when
// UnifiedComplete is disabled - in which case, the param is always
// a URL.
action.params = {
url: params,
}
}
return action;
]]></body>
</method>
@ -910,13 +934,13 @@
var where = whereToOpenLink(aEvent, false, true);
searchBar.doSearch(search, where);
}
]]></body>
</method>
</implementation>
</binding>
]]></body>
</method>
</implementation>
</binding>
<binding id="urlbar-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup">
<implementation>
<binding id="urlbar-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup">
<implementation>
<field name="_maxResults">0</field>
<field name="_bundle" readonly="true">
@ -1677,10 +1701,12 @@
sizetopopup="none">
<xul:menupopup>
<xul:menuitem anonid="trackingContentAction.unblock"
hidden="true" label="&trackingContentBlocked.unblock.label2;"
hidden="true" label="&trackingContentBlocked.unblock2.label;"
accesskey="&trackingContentBlocked.unblock2.accesskey;"
oncommand="document.getBindingParent(this).disableTrackingContentProtection();"/>
<xul:menuitem anonid="trackingContentAction.block"
hidden="true" label="&trackingContentBlocked.block.label;"
accesskey="&trackingContentBlocked.block.accesskey;"
oncommand="document.getBindingParent(this).enableTrackingContentProtection();"/>
</xul:menupopup>
</xul:button>

View File

@ -1,11 +1,25 @@
#! /usr/bin/env python
import os
import re
from distutils import spawn
import subprocess
from threading import Thread
import argparse
def find_react_version(lib_dir):
"Finds the React library version number currently used."
for filename in os.listdir(lib_dir):
match = re.match(r"react-(.*)-prod\.js", filename)
if (match and match.group(1)):
return match.group(1)
print 'Unable to find the current react version used in content.'
print 'Please checked the %s directory.' % lib_dir
exit(1)
SHARED_LIBS_DIR=os.path.join(os.path.dirname(__file__), "content", "shared", "libs")
REACT_VERSION=find_react_version(SHARED_LIBS_DIR)
src_files = [] # files to be compiled
# search for react-tools install
@ -15,6 +29,17 @@ if jsx_path is None:
print 'Please do $ npm install -g react-tools'
exit(1)
p = subprocess.Popen([jsx_path, '-V'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
info = line.rstrip()
if not info == REACT_VERSION:
print 'You have the wrong version of react-tools installed'
print 'Please use version %s' % REACT_VERSION
exit(1)
# parse the CLI arguments
description = 'Loop build tool for JSX files. ' + \
'Will scan entire loop directory and compile them in place. ' + \

View File

@ -284,6 +284,8 @@ loop.conversation = (function(OT, mozL10n) {
this._handleSessionError();
return;
}.bind(this));
this._websocket.on("progress", this._handleWebSocketProgress, this);
},
/**
@ -298,6 +300,40 @@ loop.conversation = (function(OT, mozL10n) {
}
},
/**
* Used to receive websocket progress and to determine how to handle
* it if appropraite.
* If we add more cases here, then we should refactor this function.
*
* @param {Object} progressData The progress data from the websocket.
* @param {String} previousState The previous state from the websocket.
*/
_handleWebSocketProgress: function(progressData, previousState) {
// We only care about the terminated state at the moment.
if (progressData.state !== "terminated")
return;
if (progressData.reason === "cancel") {
this._abortIncomingCall();
return;
}
if (progressData.reason === "timeout" &&
(previousState === "init" || previousState === "alerting")) {
this._abortIncomingCall();
}
},
/**
* Silently aborts an incoming call - stops the alerting, and
* closes the websocket.
*/
_abortIncomingCall: function() {
navigator.mozLoop.stopAlerting();
this._websocket.close();
window.close();
},
/**
* Accepts an incoming call.
*/

View File

@ -284,6 +284,8 @@ loop.conversation = (function(OT, mozL10n) {
this._handleSessionError();
return;
}.bind(this));
this._websocket.on("progress", this._handleWebSocketProgress, this);
},
/**
@ -298,6 +300,40 @@ loop.conversation = (function(OT, mozL10n) {
}
},
/**
* Used to receive websocket progress and to determine how to handle
* it if appropraite.
* If we add more cases here, then we should refactor this function.
*
* @param {Object} progressData The progress data from the websocket.
* @param {String} previousState The previous state from the websocket.
*/
_handleWebSocketProgress: function(progressData, previousState) {
// We only care about the terminated state at the moment.
if (progressData.state !== "terminated")
return;
if (progressData.reason === "cancel") {
this._abortIncomingCall();
return;
}
if (progressData.reason === "timeout" &&
(previousState === "init" || previousState === "alerting")) {
this._abortIncomingCall();
}
},
/**
* Silently aborts an incoming call - stops the alerting, and
* closes the websocket.
*/
_abortIncomingCall: function() {
navigator.mozLoop.stopAlerting();
this._websocket.close();
window.close();
},
/**
* Accepts an incoming call.
*/

View File

@ -36,6 +36,8 @@ loop.CallConnectionWebSocket = (function() {
throw new Error("No websocketToken in options");
}
this._lastServerState = "init";
// Set loop.debug.sdk to true in the browser, or standalone:
// localStorage.setItem("debug.websocket", true);
this._debugWebSocket =
@ -78,6 +80,16 @@ loop.CallConnectionWebSocket = (function() {
return promise;
},
/**
* Closes the websocket. This shouldn't be the normal action as the server
* will normally close the socket. Only in bad error cases, or where we need
* to close the socket just before closing the window (to avoid an error)
* should we call this.
*/
close: function() {
this.socket.close();
},
_clearConnectionFlags: function() {
clearTimeout(this.connectDetails.timeout);
delete this.connectDetails;
@ -210,6 +222,7 @@ loop.CallConnectionWebSocket = (function() {
this._log("WS Receiving", event.data);
var previousState = this._lastServerState;
this._lastServerState = msg.state;
switch(msg.messageType) {
@ -218,7 +231,7 @@ loop.CallConnectionWebSocket = (function() {
break;
case "progress":
this.trigger("progress:" + msg.state);
this.trigger("progress", msg);
this.trigger("progress", msg, previousState);
break;
}
},

View File

@ -1,5 +1,14 @@
.module-cache
node_modules
bower_components
*.pyc
content/config.js
content/VERSION.txt
# XXX Once a grunt contrib-clean command has been added (bug 1066491), or
# once legal has centralized their ToS and PP hosting infrastructure,
# (expected Q4 2014) the legal doc build stuff for Loop can be removed,
# including the following three lines:
content/legal/styles/*.css
content/legal/terms/*.html
content/legal/terms/!index.html

View File

@ -0,0 +1,21 @@
#!/usr/bin/env node
/* 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/. */
module.exports = function (grunt) {
'use strict';
// show elapsed time at the end
require('time-grunt')(grunt);
// load all grunt tasks
require('load-grunt-tasks')(grunt, {scope: 'devDependencies'});
grunt.initConfig({
});
grunt.loadTasks('grunttasks');
}
;

View File

@ -2,15 +2,31 @@
# 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/.
# Note that this Makefile is not invoked by the Mozilla build
# system, which is why it can have dependencies on things the
# build system at-large doesn't yet support.
# XXX In the interest of making the build logic simpler and
# more maintainable, we should be trying to implement new
# functionality in Gruntfile.js rather than here.
# Bug 1066176 tracks moving all functionality currently here
# to the Gruntfile and getting rid of this Makefile entirely.
LOOP_SERVER_URL := $(shell echo $${LOOP_SERVER_URL-http://localhost:5000})
NODE_LOCAL_BIN=./node_modules/.bin
install:
install: npm_install tos
npm_install:
@npm install
test:
@echo "Not implemented yet."
tos:
@$(NODE_LOCAL_BIN)/grunt replace marked
@$(NODE_LOCAL_BIN)/grunt sass
lint:
@$(NODE_LOCAL_BIN)/jshint *.js content test

View File

@ -9,8 +9,13 @@ NodeJS and npm installed.
Installation
------------
Fetch and install/build any NPM and bower dependencies, as well as the
localized Terms-of-Service content:
$ make install
Some of the above is driven by Gruntfile.js.
Configuration
-------------

View File

@ -0,0 +1,7 @@
{
"name": "loop-client",
"dependencies": {
"tos-pp": "https://github.com/mozilla/legal-docs.git"
},
"devDependencies": {}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 886 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 898 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,33 @@
/* 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/. */
// Set the current translation content
function setBody(data) {
$("#legal-copy").html(data);
}
function normalizeLocale(lang) {
return lang.replace(/-/g, "_");
}
$(document).ready(function() {
// Get the favorite language
var lang, defaultLang = "en-US";
$.get(loop.config.serverUrl, function(data) {
if (data.hasOwnProperty("i18n")) {
lang = normalizeLocale(data.i18n.lang);
defaultLang = normalizeLocale(data.i18n.defaultLang);
}
if (lang === undefined) {
lang = normalizeLocale(defaultLang);
}
$.get(lang + ".html")
.done(setBody)
.fail(function() {
$.get(defaultLang + ".html")
.done(setBody);
});
});
});

View File

@ -0,0 +1,235 @@
@font-face { font-family: 'Clear Sans'; font-style: normal; font-weight: 400; src: local(Clear Sans), local(ClearSans), url(/legal/fonts/latin/clearsans-regular.eot?#iefix) format(embedded-opentype), url(/legal/fonts/latin/clearsans-regular.woff) format(woff), url(/legal/fonts/latin/clearsans-regular.ttf) format(truetype), url(/legal/fonts/latin/clearsans-regular.svg#clearsans-regular) format(svg); }
@font-face { font-family: 'Fira Sans'; font-style: normal; font-weight: 400; src: local(Fira Sans), local(FiraSans-Regular), url(/legal/fonts/latin/firasans-regular.eot?#iefix) format(embedded-opentype), url(/legal/fonts/latin/firasans-regular.woff) format(woff), url(/legal/fonts/latin/firasans-regular.ttf) format(truetype), url(/legal/fonts/latin/firasans-regular.svg#firasans-regular) format(svg); }
@font-face { font-family: 'Fira Sans'; font-style: normal; font-weight: 300; src: local(Fira Sans Light), local(FiraSans-Light), url(/legal/fonts/latin/firasans-light.eot?#iefix) format(embedded-opentype), url(/legal/fonts/latin/firasans-light.woff) format(woff), url(/legal/fonts/latin/firasans-light.ttf) format(truetype), url(/legal/fonts/latin/firasans-light.svg#firasans-light) format(svg); }
@media (min-width: 321px) and (max-width: 480px) {
#about-mozilla {
display: none;
}
#main-content {
-webkit-box-shadow: rgb(138, 155, 168) 0px 1px 5px;
border-radius: 2px 2px;
box-shadow: rgb(138, 155, 168) 0px 1px 5px;
margin-top: 0px;
max-width: 360px;
min-height: 300px;
min-width: 300px;
padding-bottom: 10px;
padding-left: 20px;
padding-right: 20px;
padding-top: 45px;
position: relative;
top: -28px;
width: 94%;
}
.static {
-webkit-background-size: 48px 51px;
background-position-x: 50%;
background-position-y: 0%;
background-repeat: no-repeat;
background-size: 48px 51px;
height: 51px;
margin-top: 10px;
top: 0px;
width: 100%;
}
body {
padding-bottom: 20px;
}
h1 {
font-size: 20px;
margin-bottom: 20px;
}
html {
background-color: rgb(242, 242, 242);
}
}
@media (min-width: 481px) {
#main-content {
-webkit-box-shadow: rgb(138, 155, 168) 0px 1px 5px;
border-radius: 4px 4px;
box-shadow: rgb(138, 155, 168) 0px 1px 5px;
margin-top: -5px;
min-height: 450px;
padding-bottom: 40px;
padding-left: 40px;
padding-right: 40px;
padding-top: 60px;
width: 420px;
}
.static {
-webkit-background-size: 80px 85px;
background-size: 80px 85px;
height: 85px;
margin-top: 0px;
top: 40px;
width: 80px;
}
body {
padding-bottom: 20px;
}
h1 {
font-size: 24px;
margin-bottom: 32px;
}
html {
background-color: rgb(242, 242, 242);
}
}
@media (max-width: 319px) {
#about-mozilla {
display: none;
}
#main-content {
-webkit-box-shadow: none;
background-position-x: 0px;
background-position-y: 0px;
border-radius: 2px 2px;
box-shadow: none;
margin-top: 10px;
max-width: 360px;
min-height: 0px;
min-width: 250px;
padding: 0px;
position: relative;
top: 0px;
width: 250px;
}
.static {
-webkit-background-size: 48px 51px;
background-position-x: 50%;
background-position-y: 0%;
background-repeat: no-repeat;
background-size: 48px 51px;
display: none;
height: 51px;
margin-top: 10px;
top: 0px;
width: 100%;
}
body {
margin: 0px;
padding: 0px;
}
h1 {
font-size: 18px;
margin-bottom: 10px;
}
html {
background-color: rgb(255, 255, 255);
}
}
#about-mozilla {
-webkit-background-size: 69px 19px;
-webkit-transition-duration: 150ms;
-webkit-transition-property: opacity;
background-image: url(/legal/images/mozilla.png);
background-size: 69px 19px;
height: 19px;
opacity: 0.5;
position: absolute;
right: 12px;
top: 12px;
width: 69px;
}
#main-content {
background-color: rgb(255, 255, 255);
margin-bottom: 0px;
margin-left: auto;
margin-right: auto;
text-align: center;
}
* {
box-sizing: border-box;
}
.static {
background-image: url(/legal/images/firefox.png);
margin-bottom: 0px;
margin-left: auto;
margin-right: auto;
opacity: 1;
background-size: 102px 96px;
height: 102px;
width: 96px;
position: relative;
position: relative;
z-index: 999;
}
a {
color: rgb(0, 149, 221);
cursor: pointer;
}
article {
text-align: left;
}
body {
color: rgb(66, 79, 89);
font-family: 'Clear Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 14px;
}
h1, h2 {
font-family: 'Fira Sans', Helvetica, Arial, sans-serif;
font-weight: 200;
line-height: 1em;
margin-left: 0px;
margin-right: 0px;
margin-top: 0px;
}
h3 {
font-family: 'Fira Sans', Helvetica, Arial, sans-serif;
font-size: 12px;
line-height: 1em;
margin: 0px;
padding-bottom: 10px;
padding-left: 0px;
padding-right: 0px;
padding-top: 5px;
}
html {
height: 100%;
}
ol {
margin-left: 0px;
padding-left: 20px;
}
p {
font-size: 14px;
}
ul {
margin-left: 0px;
padding-left: 20px;
}

View File

@ -0,0 +1,41 @@
<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie10 lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie10 lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="lt-ie10 lt-ie9"> <![endif]-->
<!--[if IE 9]> <html class="lt-ie10"> <![endif]-->
<!--[if gt IE 9]><!--> <html dir="ltr" lang="en-US"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>WebRTC: Terms of Service</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/legal/styles/main.css">
</head>
<body>
<div id="fox-logo" class="static"></div>
<div id="stage">
<div id="main-content">
<!--[if lt IE 10]>
<p class="error browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
<header id="legal-header">
<h3>WebRTC</h3>
<h1 id="webrtc-tos-header">Terms of Service</h1>
</header>
<section>
<article id="legal-copy">
Loading...
</article>
</section>
</div>
</div>
<a id="about-mozilla" rel="author" target="_blank" href="https://www.mozilla.org/about/?utm_source=firefox-webrtc&amp;utm_medium=Referral"></a>
<script type="text/javascript" src="/shared/libs/jquery-2.1.0.js"></script>
<script type="text/javascript" src="/config.js"></script>
<script type="text/javascript" src="/legal/js/loader.js"></script>
</body>
</html>

View File

@ -0,0 +1,36 @@
/* 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/. */
var path = require('path');
var i18n = require('i18n-abide');
module.exports = function (grunt) {
'use strict';
// convert localized TOS agreement from markdown to html partials.
function rename(destPath, srcFile) {
// Normalize the filenames to use the locale name.
var lang = srcFile.replace('.md', '');
return path.join(destPath, i18n.localeFrom(lang) + '.html');
}
grunt.config('marked', {
options: {
sanitize: false,
gfm: true
},
tos: {
files: [
{
expand: true,
cwd: '<%= project_vars.tos_md_src %>',
src: ['**/*.md'],
dest: '<%= project_vars.tos_html_dest %>',
rename: rename
}
]
}
});
};

View File

@ -0,0 +1,18 @@
/* 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/. */
module.exports = function (grunt) {
'use strict';
var TEMPLATE_ROOT = 'content/legal';
var TOS_PP_REPO_ROOT = 'bower_components/tos-pp';
grunt.config('project_vars', {
app: "content",
// Translated TOS/PP agreements.
tos_pp_repo_dest: TOS_PP_REPO_ROOT,
tos_md_src: TOS_PP_REPO_ROOT + '/WebRTC_ToS/',
tos_html_dest: TEMPLATE_ROOT + '/terms'
});
};

View File

@ -0,0 +1,37 @@
/* 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/. */
module.exports = function (grunt) {
'use strict';
grunt.config('replace', {
tos: {
src: [
'<%= project_vars.tos_md_src %>/*.md'
],
overwrite: true,
replacements: [{
// remove tags not handle by the markdown-to-HTML conversation
from: /{:\s.*?\s}/g,
to: ''
}, {
// remove unhandled comments
from: /^#\s.*?\n$/m,
to: ''
}, {
// fix "smart quotes"
from: /(“|”)/g,
to: "&quot;"
}, {
// fix "smart quotes"
from: //g,
to: "&#39;"
}, {
from: //g,
to: "&mdash;"
}
]
}
});
};

View File

@ -0,0 +1,16 @@
/* 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/. */
module.exports = function (grunt) {
'use strict';
grunt.config('sass', {
styles: {
files: {
'<%= project_vars.app %>/legal/styles/main.css':
'<%= project_vars.app %>/legal/styles/main.scss'
}
}
});
};

View File

@ -1,19 +1,33 @@
{
"name": "Loop-client",
"description": "Video conferencing app powered by WebRTC.",
"name": "loop-client",
"description": "Video conferencing app powered by WebRTC",
"version": "0.0.1",
"repository": {
"type": "git",
"url": "git@github.com:mozilla/loop-client.git"
},
"engines": {
"node": "0.10.x",
"npm":"1.3.x"
},
"dependencies": {
"express": "3.x"
"npm": "1.3.x"
},
"dependencies": {},
"devDependencies": {
"jshint": "2.x"
"bower": "1.3.9",
"express": "3.x",
"grunt": "0.4.5",
"grunt-cli": "0.1.13",
"grunt-marked": "0.1.1",
"grunt-sass": "0.14.1",
"grunt-text-replace": "0.3.12",
"i18n-abide": "0.0.22",
"jshint": "2.x",
"load-grunt-tasks": "0.6.0",
"time-grunt": "0.4.0"
},
"scripts": {
"test": "make test",
"start": "make runserver"
}
"start": "make runserver",
"prepublish": "bower install --config.interactive=false -s"
},
"license": "MPL-2.0"
}

View File

@ -8,20 +8,29 @@ var app = express();
var port = process.env.PORT || 3000;
var loopServerPort = process.env.LOOP_SERVER_PORT || 5000;
app.get('/content/config.js', function (req, res) {
function getConfigFile(req, res) {
"use strict";
res.set('Content-Type', 'text/javascript');
res.send(
"var loop = loop || {};" +
"loop.config = loop.config || {};" +
"loop.config.serverUrl = 'http://localhost:" + loopServerPort + "';"
"loop.config.serverUrl = 'http://localhost:" + loopServerPort + "';" +
"loop.config.pendingCallTimeout = 20000;"
);
}
});
app.get('/content/config.js', getConfigFile);
// This lets /test/ be mapped to the right place for running tests
app.use('/', express.static(__dirname + '/../'));
// Magic so that the legal content works both in the standalone server
// and as static content in the loop-client repo
app.use('/', express.static(__dirname + '/content/'));
app.use('/shared', express.static(__dirname + '/../content/shared/'));
app.get('/config.js', getConfigFile);
// This lets /content/ be mapped right for the static contents.
app.use('/', express.static(__dirname + '/'));
// This lets standalone components load images into the UI showcase

View File

@ -223,7 +223,8 @@ describe("loop.conversation", function() {
resolve();
});
return promise;
}
},
on: sinon.spy()
});
});
@ -268,7 +269,8 @@ describe("loop.conversation", function() {
reject();
});
return promise;
}
},
on: sinon.spy()
});
});
@ -285,6 +287,102 @@ describe("loop.conversation", function() {
});
});
});
describe("Events", function() {
describe("Call cancelled or timed out before acceptance", function() {
var promise;
beforeEach(function() {
sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect", function() {
promise = new Promise(function(resolve, reject) {
resolve();
});
return promise;
});
sandbox.stub(loop.CallConnectionWebSocket.prototype, "close");
sandbox.stub(navigator.mozLoop, "stopAlerting");
sandbox.stub(window, "close");
router._setupWebSocketAndCallView();
});
describe("progress - terminated - cancel", function() {
it("should stop alerting", function(done) {
promise.then(function() {
router._websocket.trigger("progress", {
state: "terminated",
reason: "cancel"
});
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
done();
});
});
it("should close the websocket", function(done) {
promise.then(function() {
router._websocket.trigger("progress", {
state: "terminated",
reason: "cancel"
});
sinon.assert.calledOnce(router._websocket.close);
done();
});
});
it("should close the window", function(done) {
promise.then(function() {
router._websocket.trigger("progress", {
state: "terminated",
reason: "cancel"
});
sinon.assert.calledOnce(window.close);
done();
});
});
});
describe("progress - terminated - timeout (previousState = alerting)", function() {
it("should stop alerting", function(done) {
promise.then(function() {
router._websocket.trigger("progress", {
state: "terminated",
reason: "timeout"
}, "alerting");
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
done();
});
});
it("should close the websocket", function(done) {
promise.then(function() {
router._websocket.trigger("progress", {
state: "terminated",
reason: "timeout"
}, "alerting");
sinon.assert.calledOnce(router._websocket.close);
done();
});
});
it("should close the window", function(done) {
promise.then(function() {
router._websocket.trigger("progress", {
state: "terminated",
reason: "timeout"
}, "alerting");
sinon.assert.calledOnce(window.close);
done();
});
});
});
});
});
});
});

View File

@ -99,9 +99,11 @@ class Test1BrowserCall(MarionetteTestCase):
"btn-accept")
call_button.click()
# expect a video container on standalone side
video = self.wait_for_element_displayed(By.CLASS_NAME, "media")
self.assertEqual(video.tag_name, "div", "expect a video container")
# make sure the standalone progresses to the pending state
pending_header = self.wait_for_element_displayed(By.CLASS_NAME,
"pending-header")
self.assertEqual(pending_header.tag_name, "header",
"expect a pending header")
def accept_and_verify_incoming_call(self):
self.marionette.set_context("chrome")

View File

@ -61,6 +61,13 @@ add_task(function* test_mozLoop_softStart() {
Services.prefs.setCharPref("loop.soft_start_hostname", SOFT_START_HOSTNAME);
Services.prefs.setIntPref("loop.soft_start_ticket_number", -1);
registerCleanupFunction(function () {
Services.prefs.clearUserPref("loop.throttled");
Services.prefs.clearUserPref("loop.soft_start");
Services.prefs.clearUserPref("loop.soft_start_hostname");
Services.prefs.clearUserPref("loop.soft_start_ticket_number");
});
let throttled;
let ticket;

View File

@ -17,6 +17,7 @@ describe("loop.CallConnectionWebSocket", function() {
sandbox.useFakeTimers();
dummySocket = {
close: sinon.spy(),
send: sinon.spy()
};
sandbox.stub(window, 'WebSocket').returns(dummySocket);
@ -133,6 +134,16 @@ describe("loop.CallConnectionWebSocket", function() {
});
});
describe("#close", function() {
it("should close the socket", function() {
callWebSocket.promiseConnect();
callWebSocket.close();
sinon.assert.calledOnce(dummySocket.close);
});
});
describe("#decline", function() {
it("should send a terminate message to the server", function() {
callWebSocket.promiseConnect();
@ -212,7 +223,35 @@ describe("loop.CallConnectionWebSocket", function() {
});
sinon.assert.called(callWebSocket.trigger);
sinon.assert.calledWithExactly(callWebSocket.trigger, "progress", eventData);
sinon.assert.calledWithExactly(callWebSocket.trigger, "progress",
eventData, "init");
});
it("should trigger a progress event with the previous state", function() {
var previousEventData = {
messageType: "progress",
state: "alerting"
};
// This first call is to set the previous state of the object
// ready for the main test below.
dummySocket.onmessage({
data: JSON.stringify(previousEventData)
});
var currentEventData = {
messageType: "progress",
state: "terminate",
reason: "reject"
};
dummySocket.onmessage({
data: JSON.stringify(currentEventData)
});
sinon.assert.called(callWebSocket.trigger);
sinon.assert.calledWithExactly(callWebSocket.trigger, "progress",
currentEventData, "alerting");
});
it("should trigger a progress:<state> event on the callWebSocket", function() {

View File

@ -7,5 +7,6 @@
* @type {Object}
*/
navigator.mozLoop = {
getLoopCharPref: function() {}
getLoopCharPref: function() {},
getLoopBoolPref: function() {}
};

View File

@ -93,7 +93,8 @@ var gMainPane = {
gMainPane.enableE10SChange);
let e10sCheckbox = document.getElementById("e10sAutoStart");
let e10sPref = document.getElementById("browser.tabs.remote.autostart");
e10sCheckbox.checked = e10sPref.value;
let e10sTempPref = document.getElementById("e10sTempPref");
e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
#endif
// Notify observers that the UI is now ready
@ -107,6 +108,19 @@ var gMainPane = {
{
let e10sCheckbox = document.getElementById("e10sAutoStart");
let e10sPref = document.getElementById("browser.tabs.remote.autostart");
let e10sTempPref = document.getElementById("e10sTempPref");
let prefsToChange;
if (e10sCheckbox.checked) {
// Enabling e10s autostart
prefsToChange = [e10sPref];
} else {
// Disabling e10s autostart
prefsToChange = [e10sPref];
if (e10sTempPref.value) {
prefsToChange.push(e10sTempPref);
}
}
const Cc = Components.classes, Ci = Components.interfaces;
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
@ -124,13 +138,15 @@ var gMainPane = {
shouldProceed = !cancelQuit.data;
if (shouldProceed) {
e10sPref.value = e10sCheckbox.checked;
for (let prefToChange of prefsToChange) {
prefToChange.value = e10sCheckbox.checked;
}
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
}
}
// Revert the checkbox in case we didn't quit
e10sCheckbox.checked = e10sPref.value;
e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
},
#endif

View File

@ -13,6 +13,9 @@
<preference id="browser.tabs.remote.autostart"
name="browser.tabs.remote.autostart"
type="bool"/>
<preference id="e10sTempPref"
name="browser.tabs.remote.autostart.1"
type="bool"/>
#endif
<!-- Startup -->

View File

@ -64,7 +64,7 @@ function switchToURL(groupItemOne, groupItemTwo) {
* switch. The tab should be opened in group two and not in group one.
*/
// Set the urlbar to include the moz-action.
gURLBar.value = "moz-action:switchtab,about:mozilla";
gURLBar.value = "moz-action:switchtab," + JSON.stringify({url: "about:mozilla"});
// Focus the urlbar so we can press enter.
gURLBar.focus();
// Press enter.

View File

@ -67,7 +67,7 @@ function switchToURL(groupItemOne, groupItemTwo) {
* switch. The selected group should be group one.
*/
// Set the urlbar to include the moz-action.
gURLBar.value = "moz-action:switchtab,about:mozilla";
gURLBar.value = "moz-action:switchtab," + JSON.stringify({url: "about:mozilla"});
// Focus the urlbar so we can press enter.
gURLBar.focus();
// Press enter.

View File

@ -403,7 +403,7 @@
<tabpanels flex="1"/>
</tabbox>
</hbox>
<toolbar id="statusbar-line-col" class="chromeclass-toolbar"/>
<toolbar id="statusbar-line-col" class="devtools-toolbar"/>
</notificationbox>
</window>

View File

@ -83,8 +83,7 @@ function CheckLockState() {
certCheckResult.textContent = sUnknown;
if (AppManager.connection &&
AppManager.connection.status == Connection.Status.CONNECTED &&
AppManager.preferenceFront) {
AppManager.connection.status == Connection.Status.CONNECTED) {
// ADB check
if (AppManager.selectedRuntime instanceof USBRuntime) {

View File

@ -732,15 +732,17 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY mixedContentBlocked2.unblock.label "Disable protection for now">
<!ENTITY mixedContentBlocked2.unblock.accesskey "D">
<!ENTITY mixedContentBlocked2.block.label "Enable protection">
<!ENTITY mixedContentBlocked2.block.accesskey "B">
<!ENTITY mixedContentBlocked2.block.accesskey "E">
<!ENTITY mixedContentBlocked2.disabled.message "Protection is disabled">
<!ENTITY trackingContentBlocked.message "Tracking">
<!ENTITY trackingContentBlocked.moreinfo "Parts of the page that track your online activity have been blocked.">
<!ENTITY trackingContentBlocked.learnMore "Learn More">
<!ENTITY trackingContentBlocked.options "Options">
<!ENTITY trackingContentBlocked.unblock.label2 "Disable protection for this site">
<!ENTITY trackingContentBlocked.unblock2.label "Disable protection for this site">
<!ENTITY trackingContentBlocked.unblock2.accesskey "D">
<!ENTITY trackingContentBlocked.block.label "Enable protection">
<!ENTITY trackingContentBlocked.block.accesskey "E">
<!ENTITY trackingContentBlocked.disabled.message "Tracking protection is disabled">
<!ENTITY pointerLock.notification.message "Press ESC at any time to show it again.">

View File

@ -901,7 +901,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
-moz-margin-end: 3px;
}
#urlbar-display {
.urlbar-display {
margin-top: 0;
margin-bottom: 0;
-moz-margin-start: 0;

View File

@ -2147,7 +2147,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
-moz-margin-end: 3px;
}
#urlbar-display {
.urlbar-display {
margin-top: 0;
margin-bottom: 0;
color: GrayText;

View File

@ -1247,7 +1247,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
-moz-margin-end: 3px;
}
#urlbar-display {
.urlbar-display {
margin-top: 0;
margin-bottom: 0;
-moz-margin-start: 0;

View File

@ -91,6 +91,19 @@ public class ShareDialog extends LocaleAware.LocaleAwareActivity implements Send
super.onDestroy();
}
/**
* Show a toast indicating we were started with no URL, and then stop.
*/
private void abortDueToNoURL() {
Log.e(LOGTAG, "Unable to process shared intent. No URL found!");
// Display toast notifying the user of failure (most likely a developer who screwed up
// trying to send a share intent).
Toast toast = Toast.makeText(this, getResources().getText(R.string.overlay_share_no_url), Toast.LENGTH_SHORT);
toast.show();
finish();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -102,17 +115,14 @@ public class ShareDialog extends LocaleAware.LocaleAwareActivity implements Send
// The URL is usually hiding somewhere in the extra text. Extract it.
final String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (TextUtils.isEmpty(extraText)) {
abortDueToNoURL();
return;
}
final String pageUrl = new WebURLFinder(extraText).bestWebURL();
if (TextUtils.isEmpty(pageUrl)) {
Log.e(LOGTAG, "Unable to process shared intent. No URL found!");
// Display toast notifying the user of failure (most likely a developer who screwed up
// trying to send a share intent).
Toast toast = Toast.makeText(this, resources.getText(R.string.overlay_share_no_url), Toast.LENGTH_SHORT);
toast.show();
finish();
abortDueToNoURL();
return;
}

View File

@ -72,9 +72,7 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">50dp</item>
<item name="android:paddingRight">100dp</item>
<item name="android:paddingTop">0dp</item>
<item name="topDivider">true</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>

View File

@ -24,11 +24,7 @@
</style>
<style name="Widget.BookmarksListView" parent="Widget.HomeListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">120dp</item>
<item name="android:paddingRight">120dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
<style name="Widget.TopSitesGridView" parent="Widget.GridView">

View File

@ -62,11 +62,7 @@
</style>
<style name="Widget.BookmarksListView" parent="Widget.HomeListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
<style name="Widget.TopSitesGridView" parent="Widget.GridView">
@ -78,6 +74,9 @@
</style>
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="topDivider">false</item>
</style>

View File

@ -4,6 +4,12 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<resources>
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">120dp</item>
<item name="android:paddingRight">120dp</item>
<item name="topDivider">false</item>
</style>
<style name="Widget.TopSitesGridView" parent="Widget.GridView">
<item name="android:paddingLeft">55dp</item>
@ -14,9 +20,6 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">50dp</item>
<item name="android:paddingRight">100dp</item>
<item name="android:paddingTop">30dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>

View File

@ -17,9 +17,6 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">30dp</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
@ -30,4 +27,11 @@
<item name="android:paddingRight">212dp</item>
</style>
<style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
<item name="android:paddingTop">30dp</item>
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="topDivider">false</item>
</style>
</resources>

View File

@ -63,8 +63,10 @@
</style>
<style name="Widget.Home.HistoryListView">
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
<item name="android:paddingTop">0dip</item>
<item name="android:paddingRight">0dip</item>
<item name="android:paddingLeft">0dip</item>
<item name="topDivider">true</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>

View File

@ -1,7 +1,7 @@
package org.mozilla.gecko.tests;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.sync.Utils;
import android.content.ContentResolver;
import android.content.ContentValues;
@ -32,11 +32,9 @@ public class testBookmarkFolders extends AboutHomeTest {
// Verify the number of folders displayed in the Desktop Bookmarks folder is correct
ListView desktopFolderContent = findListViewWithTag(HomePager.LIST_TAG_BOOKMARKS);
ListAdapter adapter = desktopFolderContent.getAdapter();
if (mDevice.type.equals("tablet")) { // On tablets it's 4 folders and 1 view for top padding
mAsserter.is(adapter.getCount(), 5, "Checking that the correct number of folders is displayed in the Desktop Bookmarks folder");
} else { // On phones it's just the 4 folders
mAsserter.is(adapter.getCount(), 4, "Checking that the correct number of folders is displayed in the Desktop Bookmarks folder");
}
// Three folders and "Up to Bookmarks".
mAsserter.is(adapter.getCount(), 4, "Checking that the correct number of folders is displayed in the Desktop Bookmarks folder");
clickOnBookmarkFolder(StringHelper.TOOLBAR_FOLDER_LABEL);

View File

@ -492,6 +492,23 @@ function stripHttpAndTrim(spec) {
return spec;
}
/**
* Make a moz-action: URL for a given action and set of parameters.
*
* @param action
* Name of the action
* @param params
* Object, whose keys are parameter names and values are the
* corresponding parameter values.
* @return String representation of the built moz-action: URL
*/
function makeActionURL(action, params) {
let url = "moz-action:" + action + "," + JSON.stringify(params);
// Make a nsIURI out of this to ensure it's encoded properly.
return NetUtil.newURI(url).spec;
}
////////////////////////////////////////////////////////////////////////////////
//// Search Class
//// Manages a single instance of an autocomplete search.
@ -965,9 +982,12 @@ Search.prototype = {
// If actions are enabled and the page is open, add only the switch-to-tab
// result. Otherwise, add the normal result.
let [url, action] = this._enableActions && openPageCount > 0 ?
["moz-action:switchtab," + escapedURL, "switchtab"] :
[escapedURL, null];
let url = escapedURL;
let action = null;
if (this._enableActions && openPageCount > 0) {
url = makeActionURL("switchtab", {url: escapedURL});
action = "switchtab";
}
// Always prefer the bookmark title unless it is empty
let title = bookmarkTitle || historyTitle;
@ -1347,12 +1367,15 @@ UnifiedComplete.prototype = {
let search = this._currentSearch;
this.getDatabaseHandle().then(conn => search.execute(conn))
.then(null, ex => {
dump(`Query failed: ${ex}\n`);
Cu.reportError(ex);
})
.then(() => {
if (search == this._currentSearch) {
this.finishSearch(true);
}
}, ex => { dump("Query failed: " + ex + "\n");
Cu.reportError(ex); });
});
},
stopSearch: function () {

View File

@ -281,3 +281,8 @@ function stripPrefix(spec)
}
return spec;
}
function makeActionURI(action, params) {
let url = "moz-action:" + action + "," + JSON.stringify(params);
return NetUtil.newURI(url);
}

View File

@ -22,14 +22,14 @@ add_task(function* test_tab_matches() {
yield check_autocomplete({
search: "abc.com",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "http://abc.com/"}), title: "ABC rocks" } ]
});
do_log_info("two results, one tab match");
yield check_autocomplete({
search: "abc",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
matches: [ { uri: makeActionURI("switchtab", {url: "http://abc.com/"}), title: "ABC rocks" },
{ uri: uri2, title: "xyz.net - we're better than ABC" } ]
});
@ -38,8 +38,8 @@ add_task(function* test_tab_matches() {
yield check_autocomplete({
search: "abc",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
{ uri: NetUtil.newURI("moz-action:switchtab,http://xyz.net/"), title: "xyz.net - we're better than ABC" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "http://abc.com/"}), title: "ABC rocks" },
{ uri: makeActionURI("switchtab", {url: "http://xyz.net/"}), title: "xyz.net - we're better than ABC" } ]
});
do_log_info("two results, both tab matches, one has multiple tabs");
@ -47,8 +47,8 @@ add_task(function* test_tab_matches() {
yield check_autocomplete({
search: "abc",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
{ uri: NetUtil.newURI("moz-action:switchtab,http://xyz.net/"), title: "xyz.net - we're better than ABC" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "http://abc.com/"}), title: "ABC rocks" },
{ uri: makeActionURI("switchtab", {url: "http://xyz.net/"}), title: "xyz.net - we're better than ABC" } ]
});
do_log_info("two results, no tab matches");
@ -66,30 +66,30 @@ add_task(function* test_tab_matches() {
yield check_autocomplete({
search: gTabRestrictChar + " abc",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "http://abc.com/"}), title: "ABC rocks" } ]
});
do_log_info("tab match with not-addable pages");
yield check_autocomplete({
search: "mozilla",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,about:mozilla"), title: "about:mozilla" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "about:mozilla"}), title: "about:mozilla" } ]
});
do_log_info("tab match with not-addable pages and restriction character");
yield check_autocomplete({
search: gTabRestrictChar + " mozilla",
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,about:mozilla"), title: "about:mozilla" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "about:mozilla"}), title: "about:mozilla" } ]
});
do_log_info("tab match with not-addable pages and only restriction character");
yield check_autocomplete({
search: gTabRestrictChar,
searchParam: "enable-actions",
matches: [ { uri: NetUtil.newURI("moz-action:switchtab,http://abc.com/"), title: "ABC rocks" },
{ uri: NetUtil.newURI("moz-action:switchtab,about:mozilla"), title: "about:mozilla" },
{ uri: NetUtil.newURI("moz-action:switchtab,data:text/html,test"), title: "data:text/html,test" } ]
matches: [ { uri: makeActionURI("switchtab", {url: "http://abc.com/"}), title: "ABC rocks" },
{ uri: makeActionURI("switchtab", {url: "about:mozilla"}), title: "about:mozilla" },
{ uri: makeActionURI("switchtab", {url: "data:text/html,test"}), title: "data:text/html,test" } ]
});
yield cleanup();

View File

@ -1445,9 +1445,17 @@ extends="chrome://global/content/bindings/popup.xml#popup">
<method name="_adjustAcItem">
<body>
<![CDATA[
var url = this.getAttribute("url");
var title = this.getAttribute("title");
var type = this.getAttribute("type");
let url = this.getAttribute("url");
let title = this.getAttribute("title");
let type = this.getAttribute("type");
let emphasiseTitle = true;
let emphasiseUrl = true;
// Hide the title's extra box by default, until we find out later if
// we need extra stuff.
this._extraBox.hidden = true;
this._titleBox.flex = 1;
this.removeAttribute("actiontype");
@ -1457,34 +1465,36 @@ extends="chrome://global/content/bindings/popup.xml#popup">
// space when hidden. Setting the hidden property accomplishes that.
this._titleOverflowEllipsis.hidden = false;
let types = new Set(type.split(/\s+/));
// If the type includes an action, set up the item appropriately.
var types = type.split(/\s+/);
var actionIndex = types.indexOf("action");
if (actionIndex >= 0) {
let [,action, param] = url.match(/^moz-action:([^,]+),(.*)$/);
this.setAttribute("actiontype", action);
url = param;
let desc = this._stringBundle.GetStringFromName("switchToTab");
this._setUpDescription(this._action, desc, true);
if (types.has("action")) {
let action = this._parseActionUrl(url);
this.setAttribute("actiontype", action.type);
if (action.type == "switchtab") {
url = action.params.url;
let desc = this._stringBundle.GetStringFromName("switchToTab");
this._setUpDescription(this._action, desc, true);
}
// Remove the "action" substring so that the correct style, if any,
// is applied below.
types.splice(actionIndex, 1);
type = types.join(" ");
types.delete("action");
}
// Check if we have a search engine name
let searchEngine = "";
let searchIndex = types.indexOf("search");
if (searchIndex >= 0) {
if (types.has("search")) {
emphasiseUrl = false;
const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
[title, searchEngine] = title.split(TITLE_SEARCH_ENGINE_SEPARATOR);
url = this._stringBundle.formatStringFromName("searchWithEngine", [searchEngine], 1);
// Remove the "search" substring so that the correct style, if any,
// is applied below.
types.splice(searchIndex, 1);
type = types.join(" ");
types.delete("search");
}
// If we have a tag match, show the tags and icon
@ -1531,10 +1541,6 @@ extends="chrome://global/content/bindings/popup.xml#popup">
// Don't emphasize keyword searches in the title or url
this.setAttribute("text", "");
} else {
// Hide the title's extra box if we don't need extra stuff
this._extraBox.hidden = true;
this._titleBox.flex = 1;
}
// Give the image the icon style and a special one for the type
@ -1546,15 +1552,8 @@ extends="chrome://global/content/bindings/popup.xml#popup">
title = url;
// Emphasize the matching search terms for the description
this._setUpDescription(this._title, title);
if (!searchEngine) {
this._setUpDescription(this._url, url);
} else {
let desc = this._stringBundle.formatStringFromName("searchWithEngine", [searchEngine], 1);
// The search engine name, when present, is not emphasized.
this._setUpDescription(this._url, desc, true);
}
this._setUpDescription(this._title, title, !emphasiseTitle);
this._setUpDescription(this._url, url, !emphasiseUrl);
// Set up overflow on a timeout because the contents of the box
// might not have a width yet even though we just changed them
@ -1564,6 +1563,37 @@ extends="chrome://global/content/bindings/popup.xml#popup">
</body>
</method>
<method name="_parseActionUrl">
<parameter name="aUrl"/>
<body><![CDATA[
if (!aUrl.startsWith("moz-action:"))
return null;
// URL is in the format moz-action:ACTION,PARAMS
// Where PARAMS is a JSON encoded object.
aUrl = decodeURI(aUrl);
let [, type, params] = aUrl.match(/^moz-action:([^,]+),(.*)$/);
let action = {
type: type,
};
try {
action.params = JSON.parse(params);
} catch (e) {
// If this failed, we assume that params is not a JSON object, and
// is instead just a flat string. This will happen when
// UnifiedComplete is disabled - in which case, the param is always
// a URL.
action.params = {
url: params,
}
}
return action;
]]></body>
</method>
<method name="_setUpOverflow">
<parameter name="aParentBox"/>
<parameter name="aEllipsis"/>

View File

@ -5433,6 +5433,11 @@ function getInnerId(window) {
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
};
function getInnerId(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
};
const symbolProtoToString = typeof Symbol === "function" ? Symbol.prototype.toString : null;
function getSymbolName(symbol) {

View File

@ -43,6 +43,11 @@ function getWindowID(window) {
* Browser-specific actors.
*/
function getInnerId(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
};
/**
* Yield all windows of type |aWindowType|, from the oldest window to the
* youngest, using nsIWindowMediator::getEnumerator. We're usually

View File

@ -4539,7 +4539,8 @@ bool
mozilla::BrowserTabsRemoteAutostart()
{
if (!gBrowserTabsRemoteAutostartInitialized) {
bool prefEnabled = Preferences::GetBool("browser.tabs.remote.autostart", false);
bool prefEnabled = Preferences::GetBool("browser.tabs.remote.autostart", false) ||
Preferences::GetBool("browser.tabs.remote.autostart.1", false);
bool disabledForA11y = Preferences::GetBool("browser.tabs.remote.autostart.disabled-because-using-a11y", false);
gBrowserTabsRemoteAutostart = !gSafeMode && !disabledForA11y && prefEnabled;
gBrowserTabsRemoteAutostartInitialized = true;