Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

21
gaia/tv_apps/browser/bower.json Executable file
View file

@ -0,0 +1,21 @@
{
"name": "browser",
"version": "0.0.0",
"homepage": "https://github.com/mozilla-b2g/gaia/tree/master/tv_apps/browser",
"description": "Smart Screen Browser App",
"main": "index.html",
"license": "MPL",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"evt": "fxos-components/evt#~0.4.0",
"smart-button": "fxos-components/smart-button",
"smart-icons": "smart-components/smart-icons#~0.0.3"
}
}

View file

@ -0,0 +1,28 @@
{
"name": "evt",
"main": "index.js",
"version": "0.4.0",
"homepage": "https://github.com/wilsonpage/evt",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"package.json",
"test",
"tests",
"README.md"
],
"_release": "0.4.0",
"_resolution": {
"type": "version",
"tag": "v0.4.0",
"commit": "3593dd6b4dd19f683d00fd0eaf2581c11a128da6"
},
"_source": "git://github.com/gaia-components/evt.git",
"_target": "~0.4.0",
"_originalSource": "gaia-components/evt"
}

View file

@ -0,0 +1,19 @@
{
"name": "evt",
"main": "index.js",
"version": "0.4.0",
"homepage": "https://github.com/wilsonpage/evt",
"authors": [
"Wilson Page <wilsonpage@me.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"package.json",
"test",
"tests",
"README.md"
]
}

View file

@ -0,0 +1,154 @@
/**
* Evt
*
* A super lightweight
* event emitter library.
*
* @version 0.3.3
* @author Wilson Page <wilson.page@me.com>
*/
;(function() {
/**
* Locals
*/
var proto = Events.prototype;
var slice = [].slice;
/**
* Creates a new event emitter
* instance, or if passed an
* object, mixes the event logic
* into it.
*
* @param {Object} obj
* @return {Object}
*/
function Events(obj) {
if (!(this instanceof Events)) return new Events(obj);
if (obj) return mixin(obj, proto);
}
/**
* Registers a callback
* with an event name.
*
* @param {String} name
* @param {Function} cb
* @return {Event}
*/
proto.on = function(name, cb) {
this._cbs = this._cbs || {};
(this._cbs[name] || (this._cbs[name] = [])).push(cb);
return this;
};
/**
* Attach a callback that once
* called, detaches itself.
*
* TODO: Implement `.off()` to work
* with `once()` callbacks.
*
* @param {String} name
* @param {Function} cb
* @public
*/
proto.once = function(name, cb) {
this.on(name, one);
function one() {
cb.apply(this, arguments);
this.off(name, one);
}
};
/**
* Removes a single callback,
* or all callbacks associated
* with the passed event name.
*
* @param {String} name
* @param {Function} cb
* @return {Event}
*/
proto.off = function(name, cb) {
this._cbs = this._cbs || {};
if (!name) { this._cbs = {}; return; }
if (!cb) { return delete this._cbs[name]; }
var cbs = this._cbs[name] || [];
var i;
while (cbs && ~(i = cbs.indexOf(cb))) { cbs.splice(i, 1); }
return this;
};
/**
* Fires an event, triggering
* all callbacks registered on this
* event name.
*
* @param {String} name
* @return {Event}
*/
proto.fire = proto.emit = function(options) {
var cbs = this._cbs = this._cbs || {};
var name = options.name || options;
var batch = (cbs[name] || []).concat(cbs['*'] || []);
var ctx = options.ctx || this;
if (batch.length) {
this._fireArgs = arguments;
var args = slice.call(arguments, 1);
while (batch.length) {
batch.shift().apply(ctx, args);
}
}
return this;
};
proto.firer = function(name) {
var self = this;
return function() {
var args = slice.call(arguments);
args.unshift(name);
self.fire.apply(self, args);
};
};
/**
* Util
*/
/**
* Mixes in the properties
* of the second object into
* the first.
*
* @param {Object} a
* @param {Object} b
* @return {Object}
*/
function mixin(a, b) {
for (var key in b) a[key] = b[key];
return a;
}
/**
* Expose 'Event' (UMD)
*/
if (typeof exports === 'object') {
module.exports = Events;
} else if (typeof define === 'function' && define.amd) {
define(function(){ return Events; });
} else {
window.evt = Events;
}
})();

View file

@ -0,0 +1,26 @@
{
"name": "smart-button",
"version": "0.0.2",
"homepage": "https://github.com/gaia-components/smart-button",
"main": "script.js",
"license": "MPL",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests",
"examples",
"LICENSE",
"README.md"
],
"_release": "0.0.2",
"_resolution": {
"type": "version",
"tag": "v0.0.2",
"commit": "04fdae935e2f2ba99d1c4f3e156d17f12eb2d142"
},
"_source": "git://github.com/gaia-components/smart-button.git",
"_target": "*",
"_originalSource": "gaia-components/smart-button"
}

View file

@ -0,0 +1,17 @@
{
"name": "smart-button",
"version": "0.0.2",
"homepage": "https://github.com/gaia-components/smart-button",
"main": "script.js",
"license": "MPL",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests",
"examples",
"LICENSE",
"README.md"
]
}

View file

@ -0,0 +1,62 @@
'use strict';
/* global KeyEvent */
window.SmartButton = (function(win) {
// Extend from the HTMLButtonElement prototype
var proto = Object.create(HTMLButtonElement.prototype);
proto.createdCallback = function() {
this.addEventListener('mousedown', this);
this.addEventListener('mouseup', this);
this.addEventListener('touchstart', this);
this.addEventListener('touchend', this);
this.addEventListener('keydown', this);
this.addEventListener('keyup', this);
this.addEventListener('focus', this);
this.addEventListener('blur', this);
this.addEventListener('transitionend', this);
this.tabIndex = 0;
};
proto.handleEvent = function(evt) {
switch(evt.type) {
case 'mousedown':
case 'touchstart':
this.classList.add('pressed');
break;
case 'keydown':
if (evt.keyCode === KeyEvent.DOM_VK_RETURN) {
this.classList.add('pressed');
}
break;
case 'mouseup':
case 'touchend':
this.classList.remove('pressed');
this.classList.add('released');
break;
case 'keyup':
if (evt.keyCode === KeyEvent.DOM_VK_RETURN) {
this.classList.remove('pressed');
this.classList.add('released');
this.click();
}
break;
case 'transitionend':
if (this.classList.contains('released')) {
this.classList.remove('released');
}
break;
case 'focus':
this.classList.add('focused');
break;
case 'blur':
this.classList.remove('pressed');
this.classList.remove('released');
this.classList.remove('focused');
break;
}
};
// Register and return the constructor
return document.registerElement('smart-button', { prototype: proto });
})(window);

View file

@ -0,0 +1,497 @@
/**
* Button state:
* 1. normal
* In this state, we don't add any class.
* 2. focused (class name: focused)
* The focused state may be triggered by keyboard or touch/mouse.
* 3. pressed (class name: pressed)
* This state is triggered by user pressed confirm button, mousedown,
* and touchdown.
* 4. released (class name: released)
* This state is only for changing duration of transition. We enter this
* state when user release the button. After transitionend, we goes back
* to focused state.
**/
smart-button {
font-family: "Fira Sans";
display: inline-block;
width: 8rem;
height: 8rem;
/* we need to set border to none to remove the button border */
border: none;
/* the radius is still make button as round even if we don't have border */
border-radius: 50%;
/* 50% is not a real circle because of rounding, we have to use a value larger
than 50% */
-moz-outline-radius: 60%;
outline: transparent 0 solid;
background-color: rgba(0, 0, 0, 0.5);
background-repeat: no-repeat;
background-size: 5.4rem auto;
background-position: center center;
font-style: italic;
transition-property: all;
transition-timing-function: cubic-bezier(0.25, 0, 0, 1.0);
transition-duration: 0.42s;
}
smart-button.focused {
outline: 0;
background-color: #ffffff;
transform: scale(1.2);
transition-duration: 0.42s;
}
smart-button.released {
transition-duration: 0.16s;
}
smart-button.toggled {
background-color: #00caf2;
}
smart-button.pressed {
background-color: #00caf2;
transform: scale(0.8);
transition-duration: 0.06s;
}
smart-button.disabled {
background-color: rgba(0, 0, 0, 0.5);
}
smart-button[data-icon]:before {
width: 5.4rem;
left: 1.3rem;
font-size: 5.4rem;
line-height: 8rem;
text-align: center;
color: #ffffff;
white-space: normal;
top: 0;
position: absolute;
}
smart-button[data-icon].focused:before {
color: #2d2d2d;
}
smart-button[data-icon].toggled:before {
color: #00caf2;
}
smart-button[data-icon].pressed:before {
color: #ffffff;
}
smart-button[data-icon].disabled:before {
color: #ffffff;
opacity: 0.3;
}
/**
* Simple Text Button
**/
smart-button[type="simple-text"] {
color: #dddddd;
background: none;
border: none;
border-radius: 0;
width: auto;
height: 8rem;
line-height: 8rem;
font-size: 2.4rem;
-moz-user-select: none;
padding-left: 2.6rem;
padding-right: 2.6rem;
}
smart-button[type="simple-text"].focused {
color: #ffffff;
background: none;
}
smart-button[type="simple-text"].toggled {
color: #00caf2;
}
smart-button[type="simple-text"].pressed {
color: #00caf2;
background: none;
}
/**
* End of Simple Text Button
**/
/**
* underlined text button
*/
smart-button[type="underlined-text"] {
position: relative;
color: white;
font-size: 2.4rem;
padding-left: 3.8rem;
padding-right: 3.8rem;
border-radius: 4rem;
width: auto;
line-height: 8rem;
margin-right: 1.4rem;
overflow: hidden;
}
smart-button[type="underlined-text"]:after {
position: absolute;
width: 100%;
height: 100%;
left: 0;
content: ' ';
border-bottom: 0.6rem #61acd7 solid;
box-sizing: border-box;
}
smart-button[type="underlined-text"].focused {
transform: scale(1.2);
color: #2d2d2d;
}
smart-button[type="underlined-text"].pressed {
transform: scale(1);
color: white;
background-color: #00caf2;
}
/**
* End of underlined text button
*/
/**
* App Icons
**/
smart-button[type="app-button"] {
/* To use 33.4rem instead of to use 33.6rem is to work around the anti-alias
pixel. So, the circle is filled by the background almost totally. */
width: 33.4rem;
height: 33.4rem;
position: relative;
overflow: hidden;
background-color: transparent;
}
smart-button[type="app-button"].focused {
transform: scale(1.4);
/* To use outline will not change the size of button and make the whole button
thrilling. */
outline: 0.8rem solid #ffffff;
}
smart-button[type="app-button"].pressed {
/* While scaling, we may have a gap between outline and icon which may be
anti-alias pixel. So, we use scale(1.22) to prevent such kind of case */
transform: scale(1.22);
/* To use outline will not change the size of button and make the whole button
thrilling. */
outline: 1.0rem solid #ffffff;
}
smart-button[type="app-button"].fullsized {
background-size: 33.6rem auto;
}
smart-button[type="app-button"].fitted {
background-size: 22rem auto;
}
/** we use :after as label */
smart-button[type="app-button"]:after {
content: attr(label);
position: absolute;
bottom: 0;
left: auto;
right: auto;
width: 33.6rem;
height: 8rem;
padding-top: 1rem;
line-height: 3rem;
text-align: center;
font-size: 2.8rem;
font-style: italic;
color: #ffffff;
}
/**
* text backgorund color
**/
smart-button[type="app-button"][app-type="deck"]:after {
background-color: transparent;
}
smart-button[type="app-button"][app-type="tv"]:after {
background-color: #d90c83;
}
smart-button[type="app-button"][app-type="app"]:after {
background-color: rgba(0, 0, 0, 0.4);
}
smart-button[type="app-button"][app-type="device"]:after {
background-color: #4a82ea;
}
smart-button[type="app-button"][app-type="folder"] {
background-color: #595959;
}
smart-button[type="app-button"]:before {
left: 0;
line-height: 30rem;
font-size: 16rem;
width: 100%;
}
smart-button[type="app-button"][app-type="folder"]:before {
color: #CCCCCC;
}
/**
* End of App Icons
**/
/**
* text and icon button
*/
smart-button[type="text-and-icon"] {
position: relative;
color: white;
font-size: 2.4rem;
padding-left: 4.6rem;
padding-right: 4.6rem;
border-radius: 4rem;
width: auto;
line-height: 8rem;
margin-right: 1.4rem;
overflow: hidden;
}
smart-button[type="text-and-icon"][data-icon] {
padding-left: 9.6rem;
}
smart-button[type="text-and-icon"][data-icon]:before {
left: 3.8rem;
}
smart-button[type="text-and-icon"].focused {
transform: scale(1.2);
color: #2d2d2d;
}
smart-button[type="text-and-icon"].pressed {
transform: scale(1);
color: white;
background-color: #00caf2;
}
/**
* End of text and icon button
*/
/**
* banner button
**/
smart-button[type="banner-button"] {
position: relative;
color: #ffffff;
font-size: 2rem;
width: 36rem;
height: 20rem;
overflow: hidden;
border-radius: 0;
border: 0 solid #ffffff;
background-color: #5f5f5f;
background-repeat: no-repeat;
background-size: 120%;
box-sizing: border-box;
transition-property: all;
transition-timing-function: cubic-bezier(0.25, 0, 0.5, 1.0);
transition-duration: 0.1s;
}
smart-button[type="banner-button"][label]:before {
content: attr(label);
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 5rem;
line-height: 5rem;
text-align: center;
background-color: rgba(0, 0, 0, 0.4);
}
smart-button[type="banner-button"]:after {
content: " ";
position: absolute;
bottom: 0;
left: 0;
right: 0;
top: 0;
transition-property: all;
transition-timing-function: cubic-bezier(0.25, 0, 0, 1.0);
transition-duration: 0.06s;
background-color: rgba(255, 255, 255, 0);
}
smart-button[type="banner-button"].focused {
transform: none;
border-width: 1.2rem;
background-size: 100%;
transition-duration: 0.24s;
}
smart-button[type="banner-button"].pressed {
transform: scale(0.945, 0.9);
}
smart-button[type="banner-button"].pressed:after {
background-color: rgba(255, 255, 255, 0.5);
}
/**
* banner button
**/
/**
* circle text button
*/
smart-button[type="circle-text"] {
width: 21rem;
height: 21rem;
color: white;
background-color: #5f6368;
line-height: 21rem;
padding: 2.5rem 2rem 1.5rem 2rem;
text-align: center;
font-size: 3.2rem;
font-weight: bolder;
overflow: hidden;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].focused {
transform: scale(1.2);
color: #2d2d2d;
background-color: white;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].pressed {
transform: scale(1);
color: white;
background-color: #00caf2;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].primary {
background-color: #00caf2;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].primary.focused {
color: #ffffff;
background-color: #00caf2;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].primary.pressed {
background-color: #0097b5;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].danger {
background-color: #e63d2f;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].danger.focused {
color: #ffffff;
background-color: #e63d2f;
transition-property: transform, color, background-color;
}
smart-button[type="circle-text"].danger.pressed {
background-color: #ac2e23;
transition-property: transform, color, background-color;
}
/**
* End of circle text button
*/
/**
* rounded-corner text button
*/
smart-button[type="rounded-corner-text"] {
-moz-user-select: none;
width: auto;
height: 8rem;
border-radius: 4rem;
background-color: #5f6368;
padding: 0 3.8rem;
line-height: 8rem;
color: white;
text-align: center;
font-size: 2.4rem;
overflow: hidden;
transition-property: transform, color, background-color;
}
smart-button[type="rounded-corner-text"].focused,
smart-button[type="rounded-corner-text"]:hover {
transform: scale(1.2);
color: #2d2d2d;
background-color: white;
}
smart-button[type="rounded-corner-text"].pressed {
transform: scale(1);
/*color: white;*/
background-color: #00caf2;
}
smart-button[type="rounded-corner-text"].primary {
background-color: #00caf2;
}
smart-button[type="rounded-corner-text"].primary:hover,
smart-button[type="rounded-corner-text"].primary.focused {
color: #ffffff;
background-color: #00caf2;
}
smart-button[type="rounded-corner-text"].primary.pressed {
background-color: #0097b5;
}
/**
* End of rounded-corner text button
*/

View file

@ -0,0 +1,30 @@
{
"name": "smart-icons",
"version": "0.0.3",
"homepage": "https://github.com/smart-components/smart-icons",
"description": "Icon font for smart-screen",
"license": "MPL",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"templates",
"images",
"test",
"tests",
"index.html",
"Gruntfile.js",
"README.md",
"package.json"
],
"_release": "0.0.3",
"_resolution": {
"type": "version",
"tag": "v0.0.3",
"commit": "0c335ac23f484069b4fafa7b7e5afd9f3c08d66e"
},
"_source": "git://github.com/smart-components/smart-icons.git",
"_target": "~0.0.3",
"_originalSource": "smart-components/smart-icons"
}

View file

@ -0,0 +1,21 @@
{
"name": "smart-icons",
"version": "0.0.3",
"homepage": "https://github.com/smart-components/smart-icons",
"description": "Icon font for smart-screen",
"license": "MPL",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"templates",
"images",
"test",
"tests",
"index.html",
"Gruntfile.js",
"README.md",
"package.json"
]
}

Binary file not shown.

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,25 @@
/* Generated by grunt-webfont */
/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
@font-face {
font-family: "smart-icons";
src: url("fonts/smart-icons.ttf") format("truetype");
font-weight: 500;
font-style: normal;
}
[data-icon]:before,
.ligature-icons {
font-family: "smart-icons";
content: attr(data-icon);
display: inline-block;
font-weight: 500;
font-style: normal;
text-decoration: inherit;
text-transform: none;
text-rendering: optimizeLegibility;
font-size: 30px;
-webkit-font-smoothing: antialiased;
}

View file

@ -0,0 +1,88 @@
'use strict';
/* jshint node: true */
var utils = require('utils');
var preprocessor = require('preprocessor');
var BrowserAppBuilder = function() {
};
BrowserAppBuilder.prototype.setOptions = function(options) {
this.stageDir = utils.getFile(options.STAGE_APP_DIR);
this.appDir = utils.getFile(options.APP_DIR);
this.distDirPath = options.GAIA_DISTRIBUTION_DIR;
};
BrowserAppBuilder.prototype.initJSON = function() {
var defaultJSONpath =
utils.joinPath(this.appDir.path, 'build', 'default.json');
var defaultJson = utils.getJSON(utils.getFile(defaultJSONpath));
var file =
utils.getFile(this.stageDir.path, 'js', 'init.json');
utils.writeContent(file,
utils.getDistributionFileContent('browser', defaultJson, this.distDirPath));
};
BrowserAppBuilder.prototype.initTopsitesJSON = function() {
var defaultJSONpath =
utils.joinPath(this.appDir.path, 'build', 'topsites.json');
var defaultJson = utils.getJSON(utils.getFile(defaultJSONpath));
defaultJson.topSites.forEach(function(site) {
if (site.iconPath) {
var file = utils.getFile(this.appDir.path, 'build', site.iconPath);
var icon = utils.getFileAsDataURI(file);
site.iconUri = icon;
delete site.iconPath;
}
}.bind(this));
var file =
utils.getFile(this.stageDir.path, 'js', 'inittopsites.json');
utils.writeContent(file,
utils.getDistributionFileContent('topsites', defaultJson,
this.distDirPath));
};
BrowserAppBuilder.prototype.enableFirefoxSync = function(options) {
var fileList = {
process: [
['index.html'],
['js', 'awesomescreen.js'],
['js', 'bookmarkStore.js'],
['js', 'historyStore.js'],
['js', 'browser_dialog.js'],
['js', 'index.js'],
['js', 'settings.js'],
['js', 'toolbar.js'],
['style', 'settings.css'],
['style', 'browser_dialog.css']
],
remove: [
['js', 'sync', 'bookmarks.js'],
['js', 'sync', 'db.js'],
['js', 'sync', 'ds_helper.js'],
['js', 'sync', 'history.js'],
['js', 'sync', 'manager_bridge.js'],
['js', 'sync', 'settings.js'],
['js', 'sync', 'toolbar.js'],
['test', 'unit', 'sync', 'manager_bridge_test.js'],
['test', 'unit', 'sync', 'settings_test.js'],
['test', 'unit', 'sync', 'toolbar_test.js']
]
};
preprocessor.execute(options, 'FIREFOX_SYNC', fileList);
};
BrowserAppBuilder.prototype.execute = function(options) {
this.setOptions(options);
this.initJSON();
this.initTopsitesJSON();
this.enableFirefoxSync(options);
};
exports.execute = function(options) {
utils.copyToStage(options);
(new BrowserAppBuilder()).execute(options);
};

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

View file

@ -0,0 +1,14 @@
{
"topSites": [
{
"title": "Mozilla",
"uri": "http://mozilla.org",
"iconPath": "mozilla.png"
},
{
"title": "Firefox OS",
"uri": "http://mozilla.org/firefoxos",
"iconPath": "firefox.png"
}
]
}

View file

@ -0,0 +1,58 @@
.fte-container {
position: fixed;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
text-align: center;
z-index: 1000;
color: #fff;
opacity: 1;
transition: opacity 0.5s linear;
}
.fte-container.finish {
opacity: 0;
}
.fte-page {
width: 100%;
height: 100%;
}
.fte-logo {
margin: 7.5rem 0 1.5rem 0;
}
.fte-greeting {
margin: 1.5rem 0 8rem 0;
line-height: 7rem;
font-weight: lighter;
font-style: italic;
font-size: 7rem;
}
.fte-description {
width: 110rem;
margin: 8rem auto 3.5rem auto;
font-weight: lighter;
font-style: italic;
font-size: 3.8rem;
}
.fte-button-container {
position: absolute;
bottom: 10.5rem;
display: flex;
justify-content: center;
width: 100%;
}
.fte-button-container > smart-button {
width: 23.7rem;
font-size: 2.4rem;
padding: 0;
}
.fte-button-container > smart-button:first-child {
margin-right: 1.8rem;
}

View file

@ -0,0 +1,14 @@
<template>
<div id="fte-container" class="fte-container">
<div class="fte-page">
<img class="fte-logo" src="../style/images/firefox_logo.png"></img>
<h1 class="fte-greeting" data-l10n-id="fte-welcome"></h1>
<p class="fte-description" data-l10n-id="fte-description"></p>
<img class="fte-diagram" src="../style/images/account_image.png"></img>
<div class="fte-button-container">
<smart-button id="fte-skip" class="fte-button" type="rounded-corner-text" data-l10n-id="skip" data-behavior="skip"></smart-button>
<smart-button id="fte-sign-in" class="fte-button fte-finish primary" type="rounded-corner-text" class="primary" data-l10n-id="login" data-behavior="finish"></smart-button>
</div>
</div>
</div>
</template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

828
gaia/tv_apps/browser/index.html Executable file
View file

@ -0,0 +1,828 @@
<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<meta charset="utf-8">
<title>web browser</title>
<!-- building blocks -->
<link rel="stylesheet" type="text/css" href="bower_components/smart-button/style.css">
<link rel="stylesheet" type="text/css" href="bower_components/smart-icons/smart-icons.css">
<!-- Specific style -->
<link rel="stylesheet" type="text/css" href="style/components.css">
<link rel="stylesheet" type="text/css" href="style/index.css">
<link rel="stylesheet" type="text/css" href="style/awesomescreen.css">
<link rel="stylesheet" type="text/css" href="style/authentication_dialog.css">
<link rel="stylesheet" type="text/css" href="style/browser_dialog.css">
<link rel="stylesheet" type="text/css" href="style/toolbar.css">
<link rel="stylesheet" type="text/css" href="style/tooltip.css">
<link rel="stylesheet" type="text/css" href="style/search_result.css">
<link rel="stylesheet" type="text/css" href="style/settings.css">
<link rel="stylesheet" type="text/css" href="style/smartList.css">
<!-- Resources -->
<link rel="resource" type="image/png" href="shared/resources/branding/browser_336.png">
<!-- Localization -->
<script defer="" src="/shared/js/l10n.js"></script>
<!-- L10n properties -->
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="en-US">
<!--IFDEF_FIREFOX_SYNC
<link rel="localization" href="shared/locales/firefox_sync/firefox_sync.{locale}.properties">
ENDIF_FIREFOX_SYNC-->
<link rel="localization" href="/locales/browser.{locale}.properties">
<!-- building blocks -->
<script defer src="bower_components/evt/index.js"></script>
<script defer src="bower_components/smart-button/script.js"></script>
<!-- Shared code -->
<script defer src="shared/js/url_helper.js"></script>
<script defer src="shared/js/utilities.js"></script>
<script defer src="shared/js/smart-screen/connection_manager.js"></script>
<script defer src="shared/js/lazy_loader.js"></script>
<script defer src="shared/js/smart-screen/simple_key_navigation.js"></script>
<script defer src="shared/js/smart-screen/f_t_e_wizard.js"></script>
<!-- Specific code -->
<script defer src="js/resource_loader.js"></script>
<script defer src="js/browser_db.js"></script>
<!--IFDEF_FIREFOX_SYNC
<script defer src="js/sync/db.js"></script>
ENDIF_FIREFOX_SYNC-->
<script defer src="js/index.js"></script>
<script defer src="js/awesomescreen.js"></script>
<script defer src="js/search_util.js"></script>
<script defer src="js/authentication_dialog.js"></script>
<script defer src="js/browser_dialog.js"></script>
<script defer src="js/toolbar.js"></script>
<script defer src="js/tooltip.js"></script>
<script defer src="js/search_result.js"></script>
<script defer src="js/settings.js"></script>
<script defer src="js/connection_handler.js"></script>
<script defer src="js/smartList.js"></script>
<script defer src="js/bookmarkStore.js"></script>
<script defer src="js/historyStore.js"></script>
<script defer src="js/fte.js"></script>
<!-- IAC Handler (put here because it starts sending event immediately) -->
<script defer src="shared/js/iac_handler.js"></script>
<!-- Lazy loaded code -->
<!-- <script src="shared/js/settings_listener.js"><script> -->
<!-- <script src="shared/js/sync/errors.js"></script> -->
<!-- <script src="js/sync/manager_bridge.js"></script> -->
<!-- <script src="js/sync/settings.js"></script> -->
<!-- <script src="js/sync/toolbar.js"></script> -->
<!-- <script src="js/sync/ds_helper.js"></script> -->
<!-- <script src="js/sync/bookmarks.js"></script> -->
<!-- <script src="js/sync/history.js"></script> -->
<!-- Lazy loaded Templates -->
<!-- <link rel="import" href="elements/fte.html"> -->
<!-- <link rel="stylesheet" type="text/css" href="elements/fte.css"> -->
</head>
<body class="page_screen start_page" role="application">
<!-- mask for menu -->
<div id="fade-base"></div>
<!-- side -->
<div id="side-block" class="side-window">
<!-- put widget here -->
</div>
<!-- main -->
<div id="main-block" data-mode="cursor" class="main-window">
<!-- toolbar -->
<ul id="toolbar-panel" data-pvt="false">
<div id="private-bar"></div>
<li id="sidebar-button-block" data-tips="WB_LT_TIPS_CHANGE_SCREEN" data-fade="false">
<div id="sidebar-button" data-sidebar="true">
<!-- XXX: Replace the SVG to icon font -->
<svg id="sidebar-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid slice">
<g id="sidebar-close-svg" visibility="hidden">
<g>
<path class="sidebar-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231F20" d="M36.899,15.805H18.214c-1.968,0-3.716,2.093-3.716,4.061v14.997
c0,1.968,1.747,3.332,3.716,3.332h18.686c1.968,0,3.502-1.364,3.502-3.332V19.866C40.401,17.898,38.867,15.805,36.899,15.805z
M37.578,32.739c0,1.583-1.234,2.68-2.817,2.68H20.265c-1.583,0-2.989-1.097-2.989-2.68V21.849c0-1.583,1.406-3.267,2.989-3.267
h14.497c1.583,0,2.817,1.684,2.817,3.267V32.739z"></path>
<path class="sidebar-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231F20" d="M16.589,22.805h22.4v2.1h-22.4V22.805z"></path>
</g>
</g>
<g id="sidebar-open-svg" visibility="hidden">
<path class="sidebar-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231F20" d="M36.45,15.805H17.764c-1.968,0-3.716,2.093-3.716,4.061v14.997
c0,1.968,1.747,3.332,3.716,3.332H36.45c1.968,0,3.502-1.364,3.502-3.332V19.866C39.952,17.898,38.418,15.805,36.45,15.805z
M37.129,21.849v0.955H23.839v-4.222h10.472C35.895,18.583,37.129,20.266,37.129,21.849z M34.312,35.419H23.839V24.905h13.289
v7.834C37.129,34.322,35.895,35.419,34.312,35.419z"></path>
</g>
</svg>
</div>
</li>
<li id="back-button-block" data-tips="WB_LT_TIPS_HISTORY_BACK">
<div id="back-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="back-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="back-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M39.325,24.619H21.352l6.701-6.701
c-0.38-1.648-0.861-3.185-1.428-4.584L15.46,24.5c-1.385,1.384-1.385,3.628,0,5.012l11.153,11.154
c0.567-1.396,1.048-2.928,1.431-4.57L21.349,29.4h17.976C39.662,27.764,39.661,26.256,39.325,24.619z"></path>
</svg>
</div>
</li>
<li id="forward-button-block" class="disable" data-tips="WB_LT_TIPS_HISTORY_FORWARD">
<div id="forward-button-border">
<div id="forward-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="forward-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="forward-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M38.54,24.5L27.375,13.334
c-0.567,1.399-1.048,2.936-1.429,4.584l6.702,6.701H14.675c-0.338,1.637-0.338,3.145,0,4.781h17.976l-6.695,6.695
c0.383,1.643,0.863,3.174,1.431,4.57L38.54,29.512C39.925,28.128,39.925,25.883,38.54,24.5z"></path>
</svg>
</div>
</div>
</li>
<li id="space-block">
<div></div>
</li>
<li id="addressbar-block">
<form id="address-form">
<input id="private-icon" value="" type="image">
<input id="ssl-indicator" value="" type="image">
<input id="url-input" dir="auto" type="text">
<div class="input-line"></div>
<div id="address-button" data-mode="load" data-tips="WB_LT_TIPS_RELOAD">
<!-- XXX: Replace the SVG to icon font -->
<svg id="address-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<g id="address-reload-svg" visibility="hidden">
<g>
<g>
<path class="address-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M39.701,24.33c-0.953-7.119-7.035-12.616-14.416-12.616
c-8.041,0-14.56,6.52-14.56,14.561c0,8.042,6.519,14.56,14.56,14.56c4.022,0,7.663-1.63,10.298-4.266l-2.231-2.231
c-2.064,2.065-4.916,3.343-8.067,3.343c-6.299,0-11.405-5.107-11.405-11.405c0-6.299,5.106-11.405,11.405-11.405
c5.622,0,10.282,4.071,11.222,9.423c-1.445,0.126-2.765,0.437-3.866,0.883l4.343,4.343c0.539,0.539,1.413,0.539,1.951,0
l4.339-4.338C42.251,24.763,41.03,24.472,39.701,24.33z"></path>
</g>
</g>
</g>
<g id="address-stop-svg" visibility="hidden">
<g>
<g>
<polygon class="address-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" points="37.553,19.225 34.776,16.448 26.983,24.241
19.207,16.465 16.43,19.242 24.206,27.018 16.448,34.776 19.225,37.553 26.983,29.795 34.758,37.57 37.536,34.793 29.76,27.018
"></polygon>
</g>
</g>
</g>
</svg>
</div>
</form>
</li>
<li id="searchbar-block">
<form id="search-form">
<input id="search-favicon" value="" type="image">
<input id="search-input" data-tips="WB_LT_TIPS_SEARCH_BAR" dir="auto" type="text">
<div class="input-line"></div>
<div id="search-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="search-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="search-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M39.774,36.538l-5.462-5.461
c1.128-1.731,1.789-3.793,1.789-6.012c0-6.096-4.943-11.036-11.037-11.036c-6.096,0-11.035,4.94-11.035,11.036
c0,6.093,4.939,11.036,11.035,11.036c2.218,0,4.278-0.661,6.008-1.787l5.462,5.462c0.455,0.454,1.547,0.098,2.442-0.796
C39.87,38.085,40.227,36.992,39.774,36.538z M25.065,32.271c-3.98,0-7.206-3.227-7.206-7.207c0-3.981,3.227-7.208,7.206-7.208
c3.981,0,7.207,3.227,7.207,7.208C32.272,29.045,29.046,32.271,25.065,32.271z"></path>
</svg>
</div>
<div id="search-clear-button"></div>
</form>
<button id="search-close-button" data-l10n-id="LT_NETWORK_STATUS_BTN_CLOSE">close</button>
</li>
<li id="iconbutton-block">
<ul>
<li id="bookmark-button-block" data-tips="WB_LT_TIPS_BOOKMARK_THIS_PAGE">
<div id="bookmark-button" data-isbookmark="false">
<!-- XXX: Replace the SVG to icon font -->
<svg id="bookmark-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<g id="bookmark-off-svg" visibility="hidden">
<g>
<g>
<path class="bookmark-button-path" fill="#1D1D1B" d="M43.116,22.382l-11.238-1.477L27,10.673l-4.878,10.231l-11.238,1.477l8.224,7.801L17.04,41.327l9.96-5.41
l9.96,5.41l-2.068-11.145L43.116,22.382z M27,32.824l-6.404,3.479l1.33-7.165l-5.287-5.016l7.225-0.949L27,16.594l3.136,6.579
l7.226,0.949l-5.287,5.016l1.33,7.165L27,32.824z"></path>
</g>
</g>
</g>
<g id="bookmark-on-svg" visibility="hidden">
<g>
<g>
<polygon class="bookmark-button-path" fill="#00caf2" points="43.116,22.382 31.878,20.904 27,10.673 22.122,20.904 10.884,22.382 19.107,30.183 17.04,41.327
27,35.917 36.96,41.327 34.893,30.183 "></polygon>
</g>
</g>
</g>
</svg>
</div>
</li>
<li id="show-bookmarks-button-block" data-tips="WB_LT_TIPS_SHOW_YOUR_BOOKMARK">
<div id="show-bookmarks-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="show-bookmarks-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="show-bookmarks-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M38.551,18.436h-4.794l-5.571-5.406l-5.581,5.406h-5.156
c-1.205,0-2.181,0.977-2.181,2.181v18.172c0,1.204,0.976,2.181,2.181,2.181h21.102c1.204,0,2.181-0.977,2.181-2.181V20.617
C40.731,19.413,39.755,18.436,38.551,18.436z M21.83,38.06h-4.363v-4.363h4.363V38.06z M21.833,31.521h-4.361v-4.361h4.361
V31.521z M21.833,24.978h-4.361v-4.361h4.361V24.978z M23.991,27.159h14.56v4.361h-14.56V27.159z M38.552,38.06H23.999v-4.363
h14.553V38.06z M38.542,24.968l-14.538,0.007v-4.356h14.548L38.542,24.968z"></path>
</svg>
</div>
</li>
<li id="home-button-block" data-tips="WB_LT_TIPS_HOMEPAGE">
<div id="home-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="home-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="home-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M27.557,19.535l-9.028,8.469
c-0.001,0.026-0.007,0.05-0.007,0.076v10.34c0,1.119,0.935,2.071,2.088,2.071h4.028c-0.188-0.238-0.305-0.534-0.305-0.86v-7.936
c0-0.769,0.623-1.393,1.392-1.393h3.756c0.769,0,1.392,0.624,1.392,1.393v7.936c0,0.326-0.117,0.623-0.305,0.86h4.044
c1.153,0,2.088-0.952,2.088-2.071v-10.34c0-0.014-0.004-0.027-0.004-0.041L27.557,19.535z M40.929,25.98L29.117,14.352
c-0.815-0.791-2.137-0.791-2.953,0L14.352,25.98c-0.418,0.406-0.618,0.94-0.608,1.472c0.013,0,0.024-0.003,0.037-0.003h2.553
l9.863-9.18l-0.035-0.032l0.651-0.541l0.895-0.833l1.373,1.243l-0.033,0.031l9.832,9.312h2.658
C41.547,26.919,41.347,26.385,40.929,25.98z"></path>
</svg>
</div>
</li>
<li id="zoom-button-block" data-tips="WB_LT_TIPS_ZOOM_IN" data-colorbar="red">
<div id="zoom-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="zoom-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="zoom-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M39.982,36.892l-6.505-6.505
c1.148-1.698,1.818-3.746,1.818-5.95c0-5.876-4.764-10.64-10.64-10.64c-5.876,0-10.639,4.764-10.639,10.64
c0,5.876,4.763,10.64,10.639,10.64c2.074,0,4.003-0.603,5.639-1.629l6.063,6.063c0.005,0.203,0.06,0.379,0.184,0.502
c0.438,0.438,1.492,0.095,2.353-0.767c0.755-0.755,1.112-1.657,0.895-2.164L39.982,36.892z M24.656,32.544
c-4.478,0-8.107-3.63-8.107-8.107c0-4.477,3.63-8.108,8.107-8.108c4.477,0,8.108,3.631,8.108,8.108
C32.765,28.914,29.134,32.544,24.656,32.544z M25.766,19.229h-2.09v4.21h-4.212v2.089h4.212v4.192h2.09v-4.192h4.189V23.44
h-4.189V19.229z"></path>
</svg>
</div>
</li>
<li id="tabs-button-block" data-tips="WB_LT_TIPS_TABS" data-tabs="tab01" data-colorbar="yellow">
<div id="tabs-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="tabs-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<g id="tabs-00-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M29.456,24.899c-1.332,0-1.962,1.188-1.962,4.537
c0,3.385,0.63,4.573,1.962,4.573c1.333,0,1.963-1.152,1.963-4.573C31.419,26.033,30.789,24.899,29.456,24.899z"></path>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M29.456,35.757c-2.845,0-4.339-2.27-4.339-6.32c0-4.033,1.495-6.284,4.339-6.284c2.863,0,4.339,2.251,4.339,6.284
C33.795,33.487,32.319,35.757,29.456,35.757z"></path>
</g>
</g>
<g id="tabs-01-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M31.806,35.486h-2.269v-9.795l-2.701,1.639l-1.008-1.549l3.943-2.412h2.035V35.486z"></path>
</g>
<g id="tabs-02-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M33.057,35.486h-7.544v-1.692c4.141-4.214,5.149-5.348,5.149-7.059c0-1.116-0.702-1.765-1.747-1.765
c-0.954,0-1.584,0.396-2.323,1.279l-1.422-1.117c0.972-1.26,2.25-1.98,3.925-1.98c2.503,0,3.943,1.513,3.943,3.403
c0,2.053-1.17,3.547-4.916,7.112h5.186L33.057,35.486z"></path>
</g>
<g id="tabs-03-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M28.889,35.757c-1.656,0-2.989-0.612-3.925-1.747l1.314-1.242c0.738,0.828,1.531,1.188,2.485,1.188
c1.296,0,2.143-0.774,2.143-2.035c0-1.44-0.81-1.944-2.179-1.944h-0.954l0.27-1.639h0.648c1.135,0,1.945-0.647,1.945-1.836
c0-0.99-0.702-1.585-1.783-1.585c-0.936,0-1.674,0.343-2.431,1.062l-1.17-1.278c1.081-1.026,2.341-1.549,3.799-1.549
c2.503,0,3.835,1.404,3.835,3.079c0,1.513-0.936,2.467-2.358,2.845c1.512,0.145,2.755,1.08,2.755,2.953
C33.282,34.1,31.662,35.757,28.889,35.757z"></path>
</g>
<g id="tabs-04-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.062,1.264-3.062,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M33.967,32.714h-1.459v2.772h-2.25v-2.772h-5.149v-1.585l3.528-7.994l1.963,0.738l-3.097,7.076h2.772l0.234-3.043h1.998v3.043
h1.459V32.714z"></path>
</g>
<g id="tabs-05-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.062,1.264-3.062,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M28.943,35.757c-1.692,0-2.881-0.685-3.817-1.711l1.332-1.242c0.648,0.756,1.423,1.17,2.431,1.17c1.351,0,2.197-0.864,2.197-2.431
c0-1.674-0.828-2.25-1.944-2.25c-0.559,0-1.009,0.126-1.566,0.414h-1.639v-6.338h7.021l-0.27,1.71h-4.537v3.007
c0.611-0.306,1.242-0.45,1.836-0.45c2.017,0,3.476,1.44,3.476,3.907C33.463,34.028,31.68,35.757,28.943,35.757z"></path>
</g>
<g id="tabs-06-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.397-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M29.861,29.095c-0.828,0-1.584,0.485-2.143,1.242
c0.036,2.593,0.595,3.709,1.98,3.709c1.225,0,1.818-1.062,1.818-2.646C31.518,29.671,30.888,29.095,29.861,29.095z"></path>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M29.699,35.757c-3.097,0-4.375-2.396-4.375-5.87c0-4.051,1.891-6.734,4.97-6.734c1.062,0,1.944,0.307,2.646,0.774l-0.864,1.423
c-0.522-0.307-1.099-0.486-1.746-0.486c-1.531,0-2.503,1.458-2.629,3.889c0.773-0.936,1.692-1.332,2.719-1.332
c1.891,0,3.421,1.368,3.421,3.943C33.841,33.902,32.148,35.757,29.699,35.757z"></path>
</g>
</g>
<g id="tabs-07-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.062,1.264-3.062,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M33.165,24.989l-4.483,10.731l-2.106-0.685l4.213-9.885h-5.113v-1.782h7.49V24.989z"></path>
</g>
<g id="tabs-08-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M29.366,29.995l-0.558-0.198
c-0.972,0.521-1.458,1.296-1.458,2.395c0,1.152,0.829,1.854,2.125,1.854c1.351,0,2.107-0.774,2.107-1.818
C31.581,31.093,30.986,30.589,29.366,29.995z"></path>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M29.564,28.284l0.342,0.126c0.954-0.594,1.296-1.188,1.296-2.053
c0-0.954-0.594-1.584-1.729-1.584c-1.044,0-1.729,0.54-1.729,1.603C27.745,27.402,28.394,27.852,29.564,28.284z"></path>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M29.42,35.757c-2.719,0-4.394-1.531-4.394-3.493c0-1.477,0.864-2.449,2.305-3.062c-1.296-0.702-1.818-1.674-1.818-2.862
c0-1.98,1.801-3.188,3.961-3.188c2.143,0,3.961,1.081,3.961,3.098c0,1.116-0.63,2.034-1.999,2.736
c1.656,0.738,2.485,1.801,2.485,3.241C33.921,34.208,32.175,35.757,29.42,35.757z"></path>
</g>
</g>
<g id="tabs-09-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M29.411,24.863c-1.17,0-1.908,0.811-1.908,2.358
c0,1.656,0.756,2.305,1.729,2.305c0.828,0,1.53-0.45,2.07-1.242C31.337,25.781,30.761,24.863,29.411,24.863z"></path>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M26.602,35.937l-0.486-1.639c3.025-0.792,4.753-1.963,5.078-4.357c-0.576,0.738-1.422,1.261-2.593,1.261
c-1.873,0-3.403-1.494-3.403-3.943c0-2.539,1.873-4.105,4.213-4.105c2.809,0,4.25,1.909,4.25,4.699
C33.66,32.84,31.463,34.784,26.602,35.937z"></path>
</g>
</g>
<g id="tabs-10-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M33.506,24.899c-1.332,0-1.962,1.188-1.962,4.537
c0,3.385,0.63,4.573,1.962,4.573c1.333,0,1.963-1.152,1.963-4.573C35.469,26.033,34.838,24.899,33.506,24.899z"></path>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M26.648,35.486h-2.269v-9.795l-2.701,1.639l-1.008-1.549l3.943-2.412h2.035V35.486z M33.506,35.757
c-2.845,0-4.339-2.27-4.339-6.32c0-4.033,1.495-6.284,4.339-6.284c2.863,0,4.339,2.251,4.339,6.284
C37.845,33.487,36.369,35.757,33.506,35.757z"></path>
</g>
</g>
<g id="tabs-11-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M27.755,35.486h-2.269v-9.795l-2.701,1.639l-1.008-1.549l3.943-2.412h2.035V35.486z M35.855,35.486h-2.269v-9.795l-2.701,1.639
l-1.008-1.549l3.943-2.412h2.035V35.486z"></path>
</g>
<g id="tabs-12-svg" visibility="hidden">
<g>
<g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M16.515,20.219c0-1.864,1.533-3.718,3.398-3.718h13.679
c-0.176-1.671-1.596-2.786-3.341-2.786H16.746c-1.864,0-3.062,1.264-3.062,3.128v13.504c0,1.739,1.162,3.154,2.83,3.339V20.219z"></path>
</g>
</g>
<path class="tabs-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#231815" d="M36.813,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297
c0,1.968,1.748,3.332,3.716,3.332h14.485c1.969,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.813,18.595z
M27.243,35.486h-2.27v-9.795l-2.7,1.639l-1.009-1.549l3.943-2.412h2.035V35.486z M37.107,35.486h-7.544v-1.692
c4.141-4.214,5.149-5.348,5.149-7.059c0-1.116-0.702-1.765-1.747-1.765c-0.954,0-1.584,0.396-2.322,1.279l-1.423-1.117
c0.973-1.26,2.251-1.98,3.926-1.98c2.502,0,3.942,1.513,3.942,3.403c0,2.053-1.17,3.547-4.915,7.112h5.186L37.107,35.486z"></path>
</g>
</svg>
</div>
</li>
<li id="new-tab-button-block" data-tips="WB_LT_TIPS_OPEN_A_NEW_TAB" data-colorbar="blue">
<div id="new-tab-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="new-tab-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="new-tab-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M33.59,16.501c-0.176-1.671-1.595-2.786-3.341-2.786H16.746
c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.738,1.162,3.154,2.83,3.339V20.219c0-1.864,1.534-3.718,3.398-3.718H33.59z
M36.814,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297c0,1.968,1.748,3.332,3.716,3.332h14.485
c1.968,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.814,18.595z M35.394,30.061
c0,0.499-0.405,1.127-0.904,1.127h-3.981v4.006c0,0.499-0.602,0.904-1.102,0.904h-0.524c-0.5,0-1.189-0.405-1.189-0.904v-4.006
h-4c-0.5,0-0.904-0.628-0.904-1.127v-0.452c0-0.5,0.405-1.232,0.904-1.232h4v-3.982c0-0.5,0.689-0.904,1.189-0.904h0.524
c0.5,0,1.102,0.404,1.102,0.904v3.982h3.981c0.5,0,0.904,0.732,0.904,1.232V30.061z"></path>
</svg>
</div>
</li>
<li id="menu-button-block" data-tips="WB_LT_TIPS_MENU">
<div id="menu-button">
<!-- XXX: Replace the SVG to icon font -->
<svg id="menu-button-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="3 3 47 47" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="menu-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M36.783,16.15H17.217c-0.773,0-1.4,0.626-1.4,1.399v1.422
c0,0.773,0.627,1.4,1.4,1.4h19.566c0.773,0,1.4-0.627,1.4-1.4V17.55C38.183,16.776,37.557,16.15,36.783,16.15z M36.783,24.594
H17.217c-0.773,0-1.4,0.627-1.4,1.4v1.378c0,0.773,0.627,1.399,1.4,1.399h19.566c0.773,0,1.4-0.626,1.4-1.399v-1.378
C38.183,25.221,37.557,24.594,36.783,24.594z M36.783,33.672H17.217c-0.773,0-1.4,0.627-1.4,1.4v1.378
c0,0.773,0.627,1.399,1.4,1.399h19.566c0.773,0,1.4-0.626,1.4-1.399v-1.378C38.183,34.299,37.557,33.672,36.783,33.672z"></path>
</svg>
</div>
<ul id="menu-block">
<div>
<li id="history-block"><a id="history-tab" href="#" data-l10n-id="LT_SE_HISTORY"></a></li>
<li id="pocket-block"><a id="pocket-tab" href="#" data-l10n-id="pocket"></a></li>
<li id="private-window-block"><a id="private-window-tab" href="#" data-l10n-id="WB_LT_TIPS_NEW_PRIVATE_WINDOW"></a></li>
<!--IFDEF_FIREFOX_SYNC
<li id="fxsync-block"><a id="fxsync-tab" href="#" data-l10n-id="fxsync-sign-in-to-sync"></a></li>
ENDIF_FIREFOX_SYNC-->
<li id="settings-block"><a id="settings-tab" href="#" data-l10n-id="LT_APPS_SETTINGS"></a></li>
</div>
</ul>
</li>
</ul>
</li>
</ul>
<!-- bookmark animation -->
<div id="bookmark-button-anime">
<!-- XXX: Replace the SVG to icon font -->
<svg id="bookmark-button-anime-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 54 54" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<polygon class="bookmark-button-path" fill="#00CAF2" points="43.116,22.382 31.878,20.904 27,10.673 22.122,20.904 10.884,22.382 19.107,30.183 17.04,41.327
27,35.917 36.96,41.327 34.893,30.183"></polygon>
</svg>
</div>
<div id="show-bookmarks-button-anime">
<!-- XXX: Replace the SVG to icon font -->
<svg id="show-bookmarks-button-anime-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 54 54" x="0" y="0" preserveAspectRatio="xMidyMid meet">
<path class="show-bookmarks-button-path" fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M38.551,18.436h-4.794l-5.571-5.406l-5.581,5.406h-5.156
c-1.205,0-2.181,0.977-2.181,2.181v18.172c0,1.204,0.976,2.181,2.181,2.181h21.102c1.204,0,2.181-0.977,2.181-2.181V20.617
C40.731,19.413,39.755,18.436,38.551,18.436z M21.83,38.06h-4.363v-4.363h4.363V38.06z M21.833,31.521h-4.361v-4.361h4.361
V31.521z M21.833,24.978h-4.361v-4.361h4.361V24.978z M23.991,27.159h14.56v4.361h-14.56V27.159z M38.552,38.06H23.999v-4.363
h14.553V38.06z M38.542,24.968l-14.538,0.007v-4.356h14.548L38.542,24.968z"></path>
</svg>
</div>
<!-- web -->
<div id="web-block">
<!--
<iframe mozbrowser remote mozasyncpanzoom mozallowfullscreen id="browser_iframe" scrolling="yes"></iframe>
-->
</div>
<!-- scroll up down -->
<div id="scroll-u"></div>
<div id="scroll-d"></div>
<div id="awesomescreen">
<!-- awesomescreen tabview -->
<section id="tab-view">
<div id="tabview-panels">
<ul id="tab-site-list" role="listbox">
</ul>
</div>
</section>
<section id="top-sites">
<div id="top-default-panels">
<ul id="top-default-list">
<li id="default-top-list-0" class="top-default-item"></li>
<li id="default-top-list-1" class="top-default-item"></li>
<li id="default-top-list-2" class="top-default-item"></li>
<li id="default-top-list-3" class="top-default-item"></li>
<li id="default-top-list-4" class="top-default-item"></li>
<li id="default-top-list-5" class="top-default-item"></li>
<li id="default-top-list-6" class="top-default-item"></li>
<li id="default-top-list-7" class="top-default-item"></li>
<li id="default-top-list-8" class="top-default-item"></li>
</ul>
</div>
<div id="top-panels">
<ul id="top-site-list" role="listbox"></ul>
</div>
</section>
<!-- awesomescreen bookamrk,history-->
<section id="bookmark" tabindex="0"></section>
<section id="history" tabindex="0"></section>
<!-- private window -->
<div id="private-browsing-block">
<div id="private-browsing-panel">
<!-- image logo -->
<div id="private-browsing-img"></div>
<!-- title -->
<h1 id="private-browsing-title" data-l10n-id="WB_LT_SETTINGS_PRIVATE_BROWSING"></h1>
<!-- sum title -->
<h2 id="private-browsing-subtitle" data-l10n-id="WB_LT_PRIVATE_BROWSING_1"></h2>
<!-- info -->
<p class="private-browsing-text-block private-browsing-text" data-l10n-id="WB_LT_PRIVATE_BROWSING_2"></p>
<p class="private-browsing-text-block private-browsing-text" data-l10n-id="WB_LT_PRIVATE_BROWSING_3"></p>
<!-- more info -->
<div id="private-browsing-more-info">
<p class="private-browsing-text" data-l10n-id="WB_LT_PRIVATE_BROWSING_4"></p>
<a id="private-browsing-more-info-link" class="private-browsing-text" target="_blank" data-l10n-id="WB_LT_LEARN_MORE"></a>
</div>
</div>
</div>
<!-- awesomescreen alert dialog -->
<div id="dialog-area">
<div id="bmd-dialog">
<div id="message-area">
<div id="message-title" class="title-area"></div>
<div id="bmtitle-area">
<input id="input-area" value="" size="30" type="text" required pattern="\s*\S.*">
<div class="input-line"></div>
<div id="circle-img"></div>
</div>
<div id="check-area">
<div id="cbox-area">
<div id="check-box">
<div id="check-box-background"></div>
<img id="check-img" src="style/images/check-on.svg">
</div>
<div id="text-area" data-l10n-id="WB_LT_ALSO_PIN_TO_HOME">Also pin to home</div>
</div>
</div>
</div>
<div id="button-area">
<div id="bt-position">
<button class="awesomescreen-primary-button none" id="ok-button" data-l10n-id="LT_WB_OK">OK</button>
<button class="awesomescreen-default-button none" id="pinhome-button" data-l10n-id="LT_PIN_TO_HOME">Pin to HOME</button>
<button class="awesomescreen-default-button none" id="clhistory-button" data-l10n-id="WB_LT_CLEAR_HISTORY">Clear History</button>
<button class="awesomescreen-default-button none" id="remove-button" data-l10n-id="WB_LT_CLEAR_BROWSING_HISTORY">Clear All History</button>
<button class="awesomescreen-default-button none" id="remove-bookmark-button" data-l10n-id="WB_LT_REMOVE">Remove</button>
<button class="awesomescreen-default-button none" id="edit-button" data-l10n-id="LT_CL_EDIT">Edit</button>
<button class="awesomescreen-default-button none" id="sethome-button" data-l10n-id="WB_LT_SET_AS_HOMEPAGE">Set as Homepage</button>
<button class="awesomescreen-danger-button none" id="remove-topsite-button" data-l10n-id="WB_LT_REMOVE_FROM_TOP_SITES">Remove from Top Sites</button>
<button class="awesomescreen-primary-button none" id="rename-confirm-button" data-l10n-id="LT_WB_OK">OK</button>
<button class="awesomescreen-danger-button none" id="remove-confirm-button" data-l10n-id="WB_LT_REMOVE">Remove</button>
<button class="awesomescreen-danger-button none" id="clear-button" data-l10n-id="WB_LT_CLEAR">Clear</button>
<button class="awesomescreen-default-button none" id="cancel-button" data-l10n-id="LT_CANCEL">Cancel</button>
</div>
</div>
</div>
</div>
<div id="dialog-banner-message"></div>
<div id="pointer-img"><img src="style/images/img_cursor_arrow2x.png" width="64" height="64"></div>
<!-- awesomescreen loading -->
<div id="awesome-loading-icon">
<div class="awesomecircle awesomecircle-1"></div>
<div class="awesomecircle awesomecircle-2"></div>
</div>
</div>
<!-- authentication -->
<section id="http-authentication-dialog" role="region" class="hidden skin-organic">
<div id="http-authentication-dialog-wrap">
<div id="http-authentication-header">
<div id="http-authentication-key"></div>
<div id="http-authentication-message"></div>
</div>
<table id="http-authentication-body">
<tbody><tr>
<td><div class="http-authentication-title" data-l10n-id="LT_FILE_SHARING_DEVICE_USER">User</div></td>
<td>
<form class="http-authentication-input" id="http-authentication-username">
<input class="http-authentication-input-area" id="http-authentication-username-area" dir="auto" type="text">
<div class="input-line"></div>
<div id="http-authentication-username-clear" class="special-pointer"></div>
</form>
</td>
</tr>
<tr>
<td><div class="http-authentication-title" data-l10n-id="LT_FILE_SHARING_DEVICE_PASSWORD">Password</div></td>
<td>
<form class="http-authentication-input" id="http-authentication-password">
<input class="http-authentication-input-area" id="http-authentication-password-area" type="password">
<div class="input-line"></div>
<div id="http-authentication-password-clear" class="special-pointer"></div>
</form>
</td>
</tr>
</tbody></table>
<div id="http-authentication-button">
<button class="http-authentication-button" id="http-authentication-ok">
<span data-l10n-id="LT_WB_OK">OK</span>
</button>
<button class="http-authentication-button" id="http-authentication-cancel">
<span data-l10n-id="LT_CANCEL">Cancel</span>
</button>
</div>
</div>
</section>
<!-- dialog -->
<div id="browser-dialog-base" class="hide">
<div id="browser-dialog">
<div id="browser-dialog-title">
<p id="browser-dialog-title-text"></p>
</div>
<div id="browser-dialog-msg">
<p id="browser-dialog-msg-text"></p>
</div>
<form id="browser-dialog-input">
<input id="browser-dialog-input-area">
<div class="input-line"></div>
<div id="browser-dialog-input-clear"></div>
</form>
<div id="browser-dialog-margin"></div>
<div id="browser-dialog-button">
<button class="browser-dialog-button" id="browser-dialog-button2"></button>
<button class="browser-dialog-button" id="browser-dialog-button1"></button>
</div>
</div>
</div>
<!-- settings -->
<div role="region" id="settings-list" class="skin-organic">
<div id="settings-list-area">
<div id="settings-header">
<p id="settings-header-title" data-l10n-id="WB_LT_BROWSER_SETTINGS">Browser Settings</p>
</div>
<div id="settings-list-item">
<div id="settings-homepage">
<p id="settings-homepage-title" data-l10n-id="WB_LT_HOMEPAGE">Homepage</p>
<p id="settings-homepage-name"></p>
</div>
<div id="settings-search-engine">
<p id="settings-search-engine-title" data-l10n-id="WB_LT_SETTINGS_SEARCH_ENGINE">Search Engine</p>
<p id="settings-search-engine-name"></p>
<p id="settings-search-engine-icon"></p>
</div>
<div id="settings-clear-history">
<p id="settings-clear-history-title" data-l10n-id="WB_LT_CLEAR_BROWSING_HISTORY">Clear All History</p>
</div>
<div id="settings-clear-cookie">
<p id="settings-clear-cookie-title" data-l10n-id="WB_LT_CLEAR_STORED_DATA">Clear Cookies and Stored Data</p>
</div>
</div>
<!--IFDEF_FIREFOX_SYNC
<div id="fxsync-area">
<div id="fxsync-header">
<p data-l10n-id="fxsync">Firefox Sync</p>
</div>
<div id="fxsync-disabled">
<smart-button id="fxsync-sign-in-button" type="rounded-corner-text" data-l10n-id="fxsync-sign-in"></smart-button>
<p data-l10n-id="fxsync-sign-in-to-sync-description"></p>
<p data-l10n-id="fxsync-sign-in-to-sync-description-plus"></p>
</div>
<div id="fxsync-enabled" hidden>
<span id="fxsync-signed-in-as" data-l10n-id="fxsync-signed-in-as"></span>
<smart-button id="fxsync-sync-now-button" type="rounded-corner-text" data-l10n-id="fxsync-sync-now"></smart-button>
<smart-button id="fxsync-sign-out-button" type="rounded-corner-text" data-l10n-id="fxsync-sign-out"></smart-button>
<ul class="settings-horizontal-list">
<li class="settings-horizontal-list-item">
<input type="checkbox" id="fxsync-collection-bookmarks" class="settings-list-checkbox"></input>
<label for="fxsync-collection-bookmarks"></label>
<span data-l10n-id="fxsync-collections-bookmarks"></span>
</li>
<li class="settings-horizontal-list-item">
<input type="checkbox" id="fxsync-collection-history" class="settings-list-checkbox"></input>
<label for="fxsync-collection-history"></label>
<span data-l10n-id="fxsync-collections-history"></span>
</li>
</ul>
<p class="fine-print"><a id="fxsync-tos" data-l10n-id="fxsync-tos"></a></p>
<p class="fine-print"><a id="fxsync-privacy" data-l10n-id="fxsync-privacy"></a></p>
</div>
</div>
</div>
ENDIF_FIREFOX_SYNC-->
<div id="settings-dialog" class="hidden">
<div id="settings-dialog-homepage" class="hidden">
<div id="settings-dialog-homepage-header">
<p id="settings-dialog-homepage-header-title" data-l10n-id="WB_LT_SET_AS_HOMEPAGE">Set as Homepage</p>
</div>
<form id="settings-dialog-homepage-input">
<input id="settings-dialog-homepage-input-area" value="" type="url">
<div class="input-line"></div>
<div id="settings-dialog-homepage-clear"></div>
</form>
<button id="settings-dialog-homepage-default" data-l10n-id="WB_LT_RESTORE_TO_DEFAULT">Restore to default</button>
<div id="settings-dialog-homepage-button">
<button id="settings-dialog-homepage-cancel" data-l10n-id="LT_CANCEL">Cancel</button>
<button id="settings-dialog-homepage-ok" data-l10n-id="LT_WB_OK">OK</button>
</div>
</div>
<div id="settings-dialog-search" class="hidden">
<div id="settings-dialog-search-header">
<p id="settings-dialog-search-header-title" data-l10n-id="WB_LT_SETTINGS_SEARCH_ENGINE">Search Engine</p>
</div>
<div id="settings-dialog-search-select">
<div id="settings-dialog-search-select-list"></div>
</div>
<div id="settings-dialog-search-button">
<button id="settings-dialog-search-cancel" data-l10n-id="LT_CANCEL">Cancel</button>
<button id="settings-dialog-search-ok" data-l10n-id="LT_WB_OK">OK</button>
</div>
</div>
</div>
<div id="settings-banner-message"></div>
</div>
<!-- loading -->
<gaia-loading id="loading-icon">
<div class="circle circle-1"></div>
<div class="circle circle-2"></div>
</gaia-loading>
<!-- zoom banner -->
<div id="zoom-banner-message-block">
<div id="zoom-banner-message"></div>
</div>
<!-- pan cursor mode button -->
<div id="mode-button-block" data-mode="cursor" data-tips="WB_LT_PRESS_COLOR_KEY">
<div id="mode-button-panel">
<button id="pan-cursor-button"></button>
<h2 id="mode-button-title" data-l10n-id="WB_LT_CURSOR_MODE">Cursor Mode</h2>
<div id="pan-cursor-button-block" data-colorbar=""></div>
</div>
</div>
<div id="pan-cursor-banner-message" data-l10n-id="WB_LT_SWITCH_PAN_MODE">You have switched to Pan Mode</div>
<!-- search result -->
<div id="search-result">
<div id="search-result-list"></div>
</div>
</div>
<div id="block-r"></div>
<div id="block-l"></div>
<div id="block-d"></div>
<!-- scroll left right -->
<div id="scroll-l"></div>
<div id="scroll-r"></div>
<!-- Tooltip -->
<div id="tooltip-block"></div>
</body>
</html>

View file

@ -0,0 +1,412 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
/* exported AuthenticationDialog */
/**
* Handles mozbrowserusernameandpasswordrequired event and show
* authentication dialog.
* @namespace AuthenticationDialog
*/
var AuthenticationDialog = {
_confirmed: {},
focusElement: [],
focusIndex: {x:0, y:0},
/** Get all DOM elements when inited. */
getAllElements: function ad_getAllElements() {
var toCamelCase = function toCamelCase(str) {
return str.replace(/\-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
};
var elementIDs = [
'http-authentication-dialog',
'http-authentication-username', 'http-authentication-username-clear',
'http-authentication-password', 'http-authentication-password-clear',
'http-authentication-username-area', 'http-authentication-password-area',
'http-authentication-message',
'http-authentication-ok', 'http-authentication-cancel'];
// Loop and add element with camel style name to Modal Dialog attribute.
elementIDs.forEach(function createElementRef(name) {
this[toCamelCase(name)] = document.getElementById(name);
}, this);
},
currentEvents: {},
/** Initialization. Get elements and add listeners. */
init: function ad_init(bindToWindow) {
// Get all elements initially.
this.getAllElements();
this.boundToWindow = bindToWindow || false;
this.httpAuthenticationUsername.addEventListener('submit',
this.dialogInputSubmit.bind(this));
this.httpAuthenticationPassword.addEventListener('submit',
this.dialogInputSubmit.bind(this));
this.httpAuthenticationUsernameArea.addEventListener('blur',
this.dialogInputAreaBlur.bind(this));
this.httpAuthenticationPasswordArea.addEventListener('blur',
this.dialogInputAreaBlur.bind(this));
this.httpAuthenticationUsernameArea.addEventListener('focus',
this.dialogUsernameAreaFocus.bind(this));
this.httpAuthenticationPasswordArea.addEventListener('focus',
this.dialogPasswordAreaFocus.bind(this));
this.httpAuthenticationUsernameClear.addEventListener('mouseup',
this.clearUsername.bind(this));
this.httpAuthenticationUsernameClear.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.httpAuthenticationUsernameClear.tabIndex = 0;
this.httpAuthenticationPasswordClear.addEventListener('mouseup',
this.clearPassword.bind(this));
this.httpAuthenticationPasswordClear.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.httpAuthenticationPasswordClear.tabIndex = 0;
this.httpAuthenticationOk.addEventListener('mouseup', this);
this.httpAuthenticationOk.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.httpAuthenticationOk.tabIndex = 0;
this.httpAuthenticationCancel.addEventListener('mouseup', this);
this.httpAuthenticationCancel.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.httpAuthenticationCancel.tabIndex = 0;
},
/**
* Default event handler for mozbrowser event and click event.
* @param {Event} evt
* @param {String} origin Tab ID
*/
handleEvent: function ad_handleEvent(evt, origin) {
switch (evt.type) {
case 'mozbrowserusernameandpasswordrequired':
evt.preventDefault();
this.currentEvents[origin] = evt;
// Show authentication dialog only if
// the frame is currently displayed.
this.show(origin);
break;
case 'mouseup':
if (evt.currentTarget === this.httpAuthenticationCancel) {
this.focusIndex.x = 2;
this.focusIndex.y = 1;
this.cancelHandler();
} else {
this.focusIndex.x = 2;
this.focusIndex.y = 0;
this.confirmHandler();
}
break;
}
},
/**
* Show dialog and set message.
* @param {String} origin Tab ID
*/
show: function ad_show(origin) {
this.currentOrigin = origin;
var evt = this.currentEvents[origin];
this.httpAuthenticationDialog.classList.remove('hidden');
// XXX: We don't have a better way to detect login failed.
if (this._confirmed[origin]) {
//this.httpAuthenticationMessage.setAttribute('data-l10n-id',
//'the-username-or-password-is-incorrect');
//this.httpAuthenticationMessage.classList.add('error');
} else {
navigator.mozL10n.setAttributes(
this.httpAuthenticationMessage,
'WB_LT_AUTH_MESSAGE',
{
host: evt.detail.host,
msg: evt.detail.realm
}
);
/*
navigator.mozL10n.setAttributes(this.httpAuthenticationMessage,
'http-authentication-message',
{ host: evt.detail.host });
*/
this.httpAuthenticationMessage.classList.remove('error');
}
Browser.switchCursorMode(false);
this.httpAuthenticationUsername.classList.remove('exfocus');
this.httpAuthenticationPassword.classList.remove('exfocus');
this.httpAuthenticationUsername.classList.remove('input');
this.httpAuthenticationPassword.classList.remove('input');
this.httpAuthenticationUsernameArea.value = '';
this.httpAuthenticationPasswordArea.value = '';
this.httpAuthenticationUsernameArea.focus();
this.focusElement[0] = [];
this.focusElement[0][0] = this.httpAuthenticationUsernameArea;
this.focusElement[0][1] = this.httpAuthenticationUsernameClear;
this.focusElement[1] = [];
this.focusElement[1][0] = this.httpAuthenticationPasswordArea;
this.focusElement[1][1] = this.httpAuthenticationPasswordClear;
this.focusElement[2] = [];
this.focusElement[2][0] = this.httpAuthenticationOk;
this.focusElement[2][1] = this.httpAuthenticationCancel;
this.focusIndex.x = 0;
this.focusIndex.y = 0;
},
/** Hide authentication dialog. */
hide: function ad_hide() {
var evt = this.currentEvents[this.currentOrigin];
if (!evt) {
return;
}
this.httpAuthenticationDialog.classList.add('hidden');
this.currentOrigin = null;
},
clearUsername: function ad_clearUsername() {
this.focusIndex.x = 0;
this.focusIndex.y = 1;
this.httpAuthenticationUsernameArea.value = '';
},
clearPassword: function ad_clearPassword() {
this.focusIndex.x = 1;
this.focusIndex.y = 1;
this.httpAuthenticationPasswordArea.value = '';
},
dialogButtonKeyup: function ad_dialogButtonKeyup(evt) {
if( evt ) evt.preventDefault();
switch( evt.keyCode ) {
case KeyEvent.DOM_VK_RETURN :
var elm = document.activeElement;
elm.classList.remove('active');
var dEvt = document.createEvent("MouseEvents");
dEvt.initMouseEvent("mouseup", true, true, window, 0, 0, 0, 0, 0,
false, false, false, false, 0, elm);
elm.dispatchEvent( dEvt );
break;
}
},
dialogInputSubmit: function ad_dialogInputSubmit(evt) {
if( evt ) evt.preventDefault();
this.dialogInputAreaBlur(evt);
},
dialogInputAreaBlur: function ad_dialogInputBlur(evt) {
if(Awesomescreen.pointerImg.style.display == 'none') {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
}
if (evt.currentTarget === this.httpAuthenticationUsernameArea) {
this.focusIndex.x = 0;
this.focusIndex.y = 0;
this.httpAuthenticationUsername.classList.remove('input');
this.httpAuthenticationUsername.classList.add('exfocus');
} else if(evt.currentTarget === this.httpAuthenticationPasswordArea) {
this.focusIndex.x = 1;
this.focusIndex.y = 0;
this.httpAuthenticationPassword.classList.remove('input');
this.httpAuthenticationPassword.classList.add('exfocus');
}
Awesomescreen.focusImgFunc(this.focusElement[this.focusIndex.x][this.focusIndex.y]);
},
dialogUsernameAreaFocus: function ad_dialogUsernameAreaFocus(evt) {
if( evt ) evt.preventDefault();
this.httpAuthenticationUsername.classList.add('input');
this.httpAuthenticationUsername.classList.remove('exfocus');
},
dialogPasswordAreaFocus: function ad_dialogPasswordAreaFocus(evt) {
if( evt ) evt.preventDefault();
this.httpAuthenticationPassword.classList.add('input');
this.httpAuthenticationPassword.classList.remove('exfocus');
},
/**
* When user clicks OK button on authentication dialog,
* authenticate user.
*/
confirmHandler: function ad_confirmHandler() {
var evt = this.currentEvents[this.currentOrigin];
evt.detail.authenticate(this.httpAuthenticationUsernameArea.value,
this.httpAuthenticationPasswordArea.value);
this.httpAuthenticationUsername.classList.remove('exfocus');
this.httpAuthenticationPassword.classList.remove('exfocus');
this.httpAuthenticationDialog.classList.add('hidden');
// To remember we had ever logged in.
this._confirmed[this.currentOrigin] = true;
delete this.currentEvents[this.currentOrigin];
Browser.switchCursorMode(true);
Awesomescreen.pointerImg.style.display = 'none';
},
/**
* When user clicks cancel button on authentication dialog or
* when the user try to escape the dialog with the escape key,
* cancel authentication.
*/
cancelHandler: function ad_cancelHandler() {
var evt = this.currentEvents[this.currentOrigin];
evt.detail.cancel();
if (this._confirmed[this.currentOrigin]) {
delete this._confirmed[this.currentOrigin];
}
delete this.currentEvents[this.currentOrigin];
this.httpAuthenticationUsername.classList.remove('exfocus');
this.httpAuthenticationPassword.classList.remove('exfocus');
this.httpAuthenticationDialog.classList.add('hidden');
Browser.switchCursorMode(true);
Awesomescreen.pointerImg.style.display = 'none';
},
/**
* Check if the specified tab currently has any event.
* @param {String} origin Tab ID
*/
originHasEvent: function(origin) {
return origin in this.currentEvents;
},
/**
* Clear events of the specified tab ID.
* @param {String} origin Tab ID
*/
clear: function ad_clear(origin) {
if (this.currentEvents[origin]) {
delete this.currentEvents[origin];
}
},
/**
* Authentication dialog displays a confirmation.
*/
isDisplayed: function is_displayed() {
return !this.httpAuthenticationDialog.classList.contains('hidden');
},
moveFocus: function ad_moveFocus(xd, yd) {
if(xd < 0 || yd < 0) {
return;
}
if( (!this.focusElement[xd]) || (!this.focusElement[xd][yd]) ) {
return;
}
var opt = null;
var flg = false;
this.focusIndex.x = xd;
this.focusIndex.y = yd;
if(Awesomescreen.pointerImg.style.display == 'none') {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
flg = true;
}
document.activeElement.blur();
if(this.focusElement[this.focusIndex.x][this.focusIndex.y].id == 'http-authentication-username-area') {
this.httpAuthenticationPassword.classList.remove('exfocus');
if( !this.httpAuthenticationUsername.classList.contains('exfocus') ) {
this.httpAuthenticationUsername.classList.add('exfocus');
}
} else if(this.focusElement[this.focusIndex.x][this.focusIndex.y].id == 'http-authentication-username-clear') {
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
this.httpAuthenticationPassword.classList.remove('exfocus');
if( !this.httpAuthenticationUsername.classList.contains('exfocus') ) {
this.httpAuthenticationUsername.classList.add('exfocus');
}
if( flg ) opt = Awesomescreen.DEFAULT_EXCLEAR;
} else if(this.focusElement[this.focusIndex.x][this.focusIndex.y].id == 'http-authentication-password-area') {
this.httpAuthenticationUsername.classList.remove('exfocus');
if( !this.httpAuthenticationPassword.classList.contains('exfocus') ) {
this.httpAuthenticationPassword.classList.add('exfocus');
}
} else if(this.focusElement[this.focusIndex.x][this.focusIndex.y].id == 'http-authentication-password-clear') {
this.httpAuthenticationUsername.classList.remove('exfocus');
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
if( !this.httpAuthenticationPassword.classList.contains('exfocus') ) {
this.httpAuthenticationPassword.classList.add('exfocus');
}
if( flg ) opt = Awesomescreen.DEFAULT_EXCLEAR;
} else {
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
this.httpAuthenticationUsername.classList.remove('exfocus');
this.httpAuthenticationPassword.classList.remove('exfocus');
}
Awesomescreen.focusImgFunc(this.focusElement[this.focusIndex.x][this.focusIndex.y], opt);
},
handleKeyEvent: function ad_handleKeyEvent(evt) {
if( !this.isDisplayed() ) return false;
if( document.activeElement.nodeName == 'INPUT' ) {
return true;
}
switch( evt.keyCode ) {
case KeyEvent.DOM_VK_LEFT :
evt.preventDefault();
this.moveFocus(this.focusIndex.x, this.focusIndex.y-1);
break;
case KeyEvent.DOM_VK_RIGHT :
evt.preventDefault();
this.moveFocus(this.focusIndex.x, this.focusIndex.y+1);
break;
case KeyEvent.DOM_VK_UP :
evt.preventDefault();
if( this.focusIndex.x == 2 ) {
this.moveFocus(this.focusIndex.x-1, 0);
} else {
this.moveFocus(this.focusIndex.x-1, this.focusIndex.y);
}
break;
case KeyEvent.DOM_VK_DOWN :
evt.preventDefault();
if( this.focusIndex.x == 1 ) {
this.moveFocus(this.focusIndex.x+1, 0);
} else {
this.moveFocus(this.focusIndex.x+1, this.focusIndex.y);
}
break;
case KeyEvent.DOM_VK_RETURN :
evt.preventDefault();
if((this.focusIndex.x == 0 && this.focusIndex.y == 0) ||
(this.focusIndex.x == 1 && this.focusIndex.y == 0)) {
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
Awesomescreen.pointerImg.style.display = 'none';
} else {
document.activeElement.classList.remove('active');
document.activeElement.classList.add('active');
}
break;
case KeyEvent.DOM_VK_BACK_SPACE :
this.cancelHandler();
return true;
default :
return false;
}
return true;
}
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,239 @@
/* globals BrowserDB, SyncBrowserDB, SyncManagerBridge */
'use strict';
(function(exports){
//IFDEF_FIREFOX_SYNC
/**
* The root folder id of synced bookmark data.
* @type {String}
*/
const SYNC_BOOKMARK_ROOT_FOLDER_ID = 'places';
/**
* The mobile folder id of synced bookmark data.
* @type {String}
*/
const SYNC_BOOKMARK_MOBILE_FOLDER_ID = 'mobile';
//ENDIF_FIREFOX_SYNC
// TODO: for the live time bookmark data loading task.
var BookmarkStore = {
isSynced: false,
cache: [],
currentFolder : null,
//IFDEF_FIREFOX_SYNC
syncBookmarkRootFolderCache: {
id: SYNC_BOOKMARK_ROOT_FOLDER_ID,
title: '',
type: 'folder',
readOnly: true
},
syncBookmarkMobileFolderCache: {
id: SYNC_BOOKMARK_MOBILE_FOLDER_ID,
title: '',
type: 'folder',
readOnly: true
},
//ENDIF_FIREFOX_SYNC
init: function () {
//IFDEF_FIREFOX_SYNC
var l10nPromises = [];
l10nPromises
.push(navigator.mozL10n.formatValue('fxsync-desktop-bookmarks'));
l10nPromises
.push(navigator.mozL10n.formatValue('fxsync-mobile-bookmarks'));
Promise.all(l10nPromises).then(
([l10nFxsyncDesktopBookmarks, l10nFxsyncMobileBookmarks]) => {
this.syncBookmarkRootFolderCache.title = l10nFxsyncDesktopBookmarks;
this.syncBookmarkMobileFolderCache.title = l10nFxsyncMobileBookmarks;
}
);
//ENDIF_FIREFOX_SYNC
},
reset: function(cb) {
this.cache = [];
this.currentFolder = null;
return new Promise(resolve => {
//IFNDEF_FIREFOX_SYNC
resolve();
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
SyncManagerBridge.getInfo().then(message => {
if (message.state === 'enabled' || message.state === 'syncing') {
this.isSynced = true;
} else {
this.isSynced = false;
}
resolve();
});
//ENDIF_FIREFOX_SYNC
});
},
getByRange: function(start, num, folderId, cb) {
var self = this;
function getCaches(){
var length = (start + num) > self.cache.length ?
(self.cache.length - start) : (start + num);
var result = [];
for(var i = start; i < length; i++) {
result.push(self.cache[i]);
}
return result;
}
if(folderId !== this.currentFolder) {
this.currentFolder = folderId;
this.updateCache().then(() => {
cb(getCaches());
});
} else {
cb(getCaches());
}
},
getByIndex: function(index, folderId, cb) {
var self = this;
function getCache(){
var result = null;
if(index >= 0 && index < self.cache.length) {
result = self.cache[index];
}
return result;
}
if(folderId !== this.currentFolder) {
this.currentFolder = folderId;
this.updateCache().then(() => {
cb(getCache());
});
} else {
cb(getCache());
}
},
//IFDEF_FIREFOX_SYNC
_createRootFolderCache: function () {
var self = this;
// We query remote bookmarks by parentid with
// SYNC_BOOKMARK_ROOT_FOLDER_ID for checking if the indexedDB has
// remote bookmark data. If there is any remote data, we create a
// folder item to show the synced bookmark.
function getPlacesBookmarks() {
return new Promise(resolve => {
SyncBrowserDB.getBookmark({
parentid: SYNC_BOOKMARK_ROOT_FOLDER_ID
}, syncPlacesBookmarks => {
if(syncPlacesBookmarks.length > 0) {
self.cache.push(self.syncBookmarkRootFolderCache);
}
resolve();
});
});
}
// If there is mobile folder and also has children in it,
// create a folder item to show the synced mobile bookmark
function getMobileBookmarks() {
return new Promise(resolve => {
SyncBrowserDB.getBookmark({
parentid: SYNC_BOOKMARK_MOBILE_FOLDER_ID
}, syncMobileBookmarks => {
if(syncMobileBookmarks.length > 0) {
self.cache.push(self.syncBookmarkMobileFolderCache);
}
resolve();
});
});
}
// get bookmark data from origin indexdDB
function getLocalBookmarks() {
return new Promise(resolve => {
BrowserDB.getBookmarks(localBookmarks => {
if(localBookmarks.length > 0) {
self.cache = self.cache.concat(localBookmarks);
}
resolve();
});
});
}
return getPlacesBookmarks()
.then(getMobileBookmarks)
.then(getLocalBookmarks);
},
_updateFolderCache: function () {
return new Promise(resolve => {
SyncBrowserDB.getBookmark({
parentid: this.currentFolder
}, syncBookmark => {
var length = syncBookmark.length,
bookmark = null;
for(var i = 0; i < length; i++) {
bookmark = syncBookmark[i];
//hide mobile folder in sync bookmark folder
if(this.currentFolder === SYNC_BOOKMARK_ROOT_FOLDER_ID &&
bookmark.id === SYNC_BOOKMARK_MOBILE_FOLDER_ID) {
continue;
}
// XXX: Now we only support two types: folder and bookmark.
// And the data from firefox sync can't be modified.
if(bookmark.type === 'folder' && bookmark.title) {
bookmark.readOnly = true;
this.cache.push(bookmark);
} else if (bookmark.type === 'bookmark') {
bookmark.uri = bookmark.bmkUri;
bookmark.readOnly = true;
this.cache.push(bookmark);
}
}
resolve();
});
});
},
//ENDIF_FIREFOX_SYNC
updateCache: function(){
this.cache = [];
return new Promise(resolve => {
if(!this.isSynced) {
// Get bookmark data from origin indexedDB
BrowserDB.getBookmarks(bookmarks => {
this.cache = bookmarks;
resolve();
});
} else {
//IFNDEF_FIREFOX_SYNC
resolve();
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
if(!this.currentFolder) {
this._createRootFolderCache().then(resolve);
} else {
this._updateFolderCache().then(resolve);
}
//ENDIF_FIREFOX_SYNC
}
});
}
};
exports.BookmarkStore = BookmarkStore;
})(window);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,607 @@
/* global Awesomescreen */
/* global Browser */
/* global BrowserDB */
/* global KeyEvent */
/* global Settings */
'use strict';
/**
* The dialog listen to mozbrowsershowmodalprompt event.
* (alert/confirm/prompt)
*
* @namespace Dialog
*/
var BrowserDialog = {
// Dialog Event
dialogEvt: null,
browserDialogInputArea: null,
PORT_MIN: 0,
PORT_MAX: 65535,
focusElement: [],
focusIndex: {x:0, y:0},
defaultFocusIndex: {x:0, y:0},
deferredActions: new Map(),
/** Get all elements when inited. */
getAllElements: function dialog_getAllElements() {
var toCamelCase = function toCamelCase(str) {
return str.replace(/\-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
};
var elementIDs = [
'browser-dialog-base', 'browser-dialog',
'browser-dialog-title', 'browser-dialog-msg',
'browser-dialog-input',
'browser-dialog-input-area',
'browser-dialog-input-clear',
'browser-dialog-button',
'browser-dialog-button1', 'browser-dialog-button2',
];
// Loop and add element with camel style name to Dialog attribute.
elementIDs.forEach(function createElementRef(name) {
this[toCamelCase(name)] = document.getElementById(name);
}, this);
},
/** Initialization. Get DOM elements and add listeners. */
init: function dialog_init() {
// Get all elements initially.
this.getAllElements();
this.browserDialogBase.addEventListener('mouseup',
this.dialogBaseClick.bind(this));
// Add event listener(dialog)
this.browserDialogButton1.addEventListener('mouseup',
this.dialogButton1.bind(this));
this.browserDialogButton1.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.browserDialogButton2.addEventListener('mouseup',
this.dialogButton2.bind(this));
this.browserDialogButton2.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.browserDialogInput.addEventListener('submit',
this.dialogInput.bind(this));
this.browserDialogInputClear.addEventListener('mouseup',
this.dialogInputClear.bind(this));
this.browserDialogInputClear.addEventListener('keyup',
this.dialogButtonKeyup.bind(this));
this.browserDialogInputArea.addEventListener('blur',
this.dialogInputAreaBlur.bind(this));
this.browserDialogInputArea.addEventListener('focus',
this.dialogInputAreaFocus.bind(this));
this.browserDialogInputArea.addEventListener('mousedown',
this.dialogInputAreaClick.bind(this));
},
/**
* create Dialog
*/
createDialog: function dialog_createDialog(type, evt) {
var opt;
this.cancelDialog();
if( evt != null ) {
evt.preventDefault();
}
this.dialogEvt = evt;
this.browserDialogBase.classList.remove('hide');
this.browserDialogBase.dataset.type = type;
var promise;
switch(type) {
case 'del_cookie':
opt = {
title: null,
msg: 'WB_LT_CONFIRM_DELETE_COOKIES',
bt1: 'LT_CANCEL',
bt2: 'WB_LT_CLEAR'
};
break;
case 'clear_history':
opt = {
title: null,
msg: 'WB_LT_CLEAR_ALL_HISTORY',
bt1: 'LT_CANCEL',
bt2: 'WB_LT_CLEAR'
};
break;
case 'max_bookmark':
opt = {
title: null,
msg: 'WB_LT_BOOKMARK_ERROR_1',
bt1: 'LT_CANCEL',
bt2: null
};
break;
case 'alert':
opt = {
title: null,
msg: {raw: evt.detail.message},
bt1: 'LT_WB_OK',
bt2: null
};
break;
case 'prompt':
opt = {
title: null,
msg: {raw: evt.detail.message},
bt1: 'LT_CANCEL',
bt2: 'LT_WB_OK'
};
break;
case 'confirm':
opt = {
title: null,
msg: {raw: evt.detail.message},
bt1: 'LT_CANCEL',
bt2: 'LT_WB_OK'
};
break;
//IFDEF_FIREFOX_SYNC
case 'signout_confirm':
opt = {
title: 'fxsync-confirm-sign-out-title',
msg: 'fxsync-confirm-sign-out-message',
bt1: 'LT_CANCEL',
bt2: 'fxsync-sign-out'
};
var deferred = {};
deferred.promise = new Promise(function(resolve, reject) {
deferred.resolve = resolve;
deferred.reject = reject;
});
promise = deferred.promise;
this.deferredActions.set('signout_confirm', deferred);
break;
//ENDIF_FIREFOX_SYNC
default:
return;
}
Browser.switchCursorMode(false);
// title
if (opt.title) {
this.browserDialogTitle.setAttribute('data-l10n-id', opt.title);
} else {
this.browserDialogTitle.removeAttribute('data-l10n-id');
this.browserDialogTitle.textContent = '';
}
// msg
if(opt.msg) {
if (typeof opt.msg === 'string') {
this.browserDialogMsg.setAttribute('data-l10n-id', opt.msg);
} else if (opt.msg.hasOwnProperty('raw')) {
this.browserDialogMsg.innerHTML = opt.msg.raw.replace(/\\n/g, '<br>');
}
} else {
this.browserDialogMsg.removeAttribute('data-l10n-id');
this.browserDialogMsg.textContent = '';
}
var countIndex = 0;
this.focusElement = [];
this.focusElement[0] = [];
this.focusElement[1] = [];
this.defaultFocusIndex = {x:0, y:0};
// button1
if(opt.bt1) {
this.browserDialogButton1.blur();
this.browserDialogButton1.setAttribute('data-l10n-id', opt.bt1);
this.browserDialogButton1.dataset.type = type;
this.browserDialogButton1.classList.add('visible');
}
// button2
if(opt.bt2) {
this.browserDialogButton2.blur();
this.browserDialogButton2.setAttribute('data-l10n-id', opt.bt2);
this.browserDialogButton2.dataset.type = type;
this.browserDialogButton2.classList.add('visible');
}
var width = Browser.SCREEN_WIDTH;
if( Browser.sideBlock.dataset.sidebar == 'true' ) {
width -= Browser.SIDE_WINDOW_WIDTH;
}
if(type == 'prompt') {
this.browserDialogInput.style.display = 'block';
this.browserDialogInput.classList.remove('exfocus');
this.browserDialogInput.classList.remove('input');
this.browserDialogInputClear.tabIndex = 0;
countIndex = 0;
this.focusElement[1][countIndex++] = this.browserDialogInputArea;
this.focusElement[1][countIndex++] = this.browserDialogInputClear;
//this.browserDialogInput.insertBefore(this.browserDialogInputArea,
// this.browserDialogInputClear);
this.browserDialogInputArea.type = 'text';
this.browserDialogInputArea.value = '';
} else {
this.browserDialogInput.style.display = 'none';
}
// initialize position
countIndex = 0;
if(opt.bt1 && opt.bt2) {
this.defaultFocusIndex.x = 0;
this.defaultFocusIndex.y = 0;
this.focusIndex.x = 0;
//IFDEF_FIREFOX_SYNC
if(type === 'signout_confirm') {
this.focusIndex.y = 0;
this.focusElement[0][countIndex++] = this.browserDialogButton1;
this.focusElement[0][countIndex++] = this.browserDialogButton2;
} else {
this.focusIndex.y = 1;
this.focusElement[0][countIndex++] = this.browserDialogButton2;
this.focusElement[0][countIndex++] = this.browserDialogButton1;
}
//ENDIF_FIREFOX_SYNC
//IFNDEF_FIREFOX_SYNC
this.focusIndex.y = 1;
this.focusElement[0][countIndex++] = this.browserDialogButton2;
this.focusElement[0][countIndex++] = this.browserDialogButton1;
//ENDIF_FIREFOX_SYNC
} else if(opt.bt1) {
this.defaultFocusIndex.x = 0;
this.defaultFocusIndex.y = 0;
this.focusIndex.x = 0;
this.focusIndex.y = 0;
this.focusElement[0][countIndex++] = this.browserDialogButton1;
}
Awesomescreen.focusImgFunc(
this.focusElement[this.focusIndex.x][this.focusIndex.y]);
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
return promise;
},
isDisplayed: function dialog_isDisplayed() {
return !this.browserDialogBase.classList.contains('hide');
},
dialogBaseClick: function dialog_dialogBaseClick(evt) {
if( evt ) {
evt.stopPropagation();
}
},
dialogButtonKeyup: function dialog_dialogButton1Keyup(evt) {
if( evt ) {
evt.preventDefault();
}
switch( evt.keyCode ) {
case KeyEvent.DOM_VK_RETURN :
var elm = document.activeElement;
elm.classList.remove('active');
var dEvt = document.createEvent('MouseEvents');
dEvt.initMouseEvent('mouseup', true, true, window, 0, 0, 0, 0, 0,
false, false, false, false, 0, elm);
elm.dispatchEvent( dEvt );
break;
}
},
completeDeferredAction: function(type, resolution) {
if (!this.deferredActions.has(type)) {
return;
}
this.deferredActions.get(type)[resolution]();
this.deferredActions.delete(type);
},
dialogButton1: function dialog_dialogButton1(evt) {
if (evt) {
evt.preventDefault();
}
var type = this.browserDialogButton1.dataset.type;
switch(type) {
case 'del_cookie':
case 'clear_history':
case 'max_bookmark':
case 'alert':
case 'prompt':
case 'confirm':
case 'signout_confirm':
this.dialogButton2End(evt.currentTarget);
break;
default:
return;
}
this.completeDeferredAction(type, 'reject');
},
dialogButton2End: function dialog_dialogButton2End(target) {
// Animation end event
var end_event = (function() {
target.removeEventListener('transitionend', end_event, false);
BrowserDialog.cancelDialog();
});
target.addEventListener('transitionend', end_event, false);
},
dialogButton2: function dialog_dialogButton2(evt) {
if (evt) {
evt.preventDefault();
}
this.argEvt = evt.currentTarget;
var type = this.browserDialogButton2.dataset.type;
switch (type) {
case 'del_cookie':
var request = navigator.mozApps.getSelf();
request.onsuccess = function() {
var rtn = request.result.clearBrowserData();
rtn.onsuccess = function() {
//BrowserDialog.cancelDialog();
BrowserDialog.dialogButton2End(BrowserDialog.argEvt);
};
rtn.onerror = function() {
//BrowserDialog.cancelDialog();
BrowserDialog.dialogButton2End(BrowserDialog.argEvt);
Settings.clearCookieFailed();
};
};
request.onerror = function() {
//BrowserDialog.cancelDialog();
BrowserDialog.dialogButton2End(BrowserDialog.argEvt);
Settings.clearCookieFailed();
};
break;
case 'clear_history':
//BrowserDB.clearHistory(this.cancelDialog.bind(this));
BrowserDB.clearHistory(
function(){
BrowserDialog.dialogButton2End(BrowserDialog.argEvt);
}.bind(this));
Awesomescreen.selectTopSites();
break;
case 'prompt':
if (this.dialogEvt != null) {
this.dialogEvt.detail.returnValue = this.browserDialogInputArea.value;
if (this.dialogEvt.detail.unblock) {
this.dialogEvt.detail.unblock();
}
this.dialogEvt = null;
}
//this.cancelDialog();
this.dialogButton2End(this.argEvt);
break;
case 'confirm':
if (this.dialogEvt != null) {
this.dialogEvt.detail.returnValue = true;
if (this.dialogEvt.detail.unblock) {
this.dialogEvt.detail.unblock();
}
this.dialogEvt = null;
}
//this.cancelDialog();
this.dialogButton2End(this.argEvt);
break;
case 'signout_confirm':
BrowserDialog.dialogButton2End(BrowserDialog.argEvt);
break;
default:
break;
}
this.completeDeferredAction(type, 'resolve');
},
dialogInput: function dialog_dialogInput(evt) {
if( evt ) {
evt.preventDefault();
}
this.browserDialogInputArea.blur();
},
dialogInputAreaFocus: function dialog_dialogInputAreaFocus(evt) {
if( evt ) {
evt.preventDefault();
}
this.browserDialogInput.classList.add('input');
this.browserDialogInput.classList.remove('exfocus');
},
dialogInputClear: function dialog_dialogInputClear() {
this.browserDialogInputArea.value = '';
},
dialogInputAreaKeydown: function dialog_dialogInputKeydown(evt) {
if( evt ) {
evt.preventDefault();
}
switch( evt.keyCode ) {
case KeyEvent.DOM_VK_RETURN :
this.moveFocus(this.focusIndex.x+1, 0);
break;
}
},
dialogInputAreaClick: function dialog_dialogInputAreaClick(evt) {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
this.dialogInputAreaFocus();
this.focusIndex.x = 1;
this.focusIndex.y = 0;
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
Awesomescreen.pointerImg.style.display = 'none';
},
dialogInputAreaBlur: function dialog_dialogInputBlur() {
if(Awesomescreen.pointerImg.style.display == 'none') {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
}
BrowserDialog.browserDialogInput.classList.remove('input');
BrowserDialog.browserDialogInput.classList.add('exfocus');
var self = this;
setTimeout( function() {
self.focusIndex.x = 1;
self.focusIndex.y = 0;
Awesomescreen.focusImgFunc(self.browserDialogInputArea);
}, 1000);
},
/**
* cancel confirm dialog
*/
cancelDialog: function dialog_cancelDialog() {
if( !BrowserDialog.isDisplayed() ) {
return;
}
switch( BrowserDialog.browserDialogButton1.dataset.type ) {
case 'alert':
case 'prompt':
if( BrowserDialog.dialogEvt != null ) {
BrowserDialog.dialogEvt.detail.returnValue = null;
if( BrowserDialog.dialogEvt.detail.unblock ) {
BrowserDialog.dialogEvt.detail.unblock();
}
}
break;
case 'confirm':
if( BrowserDialog.dialogEvt != null ) {
BrowserDialog.dialogEvt.detail.returnValue = false;
if( BrowserDialog.dialogEvt.detail.unblock ) {
BrowserDialog.dialogEvt.detail.unblock();
}
}
break;
}
if( BrowserDialog.dialogEvt != null ) {
BrowserDialog.dialogEvt = null;
}
// hide dialog
if( BrowserDialog.browserDialogInputArea ) {
BrowserDialog.browserDialogInput.classList.remove('exfocus');
BrowserDialog.browserDialogInput.classList.remove('input');
}
BrowserDialog.browserDialogBase.classList.add('hide');
BrowserDialog.browserDialogButton1.classList.remove('visible');
BrowserDialog.browserDialogButton2.classList.remove('visible');
Browser.switchCursorMode(true);
Awesomescreen.pointerImg.style.display = 'none';
},
moveFocus: function dialog_moveFocus(xd, yd) {
if(!this.focusElement[xd]) {
return;
}
if(( xd < 0 || yd < 0 ) || ( !this.focusElement[xd][yd] )) {
if(( !this.browserDialogButton2.classList.contains('visible') ) &&
( Awesomescreen.pointerImg.style.display !== 'block' )) {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
var x = this.defaultFocusIndex.x;
var y = this.defaultFocusIndex.y;
this.focusIndex.x = x;
this.focusIndex.y = y;
Awesomescreen.focusImgFunc(this.focusElement[x][y]);
this.focusElement[x][y].focus();
}
return;
}
this.focusIndex.x = xd;
this.focusIndex.y = yd;
var opt = null;
var flg = false;
if(Awesomescreen.pointerImg.style.display == 'none') {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
flg = true;
}
document.activeElement.blur();
Awesomescreen.focusImgFunc(
this.focusElement[this.focusIndex.x][this.focusIndex.y], opt);
if(this.focusElement[this.focusIndex.x][this.focusIndex.y].nodeName ==
'INPUT') {
if( !this.browserDialogInput.classList.contains('exfocus') ) {
this.browserDialogInput.classList.add('exfocus');
}
} else if(this.focusElement[this.focusIndex.x][this.focusIndex.y].id ==
'browser-dialog-input-clear') {
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
if( !this.browserDialogInput.classList.contains('exfocus') ) {
this.browserDialogInput.classList.add('exfocus');
}
if( flg ) {
opt = Awesomescreen.DEFAULT_EXCLEAR;
}
} else {
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
this.browserDialogInput.classList.remove('exfocus');
}
},
handleKeyEvent: function dialog_handleKeyEvent(evt) {
if( !BrowserDialog.isDisplayed() ) {
return false;
}
if( document.activeElement.nodeName == 'INPUT' ) {
return true;
}
switch( evt.keyCode ) {
case KeyEvent.DOM_VK_LEFT :
evt.preventDefault();
this.moveFocus(this.focusIndex.x, this.focusIndex.y-1);
break;
case KeyEvent.DOM_VK_RIGHT :
evt.preventDefault();
this.moveFocus(this.focusIndex.x, this.focusIndex.y+1);
break;
case KeyEvent.DOM_VK_UP :
evt.preventDefault();
this.moveFocus(this.focusIndex.x+1, 0);
break;
case KeyEvent.DOM_VK_DOWN :
evt.preventDefault();
this.moveFocus(this.focusIndex.x-1, this.defaultFocusIndex.y);
break;
case KeyEvent.DOM_VK_RETURN :
evt.preventDefault();
if(this.focusIndex.x === 1 && this.focusIndex.y === 0) {
this.focusElement[this.focusIndex.x][this.focusIndex.y].focus();
Awesomescreen.pointerImg.style.display = 'none';
} else {
document.activeElement.classList.remove('active');
document.activeElement.classList.add('active');
}
break;
case KeyEvent.DOM_VK_BACK_SPACE :
BrowserDialog.cancelDialog();
return true;
default :
return false;
}
return true;
}
};

View file

@ -0,0 +1,77 @@
/* global ConnectionManager, ConnectionHandler, Browser,
UrlHelper, Awesomescreen */
'use strict';
(function(exports) {
var ConnectionHandler = function() {};
ConnectionHandler.prototype = {
_active: false,
_messageQueue: [],
init: function() {
this._connectionManager = new ConnectionManager();
this._connectionManager.init(['iac-webpage-open']);
this._connectionManager.on('view', this.preHandleMessage.bind(this));
},
preHandleMessage: function(detail) {
if (this._active) {
this._digestMessage();
this.openPage(detail.url);
} else {
this._messageQueue.push(detail);
}
},
_digestMessage: function() {
if (this._messageQueue.length !== 0) {
this._messageQueue.forEach(function(detail){
this.openPage(detail.url);
}.bind(this));
this._messageQueue = [];
}
},
openPage: function(url) {
url = Browser.getUrlFromInput(url);
if (Browser.currentInfo && Browser.currentInfo.url &&
UrlHelper.isURL(Browser.currentInfo.url)) {
var ev = {
detail: {
url: url,
frameElement: null
}
};
Awesomescreen.openNewTab(ev);
} else {
Browser.navigate(url);
}
this.bringToFront();
},
bringToFront: function() {
if (document.visibilityState === 'hidden') {
navigator.mozApps.getSelf().onsuccess = function(evt) {
var app = evt.target.result;
if (app) {
app.launch();
}
};
}
},
activate: function() {
this._active = true;
this._digestMessage();
},
pause: function() {
this._active = false;
},
};
exports.ConnectionHandler = ConnectionHandler;
}(window));
var connectionHandler = new ConnectionHandler();
connectionHandler.init();

76
gaia/tv_apps/browser/js/fte.js Executable file
View file

@ -0,0 +1,76 @@
/* 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 Browser */
/* global FTEWizard */
/* global ResourceLoader */
/* global SyncManagerBridge */
// XXX: If Firefox sign in is available outside of the browser app, we'll have
// to remove or redesign FTE.
'use strict';
(function (exports) {
if (localStorage.getItem('browserFTE.fteskip')) {
return;
}
var FTE = {
fteContainer: null,
fteWizard: null,
onuninit: function () {},
init(options) {
this.onuninit = options.onuninit;
ResourceLoader.loadByName('fte')
.then(node => {
document.body.appendChild(node);
this.fteContainer = document.getElementById('fte-container');
this.fteWizard = new FTEWizard('browserFTE');
this.fteWizard.init({
container: this.fteContainer,
propagateKeyEvent: true,
onfinish: () => {
SyncManagerBridge.enable();
this.uninit();
},
onskip: () => {
this.uninit();
}
});
document.addEventListener('visibilitychange', this);
});
},
handleEvent() {
if (!document.hidden) {
this.fteWizard.focus();
}
},
uninit() {
document.body.removeChild(this.fteContainer);
document.removeEventListener('visibilitychange', this);
ResourceLoader.unloadByName('fte');
this.onuninit();
}
};
exports.FTE = FTE;
exports.FTE.init({onuninit: () => {
Browser.switchCursorMode(true);
delete exports.FTE;
}});
})(window);

View file

@ -0,0 +1,338 @@
/* globals BrowserDB, SyncBrowserDB, SyncManagerBridge */
'use strict';
(function(exports){
const INITIAL_HISTORY_COUNT = 21;
const DAY_IN_MILLI_SECOND = 86400000;
// TODO: for the live time history data loading task.
var HistoryStore = {
isSynced: false,
cache: new Map(),
cacheIndexStartAt: 0,
cacheIndexEndAt: 0,
lastDataIndex: null,
currentFolder: null,
isHandlingCache: false,
cacheEventQueue: [],
reset: function (cb) {
return new Promise(resolve => {
this.cache.clear();
this.cacheIndexStartAt = 0;
this.cacheIndexEndAt = 0;
this.lastDataIndex = null;
this.currentFolder = null;
this.isHandlingCache = false;
this.cacheEventQueue = [];
//IFNDEF_FIREFOX_SYNC
resolve();
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
SyncManagerBridge.getInfo().then(message => {
if (message.state === 'enabled' || message.state === 'syncing') {
this.isSynced = true;
} else {
this.isSynced = false;
}
resolve();
});
//ENDIF_FIREFOX_SYNC
});
},
getByRange: function (start, num, folderId, cb) {
var self = this;
function getCaches(){
var length = (start + num) > self.cache.size ?
(self.cache.size - start) : (start + num);
var result = [];
for(var i = start; i < length; i++) {
result.push(self.cache.get(i));
}
return result;
}
if(folderId !== this.currentFolder) {
this.currentFolder = folderId;
this.fetchCache().then(() => {
cb(getCaches());
});
} else {
cb(getCaches());
}
},
//IFDEF_FIREFOX_SYNC
traverseNextCache: function(cacheIndex) {
return new Promise(resolve => {
var traverse = () =>{
var start = this.cache.get(this.cacheIndexStartAt).timestamp;
SyncBrowserDB.getHistoryTimestamp(start, 'next', false,
timestamp => {
if(timestamp) {
this.updateCacheByNextHistory(timestamp).then(() => {
var history = this.cache.get(cacheIndex);
if(!history) {
traverse();
} else {
resolve(history);
}
});
} else {
resolve(null);
}
}
);
};
traverse();
});
},
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
traversePreviousCache: function(cacheIndex) {
return new Promise(resolve => {
var traverse = () => {
var start = this.cache.get(this.cacheIndexEndAt).timestamp;
SyncBrowserDB.getHistoryTimestamp(start, 'prev', false,
timestamp => {
if(timestamp) {
this.updateCacheByPreviousHistory(timestamp).then(() => {
var history = this.cache.get(cacheIndex);
if(!history) {
traverse();
} else {
resolve(history);
}
});
} else {
this.lastDataIndex = this.cacheIndexEndAt;
resolve(null);
}
}
);
};
traverse();
});
},
//ENDIF_FIREFOX_SYNC
getCache: function(cacheIndex) {
return new Promise(resolve => {
var history = null;
//IFNDEF_FIREFOX_SYNC
if(this.cacheIndexStartAt <= cacheIndex <= this.cacheIndexEndAt) {
resolve(null);
} else {
history = this.cache.get(cacheIndex);
resolve(history);
}
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
if(cacheIndex < this.cacheIndexStartAt) {
this.traverseNextCache(cacheIndex).then(history => {
resolve(history);
});
} else if (cacheIndex > this.cacheIndexEndAt) {
if(this.lastDataIndex && cacheIndex > this.lastDataIndex) {
resolve(history);
} else {
this.traversePreviousCache(cacheIndex).then(history => {
resolve(history);
});
}
} else {
history = this.cache.get(cacheIndex);
resolve(history);
}
//ENDIF_FIREFOX_SYNC
});
},
handleCacheEvent: function() {
if(!this.isHandlingCache) {
this.isHandlingCache = true;
var handler = this.cacheEventQueue.shift();
handler().then(() => {
this.isHandlingCache = false;
if(this.cacheEventQueue.length > 0) {
this.handleCacheEvent();
}
});
}
},
getByIndex: function (index, folderId, cb) {
var handler = () => new Promise(resolve => {
if(folderId !== this.currentFolder) {
this.currentFolder = folderId;
this.fetchCache().then(() => {
this.getCache(index).then(history => {
cb(history);
resolve();
});
});
} else {
this.getCache(index).then(history => {
cb(history);
resolve();
});
}
});
this.cacheEventQueue.push(handler);
this.handleCacheEvent();
},
fetchCache: function () {
this.cache.clear();
this.cacheIndexStartAt = 0;
this.cacheIndexEndAt = -1;
this.lastDataIndex = null;
return new Promise( resolve => {
if(!this.isSynced) {
// Get bookmark data from origin indexdDB
BrowserDB.getHistory(localHistory => {
localHistory.forEach(history => {
this.cacheIndexEndAt++;
this.cache.set(this.cacheIndexEndAt, history);
});
this.lastDataIndex = this.cacheIndexEndAt;
resolve();
});
} else {
//IFNDEF_FIREFOX_SYNC
resolve();
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
if(!this.currentFolder) {
// XXX: Ideally we should use Promise.all for
// SyncBrowserDB.getBookmark and BrowserDB.getBookmarks.
// But now the implementation of these function are not
// return Promise.
SyncBrowserDB.getHistoryTimestamp(Date.now(), 'prev', true,
timestamp => {
// We query remote history by parentid for checking if
// the indexedDB has remote history data. If there is
// any remote data, we create a folder item to show the
// synced history.
if(timestamp) {
this.cacheIndexEndAt++;
this.cache.set(this.cacheIndexEndAt, {
id: 'sync_history',
title: 'Synced History',
type: 'folder',
readOnly: true
});
}
// get bookmark data from origin indexdDB
BrowserDB.getHistory(localHistory => {
localHistory.forEach(history => {
this.cacheIndexEndAt++;
this.cache.set(this.cacheIndexEndAt, history);
});
this.lastDataIndex = this.cacheIndexEndAt;
resolve();
});
}
);
} else {
SyncBrowserDB.getHistory(INITIAL_HISTORY_COUNT, syncHistory => {
syncHistory.forEach(history => {
// XXX: the data from firefox sync can't be modified.
history.readOnly = true;
this.cacheIndexEndAt++;
this.cache.set(this.cacheIndexEndAt, history);
});
if(syncHistory.length < INITIAL_HISTORY_COUNT) {
this.lastDataIndex = this.cacheIndexEndAt;
}
resolve();
});
}
//ENDIF_FIREFOX_SYNC
}
});
},
//IFDEF_FIREFOX_SYNC
updateCacheByNextHistory: function (timestamp) {
var promise = new Promise(resolve => {
var start = timestamp,
end = timestamp + DAY_IN_MILLI_SECOND;
SyncBrowserDB.getHistoryByTime(start, end, true, true, syncHistory => {
this.cache.clear();
this.cacheIndexEndAt = this.cacheIndexStartAt - 1;
var length = syncHistory.length;
while(length--) {
this.cacheIndexStartAt--;
this.cache.set(this.cacheIndexStartAt, syncHistory[length]);
}
resolve();
});
});
return promise;
},
//ENDIF_FIREFOX_SYNC
//IFDEF_FIREFOX_SYNC
updateCacheByPreviousHistory: function (timestamp) {
var promise = new Promise(resolve => {
var start = timestamp - DAY_IN_MILLI_SECOND,
end = timestamp;
SyncBrowserDB.getHistoryByTime(start, end, true, true, syncHistory => {
this.cache.clear();
this.cacheIndexStartAt = this.cacheIndexEndAt + 1;
syncHistory.forEach(history => {
// XXX: the data from firefox sync can't be modified.
history.readOnly = true;
this.cacheIndexEndAt++;
this.cache.set(this.cacheIndexEndAt, history);
});
resolve();
});
});
return promise;
},
//ENDIF_FIREFOX_SYNC
removeCache: function (index) {
if(this.cacheIndexStartAt <= index <= this.cacheIndexEndAt) {
var value = null;
for(var i = index; i<this.cacheIndexEndAt; i++) {
value = this.cache.get(i+1);
this.cache.set(i, value);
}
this.cache.delete(this.cacheIndexEndAt);
this.cacheIndexEndAt--;
}
}
};
exports.HistoryStore = HistoryStore;
})(window);

1221
gaia/tv_apps/browser/js/index.js Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
/* 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/. */
/* HTML files to be loaded should be enclosed by a <template> element.
* <template>
* put HTML content here
* </template>
*/
'use strict';
(function (exports) {
/**
* ResourceLoader is a stand-alone module which provides methods for lazy
* loading HTML, CSS and javascript resources.
*
* TODO: Methods for lazy loading javascript files.
*
* @param {object} options [description]
*/
function ResourceLoader(options) {
this.path = '';
this.init(options);
}
ResourceLoader.prototype = {
constructor: ResourceLoader,
init(options) {
options = options || {};
this.path = options.path || 'elements';
},
/**
* Load HTML and CSS by name.
* @param {string} name [description]
* @return {Promise} The returned Promise is resolved with a Node.
*/
loadByName(name) {
var path = [this.path, name].join('/');
this.loadCss(path);
return this.loadHtml(path);
},
/**
* Load an HTML file from the specified path, the resulted DOM Node can be
* directly appended or modified with DOM API.
* @param {string} path The path of the HTML file, with or without
* html extension.
* @return {Promise} The returned Promise is resolved with a DOM Node.
*/
loadHtml(path) {
if (!path.endsWith('.html')) {
path = [path, 'html'].join('.');
}
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
var template = xhr.responseXML.querySelector('template');
var node = document.importNode(template.content, true);
resolve(node);
};
xhr.open('GET', path);
xhr.responseType = 'document';
xhr.overrideMimeType('text/html');
xhr.send();
});
},
/**
* Load an CSS file from the specified path.
* @param {string} path The path of the CSS file, with or without
* css extension.
* @return {Promise}
*/
loadCss(path) {
if (!path.endsWith('.css')) {
path = [path, 'css'].join('.');
}
if (document.querySelector('link[rel=stylesheet][href="' + path + '"]')) {
return;
}
return new Promise((resolve, reject) => {
var link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = path;
link.addEventListener('load', () => {
resolve();
});
document.head.appendChild(link);
});
},
/**
* Unload a loaded template. We don't cache HTML templates, so we only need
* to remove the loaded link element from document.head.
* @param {string} name The name of the template.
*/
unloadByName(name) {
var path = [this.path, name].join('/');
this.unloadCss(path);
},
/**
* Remove a CSS link element from document.head.
* @param {string} path The path of the CSS file, with or without
* css extension.
*/
unloadCss(path) {
if (!path.endsWith('.css')) {
path = [path, 'css'].join('.');
}
var link =
document.querySelector('link[rel=stylesheet][href="' + path + '"]');
if (link) {
document.head.removeChild(link);
}
}
};
exports.ResourceLoader = new ResourceLoader();
})(window);

View file

@ -0,0 +1,242 @@
/* global _, Browser, BrowserDB, MozActivity */
'use strict';
/**
* Browser app search_result
* @namespace SearchResult
*/
var SearchResult = {
listTemplate: null,
searchResultTemplate: null,
allResult: null,
updateInProgress: false,
pendingUpdateFilter: null,
/**
* Intialise SearchResult.
*/
init: function result_init() {
/* get Element */
this.getAllElements();
/* Event Listener */
window.addEventListener('click', this);
// Create template elements
this.listTemplate = this.createList();
this.searchResultTemplate = this.createSearchTemplate();
},
/**
* CamelCase (xxx-yyy -> xxxYyy)
*/
toCamelCase: function toCamelCase(str) {
return str.replace(/-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
},
/**
* Get All Elements (from id)
*/
getAllElements: function result_getAllElements() {
var elementIDs = [
'search-result', 'search-result-list',
];
// Loop and add element with camel style name to Modal Dialog attribute.
elementIDs.forEach(function createElementRef(name) {
this[this.toCamelCase(name)] = document.getElementById(name);
}, this);
},
show: function result_show() {
this.searchResult.classList.add('visible');
this.handleSearchResultFormInput(null);
},
hide: function result_hide() {
var list = this.searchResultList.firstElementChild;
if( list ) this.searchResultList.removeChild(list);
this.searchResult.classList.remove('visible');
Toolbar.setSearchBarStyle('false');
},
isDisplayed: function result_isDisplayed() {
return this.searchResult.classList.contains('visible');
},
/**
* Submit search form
*/
handleSearchResultFormInput: function result_handleSearchResultFormInput(ev) {
if( ev ) ev.preventDefault();
this.resultUpdate(Toolbar.searchInput.value);
},
handleSearchResultFormSubmit: function result_handleSearchResultFormSubmit(ev) {
if( ev ) ev.preventDefault();
},
createList: function result_createList() {
var list = document.createElement('ul');
list.classList.add('result-box');
return list;
},
createSearchTemplate: function result_createSearchTemplate() {
var template = document.createElement('li');
template.classList.add('result-item');
var link = document.createElement('div');
link.classList.add('result-base');
var title = document.createElement('div');
title.classList.add('result-title');
var url = document.createElement('div');
url.classList.add('result-url');
link.appendChild(title);
link.appendChild(url);
template.appendChild(link);
return template;
},
resultUpdate: function result_resultUpdate(filter) {
// If an update is already in progress enqueue the following ones
if (this.updateInProgress) {
this.pendingUpdateFilter = filter;
return;
} else {
this.updateInProgress = true;
}
this.allResult = [];
BrowserDB.getBookmarks((function(bookmarks) {
this.resultFiltering(filter, bookmarks);
BrowserDB.getHistory((function(history) {
this.resultFiltering(filter, history);
this.populateResults(filter);
this.updateInProgress = false;
var pendingUpdateFilter = this.pendingUpdateFilter;
if (pendingUpdateFilter !== null) {
this.pendingUpdateFilter = null;
this.resultUpdate(pendingUpdateFilter);
}
}).bind(this));
}).bind(this));
},
resultFiltering: function result_resultFiltering(filter, data) {
if(( filter == '' ) || ( data == null )) return;
for( var i = 0 ; i < data.length ; i ++ ) {
var current = data[i];
var matched = false;
if( filter ) {
matched = this.matchesFilter(current.uri, filter) ||
this.matchesFilter(current.title, filter);
}
if( matched || !filter ) {
var j = 0;
for( ; j < this.allResult.length ; j ++ ) {
if( this.allResult[j].uri === current.uri ) {
break;
}
}
if( j == this.allResult.length ) {
this.allResult.push(current);
}
}
}
},
/**
* Check if the URI matches the regular expression filter.
* @param {String} uri
* @param {String} filter
* @returns {Boolean}
*/
matchesFilter: function result_matchesFilter(uri, filter) {
if( !uri ) return false;
return uri.match(new RegExp(filter, 'i')) !== null;
},
populateResults: function result_populateResults(filter) {
var list = this.createList();
var engine = SearchUtil.getCurrentEngineName();
if( engine ) {
var result = this.searchResultTemplate.cloneNode(true);
var title = result.childNodes[0].childNodes[0];
// title.innerHTML = 'Search by ' + engine;
navigator.mozL10n.setAttributes(title, 'WB_LT_TIPS_S_SEARCH', {
value0:engine
});
var uri = result.childNodes[0].childNodes[1];
uri.innerHTML = Browser.getSearchFromInput(filter);
list.appendChild(result);
result.addEventListener('mouseup',
this.handleResultSelect.bind(this));
}
for( var i = 0 ; i < this.allResult.length ; i ++ ) {
var result = this.searchResultTemplate.cloneNode(true);
var title = result.childNodes[0].childNodes[0];
title.innerHTML = this.allResult[i].title;
var uri = result.childNodes[0].childNodes[1];
uri.innerHTML = this.allResult[i].uri;
list.appendChild(result);
result.addEventListener('mouseup',
this.handleResultSelect.bind(this));
}
var oldList = this.searchResultList.firstElementChild;
if (oldList) {
this.searchResultList.replaceChild(list, oldList);
} else {
this.searchResultList.appendChild(list);
}
},
/**
* handle event
*/
handleEvent: function result_handleEvent(ev) {
switch(ev.type) {
case 'click':
break;
default:
break;
}
},
handleResultSelect: function result_handleResultSelect(ev) {
if( !ev ) return;
ev.preventDefault();
if(( ev.target.lastChild.lastChild.textContent != '' ) ||
( ev.target.lastChild.lastChild.textContent != undefined )) {
var url = ev.target.lastChild.lastChild.textContent;
Browser.navigate(url);
this.hide();
}
},
/**
* Handle Key Event.
*/
handleKeyEvent: function result_handleKeyEvent(ev) {
// in the input area focus (= display keyboard)
if(document.activeElement.nodeName == 'INPUT') {
return;
}
switch( ev.keyCode ) {
case KeyEvent.DOM_VK_BACK_SPACE :
this.hide();
break;
}
}
};

View file

@ -0,0 +1,283 @@
'use strict';
var SearchUtil = {
// country code
COUNTRY: 'US',
/* search engine list of the search bar */
ENGINE_LIST: {
'CN': [
{id: 2, name: 'Baidu'},
{id: 1, name: 'Bing'}
],
// default
'US': [
{id: 1, name: 'Bing'},
{id: 0, name: 'Google'}
]
},
// search engine
engineList: null,
searchId: null,
searchIdx: null,
DOMAIN_LIST: {
'US':'com' , 'CA':'ca' , 'DE':'de' , 'IE':'ie' ,
'NL':'nl' , 'HU':'hu' , 'PL':'pl' , 'CZ':'cz' ,
'SK':'sk' , 'IT':'it' , 'GB':'co.uk' , 'SI':'si' ,
'GR':'gr' , 'PT':'pt' , 'DK':'dk' , 'FI':'fi' ,
'HR':'hr' , 'NO':'no' , 'RO':'ro' , 'RU':'ru' ,
'BG':'bg' , 'LT':'lt' , 'YU':'rs' , 'SE':'se' ,
'LV':'lv' , 'EE':'ee' , 'TR':'com.tr' , 'BR':'com.br' ,
'ID':'co.id' , 'CN':'com.hk' , 'TW':'com.tw' , 'HK':'com.hk' ,
'VN':'com.vn' , 'TH':'co.th' , 'SA':'com.sa' , 'FR':'fr' ,
'ES':'es' , 'SG':'com.sg' , 'AU':'com.au' , 'NZ':'co.nz' ,
'IN':'co.in' , 'MY':'com.my' , 'AE':'ae' , 'KW':'com.kw' ,
'MX':'com.mx' , 'AT':'at' , 'BE':'be' , 'CH':'ch' ,
'MT':'com.mt' , 'AD':':' , 'LU':'lu' , 'IS':'is' ,
'UA':'com.ua' , 'KZ':'kz' , 'CIS':'by' , 'UK':'co.uk' ,
'CL':'cl' , 'PE':'com.pe' , 'CO':'com.co' , 'AR':'com.ar' ,
'PA':'com.pa' , 'JP':'co.jp' , 'MK':'mk' , 'MM':'com.mm'
},
// search domain
domainList: null,
/* URL of each search engine */
SEARCH_URL: {
//Google :
0 : [
"http://www.google.DOMAIN/search?ie=UTF-8&oe=UTF-8&q=",
"http://www.google.DOMAIN/search?ie=UTF-8&oe=UTF-8&tbm=isch&q=",
"http://www.google.DOMAIN/search?ie=UTF-8&oe=UTF-8&tbm=vid&q=",
"http://www.google.DOMAIN/search?ie=UTF-8&oe=UTF-8&tbm=nws&q=",
"http://maps.google.com/maps?q=",
"http://www.youtube.DOMAIN/results?search_query="
],
//bing :
1 : [
"http://www.bing.com/search?FORM=PANSSB&PC=PANS&q=",
"http://www.bing.com/images/search?FORM=PANSSB&PC=PANS&q=",
//"http://www.bing.com/videos/search?FORM=PANSSB&PC=PANS&q=",
"http://www.bing.com/?scope=video&FORM=PANSSB&PC=PANS&q=",
"http://www.bing.com/news/search?FORM=PANSSB&PC=PANS&q=",
"http://www.bing.com/maps/?FORM=PANSSB&PC=PANS&q=",
"http://www.bing.com/videos/search?FORM=PANSSB&PC=PANS&q="
],
//Baidu :
2 : [
"http://www.baidu.com/s?word=",
"http://image.baidu.com/i?word=",
"http://video.baidu.com/v?word=",
"http://news.baidu.com/ns?word=",
"http://map.baidu.com/m?word=",
"http://video.baidu.com/v?word="
]
},
searchUrl: null,
// keyword for auto category selection at voice search
SEARCH_CAT: {
//Google :
0 :
[
[ [ "www.google.", "/search", "" ] ],
[ [ "www.google.", "/search", "tbm=isch" ],
[ "www.google.", "/imghp", "" ] ],
[ [ "www.google.", "/search", "tbm=vid" ],
[ "www.google.", "/videohp","" ] ],
[ [ "www.google.", "/search", "tbm=nws" ],
[ "news.google.", "/nwshp", "" ] ],
[ [ "maps.google.", "", "" ],
[ "www.google.", "/maps", "" ] ],
[ [ "www.youtube.", "", "" ] ]
],
//Bing :
1 :
[
[ [ "www.bing.com", "/search", "" ] ],
[ [ "www.bing.com", "/images", "" ],
[ "www.bing.com", "", "scope=images" ] ],
[ [ "www.bing.com", "/videos", "" ],
[ "www.bing.com", "", "scope=video" ] ],
[ [ "www.bing.com", "/news", "" ],
[ "www.bing.com", "", "scope=news" ] ],
[ [ "www.bing.com", "/maps", "" ] ],
[ [ "www.bing.com", "/videos", "" ],
[ "www.bing.com", "", "scope=video" ] ]
],
//Baidu :
2 :
[
[ [ "www.baidu.com", "", "" ] ],
[ [ "image.baidu.com", "", "" ] ],
[ [ "video.baidu.com", "", "" ] ],
[ [ "news.baidu.com", "", "" ] ],
[ [ "map.baidu.com", "", "" ] ],
[ [ "video.baidu.com", "", "" ] ]
]
},
displaySearchEngineName: false,
/**
* init SearchUtil
*/
init: function searchUtil_init(country, cb) {
// set country code
this.COUNTRY = country;
// search engine (default US)
this.engineList = (country in this.ENGINE_LIST)?
this.ENGINE_LIST[country]: this.ENGINE_LIST['US'];
// search domain (default US)
this.domainList = (country in this.DOMAIN_LIST)?
this.DOMAIN_LIST[country]: this.DOMAIN_LIST['US'];
// search URL (default US)
this.searchUrl = this.SEARCH_URL;
var index;
for(index in this.searchUrl[0]){
this.searchUrl[0][index] =
this.searchUrl[0][index].replace(/DOMAIN/, this.domainList);
}
// get all database
this.getAllDatabase(cb);
},
/**
* get all database
*/
getAllDatabase: function searchUtil_getAllDatabase(cb){
// DB get all
this.getSearchEngineId((function(){
this.initDatabase((function(){
if(cb){
cb();
}
}).bind(this))
}).bind(this));
},
// init database
initDatabase: function search_initDatabase(cb){
// default search engine url
if(this.searchId != null){
this.convSearchIdToIdx(this.searchId);
}else{
this.searchIdx = 0;
this.displaySearchEngineName = true;
}
if(cb){
cb();
}
},
// get search engine id
getSearchEngineId: function searchUtil_getSearchEngineId(cb){
BrowserDB.getSetting('SEARCH_ENGINE', (function(result) {
Browser.debug("SEARCH_ENGINE = " + result);
if(result != undefined){
this.searchId = result;
this.convSearchIdToIdx(result);
}
if(cb){
cb(result);
}
}).bind(this));
},
// set search engine id
setSearchEngineId: function searchUtil_setSearchEngineId(id, cb){
this.searchId = id;
this.convSearchIdToIdx(id);
BrowserDB.updateSetting(id, 'SEARCH_ENGINE', cb);
},
// get search engine index
getSearchEngineIdx: function searchUtil_getSearchEngineIdx(cb){
if(this.searchId){
this.convSearchIdToIdx(this.searchId);
if(cb){
cb();
}
}else{
BrowserDB.getSetting('SEARCH_ENGINE', (function(result) {
if(result != undefined){
this.convSearchIdToIdx(result);
}
if(cb){
cb();
}
}).bind(this));
}
},
// Convert the search_id (DB) to search index.
convSearchIdToIdx: function searchUtil_convSearchIdToIdx(search_id) {
var index = null;
for(var i in this.engineList){
if(search_id == this.engineList[i].id){
index = i;
break;
}
}
if(index == null){
// terminated search service of Web. so select default.
this.searchIdx = 0;
this.searchId = this.engineList[0].id;
BrowserDB.updateSetting(undefined, 'SEARCH_ENGINE');
this.displaySearchEngineName = false;
}else{
this.searchIdx = index;
this.displaySearchEngineName = true;
}
},
// Get Search Engine List.
getEngineList: function searchUtil_getEngineList(){
return this.engineList;
},
// Get Current Search Engine List.
getCurrentEngineList: function searchUtil_getCurrentEngineList(){
if(this.searchIdx != null && this.searchIdx < this.engineList.length) {
return this.engineList[this.searchIdx];
}else{
return this.engineList[0];
}
},
// Get Current Search Engine Name.
getCurrentEngineName: function searchUtil_getCurrentEngineName(){
if(this.searchIdx != null && this.searchIdx < this.engineList.length) {
return this.engineList[this.searchIdx].name;
}else{
return this.engineList[0].name;
}
},
// Get Search Id.
getSearchId: function searchUtil_getSearchId(){
return this.searchId;
},
// Get Search Index.
getSearchIdx: function searchUtil_getSearchIdx(){
return this.searchIdx;
},
// Get Search Url.
getSearchUrl: function searchUtil_getSearchUrl(){
return this.searchUrl;
},
// Get Current Search Url.
getCurrentSearchUrl: function searchUtil_getCurrentSearchUrl(){
if(this.searchId != null && (this.searchId in this.searchUrl)){
return this.searchUrl[this.searchId];
}else{
return this.searchUrl[this.engineList[0].id];
}
},
// Get Display Search Engine Name flag.
getDispFlag: function searchUtil_getDispFlag(){
return this.displaySearchEngineName;
},
};

View file

@ -0,0 +1,719 @@
/* exported Settings */
/* global Awesomescreen */
/* global Browser */
/* global BrowserDB */
/* global BrowserDialog */
/* global KeyEvent */
/* global LazyLoader */
/* global SearchUtil */
/* global Toolbar */
/* global UrlHelper */
'use strict';
/**
* Browser app settings panel.
* @namespace Settings
*/
var Settings = {
DEFAULT_HOMEPAGE: 'http://www.mozilla.org',
currentSearchEngine: null,
selectSearchEngine: null,
searchEngineList: null,
focusList: null,
focusPos: 0,
/** Get all DOM elements when inited. */
getAllElements: function settings_getAllElements() {
var toCamelCase = function toCamelCase(str) {
return str.replace(/\-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
};
var elementIDs = [
'settings-list', 'settings-list-area',
'settings-homepage', 'settings-homepage-name',
'settings-search-engine', 'settings-search-engine-name',
'settings-clear-history',
'settings-clear-cookie',
'settings-dialog',
'settings-dialog-homepage',
'settings-dialog-homepage-input',
'settings-dialog-homepage-input-area',
'settings-dialog-homepage-clear',
'settings-dialog-homepage-default',
'settings-dialog-homepage-cancel',
'settings-dialog-homepage-ok',
'settings-dialog-search',
'settings-dialog-search-select',
'settings-dialog-search-select-list',
'settings-dialog-search-cancel',
'settings-dialog-search-ok',
'settings-banner-message'
];
// Loop and add element with camel style name to Modal Dialog attribute.
elementIDs.forEach(function createElementRef(name) {
this[toCamelCase(name)] = document.getElementById(name);
}, this);
},
/**
* Intialise settings panel.
*/
init: function settings_init() {
this.getAllElements();
this.getDefaultHomepage((function(result) {
/* default homepage nothing... */
Browser.debug('default homepage = ' + result);
if(!result) {
console.log('set default homepage...');
this.setDefaultHomepage();
this.setHomepage(this.DEFAULT_HOMEPAGE);
}
}).bind(this));
this.settingsList.addEventListener('mouseup',
this.handleListClick.bind(this));
this.settingsListArea.addEventListener('mouseup',
this.handleListAreaClick.bind(this));
this.settingsDialog.addEventListener('mouseup',
this.handleListAreaClick.bind(this));
this.settingsHomepage.addEventListener('mouseup',
this.handleHomepageClick.bind(this));
this.settingsSearchEngine.addEventListener('mouseup',
this.handleSearchEngineClick.bind(this));
this.settingsClearHistory.addEventListener('mouseup',
this.handleClearHistoryClick.bind(this));
this.settingsClearCookie.addEventListener('mouseup',
this.handleClearCookieClick.bind(this));
this.settingsDialogHomepageInput.addEventListener('submit',
this.handleDialogHomepageInputSubmit.bind(this));
this.settingsDialogHomepageClear.addEventListener('mouseup',
this.handleDialogHomepageClear.bind(this));
this.settingsDialogHomepageDefault.addEventListener('mouseup',
this.handleDialogHomepageDefault.bind(this));
this.settingsDialogHomepageCancel.addEventListener('mouseup',
this.handleDialogHomepageCancel.bind(this));
this.settingsDialogHomepageOk.addEventListener('mouseup',
this.handleDialogHomepageOk.bind(this));
this.settingsDialogSearchCancel.addEventListener('mouseup',
this.handleDialogSearchCancel.bind(this));
this.settingsDialogSearchOk.addEventListener('mouseup',
this.handleDialogSearchOk.bind(this));
this.settingsDialogHomepageInputArea.addEventListener('focus',
this.handleDialogHomepageInputAreaFocus.bind(this));
this.settingsDialogHomepageInputArea.addEventListener('mousedown',
this.handleDialogHomepageInputAreaClick.bind(this));
this.settingsDialogHomepageInputArea.addEventListener('blur',
this.handleDialogHomepageInputBlur.bind(this));
this.settingsDialogHomepageClear.addEventListener('keyup',
this.handleDialogHomepageClear.bind(this));
this.settingsDialogHomepageDefault.addEventListener('keyup',
this.handleDialogHomepageDefault.bind(this));
this.settingsDialogHomepageCancel.addEventListener('keyup',
this.handleDialogHomepageCancel.bind(this));
this.settingsDialogHomepageOk.addEventListener('keyup',
this.handleDialogHomepageOk.bind(this));
this.settingsDialogSearchCancel.addEventListener('keyup',
this.handleDialogSearchCancel.bind(this));
this.settingsDialogSearchOk.addEventListener('keyup',
this.handleDialogSearchOk.bind(this));
//IFDEF_FIREFOX_SYNC
LazyLoader.load('js/sync/settings.js');
//ENDIF_FIREFOX_SYNC
},
getDefaultHomepage: function settings_getDefaultHomepage(cb) {
BrowserDB.db.open((function() {
BrowserDB.getSetting( 'default_homepage', cb );
}).bind(this));
},
setDefaultHomepage: function settings_setDefaultHomepage() {
BrowserDB.db.open((function() {
BrowserDB.updateSetting( this.DEFAULT_HOMEPAGE, 'default_homepage' );
}).bind(this));
},
getHomepage: function settings_getHomepage(cb) {
BrowserDB.db.open((function() {
BrowserDB.getSetting( 'settings_homepage', cb );
}).bind(this));
},
setHomepage: function settings_setHomepage(url) {
BrowserDB.db.open((function() {
BrowserDB.updateSetting( url, 'settings_homepage' );
}).bind(this));
},
/**
* Show settings panel.
*/
show: function settings_show() {
document.body.classList.add('settings-screen');
this.getHomepage((function(result) {
this.settingsHomepageName.textContent = result;
}).bind(this));
this.settingsSearchEngineName.textContent =
SearchUtil.getCurrentEngineName();
this.currentSearchEngine = this.settingsSearchEngineName.textContent;
this.selectSearchEngine = this.currentSearchEngine;
// XXX: Get Firefox Account sign in status and display it
},
/**
* settings list displays a confirmation.
*/
isDisplayed: function settings_isDisplayed() {
return document.body.classList.contains('settings-screen');
},
/**
* Hide settings panel.
*/
hide: function settings_hide() {
// Browser.switchCursorMode( true );
BrowserDialog.cancelDialog();
this.hideDialogHomepage();
this.hideDialogSearch();
document.body.classList.remove('settings-screen');
},
handleListClick: function settings_handleListClick(evt) {
if( evt ) {
evt.stopPropagation();
}
this.hide();
},
handleListAreaClick: function settings_handleListAreaClick(evt) {
if( evt ) {
evt.stopPropagation();
}
},
focusChange: function settings_focusChange(pos) {
var opt = null;
var flg = false;
if( Awesomescreen.pointerImg.style.display == 'none' ) {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
flg = true;
}
for( var i = 0 ; i < Settings.focusList.length ; i ++ ) {
if( i == pos ) {
if(Settings.focusList[i].nodeName == 'INPUT') {
if( !Settings.settingsDialogHomepageInput
.classList.contains('exfocus') ) {
Settings.settingsDialogHomepageInput.classList.add('exfocus');
}
} else if(Settings.focusList[i].id == 'settings-dialog-homepage-clear'){
Settings.focusList[i].focus();
if( !Settings.settingsDialogHomepageInput
.classList.contains('exfocus') ) {
Settings.settingsDialogHomepageInput.classList.add('exfocus');
}
if( flg ) {
opt = Awesomescreen.DEFAULT_EXCLEAR;
}
} else {
Settings.focusList[i].focus();
Settings.settingsDialogHomepageInput.classList.remove('exfocus');
}
Awesomescreen.focusImgFunc(Settings.focusList[i], opt);
} else {
Settings.focusList[i].blur();
}
}
},
/**
* Handle homepage click.
*/
handleHomepageClick: function settings_handleHomepageClick() {
if( !this.isDialogHomepageDisplayed() ) {
this.focusList = [];
Browser.switchCursorMode(false);
this.settingsDialog.classList.remove('hidden');
this.settingsDialogHomepage.classList.remove('hidden');
this.settingsDialogHomepageInput.classList.remove('input');
this.settingsDialogHomepageInput.classList.remove('exfocus');
this.settingsDialogHomepageInputArea.value =
this.settingsHomepageName.textContent;
this.settingsDialogHomepageInputArea.tabIndex = '0';
this.settingsDialogHomepageClear.tabIndex = '0';
this.focusList.push(this.settingsDialogHomepageInputArea);
this.focusList.push(this.settingsDialogHomepageClear);
this.focusList.push(this.settingsDialogHomepageDefault);
this.focusList.push(this.settingsDialogHomepageOk);
this.focusList.push(this.settingsDialogHomepageCancel);
this.focusPos = this.focusList.length - 1;
this.focusChange(this.focusPos);
}
},
hideDialogHomepage: function settings_hideDialogHomepage() {
if( this.isDialogHomepageDisplayed() ) {
Awesomescreen.pointerImg.style.display = 'none';
this.settingsDialogHomepageInput.classList.remove('input');
this.settingsDialogHomepageInput.classList.remove('exfocus');
this.settingsDialogHomepage.classList.add('hidden');
this.settingsDialog.classList.add('hidden');
Browser.switchCursorMode(true);
}
},
isDialogHomepageDisplayed: function settings_isDialogHomepageDisplayed() {
return !this.settingsDialogHomepage.classList.contains('hidden');
},
handleDialogHomepageInputSubmit:
function settings_handleDialogHomepageInputSubmit(ev) {
if (ev) {
// Can be canceled
ev.preventDefault();
}
var hasScheme =
UrlHelper.hasScheme(this.settingsDialogHomepageInputArea.value);
// No scheme, prepend basic protocol and return
if (!hasScheme) {
this.settingsDialogHomepageInputArea.value =
'http://' + this.settingsDialogHomepageInputArea.value;
}
this.settingsDialogHomepageInputArea.blur();
},
handleDialogHomepageInputAreaFocus:
function settings_handleDialogHomepageInputAreaFocus(evt) {
if( evt ) {
evt.preventDefault();
}
Settings.settingsDialogHomepageInput.classList.add('input');
Settings.settingsDialogHomepageInput.classList.remove('exfocus');
},
handleDialogHomepageInputAreaClick:
function settings_handleDialogHomepageInputAreaClick(evt) {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
Settings.settingsDialogHomepageInput.classList.add('input');
Settings.settingsDialogHomepageInput.classList.remove('exfocus');
Settings.focusPos = 0;
Settings.focusList[Settings.focusPos].focus();
Awesomescreen.pointerImg.style.display = 'none';
},
handleDialogHomepageInputBlur:
function settings_handleDialogHomepageInputBlur(evt) {
if( evt ) {
evt.preventDefault();
}
if( Awesomescreen.pointerImg.style.display == 'none' ) {
Browser.switchCursorMode(true);
Browser.switchCursorMode(false);
}
// Pointer image to the input area(fucusPos=0)
Settings.focusPos = 0;
Settings.settingsDialogHomepageInput.classList.remove('input');
Settings.focusChange(Settings.focusPos);
Awesomescreen.pointerImg.style.display = 'block';
},
handleDialogHomepageClear:
function settings_handleDialogHomepageClear(evt) {
if( evt ) {
evt.preventDefault();
}
if(( evt.type == 'keyup' ) && ( evt.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
if( evt.keyCode != KeyEvent.DOM_VK_RETURN ) {
Awesomescreen.pointerImg.style.display = 'none';
document.activeElement.blur();
document.activeElement.classList.remove('exfocus');
}
document.activeElement.classList.remove('active');
this.settingsDialogHomepageInputArea.value = '';
},
handleDialogHomepageDefault:
function settings_handleDialogHomepageDefault(evt) {
if( evt ) {
evt.preventDefault();
}
if(( evt.type == 'keyup' ) && ( evt.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
if( evt.keyCode != KeyEvent.DOM_VK_RETURN ) {
Awesomescreen.pointerImg.style.display = 'none';
document.activeElement.blur();
document.activeElement.classList.remove('exfocus');
}
document.activeElement.classList.remove('active');
this.getDefaultHomepage((function(result) {
this.settingsDialogHomepageInputArea.value = result;
}).bind(this));
},
handleDialogHomepageCancel:
function settings_handleDialogHomepageCancel(evt) {
if( evt ) {
evt.preventDefault();
}
if(( evt.type == 'keyup' ) && ( evt.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
// animation end event handler
var end_event = (function() {
Settings.settingsDialogHomepageCancel.removeEventListener('transitionend',
end_event, false);
Settings.hideDialogHomepage();
});
// end animantion event
Settings.settingsDialogHomepageCancel.addEventListener('transitionend',
end_event, false);
document.activeElement.classList.remove('active');
},
handleDialogHomepageOk: function settings_handleDialogHomepageOk(evt) {
if( evt ) {
evt.preventDefault();
}
if(( evt.type == 'keyup' ) && ( evt.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
// animation end event handler
var end_event = (function() {
Settings.settingsDialogHomepageOk.removeEventListener('transitionend',
end_event, false);
Settings.hideDialogHomepage();
});
// end animantion event
Settings.settingsDialogHomepageOk.addEventListener('transitionend',
end_event, false);
document.activeElement.classList.remove('active');
this.setHomepage(this.settingsDialogHomepageInputArea.value);
this.settingsHomepageName.textContent =
this.settingsDialogHomepageInputArea.value;
},
/**
* Handle search engine click.
*/
handleSearchEngineClick: function settings_handleSearchEngineClick() {
if( !this.isDialogSearchDisplayed() ) {
this.focusList = [];
Browser.switchCursorMode(false);
this.settingsDialog.classList.remove('hidden');
this.settingsDialogSearch.classList.remove('hidden');
this.selectSearchEngine = this.currentSearchEngine;
this.searchEngineList = SearchUtil.getEngineList();
for(var i in this.searchEngineList) {
var title = document.createElement('div');
title.classList.add('title');
var name = document.createElement('p');
name.classList.add('name');
name.textContent = this.searchEngineList[i].name;
title.appendChild(name);
var check = document.createElement('div');
check.classList.add('check');
var onoff = document.createElement('p');
if( name.textContent == this.currentSearchEngine ) {
name.dataset.display = 'selected';
onoff.classList.add('on');
} else {
name.dataset.display = '';
onoff.classList.add('off');
}
check.appendChild(onoff);
var item = document.createElement('div');
item.classList.add('item');
item.appendChild(title);
item.appendChild(check);
item.tabIndex = '0';
this.settingsDialogSearchSelectList.appendChild(item);
item.addEventListener('mouseup',
this.handleDialogSearchSelected.bind(this));
item.addEventListener('keyup',
this.handleDialogSearchSelected.bind(this));
this.focusList.push(item);
}
this.focusList.push(this.settingsDialogSearchOk);
this.focusList.push(this.settingsDialogSearchCancel);
this.focusPos = this.focusList.length - 1;
this.focusChange(this.focusPos);
}
},
handleClearHistoryClick: function settings_handleClearHistoryClick() {
BrowserDialog.createDialog('clear_history', null);
},
handleClearCookieClick: function settings_handleClearCookieClick() {
BrowserDialog.createDialog('del_cookie', null);
},
clearCookieFailed: function settings_clearCookieFailed() {
// this.settingsBannerMessage.innerHTML =
// 'Failed to clear cookies and stored data';
this.settingsBannerMessage.setAttribute('data-l10n-id', 'LT_FAILED_');
this.showBannerMessage();
},
showBannerMessage: function settings_showBannerMessage() {
if( this.settingsBannerMessage.dataset.display != 'visible' ) {
this.settingsBannerMessage.dataset.display = 'visible';
}
clearTimeout( this.showBannerMessageTimeoutID );
this.showBannerMessageTimeoutID = setTimeout( function() {
Settings.settingsBannerMessage.dataset.display = '';
}, 3000);
},
hideDialogSearch: function settings_hideDialogSearch() {
if( this.isDialogSearchDisplayed() ) {
Awesomescreen.pointerImg.style.display = 'none';
var childs = this.settingsDialogSearchSelectList.childNodes;
var len = childs.length;
for(var i = 0 ; i < len ; i ++) {
this.settingsDialogSearchSelectList.removeChild(childs[0]);
}
this.settingsDialogSearch.classList.add('hidden');
this.settingsDialog.classList.add('hidden');
Browser.switchCursorMode(true);
}
},
isDialogSearchDisplayed: function settings_isDialogSearchDisplayed() {
return !this.settingsDialogSearch.classList.contains('hidden');
},
handleDialogSearchSelected:
function settings_handleDialogSearchSelected(ev) {
if( ev ) {
ev.preventDefault();
}
if(( ev.type == 'keyup' ) && ( ev.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
this.selectSearchEngine = ev.currentTarget.textContent;
var childs = this.settingsDialogSearchSelectList.childNodes;
var len = childs.length;
for(var i = 0 ; i < len ; i ++) {
if(childs[i].textContent == this.selectSearchEngine) {
childs[i].firstChild.firstChild.dataset.display = 'selected';
childs[i].lastChild.lastChild.classList.remove('off');
childs[i].lastChild.lastChild.classList.add('on');
} else {
childs[i].firstChild.firstChild.dataset.display = '';
childs[i].lastChild.lastChild.classList.remove('on');
childs[i].lastChild.lastChild.classList.add('off');
}
}
},
handleDialogSearchCancel: function settings_handleDialogSearchCancel(ev) {
if( ev ) {
ev.preventDefault();
}
if(( ev.type == 'keyup' ) && ( ev.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
// animation end event handler
var end_event = (function() {
Settings.settingsDialogSearchCancel.removeEventListener('transitionend',
end_event, false);
Settings.hideDialogSearch();
});
// end animantion event
Settings.settingsDialogSearchCancel.addEventListener('transitionend',
end_event, false);
document.activeElement.classList.remove('active');
},
handleDialogSearchOk: function settings_handleDialogSearchOk(ev) {
if( ev ) {
ev.preventDefault();
}
if(( ev.type == 'keyup' ) && ( ev.keyCode != KeyEvent.DOM_VK_RETURN )) {
return;
}
// animation end event handler
var end_event = (function() {
Settings.settingsDialogSearchOk.removeEventListener('transitionend',
end_event, false);
Settings.hideDialogSearch();
});
var setSearchEngine = function () {
this.currentSearchEngine = this.selectSearchEngine;
this.settingsSearchEngineName.textContent =
this.currentSearchEngine;
Toolbar.setSearchEngine();
};
// end animantion event
Settings.settingsDialogSearchOk.addEventListener('transitionend',
end_event, false);
if( this.currentSearchEngine != this.selectSearchEngine ) {
for(var i in this.searchEngineList) {
if( this.selectSearchEngine == this.searchEngineList[i].name ) {
SearchUtil.setSearchEngineId(this.searchEngineList[i].id,
setSearchEngine.bind(this));
break;
}
}
}
document.activeElement.classList.remove('active');
},
/**
* Handle Key Event.
*/
handleKeyEvent: function settings_handleKeyEvent(ev) {
if( !Settings.isDisplayed() ) {
return false;
}
// in the input area focus (= display keyboard)
if(document.activeElement.nodeName == 'INPUT') {
return true;
}
switch( ev.keyCode ) {
case KeyEvent.DOM_VK_LEFT :
ev.preventDefault();
if( Settings.isDialogHomepageDisplayed() ) {
if(( Settings.focusPos == 1 ) || ( Settings.focusPos == 4 )) {
Settings.focusPos --;
Settings.focusChange(Settings.focusPos);
}
return true;
}
if( Settings.isDialogSearchDisplayed() ) {
if( Settings.focusPos == Settings.focusList.length - 1 ) {
Settings.focusPos --;
Settings.focusChange(Settings.focusPos);
}
return true;
}
break;
case KeyEvent.DOM_VK_RIGHT :
ev.preventDefault();
if( Settings.isDialogHomepageDisplayed() ) {
if(( Settings.focusPos === 0 ) || ( Settings.focusPos === 3 )) {
Settings.focusPos ++;
Settings.focusChange(Settings.focusPos);
}
return true;
}
if( Settings.isDialogSearchDisplayed() ) {
if( Settings.focusPos == Settings.focusList.length - 2 ) {
Settings.focusPos ++;
Settings.focusChange(Settings.focusPos);
}
return true;
}
break;
case KeyEvent.DOM_VK_UP :
ev.preventDefault();
if( Settings.isDialogHomepageDisplayed() ) {
if(( Settings.focusPos === 2 ) || ( Settings.focusPos === 4 )) {
Settings.focusPos -= 2;
Settings.focusChange(Settings.focusPos);
} else if( Settings.focusPos === 3 ) {
Settings.focusPos --;
Settings.focusChange(Settings.focusPos);
}
return true;
}
if( Settings.isDialogSearchDisplayed() ) {
if( Settings.focusPos > 0 ) {
if( Settings.focusPos >= Settings.focusList.length - 1 ) {
Settings.focusPos = Settings.focusList.length - 3;
} else {
Settings.focusPos --;
}
Settings.focusChange(Settings.focusPos);
}
return true;
}
break;
case KeyEvent.DOM_VK_DOWN :
ev.preventDefault();
if( Settings.isDialogHomepageDisplayed() ) {
if(( Settings.focusPos == 1 ) || ( Settings.focusPos === 2 )) {
Settings.focusPos ++;
Settings.focusChange(Settings.focusPos);
} else if( Settings.focusPos === 0 ) {
Settings.focusPos += 2;
Settings.focusChange(Settings.focusPos);
}
return true;
}
if( Settings.isDialogSearchDisplayed() ) {
if( Settings.focusPos < Settings.focusList.length - 2 ) {
Settings.focusPos ++;
Settings.focusChange(Settings.focusPos);
}
return true;
}
break;
case KeyEvent.DOM_VK_RETURN :
ev.preventDefault();
if( Settings.focusPos === 0 ) {
Settings.focusList[Settings.focusPos].focus();
if( Settings.isDialogHomepageDisplayed() ) {
Awesomescreen.pointerImg.style.display = 'none';
}
}else{
document.activeElement.classList.remove('active');
document.activeElement.classList.add('active');
}
break;
case KeyEvent.DOM_VK_BACK_SPACE :
if( Settings.isDialogHomepageDisplayed() ) {
Settings.hideDialogHomepage();
return true;
}
if( Settings.isDialogSearchDisplayed() ) {
Settings.hideDialogSearch();
return true;
}
Settings.hide();
return true;
default :
return false;
}
return true;
}
};

View file

@ -0,0 +1,941 @@
/* globals KeyEvent */
'use strict';
(function(exports){
/**
* Max number of list item visible when scroll.
* @type {Number}
*/
const MAX_VISIBLE_ITEM = 7;
/**
* Initial list element query number when first render list view
* @type {Number}
*/
const INIT_LIST_ELEMENT_QUERY_NUMBER = 14;
/**
* Max number of list html element can be render.
* @type {Number}
*/
const MAX_LIST_ELEMENT = 21;
/**
* Height of list item element, unit is rem.
* @type {Number}
*/
const LIST_ITEM_HEIGHT = 12;
/**
* 1rem equals to 10px
* @type {Number}
*/
const PER_REM = 10;
/**
* SmartList constructor
* @param {Node} el - Target HTML element of SmartList.
* @param {String} l10nTitle - Smart list title string.
*/
function SmartList(el, l10nTitle){
this.el = el;
this.listEl = null;
this.listPointerEl = null;
this.l10nTitle = l10nTitle;
/**
* Number of list item rendered.
* @type {Number}
*/
this.listItemRenderNum = 0;
/**
* Index of focus element in list.
* @type {Number}
*/
this.focusIndex = 0;
/**
* Index of list item start at.
* @type {Number}
*/
this.listIndexStartAt = 0;
/**
* Index of list item end at.
* @type {Number}
*/
this.listIndexEndAt = 0;
/**
* Index of visible list item start at.
* @type {Number}
*/
this.listVisibleStartAt = 0;
/**
* Current navigation folder.
* @type {String}
*/
this.navState = null;
/**
* Save user browser history.
* @type {Array}
*/
this.navHistory = [];
/**
* list items which in dom tree and been initialized but render with data
* @type {Array}
*/
this.initializedItems = [];
/**
* List item element map
* @type {Object}
*/
this.listItemMap = {};
this.init();
}
SmartList.prototype = {
constructor: SmartList,
/**
* Create smart list dom tree architecture
*/
/**
* <div class="smart-list-container">
* <h2 class="smart-list-title" data-l10n-id={this.l10nTitle}></h2>
* <div class="smart-list-wrap">
* <ul class="smart-list-view"></ul>
* <div class="smart-list-mask"></div>
* <div class="smart-list-pointer"></div>
* </div>
* </div>
*/
init: function() {
var container = document.createElement('div'),
title = document.createElement('h2'),
listWrap = document.createElement('div'),
listView = document.createElement('ul'),
listMask = document.createElement('div'),
listPointer = document.createElement('div');
container.classList.add('smart-list-container');
title.classList.add('smart-list-title');
title.setAttribute('data-l10n-id', this.l10nTitle);
listWrap.classList.add('smart-list-wrap');
listView.classList.add('smart-list-view');
listMask.classList.add('smart-list-mask');
listPointer.classList.add('smart-list-pointer');
container.appendChild(title);
container.appendChild(listWrap);
listWrap.appendChild(listView);
listWrap.appendChild(listMask);
listWrap.appendChild(listPointer);
this.el.classList.add('smart-list');
this.el.addEventListener('keyup', this.handleListKeyUp.bind(this));
this.el.appendChild(container);
this.listEl = listView;
this.listPointerEl = listPointer;
},
/**
* Open smart list.
*/
open: function() {
this.reset();
this.dispatchLoadDataByRange(0, INIT_LIST_ELEMENT_QUERY_NUMBER, null,
(listData) => {
this.el.classList.add('show');
if (listData.length > 0) {
this.render(listData);
var focusEl = this.listItemMap[0];
this.pointerItem(focusEl);
this.focusItem(focusEl);
} else {
this.focusItem(this.el);
}
var event = new Event('open');
this.el.dispatchEvent(event);
}
);
},
/**
* Close smart list.
*/
close: function() {
var event = new Event('close');
this.navState = null;
this.navHistory = [];
this.el.classList.remove('show');
this.el.dispatchEvent(event);
if(this.isPointerDisplay()) {
this.hideListPointer();
}
},
/**
* Reset smart list
*/
reset: function(){
var key = 0;
this.listEl.style.transform = 'translateY(0rem)';
this.focusIndex = 0;
this.listVisibleStartAt = 0;
this.listIndexStartAt = 0;
this.listIndexEndAt = 0;
for (key in this.listItemMap) {
if (this.listItemMap.hasOwnProperty(key)) {
this.resetItem(this.listItemMap[key]);
this.initializedItems.push(this.listItemMap[key]);
delete this.listItemMap[key];
}
}
this.hideListPointer();
},
/**
* Go back to previous folder. If there is no previous folder, close list.
*/
goBack: function() {
if (!this.navState) {
this.close();
} else {
this.navHistory.pop();
this.navState = this.getCurNavHistory();
var folderId = this.navState ? this.navState.folderId : null;
this.reset();
this.switchListView(folderId);
}
},
/**
* Render smart list
* @param {Array} listData - Array of listData.
*/
render: function(listData){
var itemEl = null,
i = 0,
length = listData.length;
for (; i < length; i++) {
/*
* if there are reseted list item, use these to render data,
* else create new html element to render data
*/
if (this.initializedItems.length > 0) {
itemEl = this.initializedItems.pop();
this.updateItem(itemEl, listData[i]);
} else {
itemEl = this.createItem(listData[i]);
this.listEl.appendChild(itemEl);
this.listItemRenderNum++;
}
itemEl.setAttribute('data-index', i);
itemEl.style.transform =
'translateY(' + (LIST_ITEM_HEIGHT * i) + 'rem)';
this.listItemMap[i] = itemEl;
}
this.listIndexEndAt = length - 1;
},
/**
* Is smart list opened.
* @return {Boolean} - true when smart list opened.
*/
isDisplay: function() {
return this.el.classList.contains('show');
},
/**
* Add new list item.
* @param {Number} index - Index of new list item.
* @param {Object} data - The list item data.
*/
addItem: function(index, data) {
if (!data) {
return;
}
var itemEl = null,
transform = 0;
if (index < this.listIndexStartAt) {
// add item to the beginning of the list
if (this.initializedItems.length > 0) {
itemEl = this.initializedItems.pop();
this.updateItem(itemEl, data);
} else if (this.listItemRenderNum === MAX_LIST_ELEMENT){
itemEl = this.listItemMap[this.listIndexEndAt];
this.updateItem(itemEl, data);
delete this.listItemMap[this.listIndexEndAt];
this.listIndexEndAt--;
} else {
itemEl = this.createItem(data);
this.listEl.appendChild(itemEl);
this.listItemRenderNum++;
}
this.listItemMap[index] = itemEl;
itemEl.setAttribute('data-index', index);
transform = (index) * LIST_ITEM_HEIGHT;
itemEl.style.transform =
'translateY(' + transform + 'rem)';
this.listIndexStartAt = index;
} else if (index > this.listIndexEndAt) {
// add item to the end of the list
if (this.initializedItems.length > 0) {
itemEl = this.initializedItems.pop();
this.updateItem(itemEl, data);
} else if (this.listItemRenderNum === MAX_LIST_ELEMENT){
itemEl = this.listItemMap[this.listIndexStartAt];
this.updateItem(itemEl, data);
delete this.listItemMap[this.listIndexStartAt];
this.listIndexStartAt++;
} else {
itemEl = this.createItem(data);
this.listEl.appendChild(itemEl);
this.listItemRenderNum++;
}
this.listItemMap[index] = itemEl;
itemEl.setAttribute('data-index', index);
transform = (index) * LIST_ITEM_HEIGHT;
itemEl.style.transform =
'translateY(' + transform + 'rem)';
this.listIndexEndAt = index;
}
},
/**
* Create List Item.
* @param {Object} data - list item data object
*/
/**
* <li class="list-item">
* <div class="icon-box icon-box-left">
* <div class="icon"></div>
* </div>
* <div class="text-box">
* <span class="title"></span>
* <span class="uri"></span>
* </div>
* <div class="icon-box icon-box-right">
* <div class="icon" data-icon="arrow-right"></div>
* </div>
* </li>
*/
createItem: function(data) {
var itemEl = document.createElement('li'),
iconLeftEl = document.createElement('div'),
iconImgLeftEl = document.createElement('div'),
textEl = document.createElement('div'),
titleEl = document.createElement('span'),
uriEl = document.createElement('span'),
iconRightEl = document.createElement('div'),
iconImgRightEl = document.createElement('div');
itemEl.classList.add('list-item');
itemEl.setAttribute('tabindex', '0');
itemEl.setAttribute('data-type', data.type);
iconLeftEl.classList.add('icon-box', 'icon-box-left');
iconImgLeftEl.classList.add('icon');
iconLeftEl.appendChild(iconImgLeftEl);
textEl.classList.add('text-box');
titleEl.classList.add('title');
uriEl.classList.add('uri');
textEl.appendChild(titleEl);
textEl.appendChild(uriEl);
iconRightEl.classList.add('icon-box', 'icon-box-right');
iconImgRightEl.classList.add('icon');
iconRightEl.appendChild(iconImgRightEl);
itemEl.appendChild(iconLeftEl);
itemEl.appendChild(textEl);
itemEl.appendChild(iconRightEl);
this.updateItemContent({
item: itemEl,
iconImgLeft: iconImgLeftEl,
iconImgRight: iconImgRightEl,
title: titleEl,
uri: uriEl
}, data);
// XXX: delegate these events later
itemEl.
addEventListener('keydown', this.handleItemKeyDown.bind(this));
itemEl.
addEventListener('keyup', this.handleItemKeyUp.bind(this));
itemEl.
addEventListener('mouseup', this.handleItemMouseUp.bind(this));
itemEl.
addEventListener('mouseover', this.handleItemMouseOver.bind(this));
itemEl.
addEventListener('mouseout', this.handleItemMouseOut.bind(this));
return itemEl;
},
/**
* Update list item element content.
* @param {Node} el - HTML list item to update.
* @param {Object} data - list item data object.
*/
updateItem: function(el, data) {
var iconImgLeftEl = el.querySelector('.icon-box-left .icon'),
titleEl = el.querySelector('.title'),
uriEl = el.querySelector('.uri'),
iconImgRightEl = el.querySelector('.icon-box-right .icon');
this.updateItemContent({
item: el,
iconImgLeft: iconImgLeftEl,
iconImgRight: iconImgRightEl,
title: titleEl,
uri: uriEl
}, data);
},
/**
* Update the content of the elements in an given item.
* @param {Object} elems - all elements have to be updated.
* @param {Object} data - list item data object.
*/
updateItemContent: function(elems, data) {
var itemEl = elems.item,
iconImgLeftEl = elems.iconImgLeft,
iconImgRightEl = elems.iconImgRight,
titleEl = elems.title,
uriEl = elems.uri;
if (data.readOnly) {
itemEl.setAttribute('readOnly', data.readOnly);
} else {
itemEl.setAttribute('readOnly', false);
}
if (data.type) {
itemEl.setAttribute('data-type', data.type);
switch (data.type) {
case 'folder':
itemEl.setAttribute('data-folder', data.id);
iconImgLeftEl.style.backgroundImage = '';
iconImgLeftEl.setAttribute('data-icon', 'folder');
titleEl.textContent = data.title;
uriEl.textContent = '';
iconImgRightEl.setAttribute('data-icon', 'arrow-right');
break;
case 'bookmark':
itemEl.setAttribute('data-folder', '');
if (data.iconUri) {
iconImgLeftEl.style.backgroundImage = 'url(' + data.iconUri +')';
iconImgLeftEl.setAttribute('data-icon', '');
} else {
iconImgLeftEl.style.backgroundImage = '';
iconImgLeftEl.setAttribute('data-icon', 'default-fav');
}
titleEl.textContent = data.title ? data.title : data.uri;
uriEl.textContent = data.uri;
iconImgRightEl.setAttribute('data-icon', '');
break;
case 'button':
itemEl.setAttribute('data-folder', '');
iconImgLeftEl.style.backgroundImage = '';
iconImgLeftEl.setAttribute('data-icon', 'arrow-left');
titleEl.textContent = data.title;
uriEl.textContent = '';
iconImgRightEl.setAttribute('data-icon', '');
break;
default:
break;
}
} else {
// The records without "type" will be recognized as history records.
itemEl.setAttribute('data-type', 'bookmark');
itemEl.setAttribute('data-folder', '');
if (data.iconUri) {
iconImgLeftEl.setAttribute('data-icon', '');
iconImgLeftEl.style.backgroundImage = 'url(' + data.iconUri +')';
} else {
iconImgLeftEl.setAttribute('data-icon', 'default-fav');
iconImgLeftEl.style.backgroundImage = '';
}
titleEl.textContent = data.title ? data.title : data.uri;
uriEl.textContent = data.uri;
iconImgRightEl.setAttribute('data-icon', '');
}
},
/**
* Remove the focus list item.
*/
removeFocusItem: function() {
var targetEl = null,
i = 0;
targetEl = this.listItemMap[this.focusIndex];
if (targetEl) {
this.resetItem(targetEl);
this.initializedItems.push(targetEl);
//reindex and update transform of the element behind the focus index
for (i = this.focusIndex; i < this.listIndexEndAt; i++) {
this.listItemMap[i] = this.listItemMap[i+1];
targetEl = this.listItemMap[i];
targetEl.setAttribute('data-index', i);
this.shiftElement(targetEl, (-1 * LIST_ITEM_HEIGHT));
}
delete this.listItemMap[this.listIndexEndAt];
this.listIndexEndAt--;
// if the removed item is the last item of index,
// focus the new last element
if (this.listItemMap[this.focusIndex]) {
this.focusItem(this.listItemMap[this.focusIndex]);
} else if (this.listIndexEndAt !== -1) {
this.focusIndex = this.listIndexEndAt;
this.focusItem(this.listItemMap[this.focusIndex]);
}
var event = new Event('itemRemoved');
this.el.dispatchEvent(event);
}
},
/**
* Focus list item.
* @param {Node} el - HTML list item to focus.
*/
focusItem: function(el) {
el.focus();
},
pointerItem: function(el) {
var pos = el.getBoundingClientRect(),
transposX = (Math.ceil(pos.right) - 120 ) / PER_REM,
transposY = (Math.ceil(pos.bottom) - 40 ) / PER_REM;
this.listPointerEl.style.transform =
'translate(' + transposX + 'rem,' + transposY + 'rem)';
this.showListPointer();
},
/**
* Focus the First visible list item.
*/
focusFirstVisibleItem: function() {
var targetEl = null;
// if there is list item rendered and the current active element not in
// smart list, focus the first visible list item.
if (this.listIndexEndAt !== -1 &&
Array.prototype.indexOf.call(
this.listEl.children,
document.activeElement) === -1) {
this.focusIndex = this.listVisibleStartAt;
targetEl = this.listItemMap[this.focusIndex];
if (targetEl) {
this.pointerItem(targetEl);
this.focusItem(targetEl);
}
}
},
/**
* Reset list item.
* @param {Node} el - HTML list item to focus.
*/
resetItem: function(el) {
var iconImgEl = el.querySelector('.icon-box-left .icon'),
titleEl = el.querySelector('.title'),
uriEl = el.querySelector('.uri');
el.setAttribute('data-index', -1);
el.setAttribute('data-type', '');
el.setAttribute('data-folder', '');
el.setAttribute('readOnly', false);
el.style.transform = '';
iconImgEl.style.backgroundImage = '';
iconImgEl.setAttribute('data-icon', '');
titleEl.textContent = '';
uriEl.textContent = '';
},
/**
* Preload the item out of visible view.
* @param {Number} listIndex - preload list index.
*/
preloadItem: function(listIndex) {
var dataIndex = 0;
if (this.navState) {
if (listIndex === 0) {
var data = this.generateBackButtonData(this.navState.folderTitle);
this.addItem(0, data);
} else {
dataIndex = listIndex - 1;
this.dispatchLoadDataByIndex(
listIndex,
dataIndex,
this.navState.folderId
);
}
} else {
dataIndex = listIndex;
this.dispatchLoadDataByIndex(
listIndex,
dataIndex,
null
);
}
},
/**
* Shift list item transform
* @param {Node} el - list item element to transform
* @param {Nunber} shift - shift transform, unit is rem
*/
shiftElement: function(el, shift) {
var style = el.style.transform.split('('),
transform = parseInt(style[1], 10);
transform += shift;
el.style.transform =
'translateY(' + transform + 'rem) translateZ(0.01px)';
},
/**
* Get Focus list element's index
*/
getFocusItemIndex: function() {
return this.focusIndex;
},
/**
* Get Focus list element's uri content
*/
getFocusItemUri: function() {
var targetEl = this.listItemMap[this.focusIndex];
return targetEl ? targetEl.querySelector('.uri').textContent : null;
},
/**
* Get Focus list element's title content
*/
getFocusItemTitle: function() {
var targetEl = this.listItemMap[this.focusIndex];
return targetEl ? targetEl.querySelector('.title').textContent : null;
},
/**
* Update focus list element's title content
* @param {String} title - title to update
*/
updateFocusItemTitle: function(title) {
var targetEl = this.listItemMap[this.focusIndex];
if (targetEl) {
targetEl.querySelector('.title').textContent = title;
this.focusItem(targetEl);
var event = new Event('itemUpdated');
this.el.dispatchEvent(event);
}
},
isPointerDisplay: function() {
return this.listPointerEl.classList.contains('show');
},
showListPointer: function() {
this.listPointerEl.classList.add('show');
},
hideListPointer: function() {
this.listPointerEl.classList.remove('show');
},
/**
* Add folder id and folder title
* @param {[type]} folderId [description]
* @param {[type]} folderTitle [description]
*/
addNavHistory: function(folderId, folderTitle) {
this.navHistory.push({
folderId: folderId,
folderTitle: folderTitle
});
},
/**
* Get current user browse state.
* @return {String} current user browse folder.
*/
getCurNavHistory: function() {
var len = this.navHistory.length;
if (len > 0) {
return this.navHistory[len - 1];
} else {
return null;
}
},
/**
* Generate back button data.
* @return {Object} - back button data
*/
generateBackButtonData: function(title) {
return {
type: 'button',
title: 'Back to ' + title
};
},
switchListView: function(folderId) {
this.dispatchLoadDataByRange(0, INIT_LIST_ELEMENT_QUERY_NUMBER, folderId,
(listData) => {
// if user is browser list data in a folder,
// add back button data at the first place of listData
if (this.navState) {
listData.unshift(
this.generateBackButtonData(this.navState.folderTitle)
);
}
if (listData.length === 0) {
return;
}
this.render(listData);
// focus the first item in list. if the first item is button and list
// item length is bigger than 1, focus the second item
this.focusIndex = 0;
if (this.navState && this.listIndexEndAt > 0) {
this.focusIndex = 1;
}
var focusEl = this.listItemMap[this.focusIndex];
this.pointerItem(focusEl);
this.focusItem(focusEl);
}
);
},
/**
* Move focus to the previous element
*/
moveFocusIndexUp: function() {
this.focusIndex -= 1;
var preloadItemIndex = this.focusIndex - MAX_VISIBLE_ITEM;
if (preloadItemIndex >= 0 && preloadItemIndex < this.listIndexStartAt) {
this.preloadItem(preloadItemIndex);
}
// if the new focus element is before this.listVisibleStartAt,
// update list item's transform to shift down
var targetEl = this.listItemMap[this.focusIndex];
if (this.focusIndex < this.listVisibleStartAt) {
this.listVisibleStartAt--;
this.shiftElement(this.listEl, LIST_ITEM_HEIGHT);
this.focusItem(targetEl);
} else {
this.pointerItem(targetEl);
this.focusItem(targetEl);
}
},
/**
* Move focus to the next element
*/
moveFocusIndexDown: function() {
this.focusIndex += 1;
// pre-load list item later then listIndexEndAt
var preloadItemIndex = this.focusIndex + MAX_VISIBLE_ITEM;
if (preloadItemIndex > this.listIndexEndAt) {
this.preloadItem(preloadItemIndex);
}
// if the new focus element is after this.listIndexEndAt,
// update list item's transform to shift up
var targetEl = this.listItemMap[this.focusIndex];
if ((this.focusIndex - this.listVisibleStartAt) ===
MAX_VISIBLE_ITEM ) {
this.listVisibleStartAt++;
this.shiftElement(this.listEl, (-1 * LIST_ITEM_HEIGHT));
this.focusItem(targetEl);
} else {
this.pointerItem(targetEl);
this.focusItem(targetEl);
}
},
handleListKeyUp: function(e) {
switch(e.keyCode){
case KeyEvent.DOM_VK_ESCAPE:
case KeyEvent.DOM_VK_BACK_SPACE:
this.goBack();
break;
default:
return;
}
},
handleItemKeyDown: function(e) {
switch(e.keyCode){
case KeyEvent.DOM_VK_UP:
if(this.focusIndex > this.listIndexStartAt) {
this.moveFocusIndexUp();
}
break;
case KeyEvent.DOM_VK_DOWN:
if(this.focusIndex < this.listIndexEndAt) {
this.moveFocusIndexDown();
}
break;
default:
return;
}
},
handleItemKeyUp: function(e) {
switch(e.keyCode){
case KeyEvent.DOM_VK_SUBMENU:
this.handleKeySubmenu(e);
break;
case KeyEvent.DOM_VK_RETURN:
this.handleKeyReturn(e);
break;
default:
return;
}
},
handleItemMouseUp: function(e) {
switch(e.button){
case 0 :
// left click
this.handleKeyReturn(e);
break;
case 2:
//right click
this.handleKeySubmenu(e);
break;
default:
break;
}
},
handleItemMouseOver: function(e) {
var targetEl = e.currentTarget;
if (targetEl) {
var dataIndex = targetEl.getAttribute('data-index');
var event = new CustomEvent('mouseOverItem', {detail: targetEl});
targetEl.focus();
this.focusIndex = parseInt(dataIndex, 10);
this.el.dispatchEvent(event);
}
},
handleItemMouseOut: function(e) {
var targetEl = e.currentTarget;
if (targetEl) {
this.hideListPointer();
targetEl.blur();
}
},
handleKeyReturn: function(e) {
var targetEl = e.currentTarget,
type = targetEl.getAttribute('data-type'),
folderId = null;
switch(type) {
case 'folder':
var folderTitle = targetEl.querySelector('.title').textContent;
folderId = targetEl.getAttribute('data-folder');
this.addNavHistory(folderId, folderTitle);
this.navState = this.getCurNavHistory();
this.reset();
this.switchListView(folderId);
break;
case 'bookmark':
var uriEL = targetEl.querySelector('.uri');
if (uriEL) {
this.dispatchDisplayWebsite(uriEL.textContent);
this.close();
}
break;
case 'button':
this.navHistory.pop();
this.navState = this.getCurNavHistory();
folderId = this.navState ? this.navState.folderId : null;
this.reset();
this.switchListView(folderId);
break;
default:
break;
}
},
handleKeySubmenu: function(e) {
var targetEl = e.currentTarget;
if (targetEl.getAttribute('data-type') === 'bookmark') {
var event = new CustomEvent('showSubMenu', {
detail: {
readOnly: targetEl.getAttribute('readOnly')
}
});
this.el.dispatchEvent(event);
}
},
dispatchDisplayWebsite: function(uri) {
var event = new CustomEvent('displayWebsite', {detail: uri});
this.el.dispatchEvent(event);
},
dispatchLoadDataByRange: function(start, number, folderId, cb) {
var eventDetail = {
startAt: start,
number: number,
folderId: folderId,
callback: cb
};
var event = new CustomEvent('loadDataByRange', {detail: eventDetail});
this.el.dispatchEvent(event);
},
dispatchLoadDataByIndex: function(listIndex, dataIndex, navState) {
var event = new CustomEvent('loadDataByIndex', {
detail: {
listIndex: listIndex,
dataIndex: dataIndex,
folderId: navState
}});
this.el.dispatchEvent(event);
}
};
exports.SmartList = SmartList;
})(window);

View file

@ -0,0 +1,107 @@
/* 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';
/* exported SyncBookmark */
/* global SyncBrowserDB */
/* global SyncDsHelper */
var SyncBookmark = (function () {
var syncDataStore;
function updateWrapper(data) {
return new Promise(resolve => {
if (data.deleted) {
SyncBrowserDB.removeBookmark(data.id, () => {
resolve();
});
} else {
SyncBrowserDB.updateRawBookmark(data, () => {
resolve();
});
}
});
}
function handleTask(task) {
return new Promise((resolve, reject) => {
var data = [];
if (task.data && task.data.fxsyncRecords) {
for (var key in task.data.fxsyncRecords) {
data.push(task.data.fxsyncRecords[key]);
}
}
switch(task.operation) {
case 'update':
case 'add':
Promise.all(data.map(updateWrapper)).then(resolve);
break;
case 'clear':
// Ignore clear operation.
resolve();
break;
case 'remove':
getBookmarkByDsId(task.id, bookmark => {
if (bookmark) {
SyncBrowserDB.removeBookmark(bookmark.id, () => {
resolve();
});
}
});
break;
case 'done':
resolve();
break;
}
});
}
function getBookmarkByDsId(dsid, callback) {
SyncBrowserDB.getBookmark({bmkUri: dsid}, bookmark => {
if (bookmark) {
callback(bookmark);
} else {
var specialType =
['query', 'microsummary', 'folder', 'livemark', 'separator'];
var isSpecialType = specialType.some(value => {
return dsid.indexOf(value + '|') === 0;
});
var tmp = dsid.split('|');
if (isSpecialType && tmp.length === 2) {
var fxsyncId = tmp[1];
SyncBrowserDB.getBookmark(fxsyncId, callback);
} else {
console.warn('trying to delete a unknown type?', dsid);
callback(null);
}
}
});
}
function start() {
if (syncDataStore) {
return Promise.resolve();
}
syncDataStore = new SyncDsHelper('bookmarks_store');
return syncDataStore.init().then(() => {
return syncDataStore.start(handleTask);
});
}
function stop() {
if (!syncDataStore) {
return Promise.reject('Uninitialized DataStore');
}
return syncDataStore.stop().then(() => {
syncDataStore = null;
return SyncBrowserDB.clearBookmarks();
});
}
return {
start: start,
stop: stop
};
})();

1958
gaia/tv_apps/browser/js/sync/db.js Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,113 @@
/* 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';
/* exported SyncDsHelper */
/* global localStorage */
var SyncDsHelper = function (dataStoreName) {
if (typeof dataStoreName !== 'string') {
throw new Event('Incorrect DataStore name.');
}
this.dataStoreName = dataStoreName;
this.dataStoreRevId = dataStoreName + '::revId';
};
SyncDsHelper.prototype = {
store: null,
dataChangeHandler: null,
init() {
return this._ensureStore();
},
_ensureStore() {
if (this.store) {
return Promise.resolve(this.store);
}
return navigator.getDataStores(this.dataStoreName).then(stores => {
this.store = stores[0];
return this.store;
});
},
setSyncedRevId(revId) {
localStorage.setItem(this.dataStoreRevId, revId);
},
getSyncedRevId() {
return localStorage.getItem(this.dataStoreRevId);
},
registerStoreChangeEvent(handler) {
this._ensureStore().then(() => {
if (!this.dataChangeHandler) {
this.store.removeEventListener('change', this.dataChangeHandler);
}
this.dataChangeHandler = handler;
this.store.addEventListener('change', this.dataChangeHandler);
});
},
unregisterStoreChangeEvent() {
return this._ensureStore().then(() => {
this.store.removeEventListener('change', this.dataChangeHandler);
this.dataChangeHandler = null;
});
},
clear() {
localStorage.removeItem(this.dataStoreRevId);
return this._ensureStore().then(() => {
return this.store.clear();
});
},
start(handleTask) {
return this.init().then(() => {
this.registerStoreChangeEvent(() => {
this.dataStoreSync(handleTask);
});
return this.dataStoreSync(handleTask);
});
},
stop() {
return this.unregisterStoreChangeEvent().then(this.clear.bind(this));
},
dataStoreSync(handle) {
return this._ensureStore().then(() => {
var _revId = this.getSyncedRevId();
return new Promise((resolve, reject) => {
var runNextTask = (cursor) => {
cursor.next().then(task => {
manageTask(cursor, task);
});
};
var post = (cursor, task) => {
if (task.operation === 'done') {
this.setSyncedRevId(this.store.revisionId);
resolve();
return;
}
runNextTask(cursor);
};
var manageTask = (cursor, task) => {
if (handle) {
handle(task).then(() => post(cursor, task));
} else {
post(cursor, task);
}
};
runNextTask(this.store.sync(_revId));
});
});
}
};

View file

@ -0,0 +1,86 @@
/* 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';
/* exported SyncHistory */
/* global SyncBrowserDB */
/* global SyncDsHelper */
/*
exampleHistroyInIndexedDB = {
"uri": "http://example.com/",
"title": "Hello World",
"frecency": 1,
"iconUri": "http://example.com/favicon.ico",
"screenshot": {}
}
*/
var SyncHistory = (function () {
var syncDataStore;
function handleTask(task) {
return new Promise(resolve => {
switch(task.operation) {
case 'update':
case 'add':
var data = {};
var syncedData = task.data;
if (syncedData && syncedData.url &&
Array.isArray(syncedData.visits) && syncedData.visits.length > 0) {
data.uri = syncedData.url;
data.title = syncedData.title;
data.fxsyncId = syncedData.fxsyncId;
data.timestamp = syncedData.visits[0];
} else {
console.warn('Invalid places record:', task);
resolve();
return;
}
SyncBrowserDB.updateRawHistory(data, () => {
resolve();
});
break;
case 'clear':
// Ignore clear operation.
resolve();
break;
case 'remove':
SyncBrowserDB.removeHistory(task.id, () => {
resolve();
});
break;
case 'done':
resolve();
break;
}
});
}
function start() {
if (syncDataStore) {
return Promise.resolve();
}
syncDataStore = new SyncDsHelper('places');
return syncDataStore.init().then(() => {
return syncDataStore.start(handleTask);
});
}
function stop() {
if (!syncDataStore) {
return Promise.reject('Uninitialized DataStore');
}
return syncDataStore.stop().then(() => {
syncDataStore = null;
return SyncBrowserDB.clearHistoryDeep();
});
}
return {
start: start,
stop: stop
};
})();

View file

@ -0,0 +1,163 @@
/* 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/. */
/**
* This module acts as a bridge between the browser UI and the Sync manager
* that lives in the System application.
*
* It allows consumers to subscribe to updates done in the Sync state machine
* so they can update the UI accordingly.
*
* The simple high level picture of Sync in the browser is:
*
* settings.js toolbar.js
* | |
* | |
* \______ manager_bridge.js _______/
* |
* | IAC
* |
* smart_system/sync_manager.js
*
*/
/* global LazyLoader */
/* global SyncBookmark */
/* global SyncHistory */
'use strict';
(function(exports) {
const DEBUG = false;
function debug() {
if (DEBUG) {
console.log('[SyncManagerBridge] ' + Array.slice(arguments).concat());
}
}
var SyncManagerBridge = {
_port: null,
_requests: new Map(),
_listeners: new Map(),
addListener(listener) {
debug('addListener', listener);
if (!this._listeners.has(listener)) {
this._listeners.set(listener);
}
},
removeListener(listener) {
debug('removeListener', listener);
if (!this._listeners.has(listener)) {
return;
}
this._listeners.delete(listener);
},
connect() {
if (this._port) {
return Promise.resolve(this._port);
}
return new Promise((resolve, reject) => {
navigator.mozApps.getSelf().onsuccess = event => {
var app = event.target.result;
app.connect('gaia-sync-management').then(ports => {
if (!ports || !ports.length) {
return reject();
}
this._port = ports[0];
this._port.onmessage = this.onmessage.bind(this);
resolve(this._port);
}).catch(reject);
};
});
},
iacRequest(request) {
debug('iacRequest', JSON.stringify(request));
return new Promise(resolve => {
this.connect().then(port => {
if (request.id) {
this._requests.set(request.id, resolve);
}
port.postMessage(request);
});
});
},
onmessage(event) {
var self = this;
function notify() {
if (self._listeners.size) {
Array.from(self._listeners.keys()).forEach(listener => {
listener(message);
});
}
}
var message = event.data;
if (!message) {
return;
}
debug('message', JSON.stringify(message));
if (message.id && this._requests.has(message.id)) {
this._requests.get(message.id)(message);
this._requests.delete(message.id);
return;
}
if (message.name !== 'onsyncchange') {
return;
}
if (message.state == 'disabled' ||
message.state == 'enabled') {
LazyLoader.load([
'js/sync/ds_helper.js',
'js/sync/bookmarks.js',
'js/sync/history.js'
]).then(() => {
var method = message.state == 'enabled' ? 'start'
: 'stop';
Promise.all([
SyncBookmark[method](),
SyncHistory[method]()
]).catch(error => {
console.warn(error);
});
notify();
});
return;
}
notify();
},
getInfo() {
return this.iacRequest({
name: 'getInfo',
id: Date.now()
});
}
};
['enable',
'disable',
'sync'].forEach(requestName => {
SyncManagerBridge[requestName] = () => {
return SyncManagerBridge.iacRequest({
name: requestName
});
};
});
exports.SyncManagerBridge = SyncManagerBridge;
}(window));

View file

@ -0,0 +1,507 @@
/* 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 Awesomescreen */
/* global Browser */
/* global BrowserDialog */
/* global ERROR_DIALOG_CLOSED_BY_USER */
/* global ERROR_INVALID_SYNC_ACCOUNT */
/* global ERROR_OFFLINE */
/* global ERROR_SYNC_APP_KILLED */
/* global ERROR_UNKNOWN */
/* global LazyLoader */
/* global Settings */
/* global SettingsListener */
/* global SyncManagerBridge */
'use strict';
(function(exports) {
const DEBUG = false;
function debug() {
if (DEBUG) {
console.log('[FirefoxSyncSettings] ' + Array.slice(arguments).concat());
}
}
// Screens
const ENABLED = 'enabled';
const DISABLED = 'disabled';
const BOOKMARKS_SETTING = 'sync.collections.bookmarks.enabled';
const HISTORY_SETTING = 'sync.collections.history.enabled';
const ELEMENTS = [{
screen: DISABLED,
selector: '#fxsync-sign-in-button',
event: 'mouseup',
listener: 'enable'
}, {
screen: ENABLED,
selector: '#fxsync-signed-in-as'
}, {
screen: ENABLED,
selector: '#fxsync-sync-now-button',
event: 'mouseup',
listener: 'sync'
}, {
screen: ENABLED,
selector: '#fxsync-sign-out-button',
event: 'mouseup',
listener: 'disable'
}, {
screen: ENABLED,
selector: '#fxsync-collection-bookmarks',
event: 'click',
listener: 'onbookmarkschecked',
init: 'onbookmarkschange'
}, {
screen: ENABLED,
selector: '#fxsync-collection-history',
event: 'click',
listener: 'onhistorychecked',
init: 'onhistorychange'
}, {
screen: ENABLED,
selector: '#fxsync-tos',
event: 'click',
listener: 'openTos'
}, {
screen: ENABLED,
selector: '#fxsync-privacy',
event: 'click',
listener: 'openPrivacy'
}];
function getElementName(str) {
str = str.toLowerCase().replace('#fxsync-', '');
return str.replace(/-([a-z])/g, g => {
return g[1].toUpperCase();
});
}
var FirefoxSyncSettings = {
init() {
this.area = document.querySelector('#fxsync-area');
this.elements = {
enabled: this.area.querySelector('#fxsync-enabled'),
disabled: this.area.querySelector('#fxsync-disabled')
};
this.listeners = new Map();
this.collections = new Map();
this.screen = null;
this.state = 'disabled';
this.showScreen(DISABLED);
LazyLoader.load('shared/js/settings_listener.js').then(() => {
[{
name: BOOKMARKS_SETTING,
onchange: 'onbookmarkschange'
}, {
name: HISTORY_SETTING,
onchange: 'onhistorychange'
}].forEach(setting => {
SettingsListener.observe(setting.name, true, enabled => {
debug(setting.name + ' changed to ' + enabled);
enabled ? this.collections.set(setting.name, enabled)
: this.collections.delete(setting.name);
this[setting.onchange]();
this.maybeEnableSyncNow();
});
});
});
SyncManagerBridge.addListener(this.onsyncchange.bind(this));
document.addEventListener('visibilitychange', () => {
debug('Visibility change', document.hidden);
if (!document.hidden) {
this.refresh();
}
});
this.refresh();
},
refresh() {
debug('Refreshing');
SyncManagerBridge.getInfo().then(this.onsyncchange.bind(this));
},
/**
* This is where most part of the Sync settings logic lives.
*
* Here we handle Sync lifecycle events coming from the SyncManager
* through the SyncMangerBridge. We react to these events by
* changing the screen depending on the state.
*
* We show two possible different state:
* 1. Logged out screen. We simply show the user what Sync is and
* allow her to start using it or to keep walking.
* 2. Logged in screen. We show to the user several different options:
* + The user owning the Sync account. If the account belongs to a
* verified user that previosly used Sync, we are fine, if not, we
* show a warning asking the user to go to other Firefox client to
* create a FxA and login into Sync.
* + A button to disable sync. Clicking it will log the user out from
* FxA and will clear the synchronized data.
* + A button to start a sync on demand. Clicking it will disable the
* button and the collections switches while the synchronization is
* being performed. Once the sync is done successfully, we enable
* all the options back and refresh the last sync time.
* We disable this button if no collection is selected.
* + Collections switches. Allow the user to select which collections
* she wants to keep synchronized. If no collection is selected, the
* synchronization will be disabled.
* + ToS and Privacy links.
*/
onsyncchange(message) {
debug(JSON.stringify(message));
if (!message || !message.state) {
throw new Error('Missing sync state');
}
switch (message.state) {
case 'disabled':
// We want to show a dialog once Sync is disabled
// but we only want to do that if it's disabled via user action
// and the user has already logged in.
// (and not because it is already disabled from a previous run).
if (this.state === 'disabling' &&
(this.previousState === 'enabled' ||
this.previousState === 'syncing')) {
navigator.mozL10n.formatValue('fxsync-disabled').then(result => {
window.alert(result);
});
}
this.showScreen(DISABLED);
this.hideEnabling();
break;
case 'enabling':
this.showEnabling();
break;
case 'enabled':
// We want to show a dialog once Sync is enabled
// but we only want to do that if its enabled via user action
// (and not because it is already enabled from a previous run).
if (this.state === 'enabling') {
navigator.mozL10n.formatValue('fxsync-enabled').then(result => {
window.alert(result);
});
}
this.hideEnabling();
this.showScreen(ENABLED);
this.showUser(message.user);
this.showSyncNow();
break;
case 'syncing':
this.showScreen(ENABLED);
// In case that the user opens the browser app while we are on a
// syncing state the previous 'enabled' state is missed and so
// we need to make sure that we show the user here as well.
this.showUser(message.user);
this.showSyncing();
break;
case 'errored':
LazyLoader.load('shared/js/sync/errors.js', () => {
const IGNORED_ERRORS = [
ERROR_DIALOG_CLOSED_BY_USER,
ERROR_SYNC_APP_KILLED
];
if (IGNORED_ERRORS.indexOf(message.error) > -1) {
Settings.hide.bind(Settings)();
return;
}
var errorIds = [ERROR_UNKNOWN, ERROR_UNKNOWN + '-explanation'];
const KNOWN_ERRORS = [
ERROR_INVALID_SYNC_ACCOUNT,
ERROR_OFFLINE
];
if (KNOWN_ERRORS.indexOf(message.error) > -1) {
errorIds[0] = message.error;
errorIds[1] = message.error + '-explanation';
}
var l10n = navigator.mozL10n;
Promise.all(
errorIds.map(l10n.formatValue.bind(l10n))
).then(result => {
window.alert(result[0] + '\n' + result[1], () => {
this.showScreen(DISABLED);
});
});
});
break;
}
this.previousState = this.state;
this.state = message.state;
},
onbookmarkschange() {
debug('onbookmarkschange');
var needsCleanup;
if (!this.elements.collectionBookmarks) {
// We may observe a setting change once we already disabled Sync
// because the Sync Manager is reverting user preference changes to
// the default ones. In that case, we need to create the object
// briefly, so we can update the DOM accordingly.
this.elements.collectionBookmarks = this.area.querySelector(
'#fxsync-collection-bookmarks'
);
needsCleanup = true;
}
this.elements.collectionBookmarks.checked =
this.collections.has(BOOKMARKS_SETTING);
if (needsCleanup) {
this.elements.collectionBookmarks = null;
}
},
onbookmarkschecked() {
debug('onbookmarkschecked');
this.oncollectionchecked(this.elements.collectionBookmarks,
BOOKMARKS_SETTING);
},
onhistorychange() {
debug('onhistorychange');
var needsCleanup;
if (!this.elements.collectionHistory) {
// We may observe a setting change once we already disabled Sync
// because the Sync Manager is reverting user preference changes to
// the default ones. In that case, we need to create the object
// briefly, so we can update the DOM accordingly.
this.elements.collectionHistory = this.area.querySelector(
'#fxsync-collection-history'
);
needsCleanup = true;
}
this.elements.collectionHistory.checked =
this.collections.has(HISTORY_SETTING);
if (needsCleanup) {
this.elements.collectionHistory = null;
}
},
onhistorychecked() {
debug('onhistorychecked');
this.oncollectionchecked(this.elements.collectionHistory,
HISTORY_SETTING);
},
oncollectionchecked(element, setting) {
if (!element || !setting) {
return;
}
var checked = element.checked;
var settingObj = {};
settingObj[setting] = checked;
if (!checked) {
this.collections.delete(setting);
navigator.mozSettings.createLock().set(settingObj);
return;
}
// Yeah, mozId sucks...
// We cannot call watch twice to change the id lifetime
// callbacks. But we still need to do different stuff
// within the onlogin callback depending on who calls
// oncollectionchecked. So we need to save state.
// Thank you mozId.
this.setting = setting;
this.settingObj = settingObj;
try {
navigator.mozId.watch({
wantIssuer: 'firefox-accounts',
onlogin: () => {
// This callback is fired every time a new account logs in,
// but we only want to enable the history setting when this
// callback is called because the refresh auth flow succeeded.
// This can happen only if Sync is already enabled.
if (this.state !== 'enabled') {
return;
}
this.collections.set(this.setting, true);
navigator.mozSettings.createLock().set(this.settingObj);
},
onlogout: () => {},
onready: () => {},
onerror: error => {
element.checked = false;
console.error(error);
}
});
} catch(e) {}
navigator.mozId.request({
oncancel: () => {
element.checked = false;
},
// We keep authenticated sessions of 5 minutes, if the user clicks on
// the history collection switch after the 5 minutes are expired, we
// will be asking her to re-enter her fxa password.
refreshAuthentication: 5 * 60
});
},
addListener(element, event, listenerName) {
if (!element || !event || !listenerName) {
return;
}
// Because we bind this to the listener, we need to save
// the reference so we can remove it afterwards.
var listener = this[listenerName].bind(this);
element.addEventListener(event, listener);
return listener;
},
removeListener(element, event, listener) {
if (!element || !event || !listener) {
return;
}
element.removeEventListener(event, listener);
},
loadElements(screen) {
ELEMENTS.forEach(element => {
var name = getElementName(element.selector);
if (!Array.isArray(element.screen)) {
element.screen = [element.screen];
}
if (!this.elements[name]) {
this.elements[name] = this.area.querySelector(element.selector);
this.listeners.set(
name,
this.addListener(this.elements[name],
element.event, element.listener)
);
if (element.init) {
this[element.init]();
}
return;
}
if (element.init) {
this[element.init]();
return;
}
if (!this.listeners.has(name)) {
return;
}
if (this.elements[name].checked) {
this.elements[name].checked = false;
}
});
},
showScreen(screen) {
if (this.screen == screen) {
return;
}
this.screen = screen;
this.loadElements(screen);
this.elements.enabled.hidden = (screen != ENABLED);
this.elements.disabled.hidden = (screen != DISABLED);
},
showUser(user) {
navigator.mozL10n.setAttributes(this.elements.signedInAs,
'fxsync-signed-in-as', {
email: user
});
},
maybeEnableSyncNow() {
if (!this.elements.syncNowButton) {
return;
}
(this.collections.size <= 0) ?
this.elements.syncNowButton.classList.add('disabled') :
this.elements.syncNowButton.classList.remove('disabled');
},
disableSyncNowAndCollections(disabled) {
['collectionBookmarks',
'collectionHistory'].forEach(name => {
if (!this.elements[name]) {
return;
}
this.elements[name].disabled = disabled;
});
disabled ? this.elements.syncNowButton.classList.add('disabled')
: this.elements.syncNowButton.classList.remove('disabled');
},
showEnabling() {
this.elements.signInButton.classList.add('disabled');
this.elements.signInButton.dataset.l10nId = 'fxsync-signing';
},
hideEnabling() {
this.elements.signInButton.classList.remove('disabled');
this.elements.signInButton.dataset.l10nId = 'fxsync-sign-in';
},
showSyncNow() {
this.elements.syncNowButton.dataset.l10nId = 'fxsync-sync-now';
this.disableSyncNowAndCollections(false);
this.maybeEnableSyncNow();
},
showSyncing() {
this.elements.syncNowButton.dataset.l10nId = 'fxsync-syncing';
this.disableSyncNowAndCollections(true);
},
enable() {
SyncManagerBridge.enable();
},
disable() {
BrowserDialog.createDialog('signout_confirm').then(() => {
SyncManagerBridge.disable();
});
},
sync() {
SyncManagerBridge.sync();
},
openTos() {
this.showWebpage('https://accounts.firefox.com/legal/terms');
},
openPrivacy() {
this.showWebpage('https://accounts.firefox.com/legal/privacy');
},
showWebpage(url) {
Awesomescreen.createAddNewTab();
Browser.navigate(url);
Settings.hide();
}
};
exports.FirefoxSyncSettings = FirefoxSyncSettings;
LazyLoader.load('js/sync/manager_bridge.js', () => {
FirefoxSyncSettings.init();
});
}(window));

View file

@ -0,0 +1,113 @@
/* 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/. */
/* exports FirefoxSyncToolbar */
/* global LazyLoader */
/* global Settings */
/* global SyncManagerBridge */
'use strict';
/**
* This small module handles the logic of the Sync entry in the browser's
* top right toolbar menu.
*
* We show two different variations of the UI depending on the state of Sync:
*
* - When Sync is disabled, we show a 'Sign in to Sync' entry. Clicking it
* triggers the Firefox Accounts flow and signs the user into Sync if the
* FxA flow is completed successfuly.
* - When Sync is enabled, we show the 'Sign is as {{email}}' entry. Where
* {{email}} is the email used by the user to login into FxA.
*
* We also handle a third Sync state. When an error is received through the
* Sync Manager Bridge, we inform the user about them. The expected errors are:
*
* - ERROR_OFFLINE: The user is trying to log in Sync when the device is
* offline.
* - ERROR_INVALID_SYNC_ACCOUNT: The user is trying to log into Sync with a
* Firefox Account that has never been used before with Sync. On the first
* version we don't support the creation of new Sync accounts, so we ask the
* user to first login in Firefox Desktop or Android and try login again
* in the TV.
* - ERROR_TRY_LATER: The server is probably down. We inform the user about it
* and ask her to retry in a few minutes.
* - ERROR_UNKNOWN: We don't know what the h* was wrong, but we can't log the
* user in.
*
* Here we don't need to worry about keeping any kind of state or managing
* any state transistion apart from the UI changes. The Sync State Machine
* and Sync State Manager takes care of handling all that for us.
*/
(function(exports) {
const DEBUG = true;
function debug() {
if (DEBUG) {
console.log('[FirefoxSyncToolbar] ' + Array.slice(arguments).concat());
}
}
var FirefoxSyncToolbar = {
init() {
SyncManagerBridge.addListener(this.onsyncchange.bind(this));
this.syncBlock = document.getElementById('fxsync-block');
this.syncTab = this.syncBlock.querySelector('#fxsync-tab');
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
this.refresh();
}
});
this.refresh();
},
refresh() {
SyncManagerBridge.getInfo().then(this.onsyncchange.bind(this));
},
onsyncchange(message) {
debug(JSON.stringify(message));
if (!message || !message.state) {
throw new Error('Missing sync state');
}
switch (message.state) {
case 'disabled':
if (this.showListener) {
this.syncBlock.removeEventListener('mouseup', this.showListener);
this.showListener = null;
}
this.syncBlock.addEventListener('mouseup', SyncManagerBridge.enable);
this.syncTab.setAttribute('data-l10n-id', 'fxsync-sign-in-to-sync');
this.syncTab.removeAttribute('data-l10n-args');
break;
case 'enabling':
Settings.show();
this.syncTab.setAttribute('data-l10n-id', 'fxsync-signing');
break;
case 'syncing':
case 'enabled':
this.showListener = Settings.show.bind(Settings);
this.syncBlock.addEventListener('mouseup', this.showListener);
this.syncBlock.removeEventListener('mouseup',
SyncManagerBridge.enable);
navigator.mozL10n.setAttributes(this.syncTab, 'fxsync-signed-in-as', {
email: message.user
});
break;
}
}
};
// Exported only for testing purposes
exports.FirefoxSyncToolbar = FirefoxSyncToolbar;
LazyLoader.load('js/sync/manager_bridge.js', () => {
FirefoxSyncToolbar.init();
});
}(window));

View file

@ -0,0 +1,758 @@
/* global Awesomescreen */
/* global Browser */
/* global BrowserDB */
/* global LazyLoader */
/* global SearchResult */
/* global SearchUtil */
/* global Settings */
/* global Tooltip*/
/* global UrlHelper */
'use strict';
/**
* Browser app toolbar
* @namespace Toolbar
*/
var Toolbar = {
/* screen size */
SCREEN_HEIGHT: 1080,
SCREEN_WIDTH: 1920,
/* zoom */
availableZoomScale: [
{'scale': 1.25, 'disp': '100%'},
{'scale': 1.625, 'disp': '130%'},
{'scale': 2.0, 'disp': '160%'},
],
defaultZoomScale: 0,
zoomScale: 0,
availableZoomScaleYoutube: [
{'scale': 1.55, 'disp': '100%'},
{'scale': 1.775, 'disp': '130%'},
{'scale': 2.0, 'disp': '160%'},
],
urlButtonMode: null,
GO: 0,
REFRESH: 1,
STOP: 2,
SEARCH: 3,
initStart: true,
/**
* Intialise toolbar.
*/
init: function toolbar_init() {
/* get Element */
this.getAllElements();
/* Event Listener */
window.addEventListener('click', this);
this.sidebarButtonBlock.addEventListener('mouseup',
this.showHideSidebar.bind(this));
this.backButtonBlock.addEventListener('mouseup',
this.goBack.bind(this));
this.forwardButtonBlock.addEventListener('mouseup',
this.goForward.bind(this));
this.addressForm.addEventListener('submit',
this.handleUrlFormSubmit.bind(this));
this.urlInput.addEventListener('input',
this.handleUrlInputKeypress.bind(this));
this.addressButton.addEventListener('mouseup',
this.clickAddressButton.bind(this));
this.searchForm.addEventListener('submit',
this.handleSearchFormSubmit.bind(this));
this.searchInput.addEventListener('focus',
this.handleSearchInputFocus.bind(this));
// this.searchInput.addEventListener('keyup',
// this.handleSearchInputKeypress.bind(this));
this.searchInput.addEventListener('input',
this.handleSearchInputInput.bind(this));
this.searchButton.addEventListener('mouseup',
this.clickSearchButton.bind(this));
this.searchClearButton.addEventListener('mouseup',
this.clickSearchClearButton.bind(this));
this.searchCloseButton.addEventListener('mouseup',
this.clickSearchCloseButton.bind(this));
this.bookmarkButtonBlock.addEventListener('mouseup',
Browser.addBookmark.bind(Browser));
this.bookmarkButtonAnime.addEventListener('animationend',
Browser.bookmarkButtonAnimeEnd.bind(Browser));
this.showBookmarksButtonBlock.addEventListener('mouseup',
Awesomescreen.selectBookmarksTab.bind(Awesomescreen));
this.homeButtonBlock.addEventListener('mouseup',
this.clickHomeButtonBlock.bind(this));
this.zoomButtonBlock.addEventListener('mouseup',
this.clickZoomButtonBlock.bind(this));
this.tabsButtonBlock.addEventListener('click',
Awesomescreen.handleNewTab.bind(Awesomescreen));
this.newTabButtonBlock.addEventListener('click',
Awesomescreen.createAddNewTab.bind(Awesomescreen));
this.menuButtonBlock.addEventListener('mouseup',
this.clickMenuButtonBlock.bind(this));
this.historyBlock.addEventListener('mouseup',
Awesomescreen.selectHistoryTab.bind(Awesomescreen));
this.pocketBlock.addEventListener('mouseup',
this.clickPocketListBlock.bind(this));
this.privateWindowBlock.addEventListener('mouseup',
Browser.handlePrivateBrowsing.bind(Browser));
this.settingsBlock.addEventListener('mouseup',
Settings.show.bind(Settings));
this.modeButtonBlock.addEventListener('mouseover',
this.selectedModeButtonBlock.bind(this));
this.modeButtonBlock.addEventListener('mouseout',
this.unselectedModeButtonBlock.bind(this));
this.toolbarPanel.dataset.search = 'false';
var colorBar = Browser.getColorBarData();
this.panCursorButtonBlock.dataset.colorbar = colorBar[0].COLOR;
this.zoomButtonBlock.dataset.colorbar = colorBar[1].COLOR;
this.tabsButtonBlock.dataset.colorbar = colorBar[2].COLOR;
this.newTabButtonBlock.dataset.colorbar = colorBar[3].COLOR;
// li = 73px * 3(list) + 20px(hover) + 10px(padding)
this.menuBlock.style.height = 73 * 3 + 20 + 10 + 'px';
Tooltip.init();
//IFDEF_FIREFOX_SYNC
LazyLoader.load('js/sync/toolbar.js');
//ENDIF_FIREFOX_SYNC
},
/**
* toolbar bookmark registered check.
*/
isBookmarks: function toolbar_isBookmarks() {
if(Toolbar.bookmarkButton.dataset.isbookmark == 'true'){
return true;
}else{
return false;
}
},
/**
* Set search engine
*/
setSearchEngine: function toolbar_setSearchEngine() {
var engineName = SearchUtil.getCurrentEngineName().toLowerCase();
// favicon
this.searchFavicon.dataset.engine = engineName;
// placeholder
engineName = engineName.charAt(0).toUpperCase() + engineName.slice(1);
this.searchInput.placeholder = engineName;
// tooltip
navigator.mozL10n.formatValue('WB_LT_TIPS_SEARCH_BAR2', {
engine: engineName
}).then(val => {
this.searchInput.dataset.tips = val;
});
},
/**
* CamelCase (xxx-yyy -> xxxYyy)
*/
toCamelCase: function toCamelCase(str) {
return str.replace(/-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
},
/**
* Get All Elements (from id)
*/
getAllElements: function toolbar_getAllElements() {
var elementIDs = [
'toolbar-panel',
'sidebar-button-block', 'sidebar-button',
'back-button-block', 'back-button',
'forward-button-block', 'forward-button-border', 'forward-button',
'space-block',
'addressbar-block', 'address-form', 'ssl-indicator', 'url-input',
'address-button',
'searchbar-block', 'search-form', 'search-favicon', 'search-input',
'search-button', 'search-clear-button', 'search-close-button',
'iconbutton-block',
'bookmark-button-block', 'bookmark-button',
'show-bookmarks-button-block', 'show-bookmarks-button',
'home-button-block', 'home-button',
'zoom-button-block', 'zoom-button',
'tabs-button-block', 'tabs-button',
'new-tab-button-block', 'new-tab-button',
'menu-button-block', 'menu-button',
'menu-block',
'history-block', 'private-window-block',
'settings-block',
'history-tab', 'private-window-tab', 'settings-tab',
'mode-button-block',
'mode-button-title', 'pan-cursor-button', 'pan-cursor-button-block',
'pan-cursor-banner-message',
'zoom-banner-message-block', 'zoom-banner-message',
'loading-icon',
//'tooltip-block',
'bookmark-button-anime', 'show-bookmarks-button-anime',
'pocket-block', 'pocket-tab'
];
// Loop and add element with camel style name to Modal Dialog attribute.
elementIDs.forEach(function createElementRef(name) {
this[this.toCamelCase(name)] = document.getElementById(name);
}, this);
},
/**
* handle event
*/
handleEvent: function toolbar_handleEvent(ev) {
switch(ev.type) {
case 'click':
if(ev.target != this.menuButtonBlock) {
this.toolbarPanel.dataset.menu = 'hide';
}
// Settings in the display
if(Settings.isDisplayed()) {
switch(ev.target) {
case this.backButtonBlock:
case this.forwardButtonBlock:
case this.addressForm:
case this.urlInput:
case this.addressButton:
case this.searchForm:
case this.searchInput:
case this.searchButton:
case this.bookmarkButtonBlock:
case this.showBookmarksButtonBlock:
case this.homeButtonBlock:
case this.zoomButtonBlock:
case this.tabsButtonBlock:
case this.newTabButtonBlock:
case this.menuButtonBlock:
Settings.hide();
break;
}
}
break;
default:
break;
}
},
/**
* Specialized processing youtube (zoom)
*/
checkYoutube: function toolbar_checkYoutube() {
if(!Browser.currentInfo || !Browser.currentInfo.url) {
return false;
}
var end_pos1 =
Browser.currentInfo.url.indexOf('https://www.youtube.com', 0);
var end_pos2 = Browser.currentInfo.url.indexOf('http://www.youtube.com', 0);
if(end_pos1 < 0 && end_pos2 < 0) {
return false;
}
return true;
},
/**
* Full screen or Screen with submenu
*/
showHideSidebar: function toolbar_showHideSidebar() {
this.sidebarButtonBlock.blur();
// Hide Tooltip
Tooltip.hide();
// Fade animation end event handler
var fade_event = (function() {
Browser.fadeBase.classList.toggle('fade');
if(Browser.sideBlock.dataset.sidebar == 'true'){
// Full screen
Browser.sideBlock.dataset.sidebar = 'false';
Browser.mainBlock.dataset.sidebar = 'false';
// save screen mode
BrowserDB.updateSetting('full', 'screen_mode');
}else{
// Disp side screen
Browser.sideBlock.dataset.sidebar = 'true';
Browser.mainBlock.dataset.sidebar = 'true';
// save screen mode
BrowserDB.updateSetting('side', 'screen_mode');
}
Browser.fadeBase.removeEventListener('transitionend', fade_event, false);
// Specialized processing youtube (zoom)
Browser.currentInfo.dom.zoom(Toolbar.getZoomScale());
});
// Add fade animantion event
Browser.fadeBase.addEventListener('transitionend', fade_event, false);
Browser.fadeBase.classList.toggle('fade');
this.sidebarButtonBlock.dataset.fade='true';
},
/**
* Go back to the previous page
*/
goBack: function toolbar_goBack() {
if (Awesomescreen.isDisplayedTop()){
Awesomescreen.topsiteReturnFunc();
return;
}
if (!Browser.currentInfo.dom.getCanGoBack){
return;
}
Browser.currentInfo.dom.getCanGoBack().onsuccess = (function(ev) {
if(!ev.target.result){
// dialog
// XXX: refactor this and the same code in awesomescreen.js
navigator.mozL10n.formatValue('LT_BROWSER_CONFIRM_EXIT2')
.then(result => {
if (window.confirm(result)) {
window.close();
}
});
return;
}
}).bind(this);
Browser.currentInfo.dom.goBack();
},
/**
* Go forward to the next page
*/
goForward: function toolbar_goForward() {
Browser.currentInfo.dom.goForward();
},
// Set url form input
setUrlBar: function toolbar_setUrlBar(value) {
this.urlInput.value = value;
},
// Get url form input
getUrlFromInput: function toolbar_getUrlFromInput(input) {
var hasScheme = UrlHelper.hasScheme(input);
// No scheme, prepend basic protocol and return
if (!hasScheme) {
return 'http://' + input;
}
return input;
},
/**
* Url form submit
*/
handleUrlFormSubmit: function toolbar_handleUrlFormSubmit(ev) {
if (ev) {
// Can be canceled
ev.preventDefault();
}
if (this.urlButtonMode === null) {
return;
}
var url = this.getUrlFromInput(this.urlInput.value);
if (url !== Browser.currentInfo.url) {
this.setUrlBar(url);
Browser.currentInfo.url = url;
}
this.urlInput.blur();
Browser.navigate(url);
},
/**
* Input Url
*/
handleUrlInputKeypress: function toolbar_handleUrlInputKeypress(evt) {
var input = this.urlInput.value;
if (input === '') {
this.setUrlButtonMode(null);
this.addressButton.classList.add('disable');
return;
}
this.addressButton.classList.remove('disable');
this.setUrlButtonMode(
UrlHelper.isNotURL(input) ? this.SEARCH : this.GO
);
},
/**
* Address Bookmark Current url
*/
clickAddressButton: function toolbar_clickAddressButton(ev) {
//if(this.addressButton.classList.contains('disable')){
//return;
//}
if(this.addressButton.dataset.mode == 'load') {
if(Browser.currentInfo.url){
Browser.currentInfo.dom.reload(false);
}
this.stopAddressIcon();
} else {
Browser.currentInfo.dom.stop();
this.hiddenLoadingIcon();
this.loadAddressIcon();
}
},
loadAddressIcon: function toolbar_loadAddressIcon() {
this.addressButton.dataset.mode = 'load';
this.addressButton.dataset.tips = 'WB_LT_TIPS_RELOAD';
},
stopAddressIcon: function toolbar_stopAddressIcon() {
this.addressButton.dataset.mode = 'stop';
this.addressButton.dataset.tips = 'WB_LT_TIPS_STOP_LOADING';
},
showLoadingIcon: function toolbar_showLoadingIcon() {
if(Settings.isDisplayed()) {
return;
}
if(!this.loadingIcon.classList.contains('visible')){
this.loadingIcon.classList.add('visible');
this.stopAddressIcon();
}
},
hiddenLoadingIcon: function toolbar_hiddenLoadingIcon() {
if(Tooltip.isShow(this.addressButton)){
Tooltip.hide();
}
this.loadingIcon.classList.remove('visible');
this.loadAddressIcon();
},
/**
* Submit search form
*/
handleSearchFormSubmit: function toolbar_handleSearchFormSubmit(ev) {
if (ev) {
// Can be canceled
ev.preventDefault();
}
if( SearchResult.isDisplayed() ) {
this.searchInput.blur();
SearchResult.hide();
}
var url = Browser.getSearchFromInput(this.searchInput.value);
Browser.navigate(url);
},
/**
* Click search button
*/
clickSearchButton: function toolbar_clickSearchButton(ev) {
this.handleSearchFormSubmit(ev);
},
clickSearchClearButton: function toolbar_clickSearchClearButton(ev) {
if( ev ) {
ev.preventDefault();
}
this.searchInput.value = '';
SearchResult.resultUpdate(this.searchInput.value);
},
clickSearchCloseButton: function toolbar_clickSearchCloseButton(ev) {
if( ev ) {
ev.preventDefault();
}
SearchResult.hide();
},
/**
* Input Search
*/
getSearchBarStyle: function toolbar_getSearchBarStyle() {
return this.toolbarPanel.dataset.search;
},
setSearchBarStyle: function toolbar_setSearchBarStyle(value) {
this.toolbarPanel.dataset.search = value;
},
handleSearchInputFocus: function toolbar_handleSearchInputFocus(evt) {
this.handleSearchInputKeypress(evt);
},
handleSearchInputInput: function toolbar_handleSearchInputInput(evt) {
this.handleSearchInputKeypress(evt);
},
handleSearchInputKeypress: function toolbar_handleSearchInputKeypress(evt) {
if( this.getSearchBarStyle() == 'false' ) {
if( evt ) {
evt.preventDefault();
}
if(Toolbar.searchInput.value) {
Tooltip.hide();
this.setSearchBarStyle('true');
SearchResult.show();
}
} else {
SearchResult.handleSearchResultFormInput(evt);
}
},
/**
* Click home button
*/
clickHomeButtonBlock: function toolbar_clickHomeButtonBlock(ev) {
Settings.getHomepage((function(result) {
if(result) {
Browser.navigate(result);
}
}).bind(this));
},
/**
* Click zoom button
*/
clickZoomButtonBlock: function toolbar_clickZoomButtonBlock(ev) {
if(ev){
// stop event
ev.stopPropagation();
}
clearTimeout(this.showZoomBannerTimeoutID);
this.zoomScale = Browser.currentInfo.zoom;
this.zoomScale++;
if(this.zoomScale >= this.availableZoomScale.length) {
this.zoomScale = 0;
}
Browser.currentInfo.zoom = this.zoomScale;
Browser.currentInfo.dom.zoom(this.getZoomScale());
this.zoomBannerMessage.innerHTML =
this.availableZoomScale[this.zoomScale].disp;
if(!this.zoomBannerMessageBlock.classList.contains('visible')){
this.zoomBannerMessageBlock.classList.add('visible');
}
this.showZoomBannerTimeoutID = setTimeout(function(){
Toolbar.zoomBannerMessageBlock.classList.remove('visible');
}, 1500);
},
getZoomScale: function toolbar_getZoomScale() {
if(this.checkYoutube() && Browser.sideBlock.dataset.sidebar == 'false'){
return this.availableZoomScaleYoutube[this.zoomScale].scale;
} else {
return this.availableZoomScale[this.zoomScale].scale;
}
},
setZoomScale: function toolbar_setZoomScale(scale) {
this.zoomScale = scale;
},
getDefaultZoomScale: function toolbar_getDefaultZoomScale() {
if(this.checkYoutube() && Browser.sideBlock.dataset.sidebar == 'false'){
return this.availableZoomScaleYoutube[this.defaultZoomScale].scale;
} else {
return this.availableZoomScale[this.defaultZoomScale].scale;
}
},
/**
* Zoom out(for ars)
*/
zoomOut: function toolbar_zoomOut() {
clearTimeout(this.showZoomBannerTimeoutID);
this.zoomScale = Browser.currentInfo.zoom;
if(this.zoomScale === 0) {
return;
}
this.zoomScale--;
Browser.currentInfo.zoom = this.zoomScale;
Browser.currentInfo.dom.zoom(this.getZoomScale());
this.zoomBannerMessage.innerHTML =
this.availableZoomScale[this.zoomScale].disp;
if(!this.zoomBannerMessageBlock.classList.contains('visible')){
this.zoomBannerMessageBlock.classList.add('visible');
}
this.showZoomBannerTimeoutID = setTimeout(function(){
Toolbar.zoomBannerMessageBlock.classList.remove('visible');
}, 1500);
},
/**
* Click menu button
*/
clickMenuButtonBlock: function toolbar_clickMenuButtonBlock(ev) {
if(ev){
// stop event
ev.stopPropagation();
}
if(this.toolbarPanel.dataset.menu == 'show') {
this.toolbarPanel.dataset.menu = 'hide';
} else {
this.toolbarPanel.dataset.menu = 'show';
if(!this.menuBlock.style.minWidth) {
var ar = [];
// rate 1.25
ar.push(432); // default 432(540 / 1.25)
ar.push(this.historyTab.offsetWidth);
ar.push(this.privateWindowTab.offsetWidth);
ar.push(this.settingsTab.offsetWidth);
this.menuBlock.style.minWidth =
(Math.max.apply(null, ar) * 1.25) + 'px';
}
}
},
/**
* Show mode button
*/
showModeButtonTimer: function toolbar_showModeButtonTimer() {
this.showModeButtonTimeoutID = setTimeout(function(){
Toolbar.modeButtonBlock.classList.remove('visible');
}, 5000);
},
/**
* Show mode button
*/
showPanCursorButton: function toolbar_showPanCursorButton() {
if(!this.modeButtonBlock.classList.contains('visible')){
this.modeButtonBlock.classList.add('visible');
this.showModeButtonTimer();
}
},
/**
* Selected mode button
*/
selectedModeButtonBlock: function toolbar_selectedModeButtonBlock() {
clearTimeout(this.showModeButtonTimeoutID);
},
/**
* Unselected mode button
*/
unselectedModeButtonBlock: function toolbar_unselectedModeButtonBlock() {
this.showModeButtonTimer();
},
/**
* Show pan cursor banner
*/
showPanCursorBanner: function toolbar_showPanCursorBanner() {
if(!this.panCursorBannerMessage.classList.contains('visible')){
this.panCursorBannerMessage.classList.add('visible');
}
clearTimeout(this.showPanCursorBannerTimeoutID);
this.showPanCursorBannerTimeoutID = setTimeout(function(){
Toolbar.panCursorBannerMessage.classList.remove('visible');
}, 5000);
},
/**
* Click mode button
*/
clickModeButtonBlock: function toolbar_clickModeButtonBlock() {
if(Browser.getCursorPanMode() == 'cursor') {
Browser.setCursorPanMode('pan');
this.modeButtonTitle.setAttribute('data-l10n-id', 'WB_LT_PAN_MODE');
this.panCursorBannerMessage.setAttribute(
'data-l10n-id', 'WB_LT_SWITCH_PAN_MODE');
} else {
this.clearDragMode();
}
// Show mode button
this.showPanCursorButton();
// Show pan cursor banner
this.showPanCursorBanner();
},
// clear drag mode
clearDragMode: function toolbar_clearDragMode(){
if(Browser.getCursorPanMode() == 'pan') {
Browser.setCursorPanMode('cursor');
this.modeButtonTitle.setAttribute('data-l10n-id', 'WB_LT_CURSOR_MODE');
this.panCursorBannerMessage.setAttribute(
'data-l10n-id', 'WB_LT_SWITCH_CURSOR_MODE');
}
},
setUrlButtonMode: function toolbar_setUrlButtonMode(mode) {
this.urlButtonMode = mode;
},
setPrivateBrowsing: function toolbar_setPrivateBrowsing(bool) {
this.toolbarPanel.dataset.pvt = bool;
},
isPrivateBrowsing: function toolbar_getPrivateBrowsing() {
return (this.toolbarPanel.dataset.pvt == 'true');
},
initStartBrowsing: function toolbar_initStartBrowsing() {
if(this.initStart) {
this.initStart = false;
/* show pan cursor mode button */
this.showPanCursorButton();
}
},
setToolbarMode: function toolbar_setToolbarMode(mode) {
this.toolbarPanel.dataset.mode = mode;
},
getToolbarMode: function toolbar_getToolbarMode() {
return this.toolbarPanel.dataset.mode;
},
/**
* Open Pocket List
*/
clickPocketListBlock: function toolbar_clickPocketListBlock() {
var pocketHomePageUri = 'https://getpocket.com/fxostv';
if (Browser.currentInfo.url &&
UrlHelper.isURL(Browser.currentInfo.url)) {
var ev = {
detail: {
url: pocketHomePageUri,
frameElement: null
}
};
Awesomescreen.openNewTab(ev);
} else {
Browser.navigate(pocketHomePageUri);
}
}
};

View file

@ -0,0 +1,190 @@
/* global _ */
/* global Toolbar */
'use strict';
/**
* Browser App Tooltip.
* @namespace Tooltip
*/
var Tooltip = {
tooltipBlock: null,
showTimeoutID: null,
hideTimeoutID: null,
hideTimeoutData: 100,
overObj: null,
moveObj: null,
showTarget: null,
/**
* initialize
*/
init: function tooltip_init() {
this.tooltipBlock = document.getElementById('tooltip-block');
var elements = [
{target: Toolbar.sidebarButtonBlock},
{target: Toolbar.backButtonBlock},
{target: Toolbar.forwardButtonBlock},
{target: Toolbar.addressButton},
{target: Toolbar.searchInput},
{target: Toolbar.bookmarkButtonBlock},
{target: Toolbar.showBookmarksButtonBlock},
{target: Toolbar.homeButtonBlock},
{target: Toolbar.zoomButtonBlock},
{target: Toolbar.tabsButtonBlock},
{target: Toolbar.newTabButtonBlock},
{target: Toolbar.menuButtonBlock},
{target: Toolbar.modeButtonBlock},
];
this.overObj = this.mouseoverEvent.bind(this);
this.moveObj = this.mousemoveEvent.bind(this);
// toolbar icon
elements.forEach(function addEvent(elm) {
var target = elm.target;
// add event
target.addEventListener('mouseover', this.overObj);
target.addEventListener('mouseout', this.mouseoutEvent.bind(this));
target.addEventListener('mousedown', this.clickEvent.bind(this));
target.addEventListener('mouseup', this.clickEvent.bind(this));
}, this);
},
/**
* mousemove event
*/
mousemoveEvent: function tooltip_mousemoveEvent(ev) {
if(this.isShow()) {
// hide the tooltip in mouse movement at tooltip display.
this.stopMousemoveEvent(ev.target);
this.hideTimeoutID = setTimeout(function(){
Tooltip.hide();
}, this.hideTimeoutData);
return;
}
if(this.showTimeoutID) {
clearTimeout(this.showTimeoutID);
}
var bounds = ev.currentTarget.getBoundingClientRect();
var posY = Math.ceil(bounds.bottom);
var top = Math.ceil(bounds.top);
var tips = null;
if(ev.target.dataset.tips != null && ev.target.dataset.tips != undefined) {
if(ev.target == Toolbar.searchInput) {
tips = {raw: ev.target.dataset.tips};
} else {
tips = ev.target.dataset.tips;
}
}
this.showTimeoutID = setTimeout(function(){
Tooltip.showTarget = ev.target;
var disp = {
top: top,
text: tips,
x: ev.pageX,
//y: ev.pageY
y: posY,
};
Tooltip.displaySetting(disp);
}, 150);
},
startMousemoveEvent: function tooltip_startMousemoveEvent(target) {
target.addEventListener('mousemove', this.moveObj);
},
stopMousemoveEvent: function tooltip_stopMousemoveEvent(target) {
target.removeEventListener('mousemove', this.moveObj);
},
/**
* mouseover event
*/
mouseoverEvent: function tooltip_mouseoverEvent(ev) {
this.startMousemoveEvent(ev.target);
},
/**
* mouseout event
*/
mouseoutEvent: function tooltip_mouseoutEvent(ev) {
this.hide();
},
/**
* click event
*/
clickEvent: function tooltip_clickEvent(ev) {
this.hide();
},
/**
* show tooltip
*/
isShow: function tooltip_isShow(target) {
if(!target){
return this.tooltipBlock.classList.contains('visible');
} else {
if(target == this.showTarget){
return this.tooltipBlock.classList.contains('visible');
} else {
return false;
}
}
},
/**
* show tooltip
*/
show: function tooltip_show() {
this.tooltipBlock.classList.add('visible');
},
/**
* hide tooltip
*/
hide: function tooltip_hide() {
clearTimeout(this.showTimeoutID);
clearTimeout(this.hideTimeoutID);
this.tooltipBlock.classList.remove('visible');
},
/**
* display setting
*/
displaySetting: function tooltip_displaySetting(disp) {
if(disp.text == null || disp.text == undefined) {
return;
}
this.show();
this.tooltipBlock.style.left = '0px';
if (typeof disp.text === 'string') {
this.tooltipBlock.setAttribute('data-l10n-id', disp.text);
} else if (disp.text.hasOwnProperty('raw')) {
this.tooltipBlock.innerHTML = disp.text.replace(/\\n/g, '<br>');
}
// pos x adjustment
// 25 = scrollbar margin
var maxW = this.tooltipBlock.offsetWidth + disp.x + 25;
var posX = disp.x;
if(maxW >= Browser.SCREEN_WIDTH) {
// 58 = margin
posX = Browser.SCREEN_WIDTH - this.tooltipBlock.offsetWidth - 58;
}
// pos y adjustment
var bounds = this.tooltipBlock.getBoundingClientRect();
var hg = Math.ceil(bounds.height);
var posY = disp.y + 20;
var maxH = posY + hg;
if(maxH >= Browser.SCREEN_HEIGHT) {
// hover item
posY = disp.top - 20 - hg;
}
this.tooltipBlock.style.top = (posY + 0) + 'px';
this.tooltipBlock.style.left = (posX + 0) + 'px';
},
};

18
gaia/tv_apps/browser/jsdoc.json Executable file
View file

@ -0,0 +1,18 @@
{
"name": "tv-browser",
"tags": {
"dictionaries": ["jsdoc"]
},
"source": {
"include": ["tv_apps/browser/js/**/*.js"]
},
"plugins": [
"plugins/markdown",
"plugins/summarize"
],
"opts": {
"private": true,
"recurse": true,
"destination": "docs/tv-browser"
}
}

View file

@ -0,0 +1,226 @@
# modal-dialog buttons
ok=OK
cancel=Cancel
done=Done
enter-search-or-address.placeholder=Search or enter address
history=History
new-tab=New tab
open-in-new-tab=Open link in new tab
edit=Edit
# History headings
future=Future
today=Today
yesterday=Yesterday
last-7-days=Last 7 days
this-month=This month
last-6-months=Last 6 months
older-than-6-months=Older than 6 months
# Months
month-0=January
month-1=February
month-2=March
month-3=April
month-4=May
month-5=June
month-6=July
month-7=August
month-8=September
month-9=October
month-10=November
month-11=December
# Start Page
browser={{browserBrandShortName}}
start-browsing=Enter a search term or Web address to start browsing.
# LOCALIZATION NOTE: depending on your locale, you might want to use a more
# compact translation for top-sites-tab than for top-sites-startPage.
top-sites-startPage = Top sites
top-sites-tab = Top sites
# Settings
browser-settings=Settings
privacy-and-security=Privacy & Security
clear-browsing-history=Clear browsing history
confirm-clear-browsing-history=Clear browsing history?
clear-cookies-and-stored-data=Clear cookies and stored data
confirm-clear-cookies-and-stored-data=Clear cookies and other data stored by sites on this device?
search-engines=Search Engines
default-search-engine=Default search engine
# Bookmarks
bookmarks=Bookmarks
bookmark=Bookmark
unbookmark=Unbookmark
edit-bookmark=Edit bookmark
edit-bookmark-header=Edit bookmark
page-title=Page title
address=Address
add-to-home-screen=Add to home screen
# HTTP Authentication dialog
username=Username
password=Password
login=Sign in
login-to-a-website=Sign in to website
http-authentication-message=The website {{host}} requires you to sign in.
the-username-or-password-is-incorrect=The username or password is incorrect.
# Crash screen
this-is-embarrassing=Well, this is embarrassing.
not-responding=We tried to display this Web page, but it’s not responding.
close-tab=Close tab
reload-tab=Reload
# Awesomescreen
search-for=Search for
# Generic save link context menu
save-link=Save linked file
# Image saving context menu
save-image=Save Image
# Video saving context menu
save-video=Save Video
# Audio saving context menu
save-audio=Save Audio
# Toolbar
pocket=Pocket
# FTE
fte-welcome=Welcome to Firefox
fte-description=To sign in with Firefox Account lets you access your bookmarks and more whenever you use Firefox. You can register a Firefox Account on your mobile or tablet.
skip=Skip
# Firefox Sync
fxsync-sign-in=Sign In
fxsync-sign-out=Sign Out
fxsync-confirm-sign-out-title=Are you sure?
fxsync-confirm-sign-out-message=Your synced Firefox bookmarks and history will no longer be available on this TV until you sign in again.
fxsync-signed-in-as={{email}}
fxsync-sign-in-to-sync=Sign in to Sync
fxsync-sign-in-to-sync-description=Sync your bookmarks and history from your Firefox Account.
fxsync-sign-in-to-sync-description-plus=You can create a Firefox Account on your smartphone or computer at https://accounts.firefox.com
fxsync-desktop-bookmarks=Desktop bookmarks
fxsync-mobile-bookmarks=Mobile bookmarks
fxsync-enabled=Success! Your Firefox Account is ready to go! In the future, you can access and manage your account from Settings.
fxsync-disabled=You have signed out successfully.
# XXX: from partner
LT_APPS_SETTINGS=Settings
LT_AUX=AUX
LT_AV1_COMPONENT1=AV1/COMPONENT1
LT_AV2_COMPONENT2=AV2/COMPONENT2
LT_AV_COMPONENT=AV/COMPONENT
LT_BD=Blu-ray
LT_BROWSER_CONFIRM_EXIT2=Do you want to exit Browser?
LT_CABLE=CABLE
LT_CAMERA=CAMERA
LT_CANCEL=Cancel
LT_CH_BS=[MP]ch BS
LT_CH_CS1=[MP]ch CS1
LT_CH_CS2=[MP]ch CS2
LT_CH_DIGITAL=[MP]ch digital
LT_CL_EDIT=Edit
LT_COMPUTER=COMPUTER
LT_DEFAULT=Default
LT_DIGA=[JP] DIGA
LT_DISK=DISK
LT_DISPLAYPORT=DisplayPort
LT_DVD=DVD
LT_DVD1=DVD1
LT_DVD2=DVD2
LT_DVD_REC=DVD REC
LT_DVR=DVR
LT_FAILED_=Failed.
LT_FILE_SHARING_DEVICE_PASSWORD=Password
LT_FILE_SHARING_DEVICE_USER=User
LT_GAME=GAME
LT_HDD_RECORDER=[JP]HDD Recorder
LT_HDMI=HDMI
LT_HDMI1=HDMI1
LT_HDMI2=HDMI2
LT_HDMI3=HDMI3
LT_HDMI4=HDMI4
LT_HOME_THTR=HOME THTR
LT_INPUT=Input
LT_INP_SAT=SATELLITE
LT_LABEL_NOT_USED=Not used
LT_LD_NETWORK_ERROR=Network error occured.
LT_MEDIA_CTR=MEDIA CTR
LT_MEDIA_EXT=MEDIA EXT
LT_MONITOR2=MONITOR
LT_NETWORK=Network
LT_NETWORK_STATUS_BTN_CLOSE=close
LT_NET_BOOKMARK=Bookmark
LT_OTHER2=OTHER
LT_PC=PC
LT_PIN_TO_HOME=Pin to HOME
LT_PVR=PVR
LT_RECEIVER=RECEIVER
LT_SE_HISTORY=History
LT_STB=STB
LT_TERR=TERR
LT_TITEL_NO_DISPLAY=no display
LT_TZ_CLOCK_ERROR_NW=Please setup network connection.
LT_USER_INPUT=Customize
LT_VCR=VCR
LT_WB_OK=OK
LT_WCL_RESET_TO_DEF=Reset to Default
LT_WCL_SELECT_PAGE=Select webpage
WB_LT_ALSO_PIN_TO_HOME=Also pin to home
WB_LT_AUTH_MESSAGE=The server {{ host }} requires a user name and password. <br /> Message from the server : {{ msg }}
WB_LT_BOOKMARK_ERROR_1=Bookmarks limit reached. Cannot add anymore bookmarks.
WB_LT_BOOKMARK_THIS_PAGE=Bookmark this page?
WB_LT_BROWSER_SETTINGS=Browser Settings
WB_LT_CLEAR=Clear
WB_LT_CLEAR_ALL_HISTORY=Clear all history?
WB_LT_CLEAR_BROWSING_HISTORY=Clear All History
WB_LT_CLEAR_HISTORY=Clear History
WB_LT_CLEAR_STORED_DATA=Clear Cookies and Stored Data
WB_LT_CONFIRM_DELETE_COOKIES=Do you want to delete Cookies?
WB_LT_CONNECTION_IS_UNTRUSTED=This Connection is Untrusted
WB_LT_CURSOR_MODE=Cursor Mode
WB_LT_HOMEPAGE=Homepage
WB_LT_LEARN_MORE=Learn More
WB_LT_PAGE_CANNOT_BE_DISPLAYED=The page cannot be displayed
WB_LT_PAN_MODE=Pan Mode
WB_LT_PRESS_COLOR_KEY=Press hardware shortcut color key to switch in between Cursor mode and Pan mode.
WB_LT_PRIVATE_BROWSING_1=Firefox won't remember any history for this window.
WB_LT_PRIVATE_BROWSING_2=In a Private Browsing window, Firefox won't keep any browser history, search history, download history, web form history, cookies, or temporary internet files. However, files you download and bookmarks you make will be kept.
WB_LT_PRIVATE_BROWSING_3=To stop Private Browsing, you can close this window.
WB_LT_PRIVATE_BROWSING_4=While this computer won't have a record of your browsing history, your internet service provider or employer can still track the pages you visit.
WB_LT_REMOVE=Remove
WB_LT_REMOVE_FROM_BOOKMARKS=Remove webpage from bookmarks?
WB_LT_REMOVE_FROM_TOP_SITES=Remove from Top Sites
WB_LT_REMOVE_HISTORY=Remove history?
WB_LT_RENAME_BOOKMARK=Rename bookmark?
WB_LT_RESTORE_TO_DEFAULT=Restore to default
WB_LT_SETTINGS_PRIVATE_BROWSING=Private Browsing
WB_LT_SETTINGS_SEARCH_ENGINE=Search Engine
WB_LT_SET_AS_HOMEPAGE=Set as Homepage
WB_LT_SET_HOMEPAGE={{value0}} is now set as your homepage
WB_LT_SWITCH_CURSOR_MODE=You have switched to Cursor Mode
WB_LT_SWITCH_PAN_MODE=You have switched to Pan Mode
WB_LT_TIPS_BOOKMARK_THIS_PAGE=Bookmark this page
WB_LT_TIPS_CHANGE_SCREEN=Change screen
WB_LT_TIPS_HISTORY_BACK=Previous page
WB_LT_TIPS_HISTORY_FORWARD=Next page
WB_LT_TIPS_HOMEPAGE=Show homepage
WB_LT_TIPS_MENU=Menu
WB_LT_TIPS_NEW_PRIVATE_WINDOW=New private window
WB_LT_TIPS_OPEN_A_NEW_TAB=Open a new tab
WB_LT_TIPS_RELOAD=Reload
WB_LT_TIPS_SEARCH_BAR2={{ engine }} Search the Web
WB_LT_TIPS_SHOW_YOUR_BOOKMARK=Show your bookmarks
WB_LT_TIPS_STOP_LOADING=Stop loading this page
WB_LT_TIPS_S_SEARCH={{value0}} search
WB_LT_TIPS_TABS=Show tabs
WB_LT_TIPS_ZOOM_IN=Zoom in
WB_LT_W_BOOKMARK_DELETE=Delete bookmark

View file

@ -0,0 +1,70 @@
{
"name": "Browser",
"description": "Browser",
"launch_path": "/index.html",
"type": "certified",
"role": "deck",
"permissions": {
"browser":{},
"systemXHR":{},
"desktop-notification" : {},
"firefox-accounts": {},
"moz-extremely-unstable-and-will-change-webcomponents":{},
"settings": { "access": "readwrite" },
"geolocation": {},
"audio-capture": {},
"video-capture": {}
},
"locales": {
"ar": {
"name": "المتصفح",
"description": "متصفح الويب"
},
"en-US": {
"name": "Browser",
"description": "Web Browser"
},
"fr": {
"name": "Navigateur",
"description": "Navigateur Web"
},
"ja-JP": {
"name": "ブラウザ",
"description": "ブラウザ"
},
"zh-TW": {
"name": "網路瀏覽器",
"description": "網路瀏覽器"
}
},
"default_locale": "en-US",
"icons": {
"336": "/shared/resources/branding/browser_336.png"
},
"activities": {
"view": {
"filters": {
"type": "url",
"url": {
"required":true, "pattern":"https?:.{1,16384}", "patternFlags":"i"
}
}
}
},
"datastores-access": {
"places": {
"readonly": false,
"description": "Read synced browsing history."
},
"bookmarks_store": {
"readonly": false,
"description": "Read synced browser bookmarks."
}
},
"connections": {
"webpage-open": {
"description": "connection for opening webpage",
"rules": {}
}
}
}

View file

@ -0,0 +1,225 @@
/*
* HTTP Authentication Dialog
*/
#http-authentication-dialog {
display: block;
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
opacity: 1;
background-color: rgba(0,0,0,0.9);
z-index: 500;
}
#http-authentication-dialog.hidden {
display: none;
}
#http-authentication-dialog-wrap {
-moz-box-sizing: border-box;
width: 1400px;
margin: 50px auto;
color: #f9f9f9;
font-family: Fira Sans;
font-size: 32px;
text-align: center;
}
#http-authentication-header {
-moz-box-sizing: border-box;
width: 100%;
padding: 30px;
vertical-align: top;
margin: 0px auto;
text-align: left;
display: inline-flex;
}
#http-authentication-key {
-moz-box-sizing: border-box;
float: left;
width: 36px;
height: 54px;
margin-left: 30px;
background-size: auto;
background-position: 90%;
background-repeat: no-repeat;
background-image: url('../img/key_active.png');
}
#http-authentication-message {
-moz-box-sizing: border-box;
margin: 0px 20px 0px 100px;
text-align: left;
overflow: hidden;
font-family: Fira Sans;
display: inline;
}
#http-authentication-body {
-moz-box-sizing: border-box;
width: 100%;
font-size: 32px;
font-family: Fira Sans;
text-align: left;
color: white;
}
.http-authentication-title {
text-align: right;
height: 56px;
width: 400px;
}
.http-authentication-input {
display: flex;
align-items: center;
position: relative;
padding-left: 50px;
padding-right: 50px;
background-color: transparent;
width: 700px;
background-image: none;
border-bottom: solid 2px #fff;
-moz-transition: -moz-transform 0.16s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
.http-authentication-input-area {
width: 600px;
height: 100%;
font-size: 38px;
font-style: Italic;
font-family: Fira Sans;
color: #fff;
text-align: center;
background-color: transparent;
border: none;
background-image: none;
}
.http-authentication-input:hover,
.http-authentication-input.exfocus {
border-bottom: solid 3px #00caf2;
transform: scale(1.2);
outline:none;
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
.http-authentication-input .input-line {
width: 100%;
}
.http-authentication-input:hover .input-line,
.http-authentication-input.exfocus .input-line {
transform: scaleX(1);
}
.http-authentication-input.input {
border-bottom: solid 3px #00caf2;
transform: scale(1.0);
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
.http-authentication-input.input .http-authentication-input-area {
font-style: normal;
-moz-transition: font-style 0.06s cubic-bezier(0.25, 0, 0, 1.0);
}
#http-authentication-username-clear,
#http-authentication-password-clear {
width: 30px;
height: 30px;
left: 40px;
margin-left: -30px;
display: inline-block;
border-radius: 50%;
border : 1px solid #5f6368;
background: url("../style/images/ic_close.png") no-repeat center/contain #5f6368;
position: relative;
-moz-transition: -moz-transform 0.16s cubic-bezier(0.25, 0, 0, 1.0) ,
background 0.16s cubic-bezier(0.25, 0, 0, 1.0) ,
border 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
#http-authentication-username-clear:focus,
#http-authentication-password-clear:focus,
#http-authentication-username-clear:hover,
#http-authentication-password-clear:hover {
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0) ,
background 0.42s cubic-bezier(0.25, 0, 0, 1.0) ,
border 0.42s cubic-bezier(0.25, 0, 0, 1.0);
transform: scale(1.2);
outline:none;
border : 1px solid #fff;
background: url("../style/images/ic_close_black.png") no-repeat center/contain #fff;
}
#http-authentication-password-clear.active,
#http-authentication-password-clear:active,
#http-authentication-username-clear.active,
#http-authentication-username-clear:active {
-moz-transition: -moz-transform 0.06s cubic-bezier(0.25, 0, 0, 1.0);
-moz-transform: scale(1.0);
border : 1px solid #00caf2;
background: url("../style/images/ic_close.png") no-repeat center/contain #00caf2;
}
#http-authentication-button {
height: 100px;
font-size: 32px;
padding-top: 130px;
}
.http-authentication-button {
-moz-box-sizing: border-box;
position: relative;
text-align: center;
width: 210px;
height: 210px;
top: 50%;
color: white;
font-family: Fira Sans;
font-style: Italic;
font-size: 24px;
background-image: none;
border: 0;
border-radius: 50%;
display: inline-table;
-moz-transition: -moz-transform 0.16s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.16s cubic-bezier(0.25, 0, 0, 1.0),
color 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
#http-authentication-cancel {
left: 22px;
background-color: #5f6368;
color: #ffffff;
}
#http-authentication-ok {
right: 22px;
background-color: #0097b6;
color: #ffffff;
}
#http-authentication-cancel:focus,
#http-authentication-cancel:hover {
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.42s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #ffffff;
color: #2d2d2d;
-moz-transform: scale(1.2);
}
#http-authentication-ok:focus,
#http-authentication-ok:hover {
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0);
-moz-transform: scale(1.2);
}
#http-authentication-cancel.active,
#http-authentication-cancel:active {
-moz-transition: -moz-transform 0.06s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0),
color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00caf2;
color: #ffffff;
-moz-transform: scale(1.0);
}
#http-authentication-ok.active,
#http-authentication-ok:active {
-moz-transition: -moz-transform 0.06s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00758c;
color: #ffffff;
-moz-transform: scale(1.0);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,267 @@
/* --------------- dialog --------------- */
#browser-dialog-base {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
width: inherit;
height: 1080px;
z-index: 500;
background-color: rgba(0,0,0,0.9);
}
#browser-dialog-base.hide {
display: none;
}
#browser-dialog {
-moz-box-sizing: border-box;
position: relative;
width: 700px;
height: 640px;
color: #f9f9f9;
}
#browser-dialog-title {
position: relative;
width: 100%;
min-height: 0px;
text-align: center;
font-size: 34px;
font-family: Fira Sans;
font-style: Italic; /* TODO : Light Italic */
color: #f9f9f9;
}
#browser-dialog-msg {
position: relative;
width: 100%;
min-height: 38px;
margin-bottom: 34px;
text-align: center;
font-size: 38px;
font-family: Fira Sans;
font-style: Italic; /* TODO : Light Italic */
color: #f9f9f9;
display: inline-block;
}
#browser-dialog-input {
position: relative;
height: 70px;
width: 700px;
text-align: center;
display: table;
vertical-align: middle;
margin: 24px auto 20px;
border-bottom: 2px solid #E7E7E7;
-moz-transform: scale(1);
-moz-transition: all 0.16s cubic-bezier(0.25, 0, 0, 1) 0s;
}
#browser-dialog-input:hover,
#browser-dialog-input.exfocus {
-moz-transform: scale(1.2);
outline:none;
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
#browser-dialog-input.input {
border-bottom: solid 3px #00caf2;
-moz-transform: scale(1.0);
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
#browser-dialog-input.input #browser-dialog-input-area {
font-style: normal;
-moz-transition: font-style 0.06s cubic-bezier(0.25, 0, 0, 1.0);
}
#browser-dialog-input-area {
position: absolute;
top: 0px;
bottom: 0px;
width: 600px;
height: 100%;
background: none repeat scroll 0% 0% transparent;
border: medium none;
vertical-align: middle;
margin: auto 50px;
text-align: center;
font-family: "Fira Sans";
font-style: italic;
font-size: 38px;
color: #FFF;
display: table-cell;
}
#browser-dialog-input .input-line {
width: 100%;
}
#browser-dialog-input:hover .input-line,
#browser-dialog-input.exfocus .input-line {
transform: scaleX(1);
}
#browser-dialog-input-clear {
width: 30px;
height: 30px;
background: url('../style/images/ic_close.png') no-repeat scroll center center / contain #5F6368;
border-radius: 50%;
transition: -moz-transform 0.16s cubic-bezier(0.25, 0, 0, 1) 0s, background-color 0.16s cubic-bezier(0.25, 0, 0, 1) 0s, color 0.16s cubic-bezier(0.25, 0, 0, 1) 0s;
pointer-events: auto;
display: table-cell;
position: absolute;
top: 0px;
bottom: 0px;
margin: auto;
right: calc(50px / 2 - 15px);
}
#browser-dialog-input-clear:focus,
#browser-dialog-input-clear:hover {
-moz-transition : -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0) ,
background 0.42s cubic-bezier(0.25, 0, 0, 1.0) ,
border 0.42s cubic-bezier(0.25, 0, 0, 1.0);
-moz-transform: scale(1.2);
outline:none;
border : 1px solid #fff;
background: url("../style/images/ic_close_black.png") no-repeat center/contain #fff;
}
#browser-dialog-input-clear.active,
#browser-dialog-input-clear:active {
-moz-transition : -moz-transform 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
background 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
border 0.06s cubic-bezier(0.25, 0, 0, 1.0);
-moz-transform: scale(1.0);
border : 1px solid #00caf2;
background: url("../style/images/ic_close.png") no-repeat center/contain #00caf2;
}
#browser-dialog-button {
position: relative;
display: table;
height: 210px;
margin: 130px auto;
}
.browser-dialog-button {
position: relative;
bottom: 0;
height: 210px;
width: 210px;
margin-left: 22px;
margin-right: 22px;
padding-left: 20px;
padding-right: 20px;
float: left;
font-size: 24px;
font-family: Fira Sans;
font-style: Italic;
border: 0;
border-radius: 50%;
color: #ffffff;
background-image: none;
-moz-transition: -moz-transform 0.16s cubic-bezier(0.25, 0, 0, 1.0);
-moz-transform: scale(1.0);
}
#browser-dialog-button1,
#browser-dialog-button2 {
display: none;
}
#browser-dialog-button1.visible,
#browser-dialog-button2.visible {
display: block;
}
#browser-dialog-button1 {
background-color: #5f6368;
}
#browser-dialog-button2 {
background-color: #0097b6;
}
#browser-dialog-button2[data-type="del_cookie"],
#browser-dialog-button2[data-type="clear_history"] {
background-color: #e63d2f;
}
.browser-dialog-button:focus,
.browser-dialog-button:hover {
-moz-transition: -moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0);
-moz-transform: scale(1.2);
}
#browser-dialog-button1:focus,
#browser-dialog-button1:hover {
-moz-transition: background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
-moz-transform 0.42s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #ffffff;
color: #2d2d2d;
}
#browser-dialog-button2:focus,
#browser-dialog-button2:hover {
}
#browser-dialog-button1.active,
#browser-dialog-button2.active,
.browser-dialog-button:active {
-moz-transition: -moz-transform 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00758c;
-moz-transform: scale(1.0);
}
#browser-dialog-button1.active,
#browser-dialog-button1:active {
-moz-transition: background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00caf2;
color: #ffffff;
}
#browser-dialog-button2.active,
#browser-dialog-button2:active {
-moz-transition: background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00758c;
}
#browser-dialog-button2[data-type="del_cookie"].active,
#browser-dialog-button2[data-type="del_cookie"]:active,
#browser-dialog-button2[data-type="clear_history"]:active {
-moz-transition: background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #ac2e23;
color: #ffffff;
}
/*IFDEF_FIREFOX_SYNC*/
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog {
width: 91rem;
height: 100%;
}
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-title {
position: absolute;
top: 24.5rem;
font-size: 3.8rem;
font-weight: lighter;
line-height: 3.8rem;
}
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-msg {
position: absolute;
top: calc(24.5rem + 3.8rem + 6rem);
font-size: 3.8rem;
font-weight: lighter;
line-height: 4.8rem;
}
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-button {
position: absolute;
bottom: 24.5rem;
display: flex;
width: 100%;
flex-direction: row-reverse;
justify-content: center;
margin: 0;
}
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-button1 {
background-color: #5f6368;
}
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-button1:hover,
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-button1:focus {
color: #fff;
}
#browser-dialog-base[data-type="signout_confirm"] #browser-dialog-button2{
background-color: #e63d2f;
}
/*ENDIF_FIREFOX_SYNC*/

View file

@ -0,0 +1,43 @@
/* checkbox */
.settings-horizontal-list-item {
display: flex;
align-items: center;
}
input[type="checkbox"].settings-list-checkbox {
display: none;
}
input[type="checkbox"].settings-list-checkbox + label {
display: inline-flex;
align-items: center;
justify-content: center;
width: 5rem;
height: 5rem;
border: 0.4rem solid #5f6368;
border-radius: 50%;
margin-right: 2rem;
line-height: 5rem;
text-align: center;
}
input[type="checkbox"].settings-list-checkbox:disabled + label,
input[type="checkbox"].settings-list-checkbox:disabled ~ span {
opacity: 0.5;
}
input[type="checkbox"].settings-list-checkbox:checked + label::after {
font-family: "smart-icons";
font-style: normal;
font-weight: 500;
font-size: 3rem;
text-rendering: optimizelegibility;
content: "check";
color: #00caf2;
}
input[type="checkbox"].settings-list-checkbox ~ span {
line-height: normal;
font-size: 3rem;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="54px"
height="54px" viewBox="0 0 54 54" enable-background="new 0 0 54 54" xml:space="preserve">
<g id="Layer_40" display="none">
<rect x="-274.333" y="-526" display="inline" fill="#464445" width="691.333" height="784"/>
</g>
<g id="Layer_6">
</g>
<g id="Dark">
<g>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M33.59,16.501c-0.176-1.671-1.595-2.786-3.341-2.786H16.746
c-1.864,0-3.061,1.264-3.061,3.128v13.504c0,1.738,1.162,3.154,2.83,3.339V20.219c0-1.864,1.534-3.718,3.398-3.718H33.59z
M36.814,18.595H22.328c-1.968,0-3.716,2.094-3.716,4.062v14.297c0,1.968,1.748,3.332,3.716,3.332h14.485
c1.968,0,3.502-1.364,3.502-3.332V22.656C40.315,20.688,38.782,18.595,36.814,18.595z M35.394,30.061
c0,0.499-0.405,1.127-0.904,1.127h-3.981v4.006c0,0.499-0.602,0.904-1.102,0.904h-0.524c-0.5,0-1.189-0.405-1.189-0.904v-4.006
h-4c-0.5,0-0.904-0.628-0.904-1.127v-0.452c0-0.5,0.405-1.232,0.904-1.232h4v-3.982c0-0.5,0.689-0.904,1.189-0.904h0.524
c0.5,0,1.102,0.404,1.102,0.904v3.982h3.981c0.5,0,0.904,0.732,0.904,1.232V30.061z"/>
</g>
</g>
</g>
<g id="Layer_5" display="none">
<path display="inline" opacity="0.3" fill-rule="evenodd" clip-rule="evenodd" fill="#E30613" d="M0,0v54h54V0H0z M47,47H7V7h40V47
z"/>
</g>
<g id="name" display="none">
<text transform="matrix(1 0 0 1 4.1891 51.1551)" display="inline" fill="#646363" font-family="'UniversLTStd-Cn'" font-size="8">add-tab</text>
</g>
<g id="Title" display="none">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="54px"
height="54px" viewBox="0 0 54 54" enable-background="new 0 0 54 54" xml:space="preserve">
<g id="Layer_40" display="none">
<rect x="-52.333" y="-600" display="inline" fill="#464445" width="691.333" height="784"/>
</g>
<g id="Layer_6">
</g>
<g id="Dark">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#00caf2" d="M25.019,38.429c-1.165,1.165-2.936,1.333-4.29,0.527l-6.786-9.133
l2.462-2.891l5.262,7.151c0.009,0.01,0.015,0.021,0.024,0.03c0.447,0.446,1.158,0.458,1.623,0.042l0.005,0.005l16.739-19.613v6.009
L25.019,38.429z"/>
</g>
<g id="Layer_5" display="none">
<path display="inline" opacity="0.3" fill-rule="evenodd" clip-rule="evenodd" fill="#E30613" d="M0,0v54h54V0H0z M47,47H7V7h40V47
z"/>
</g>
<g id="name" display="none">
<text transform="matrix(1 0 0 1 4.3136 51.1551)" display="inline" fill="#646363" font-family="'UniversLTStd-Cn'" font-size="8">check</text>
</g>
<g id="Title" display="none">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="54px"
height="54px" viewBox="0 0 54 54" enable-background="new 0 0 54 54" xml:space="preserve">
<g id="Layer_40" display="none">
<rect x="-52.333" y="-600" display="inline" fill="#464445" width="691.333" height="784"/>
</g>
<g id="Layer_6">
</g>
<g id="Dark">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#1D1D1B" d="M25.019,38.429c-1.165,1.165-2.936,1.333-4.29,0.527l-6.786-9.133
l2.462-2.891l5.262,7.151c0.009,0.01,0.015,0.021,0.024,0.03c0.447,0.446,1.158,0.458,1.623,0.042l0.005,0.005l16.739-19.613v6.009
L25.019,38.429z"/>
</g>
<g id="Layer_5" display="none">
<path display="inline" opacity="0.3" fill-rule="evenodd" clip-rule="evenodd" fill="#E30613" d="M0,0v54h54V0H0z M47,47H7V7h40V47
z"/>
</g>
<g id="name" display="none">
<text transform="matrix(1 0 0 1 4.3136 51.1551)" display="inline" fill="#646363" font-family="'UniversLTStd-Cn'" font-size="8">check</text>
</g>
<g id="Title" display="none">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="54px"
height="54px" viewBox="0 0 54 54" enable-background="new 0 0 54 54" xml:space="preserve">
<g id="Layer_40" display="none">
<rect x="-52.333" y="-526" display="inline" fill="#464445" width="691.333" height="784"/>
</g>
<g id="Layer_6">
</g>
<g id="Dark">
<path fill="#1D1D1B" d="M37.209,30.338c0.622-1.237,1.562-4.018,0.758-6.292c0.006,0.022,0.011,0.044,0.017,0.066
c-0.009-0.027-0.014-0.041-0.014-0.041s-0.151,0.455-0.363,1.158c-0.014-0.094-0.029-0.187-0.046-0.28
c0.059-0.854,0.035-1.773-0.138-2.646c-0.273-1.381-1.34-2.58-1.904-2.967c0.028,0.021,0.057,0.046,0.087,0.073
c-0.064-0.05-0.103-0.076-0.103-0.076s0.023,0.126,0.064,0.349c-0.612-0.962-1.544-1.415-1.544-1.415s0.029,0.161,0.075,0.498
c-1.91-1.7-4.426-2.733-7.184-2.733c-2.806,0-5.363,1.069-7.285,2.823c0.106,0.127,0.216,0.274,0.33,0.445
c0,0,0.731-0.131,1.622-0.046c1.55-1.095,3.397-1.684,5.333-1.684c2.477,0,4.806,0.965,6.558,2.718
c0.092,0.092,0.18,0.185,0.268,0.28c-0.526-0.396-1.162-0.725-1.634-0.761c0.965,0.717,2.399,2.509,2.251,5.661
c-0.247-0.519-0.544-0.927-0.866-1.211c0.346,3.164,0.043,3.844-0.167,4.685c-0.046-0.386-0.186-0.677-0.266-0.853
c0,0-0.037,0.989-0.68,2.398c-0.487,1.067-0.989,1.397-1.212,1.36c-0.197-0.033-0.062-0.222-0.099-0.408
c0,0-0.334,0.161-0.668,0.507c-0.316,0.327-0.6,0.69-0.748,0.587c0.111-0.093,0.192-0.247,0.278-0.389
c-0.124,0.087-0.439,0.321-1.144,0.426c-0.288,0.043-1.515,0.266-3.147-0.55c0.238-0.027,0.593-0.111,0.865,0.049
c-0.272-0.297-0.927-0.235-1.397-0.383c-0.409-0.129-0.944-0.704-1.251-0.994c1.255,0.307,2.589,0.086,3.361-0.442
c0.779-0.533,1.24-0.922,1.654-0.829c0.414,0.092,0.689-0.323,0.368-0.691c-0.322-0.369-1.103-0.876-2.16-0.599
c-0.745,0.195-1.669,1.019-3.078,0.185c-1.203-0.712-1.195-1.291-1.195-1.66c0-0.253,0.154-0.595,0.443-0.756
c0.156,0.056,0.253,0.107,0.253,0.107s-0.072-0.111-0.118-0.165c0.011-0.003,0.022-0.006,0.033-0.009
c0.127,0.043,0.414,0.149,0.559,0.222c0.196,0.099,0.263,0.199,0.263,0.199s0.046-0.029-0.002-0.13
c-0.02-0.042-0.09-0.164-0.285-0.282c0.004,0,0.007,0,0.01-0.001c0.102,0.04,0.21,0.092,0.33,0.159
c0.037-0.173,0.112-0.353,0.062-0.667c-0.035-0.221-0.031-0.278-0.087-0.359c-0.047-0.069,0.012-0.099,0.087-0.037
c-0.018-0.055-0.043-0.109-0.072-0.164c0-0.001,0.001-0.002,0.001-0.003c0.004-0.017,0.014-0.036,0.029-0.058
c0.23-0.319,1.665-1.072,1.779-1.157c0.141-0.104,0.284-0.257,0.391-0.435c0.146-0.091,0.25-0.466,0.277-0.749
c0.011-0.113-0.235-0.247-0.365-0.272c-0.074-0.019-0.335-0.063-0.525-0.031c0.008,0.004,0.018,0.009,0.029,0.014
c-0.266-0.017-0.625-0.024-1.11-0.02c-0.475,0.004-0.783-0.273-0.969-0.536c-0.037-0.056-0.07-0.11-0.1-0.158
c-0.041-0.074-0.072-0.14-0.094-0.193c0.207-0.752,0.626-1.403,1.273-1.931c0.04-0.032-0.154,0.023-0.117-0.012
c0.044-0.041,0.318-0.172,0.369-0.201c0.067-0.037-0.298-0.136-0.611-0.071c-0.312,0.065-0.374,0.102-0.535,0.185
c0.065-0.068,0.277-0.175,0.226-0.164c-0.341,0.076-0.741,0.3-1.082,0.541c-0.003-0.031,0-0.055,0.006-0.105
c-0.161,0.084-0.55,0.383-0.649,0.612c0-0.049,0-0.074-0.006-0.13c-0.111,0.102-0.217,0.221-0.313,0.354
c-0.001,0.002-0.003,0.003-0.004,0.005c-1.013-0.252-1.874-0.191-2.593,0.04c-0.24-0.194-0.605-0.54-0.882-0.988
c-0.026-0.041-0.029,0.092-0.052,0.049c-0.156-0.279-0.289-0.737-0.323-1.1c-0.003-0.036-0.006-0.072-0.007-0.106
c0,0-0.133,0.078-0.276,0.316c-0.064,0.106-0.129,0.244-0.186,0.422c-0.032,0.102-0.056,0.162-0.079,0.218
c-0.007,0.018,0.014-0.185,0.006-0.168c-0.035,0.072-0.135,0.185-0.167,0.315c-0.025,0.098-0.064,0.157-0.079,0.28
c-0.001,0.002-0.002,0.004-0.003,0.006c-0.003-0.03-0.005-0.143-0.013-0.121c-0.083,0.218-0.16,0.468-0.221,0.751
c-0.053,0.208-0.094,0.444-0.118,0.713c-0.027,0.308-0.031,0.658-0.003,1.057c-0.001,0.062-0.003,0.119-0.005,0.175
c-0.273,0.376-0.439,0.7-0.508,0.859c-0.333,0.648-0.674,1.646-0.948,3.195c0,0,0.181-0.574,0.545-1.229
c-0.001,0.008-0.003,0.017-0.004,0.025c-0.266,0.834-0.47,2.119-0.347,4.03c0.005-0.064,0.062-0.554,0.207-1.216
c0.07,1.292,0.44,2.865,1.446,4.587c0.739,1.265,1.608,2.214,2.58,2.92c0.179,0.144,0.363,0.282,0.551,0.415
c1.203,0.877,3.073,1.957,4.667,2.187c-0.557-0.161-0.903-0.482-0.903-0.482s1.895,0.608,3.277,0.556
c-0.433-0.074-0.52-0.284-0.52-0.284s3.938,0.222,5.983-1.393c0.458-0.345,0.759-0.744,0.849-1.109
c0.603-0.321,1.254-0.759,1.923-1.417c1.113-1.095,1.234-1.928,1.354-2.707c-0.004,0.024-0.01,0.049-0.015,0.073
C37.366,30.815,37.332,30.54,37.209,30.338z"/>
</g>
<g id="Layer_5" display="none">
<path display="inline" opacity="0.3" fill-rule="evenodd" clip-rule="evenodd" fill="#E30613" d="M0,0v54h54V0H0z M47,47H7V7h40V47
z"/>
</g>
<g id="name" display="none">
<text transform="matrix(1 0 0 1 4.3136 51.1551)" display="inline" fill="#646363" font-family="'UniversLTStd-Cn'" font-size="8">default-fav </text>
</g>
<g id="Title" display="none">
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="54px"
height="54px" viewBox="0 0 54 54" enable-background="new 0 0 54 54" xml:space="preserve">
<g id="Layer_40" display="none">
<rect x="-52.333" y="-452" display="inline" fill="#464445" width="691.333" height="784"/>
</g>
<g id="Layer_6">
</g>
<g id="Dark">
<g>
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#5F6368" d="M39.701,24.33c-0.953-7.119-7.035-12.616-14.416-12.616
c-8.041,0-14.56,6.52-14.56,14.561c0,8.042,6.519,14.56,14.56,14.56c4.022,0,7.663-1.63,10.298-4.266l-2.231-2.231
c-2.064,2.065-4.916,3.343-8.067,3.343c-6.299,0-11.405-5.107-11.405-11.405c0-6.299,5.106-11.405,11.405-11.405
c5.622,0,10.282,4.071,11.222,9.423c-1.445,0.126-2.765,0.437-3.866,0.883l4.343,4.343c0.539,0.539,1.413,0.539,1.951,0
l4.339-4.338C42.251,24.763,41.03,24.472,39.701,24.33z"/>
</g>
</g>
</g>
<g id="Layer_5" display="none">
<path display="inline" opacity="0.3" fill-rule="evenodd" clip-rule="evenodd" fill="#E30613" d="M0,0v54h54V0H0z M47,47H7V7h40V47
z"/>
</g>
<g id="name" display="none">
<text transform="matrix(1 0 0 1 4.1891 50.4886)" display="inline" fill="#646363" font-family="'UniversLTStd-Cn'" font-size="8">reload</text>
</g>
<g id="Title" display="none">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,176 @@
html, body {
width: 1920px;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
cursor: default;
background-color : #e0e2e4;
}
html {
font-size: 10px;
}
body {
font-size: 20px;
}
a {
overflow: hidden;
outline: none;
}
.input-line {
position: absolute;
bottom: -2px;
left: 0px;
height: 3px;
transition: transform 0.3s ease-in 0s;
transform: scaleX(0);
background-color: #00CAF2;
}
/* --------------- layout --------------- */
.side-window {
width: 400px;
height: 1080px;
float: left;
background-color: #282929;
display: none;
cursor: default;
}
#side-block[data-sidebar="true"] {
display: block;
}
.main-window {
position: relative;
width: 1920px;
height: 100%;
float: left;
cursor: default;
display: block;
}
#main-block[data-sidebar="true"] {
width: -moz-calc(1920px - 400px);
}
/* --------------- block --------------- */
#web-block {
position: absolute;
width: 100%;
height: -moz-calc(100% - 100px);
cursor: default;
top: 100px;
}
/* --------------- other --------------- */
input::-moz-focus-inner {
border: 0;
}
/* --------------- browser --------------- */
#web-block > iframe {
-moz-box-sizing: border-box;
height: 100%;
width: 100%;
border: solid 0px;
}
#block-l {
position: absolute;
left: 1px;
width: 10px;
height: 1080px;
z-index: 200;
cursor: default;
}
#block-r {
position: absolute;
right: 1px;
width: 10px;
height: 1080px;
z-index: 200;
cursor: default;
}
#block-d {
position: absolute;
bottom: 1px;
width: 100%;
height: 10px;
z-index: 200;
cursor: default;
}
/* --------------- scroll --------------- */
#scroll-u, #scroll-d {
position: absolute;
width: 100%;
height: 1px;
z-index: 190;
}
#scroll-u {
top: 0px;
}
#scroll-d {
bottom: 0px;
}
#scroll-l, #scroll-r {
position: absolute;
width: 1px;
height: 1080px;
z-index: 190;
}
#scroll-l {
left: 0px;
}
#scroll-r {
right: 0px;
}
#scroll-u:not(.disable):hover {
cursor: url('../img/scroll_up.cur'), auto;
}
#scroll-d:not(.disable):hover {
cursor: url('../img/scroll_down.cur'), auto;
}
#scroll-l:not(.disable):hover {
cursor: url('../img/scroll_left.cur'), auto;
}
#scroll-r:not(.disable):hover {
cursor: url('../img/scroll_right.cur'), auto;
}
/* --------------- fade --------------- */
#fade-base {
display: block;
visibility: hidden;
position: absolute;
width: 1920px;
height: 1080px;
opacity: 0;
background-color: black;
z-index: 1200;
}
#fade-base.fade {
visibility: visible;
opacity: 1;
}
/* animation */
#fade-base {
-moz-transition-property: all;
-moz-transition-duration: 1s;
-moz-transition-timing-function: ease-out;
-moz-transition-delay: 0s;
transition-property: all;
transition-duration: 1s;
transition-timing-function: ease-out;
transition-delay: 0s;
}

View file

@ -0,0 +1,147 @@
/* --------------- search-result --------------- */
#search-result {
display: none;
position: absolute;
top: 100px;
left: 0;
width: 100%;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
background-color: #e0e2e4;
z-index: 310;
}
#search-result.visible {
display: block;
}
#search-result-list {
-moz-box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 40px;
font-family: Fira Sans;
font-size: 32px;
}
.result-box {
width: 100%;
height: 100%;
margini: auto;
}
.result-item {
display: inline-block;
width: 100%;
height: 112px;
margin: auto;
padding: 20px;
border-bottom: solid 1px #b4b5b6;
position: relative;
-moz-transition: -moz-transform 0.6s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.6s cubic-bezier(0.25, 0, 0, 1.0),
height 0.6s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.6s cubic-bezier(0.25, 0, 0, 1.0);
}
.result-base {
position: relative;
display: inline-block;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.result-title {
display: inline;
position: relative;
top: 0;
left: 0;
right: 0;
text-align: left;
width: 100%;
height: 40px;
font-size: 32px;
font-family: Fira Sans;
color: #4d4d4d;
float: left;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-moz-transition: height 0.6s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.6s cubic-bezier(0.25, 0, 0, 1.0);
}
.result-url {
display: inline;
position: relative;
text-align: left;
width: 100%;
height: 31px; /* TODO: 24px */
margin-top: 2px;
font-size: 24px;
font-family: Fira Sans;
color: #9a9a9a;
float: left;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-moz-transition: height 0.6s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.6s cubic-bezier(0.25, 0, 0, 1.0);
padding-left 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
.result-base,
.result-title,
.result-url {
pointer-events: none;
}
.result-item:hover {
height: 132px;
border-bottom: solid 6px #b4b5b6;
}
.result-item:hover > .result-base > .result-title {
height: 50px;
font-size: 38px;
}
.result-item:hover > .result-base > .result-url {
height: 36px;
font-size: 28px;
}
.result-item:active {
height: 132px;
border-bottom: solid 6px #b4b5b6;
-moz-transition: -moz-transform 0.16s cubic-bezier(0.25, 0, 0, 1.0),
height 0.16s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
.result-item:active > .result-base > .result-title {
height: 50px;
font-size: 38px;
color: #00aac5;
-moz-transition: height 0.16s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.16s cubic-bezier(0.25, 0, 0, 1.0),
color 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
.result-item:active > .result-base > .result-url {
height: 36px;
font-size: 28px;
color: #00aac5;
-moz-transition: height 0.16s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.16s cubic-bezier(0.25, 0, 0, 1.0),
color 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}

View file

@ -0,0 +1,753 @@
/* XXX: smart-button uses box-sizing: content-box, but it's overidden in toolbar.css */
smart-button {
box-sizing: content-box;
}
smart-button[type=simple-text] {
background-color: #5f6368;
border-radius: 4rem;
text-align: center;
}
smart-button[type=simple-text].disabled {
background-color: rgba(0, 0, 0, 0.5);
pointer-events: none;
}
/* --------------- settings-list --------------- */
#settings-list {
box-sizing: border-box;
font-size: 32px;
position: absolute;
left: 0;
/* top: 100px; */
top: 0;
width: 100%;
/* height: 980px; */
height: 1080px;
background-color: #e0e2e4;
color: #4d4d4d;
z-index: 320;
transition: 0.5s ease-in-out;
transform: translateY(100%);
}
.settings-screen #settings-list {
transform: translateY(0%);
}
/*IFDEF_FIREFOX_SYNC*/
#fxsync-area {
margin-top: 13rem
}
/*ENDIF_FIREFOX_SYNC*/
#settings-list-area {
width: 120rem;
margin: 50px auto 0 auto;
}
/*IFDEF_FIREFOX_SYNC*/
#fxsync-header,
/*ENDIF_FIREFOX_SYNC*/
#settings-header
{
top: 0;
left: 0;
right: 0;
height: 4.6rem;
width: 100%;
font-family: Fira Sans;
font-size: 4.6rem;
font-style: Italic; /* TODO: Regular? */
color: #4d4d4d;
pointer-events: none;
}
p.fine-print {
font-size: 2rem;
line-height: 1.6rem;
color: #00caf2;
}
#settings-header {
margin: 7rem 0;
}
/*IFDEF_FIREFOX_SYNC*/
#fxsync-header {
margin-bottom: 5rem;
}
/*ENDIF_FIREFOX_SYNC*/
#settings-header-title {
display: inline;
}
#settings-list-item {
top: 72px;
left: 0;
bottom: 0;
right: 0;
margin: auto;
width: 100%;
}
#settings-homepage,
#settings-search-engine,
#settings-clear-history,
#settings-clear-cookie {
position: relative;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
width: 100%;
height: 72px;
padding: 15px; /* TODO: 20px */
font-family: Fira Sans;
font-size: 32px;
border-bottom: solid 1px #b4b5b6;
transition: height 0.6s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.6s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.6s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-homepage:hover,
#settings-search-engine:hover,
#settings-clear-history:hover,
#settings-clear-cookie:hover {
height: 92px;
font-size: 38px;
border-bottom: solid 6px #b4b5b6;
}
#settings-homepage:active,
#settings-search-engine:active,
#settings-clear-history:active,
#settings-clear-cookie:active {
height: 92px;
font-size: 38px;
border-bottom: solid 6px #b4b5b6;
transition: height 0.16s cubic-bezier(0.25, 0, 0, 1.0),
font-size 0.16s cubic-bezier(0.25, 0, 0, 1.0),
border-bottom 0.16s cubic-bezier(0.25, 0, 0, 1.0);}
#settings-homepage-title,
#settings-search-engine-title,
#settings-clear-history-title,
#settings-clear-cookie-title,
#settings-homepage-name,
#settings-search-engine-name {
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
margin: auto;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: padding-left 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-homepage-title,
#settings-search-engine-title {
width: 54%;
text-align: left;
color: #4d4d4d;
}
#settings-clear-history-title,
#settings-clear-cookie-title {
width: 100%;
text-align: left;
color: #4d4d4d;
}
#settings-homepage-name,
#settings-search-engine-name {
padding-right: 5px;
width: 45%;
text-align: right;
color: #8f8f8f;
font-family: Fira Sans;
font-style: Italic; /* TODO: Light Italic */
}
#settings-search-engine-icon {
position: absolute;
bottom: 25%;
right: 5px;
width: 6px;
height: 6px;
margin: auto;
border: 6px solid #8f8f8f;
border-color: transparent #8f8f8f #8f8f8f transparent;
}
#settings-homepage:active > #settings-homepage-title,
#settings-search-engine:active > #settings-search-engine-title,
#settings-clear-history:active > #settings-clear-history-title,
#settings-clear-cookie:active > #settings-clear-cookie-title {
padding-left: 10px;
/*transition: padding-left 0.42s cubic-bezier(0.25, 0, 0, 1.0);*/
}
#settings-homepage:active > #settings-homepage-title,
#settings-homepage:active > #settings-homepage-name,
#settings-search-engine:active > #settings-search-engine-title,
#settings-search-engine:active > #settings-search-engine-name,
#settings-clear-history:active > #settings-clear-history-title,
#settings-clear-cookie:active > #settings-clear-cookie-title {
color: #00aac5;
/*transition: color 0.42s cubic-bezier(0.25, 0, 0, 1.0);*/
}
#settings-search-engine:active > #settings-search-engine-icon {
border: 6px solid #00aac5;
border-color: transparent #00aac5 #00aac5 transparent;
}
/* Firefox Sync */
/*IFDEF_FIREFOX_SYNC*/
#fxsync-sign-in > smart-button {
background-color: #4d4d4d;
line-height: 4rem;
height: 4rem;
}
#fxsync-sign-in-to-sync-description,
#fxsync-signed-in-as {
color: #4d4d4d;
font-style: italic;
font-size: 2.8rem;
font-weight: lighter;
flex-grow: 1;
}
#fxsync-disabled {
margin-left: 4.5rem;
}
#fxsync-disabled > p {
font-size: 2.8rem;
font-style: italic;
font-weight: lighter;
}
#fxsync-enabled {
display: flex;
align-items: center;
margin-top: -5.1rem;
flex-wrap: wrap;
justify-content: space-between;
}
#fxsync-enabled > p {
width: 100%;
}
#fxsync-enabled[hidden] {
display: none;
}
#fxsync-enabled > smart-button {
margin-left: 1.8rem;
}
#fxsync-area.hidden,
/*ENDIF_FIREFOX_SYNC*/
#settings-dialog.hidden,
#settings-dialog-homepage.hidden,
#settings-dialog-search.hidden {
display: none;
}
.settings-horizontal-list {
display: flex;
width: 100%;
margin-top: 2rem;
margin-left: 1rem;
margin-bottom: 2rem;
}
.settings-horizontal-list-item {
margin-right: 4rem;
}
.settings-horizontal-list-item.disabled > span {
opacity: 0.5;
}
#settings-dialog {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: auto;
background-color: rgba(0,0,0,0.9);
font-size: 38px;
}
/*
* Homepage setting dialog
*/
#settings-dialog-homepage {
position: relative;
top: 50%;
width: 700px;
height: 640px;
margin: 0 auto;
transform: translateY(-50%);
}
#settings-dialog-homepage-header {
position: relative;
width: 100%;
height: 38px;
margin: 0 auto 34px;
text-align: center;
}
#settings-dialog-homepage-header-title {
display: inline;
top: 0;
left: 0;
font-size: 38px;
font-family: Fira Sans;
font-style: Italic; /* TODO: Light Italic */
color: #f9f9f9;
}
#settings-dialog-homepage-input {
position: relative;
height: 70px;
width: 700px;
text-align: center;
display: table;
vertical-align: middle;
margin: 24px auto 20px;
border-bottom: 2px solid #E7E7E7;
transform: scale(1);
transition: all 0.16s cubic-bezier(0.25, 0, 0, 1) 0s;
}
#settings-dialog-homepage-input:hover,
#settings-dialog-homepage-input.exfocus {
transform: scale(1.2);
outline:none;
}
#settings-dialog-homepage-input.input {
transition: transform 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
border-bottom 0.06s cubic-bezier(0.25, 0, 0, 1.0);
border-bottom: solid 3px #00caf2;
transform: scale(1.0);
outline:none;
}
#settings-dialog-homepage-input.input #settings-dialog-homepage-input-area {
font-style: normal;
transition: font-style 0.06s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-homepage-input-area {
position: absolute;
top: 0px;
bottom: 0px;
width: 600px;
height: 100%;
background: none repeat scroll 0% 0% transparent;
border: medium none;
vertical-align: middle;
margin: auto 50px;
text-align: center;
font-family: "Fira Sans";
font-style: italic;
font-size: 38px;
color: #FFF;
display: table-cell;
}
#settings-dialog-homepage-input .input-line {
width: 100%;
bottom: 0px;
}
#settings-dialog-homepage-input:hover .input-line,
#settings-dialog-homepage-input.exfocus .input-line {
transform: scaleX(1);
}
#settings-dialog-homepage-clear {
width: 30px;
height: 30px;
background: url('../style/images/ic_close.png') no-repeat scroll center center / contain #5F6368;
border-radius: 50%;
display: table-cell;
position: absolute;
top: 0px;
bottom: 0px;
margin: auto;
right: calc(50px / 2 - 15px);
transition: transform 0.16s cubic-bezier(0.25, 0, 0, 1) 0s,
background-color 0.16s cubic-bezier(0.25, 0, 0, 1) 0s,
color 0.16s cubic-bezier(0.25, 0, 0, 1) 0s;
}
#settings-dialog-homepage-clear:focus,
#settings-dialog-homepage-clear:hover {
transition : transform 0.42s cubic-bezier(0.25, 0, 0, 1.0) ,
background 0.42s cubic-bezier(0.25, 0, 0, 1.0) ,
border 0.42s cubic-bezier(0.25, 0, 0, 1.0);
transform: scale(1.2);
outline:none;
border : 1px solid #fff;
background: url("../style/images/ic_close_black.png") no-repeat center/contain #fff;
}
#settings-dialog-homepage-clear.active,
#settings-dialog-homepage-clear:active {
transition : transform 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
background 0.06s cubic-bezier(0.25, 0, 0, 1.0) ,
border 0.06s cubic-bezier(0.25, 0, 0, 1.0);
transform: scale(1.0);
border : 1px solid #00caf2;
background: url("../style/images/ic_close.png") no-repeat center/contain #00caf2;
}
#settings-dialog-homepage-default {
position: relative;
top: 40px;
left: 400px;
height: 80px;
min-width: 250px;
margin-bottom: 40px;
padding-left: 38px;
padding-right: 38px;
background-color: #000000;
color: #ffffff;
font-family: Fira Sans;
font-size: 24px;
border-radius: 40px;
background-image: none;
transition: transform 0.16s cubic-bezier(0.25, 0, 0, 1.0),
color 0.16s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.16s cubic-bezier(0.25, 0, 0, 1.0);
border: 1px solid #ffffff;
}
#settings-dialog-homepage-default:focus,
#settings-dialog-homepage-default:hover {
transition: transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0);
border: none;
color: #2d2d2d;
background-color: #ffffff;
transform: scale(1.2);
}
#settings-dialog-homepage-default.active,
#settings-dialog-homepage-default:active {
transition: transform 0.06s cubic-bezier(0.25, 0, 0, 1.0),
color 0.06s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
border: none;
color: #ffffff;
background-color: #00caf2;
transform: scale(1.0);
}
#settings-dialog-homepage-button {
position: relative;
margin: 130px auto;
height: 210px;
}
#settings-dialog-homepage-cancel,
#settings-dialog-search-cancel {
position: absolute;
top: 0;
left: 372px;
height: 210px;
width: 210px;
font-family: Fira Sans;
font-style: Italic;
font-size: 24px;
border: 0;
border-radius: 50%;
background-image: none;
background-color: #5f6368;
color: #ffffff;
transition: transform 0.16s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.16s cubic-bezier(0.25, 0, 0, 1.0),
color 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-homepage-ok,
#settings-dialog-search-ok {
position: absolute;
top: 0;
left: 118px;
height: 210px;
width: 210px;
font-family: Fira Sans;
font-style: Italic;
font-size: 24px;
border: 0;
border-radius: 50%;
background-image: none;
background-color: #0097b6;
color: #ffffff;
transition: transform 0.16s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.16s cubic-bezier(0.25, 0, 0, 1.0),
color 0.16s cubic-bezier(0.25, 0, 0, 1.0);
}
/*
* Search Engine setting dialog
*/
#settings-dialog-search {
position: absolute;
width: 700px;
height: 658px;
top: calc(100% / 2 - 658px / 2); /* dialog centering */
left: calc(100% / 2 - 700px / 2); /* dialog centering */
}
#settings-dialog-search-header {
position: absolute;
top: -50px;
left: 0;
width: 100%;
height: 38px;
margin: auto;
text-align: center;
}
#settings-dialog-search-header-title {
display: inline;
top: 0;
left: 0;
font-size: 44px;
font-family: Fira Sans;
font-style: Italic; /* TODO: Light Italic */
color: #f9f9f9;
}
#settings-dialog-search-select {
position: absolute;
top: 48px;
left: 0;
width: 100%;
height: 120px;
}
#settings-dialog-search-select-list {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: auto;
}
#settings-dialog-search-select-list > .item {
top: 0;
left: 0;
width: 100%;
height: 100%;
display: inline-flex;
outline: none;
position: relative;
}
#settings-dialog-search-select-list > .item > .title {
top: 0;
left: 0;
width: 100%;
height: 100%;
display: inline-flex;
}
#settings-dialog-search-select-list > .item > .title > .name {
top: 0;
left: 0;
display: inline;
width: 100%;
height: 60px;
line-height: 100%;
margin-left: 94px;
font-size: 44px;
text-align: center;
font-family: Fira Sans;
font-style: Italic; /* TODO: Light Italic */
color: #ffffff;
transition: transform 0.6s cubic-bezier(0.25, 0, 0, 1.0),
color 0.6s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-search-select-list > .item > .check {
top: 0;
height: 100%;
width: 94px;
margin: auto;
display: inline-flex;
}
#settings-dialog-search-select-list > .item > .check > .off {
width: 48px;
height: 48px;
transition: transform 0.6s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-search-select-list > .item > .check > .on {
width: 60px;
height: 60px;
background-image: url('../style/images/check-on.svg');
background-position: contain;
background-size: cover;
transition: transform 0.6s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-search-button {
position: absolute;
margin: auto;
top: 448px;
left: 0;
width: 100%;
height: 210px;
}
#settings-dialog-search-cancel {
position: absolute;
top: 0;
left: 372px;
height: 210px;
width: 210px;
font-size: 24px;
font-family: Fira Sans;
font-style: Italic;
border: 0;
border-radius: 50%;
background-image: none;
background-color: #5f6368;
color: #ffffff;
transition: transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-search-ok {
position: absolute;
top: 0;
left: 118px;
height: 210px;
width: 210px;
font-size: 24px;
font-family: Fira Sans;
font-style: Italic;
border: 0;
border-radius: 50%;
background-image: none;
background-color: #0097b6;
color: #ffffff;
transition: transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.4s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-dialog-search-select-list > .item:focus > .title > .name,
#settings-dialog-search-select-list > .item:hover > .title > .name,
#settings-dialog-search-select-list > .item:focus > .check > .on,
#settings-dialog-search-select-list > .item:hover > .check > .on {
transform: scale(1.2);
}
#settings-dialog-search-select-list > .item > .title > .name[data-display="selected"],
#settings-dialog-search-select-list > .item > .title > .name[data-display="selected"] {
color: #00caf2;
}
#settings-dialog-homepage-cancel:focus,
#settings-dialog-search-cancel:focus,
#settings-dialog-homepage-cancel:hover,
#settings-dialog-search-cancel:hover {
transition: transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0),
color 0.42s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #ffffff;
color: #2d2d2d;
transform: scale(1.2);
}
#settings-dialog-homepage-ok:focus,
#settings-dialog-search-ok:focus,
#settings-dialog-homepage-ok:hover,
#settings-dialog-search-ok:hover {
transition: transform 0.42s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.42s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #0097b6;
transform: scale(1.2);
}
#settings-dialog-homepage-cancel.active,
#settings-dialog-search-cancel.active,
#settings-dialog-homepage-cancel:active,
#settings-dialog-search-cancel:active {
transition: transform 0.06s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0),
color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00caf2;
color: #ffffff;
transform: scale(1.0);
}
#settings-dialog-homepage-ok.active,
#settings-dialog-search-ok.active ,
#settings-dialog-homepage-ok:active,
#settings-dialog-search-ok:active {
transition: transform 0.06s cubic-bezier(0.25, 0, 0, 1.0),
background-color 0.06s cubic-bezier(0.25, 0, 0, 1.0),
color 0.06s cubic-bezier(0.25, 0, 0, 1.0);
background-color: #00758c;
color: #ffffff;
transform: scale(1.0);
}
#settings-banner-message {
position: absolute;
left: 0px;
right: 0px;
bottom: 100px;
width: auto;
height: auto;
padding-left: 44px;
padding-right: 44px;
padding-top: 20px;
padding-bottom: 20px;
max-width : 80%;
margin: 0 auto;
z-index: 325;
background: rgba(0, 0, 0, 0.7);
background-color: #000000;
display: none;
font-family: Fira Sans;
font-size: 1.4rem;
font-style: Italic;
color: #ffffff;
text-align: center;
word-wrap: break-word;
border-radius: 55px;
transition: opacity 0.7s cubic-bezier(0.25, 0, 0, 1.0);
}
#settings-banner-message[data-display="visible"] {
display: table;
}

View file

@ -0,0 +1,218 @@
.smart-list {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index : 310;
display : none;
background-color: rgba(0, 0, 0, 0.75);
}
.smart-list.show {
display: block;
}
.smart-list-container {
width: 149rem;
margin: 0px auto;
margin-top: 7rem;
pointer-events : none;
}
.smart-list-title {
width: 132rem;
height: 5rem;
margin: 0 auto;
font-family: Fira Sans;
font-size: 4.2rem;
font-style: italic;
font-weight: normal;
color: #FFF;
}
.smart-list-wrap {
position: relative;
height: 90rem;
margin-top: 6rem;
overflow: hidden;
}
.smart-list-view {
position: relative;
width: 132rem;
height: 100%;
margin: 0 auto;
}
.smart-list-view .list-item {
display: flex;
position: absolute;
height: 12rem;
border-bottom: 0.1rem solid rgba(255, 255, 255, 0.3);
pointer-events: auto;
transform: translateY(-12rem);
}
.smart-list-view .list-item:focus {
background-color: rgba(255,255,255,0.2);
}
.smart-list-view .list-item .icon-box {
display: inline-flex;
align-items: center;
}
.smart-list-view .list-item .icon-box-left {
width: 12rem;
height: 100%;
padding: 2rem;
}
.smart-list-view .list-item .text-box {
display: inline-flex;
width: 108rem;
height: 100%;
padding-top: 1.5rem;
padding-bottom: 1.5rem;
font-family: Fira Sans;
}
.smart-list-view .list-item .text-box .title {
display: inline-block;
width: 100%;
font-size: 4rem;
color: #fff;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.smart-list-view .list-item .icon-box-right {
width: 12rem;
height: 100%;
}
.smart-list-view .list-item .icon-box-right .icon:before {
font-size: 12rem;
line-height: 12rem;
color: #fff;
opacity: 0.5;
}
.smart-list-view .list-item[data-type="folder"] .icon-box-left {
padding: 0;
}
.smart-list-view .list-item[data-type="folder"] .icon-box-left .icon {
color: #57d1ef;
}
.smart-list-view .list-item[data-type="folder"] .icon-box-left .icon:before {
font-size: 12rem;
line-height: 12rem;
}
.smart-list-view .list-item[data-type="folder"] .text-box {
align-items: center;
}
.smart-list-view .list-item[data-type="folder"] .uri {
display: none;
}
.smart-list-view .list-item[data-type="bookmark"] .icon-box-left .icon {
width: 100%;
height: 100%;
background-color: #858585;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
background-size: 3rem 3rem;
}
.smart-list-view .list-item[data-type="bookmark"] .icon-box-left .icon:before {
font-size: 8rem;
line-height: 8rem;
}
.smart-list-view .list-item[data-type="bookmark"] .text-box {
width: 120rem;
flex-direction: column;
}
.smart-list-view .list-item[data-type="bookmark"] .title {
height: 55%;
}
.smart-list-view .list-item[data-type="bookmark"] .uri {
display: inline-block;
width: 100%;
height: 45%;
font-size: 3rem;
color: #9A9A9A;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.smart-list-view .list-item[data-type="bookmark"] .icon-box-right {
display: none;
}
.smart-list-view .list-item[data-type="button"] .icon-box-left {
padding: 0;
}
.smart-list-view .list-item[data-type="button"] .icon-box-left .icon {
color: #fff;
opacity: 0.5;
}
.smart-list-view .list-item[data-type="button"] .icon-box-left .icon:before {
font-size: 12rem;
line-height: 12rem;
}
.smart-list-view .list-item[data-type="button"] .text-box {
width: 120rem;
align-items: center;
}
.smart-list-view .list-item[data-type="button"] .uri {
display: none;
}
.smart-list-view .list-item[data-type="button"] .icon-box-right {
display: none;
}
.smart-list-mask {
position: absolute;
right: 0;
left: 0;
bottom: 0;
width: 132rem;
height: 6rem;
margin: 0 auto;
background: transparent linear-gradient(to bottom, transparent, rgb(64, 65, 65)) repeat scroll 0% 0%;
}
.smart-list-pointer {
position: fixed;
top: 0;
left: 0;
display: none;
width: 6.4rem;
height: 6.4rem;
z-index: 550;
background: url('./images/img_cursor_arrow2x.png') no-repeat center;
background-size: cover;
transform: translate(0, 0);
transition: transform 0.42s cubic-bezier(0.25, 0, 0, 1.0);
}
.smart-list-pointer.show {
display: block;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,41 @@
#tooltip-block {
display: none;
position: absolute;
top: 0px;
left: 0px;
max-width: 80rem;
height: auto;
background-color: #000000;
/*opacity: 0.7;*/
background: rgba(0, 0, 0, 0.7);
word-wrap: break-word;
border-radius: 55px;
/*word-break: break-all;*/
z-index: 305;
padding-left: 44px;
padding-right: 44px;
padding-top: 20px;
padding-bottom: 20px;
font-family: Fira Sans;
font-size: 2.8rem;
font-style: Italic;
color: #ffffff;
}
#tooltip-block.visible {
display: block;
}
#tooltip-block {
-moz-transition-property: opacity;
-moz-transition-duration: 0.3s;
-moz-transition-timing-function: ease;
-moz-transition-delay: 0s;
transition-property: opacity;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;
}

View file

@ -0,0 +1,17 @@
{
"extends": "../../../../.jshintrc",
"predef": [
"assert",
"suite",
"test",
"setup",
"teardown",
"suiteSetup",
"suiteTeardown",
"require",
"requireApp",
"sinon",
"mocha",
"loadBodyHTML"
]
}

View file

@ -0,0 +1,834 @@
'use strict';
/* global BrowserDB, NumberHelper, MockNavigatorSettings */
/* jshint latedef:false */
requireApp('browser/shared/test/unit/mocks/' +
'mock_navigator_moz_set_message_handler.js');
// Stub of Browser object.
var Browser = {
_doNotCustomize: true,
_hasSV: false,
getDefaultData: function getDefaultData(callback) {
var data = {
'topSites': [
{
'title': 'Mozilla',
'uri': 'http://mozilla.org'
},
{
'title': 'Firefox OS',
'uri': 'http://mozilla.org/firefoxos'
}
]
};
// Imitate real getConfigurationData function by creating JSON from our
// object and parsing it before returning it.
var json = JSON.stringify(data);
// Select the data from the object.
var parsed = JSON.parse(json);
// Done, notify callback.
callback(parsed);
},
getConfigurationData: function browser_getDefaultData(variant, callback) {
// For all other tests in the suite, we do _not_ want any customizations.
// We use this handy boolean to skip this step.
if (this._doNotCustomize) {
callback({});
return;
}
var mccCode = NumberHelper.zfill(variant.mcc, 3);
var mncCode = NumberHelper.zfill(variant.mnc, 3);
// Customization test data.
var dataNoSV = {
'000000': {
bookmarks: [
{
title: 'customize test 1',
uri: 'http://customize.test.mozilla.org/1'
},
{
title: 'customize test 2',
uri: 'http://customize.test.mozilla.org/2'
}
],
searchEngines: [
{
title: 'customize search test 1',
uri: 'http://customize.test.mozilla.org/search/1',
iconUri: DATA_URI
}
],
settings: {
defaultSearchEngine: 'http://customize.test.mozilla.org/search/1'
}
}
};
var dataSV = {
'000000': {
bookmarks: [
{
title: 'customize test 1',
uri: 'http://customize.test.mozilla.org/1'
},
{
title: 'customize test 2',
uri: 'http://customize.test.mozilla.org/2'
}
],
searchEngines: [
{
title: 'customize search test 1',
uri: 'http://customize.test.mozilla.org/search/1',
iconUri: DATA_URI
}
],
settings: {
defaultSearchEngine: 'http://customize.test.mozilla.org/search/1'
}
},
'214007': {
bookmarks: [
{
title: 'customize SV test 1',
uri: 'http://customize.sv.test.mozilla.org/1'
},
{
title: 'customize SV test 2',
uri: 'http://customize.sv.test.mozilla.org/2'
}
],
searchEngines: [
{
title: 'customize SV search test 1',
uri: 'http://customize.sv.test.mozilla.org/search/1',
iconUri: DATA_URI
}
],
settings: {
defaultSearchEngine: 'http://customize.sv.test.mozilla.org/search/1'
}
}
};
// Imitate real getConfigurationData function by creating JSON from our
// object and parsing it before returning it.
var json =
this._hasSV ? JSON.stringify(dataSV) : JSON.stringify(dataNoSV);
// Select the data from the object.
var parsed = JSON.parse(json);
if (mccCode === '000' && mncCode === '000' && this._hasSV) {
BrowserDB.waitFirstRunWithSim();
return;
}
// Done, notify callback.
callback(parsed[mccCode + mncCode]);
return;
},
setSearchProvider: function browser_setSearchProvider(uri, title, iconUri) {
return;
}
};
requireApp('browser/shared/test/unit/mocks/mock_navigator_moz_settings.js');
requireApp('browser/shared/js/utilities.js');
requireApp('browser/js/browser_db.js');
/* jshint maxlen:false */
const DATA_URI =
'data:image/x-icon;base64,AAABAAIAEBAAAAEACABoBQAAJgAAABAQAAABACAAaAQAAI4FAAAoAAAAEAAAACAAAAABAAgAAAAAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAICNgB6Pg4AajoaAHo6FgBuRioAAhJqADJCdgBmVkIAbm5eAIJCEgCGRhYAikoSAIpKFgCGShoAllYaAJJWHgCeWhoAnl4eAJJaKgCSXi4AnmYmAJZiLgCmZiIApmomALJ2LgDKjjoA1po+ANqaOgC+ikoA0qJWANquVgDeslIA5q5OAO66UgDmvl4A6sp2AOrKfgAGJooAAiaeAAIymgACHqIAAi6iAAYupgACOqYADjqmAAIyqgAGMqoABjauAAIutgACPrIACj62AAJCqgAGSq4AGlKmAAJCsgACRrIAAkq2AApOtgACQroABkK+AApKvgAOUrIAAla6AAZSvgAKWr4AFlayABZetgAiTqoARnKCAEJqpgAGRsIACkrCAAZKygAKSs4AElbOABZaygAKUtIAClbWAApa0gAOXtYADl7aABZe2gAGZs4ACmbOAA5i1gAObtYADmraAA5q3gASYtoAGm7eAAZy1gAKctoADnLiABZ24gAacuIAEnriABJ65gAaeuIAEnrqABZ+6gAqcuIAcpKGACaGwgAGiuoAFobmABqC5gASguoAEobuABaK6gASjvIAIorqACKS7gA2nuYAHqLmABqi6gAWpvoAGq76ADKq4gA6uvIARqLSAEKu4gBOrvIAdqbuADLC7gAuxv4APtb+AGbCzgBWxuYAUsruAFrW9gDmyoYA7tKKAPbengAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAJiYmJiYmAAAAAAAAAAAmJig3Nzc3NCYmAAAAAAAsMjJHTU1PT09ANSgAAAAyLDxXYWFhYV1XXVxAOgAAMjxha15aLTY+VGtpUzoAPDxVa2RZSDAnBAdndGg6OTw9a2tJSktRTCcLA3J1Wzk8VmthMTACDERGDgxFfXM5PGluMyknJwsRERAQCH58OTxtcGFxcXoqHBoZFwWBdzk8aXBrX2V7JyIhGxgJgHZBPGJwb2JkUlIGIyAVZoJDAABSa3BqaycnASQfFn95QwAAUmtSUmsqhIQlHhR4QgAAAFJSFBRSMIWFgx0UFAAAAABSAAAAFBQUFBQUAAAAAAD4HwAA4AcAAMADAACAAQAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAACAAQAAgAMAAIAHAAC4HwAAKAAAABAAAAAgAAAAAQAgAAAAAABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAAC0AAABSAQMlhQIGRLMDCVTHAwlVyAIGQbIBAyOKAAAAVQAAAC0AAAAWAAAAAAAAAAAAAAAAAAAAAAAAAEcBAyOKAR186AIym/kBQLD/AEay/wBGs/8CRbL/BESr+wUniPACBCaaAAAASgAAAAAAAAAAAAAAAAAAAAAAJV1eATKS6gM/s/8HRcL/ClPT/wtV1P8MWtP/DV7V/whb0v8HUr7/B0ms9wEkVnIAAAAAAAAAAAAAAAAAQ6o3ATqk6QdCvP8Pa9r/EXrn/xF45/8TeuL/EXvm/w9z4f8Oa93/DXDi/wty2P8DV7v3A0OPXQAAAAAAR7IKAT2yzwhBvP8QeOT/E4Dq/xZ34/8bb9z/DDin/xlQp/8OUbH/CWfP/xCH7/8Uh+b/B2TN/xBZuPElbMgYAUC0WgI3sPYNYdT/E4ft/xR96P8TYtn/CErD/wU2r/8CJp3/ejkV/zFBdv8nhsP/F6X6/weJ6v8IT7f/F1K4ggFAuK8JSL//E4ft/xOH7f8HSsr/CEvN/xBVzv8MXdn/FVvL/wImnf+GRxX/azka/x6i5/8Yrvj/BnLW/wBKtscBR7byD2zX/xOH7f8ReOH/ASy2/wIzqv96PA//ikoT/yNPqv9DaqX/h0sY/4pLFf9HcoD/Lcb//xmh6f8CTrb0AEez/hSH6P8SjvL/CDy1/wMfof8CJp3/Aiad/4FCEf+cWxr/n18e/5JXH/+VVBn/ZVZB/z/X//8wwO//AUiy/gU+r/cUiej/I5Dv/xR65f83nOX/N5zl/02s8v8CLaL/2ps7/8qPOv+wdS7/p2Yh/29GKv9Rye//Obvx/wVOtfoHM6jpF4fo/yOQ7/8Tgev/GXHi/yly4v93p+7/Aiad/+y4UP/kr0//1pg9/6RoJP9tb13/VMfm/zGq4/8IWLzSBiKczxl64f0jkO//IYrr/xp54/8Seuj/FF/a/xRf2v8CEmn/571e/9+yUP+fZCb/c5OH/1jW9f8ed8j/EWXAkQUUkZwXbtz/EoHr/yOQ7/8Yg+b/EoHr/wImnf8CJp3/AgM3/+vKdf/ar1X/l2Es/2TAz/9BruH/FVy38BZyxxgCB4dcFF/a/xKB6/8UX9r/FF/a/xKB6/8ELaX/8NSJ/+/Tiv/qy3//0qJU/5JdLP9FoNP/Flex9xNkwVYAAAAAAAAAABRf2v8UX9r/X0FThXZQRt0UX9r/BzOr//Tfnv/0357/5suG/7yJSf+hYyX/UkJZuQhPtzsAAAAAAAAAAAAAAAAUX9qsFF/aMwAAAACZZjM0Z0ZPmVtSaNeZZjPtmWYz7ZVhL82QWyuukForXQAAAAAAAAAAAAAAAAAAAADAAwAAwAMAAMADAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIADAACQDwAA';
/* jshint maxlen:80 */
var clearBrowserStores = function(done) {
BrowserDB.db.open(function() {
BrowserDB.db.clearPlaces(function() {
BrowserDB.db.clearVisits(function() {
BrowserDB.db.clearIcons(function() {
BrowserDB.db.clearBookmarks(function() {
BrowserDB.db.clearSearchEngines(function() {
BrowserDB.db.clearSettings(function() {
done();
});
});
});
});
});
});
});
};
suite('BrowserDB', function() {
var realMozSettings = null;
const MSG_NAME = 'first-run-with-sim';
var message = { mcc: '214', mnc: '007' };
suiteSetup(function() {
realMozSettings = navigator.mozSettings;
navigator.mozSettings = MockNavigatorSettings;
});
suiteTeardown(function() {
navigator.mozSettings = realMozSettings;
});
// XXX: Disable this test since TV doesn't have operator customizations.
// Enable and modify this test once customization is implemented.
// suite('BrowserDB.operatorVariantCustomization WITH SV configuration',
// function() {
// var realSetMessageHandler = null;
// suiteSetup(function() {
// realSetMessageHandler = window.navigator.mozSetMessageHandler;
// window.navigator.mozSetMessageHandler =
// window.MockNavigatormozSetMessageHandler;
// });
// suiteTeardown(function() {
// window.navigator.mozSetMessageHandler = realSetMessageHandler;
// });
// setup(function(done) {
// this.sinon.useFakeTimers();
// navigator.mozSetMessageHandler.mSetup();
// navigator.mozSettings.createLock()
// .set({'operatorResources.data.topsites': {
// 'topSites': [
// {
// 'title': 'Topsite',
// 'uri': 'http://customize.test.mozilla.org/topsite'
// }
// ]}});
// // For these series of tests, we *do* want customizations to run.
// Browser._doNotCustomize = false;
// Browser._hasSV = true;
// // And we want to manually initialize the DB.
// BrowserDB.init(function() {
// var itemsToAdd = 3;
// BrowserDB.populate(0, function() {
// if (--itemsToAdd <= 0) {
// done();
// }
// });
// window.navigator.mozSetMessageHandler.mTrigger(MSG_NAME, message);
// });
// });
// teardown(function(done) {
// Browser._doNotCustomize = true;
// Browser._hasSV = false;
// clearBrowserStores(done);
// window.navigator.mozSetMessageHandler.mTeardown();
// });
// test('Operator Variant Customization -- Bookmarks with SV configuration',
// function(done) {
// BrowserDB.db.getAllBookmarks(function(bookmarks) {
// assert.equal(bookmarks.length, 2);
// // We can't yet guarantee order of bookmarks (bug 895807)
// if (bookmarks[0].uri == 'http://customize.sv.test.mozilla.org/2') {
// assert.equal(bookmarks[0].uri,
// 'http://customize.sv.test.mozilla.org/2');
// assert.equal(bookmarks[0].title, 'customize SV test 2');
// assert.equal(bookmarks[1].uri,
// 'http://customize.sv.test.mozilla.org/1');
// assert.equal(bookmarks[1].title, 'customize SV test 1');
// } else {
// assert.equal(bookmarks[1].uri,
// 'http://customize.sv.test.mozilla.org/2');
// assert.equal(bookmarks[1].title, 'customize SV test 2');
// assert.equal(bookmarks[0].uri,
// 'http://customize.sv.test.mozilla.org/1');
// assert.equal(bookmarks[0].title, 'customize SV test 1');
// }
// done();
// });
// });
// });
// XXX: Disable this test since TV doesn't have operator customizations.
// Enable and modify this test once customization is implemented.
// suite('BrowserDB.operatorVariantCustomization', function() {
// setup(function(done) {
// navigator.mozSettings.createLock()
// .set({'operatorResources.data.topsites': {
// 'topSites': [
// {
// 'title': 'Topsite',
// 'uri': 'http://customize.test.mozilla.org/topsite'
// }
// ]}});
// // For these series of tests, we *do* want customizations to run.
// Browser._doNotCustomize = false;
// // And we want to manually initialize the DB.
// BrowserDB.init(function() {
// var itemsToAdd = 3;
// BrowserDB.populate(0, function() {
// if (--itemsToAdd <= 0) {
// done();
// }
// });
// });
// });
// teardown(function(done) {
// Browser._doNotCustomize = true;
// Browser._hasSV = false;
// clearBrowserStores(done);
// });
// test('Operator Variant Customization -- Bookmarks without SV configuration',
// function(done) {
// BrowserDB.db.getAllBookmarks(function(bookmarks) {
// assert.equal(bookmarks.length, 2);
// // We can't yet guarantee order of bookmarks (bug 895807)
// if (bookmarks[0].uri == 'http://customize.test.mozilla.org/2') {
// assert.equal(bookmarks[0].uri, 'http://customize.test.mozilla.org/2');
// assert.equal(bookmarks[0].title, 'customize test 2');
// assert.equal(bookmarks[1].uri, 'http://customize.test.mozilla.org/1');
// assert.equal(bookmarks[1].title, 'customize test 1');
// } else {
// assert.equal(bookmarks[1].uri, 'http://customize.test.mozilla.org/2');
// assert.equal(bookmarks[1].title, 'customize test 2');
// assert.equal(bookmarks[0].uri, 'http://customize.test.mozilla.org/1');
// assert.equal(bookmarks[0].title, 'customize test 1');
// }
// done();
// });
// });
// test('Operator Variant Customization -- Search Engines', function(done) {
// BrowserDB.getSearchEngine(
// 'http://customize.test.mozilla.org/search/1',
// function(searchEngine) {
// assert.equal(searchEngine.uri,
// 'http://customize.test.mozilla.org/search/1');
// assert.equal(searchEngine.title,
// 'customize search test 1');
// done();
// }
// );
// });
// test('Operator Variant Customization -- Top sites', function(done) {
// BrowserDB.getTopSites(20, null, function(places) {
// assert.equal(places.length, 3);
// assert.equal(places[0].uri,
// 'http://customize.test.mozilla.org/topsite');
// assert.equal(places[0].title, 'Topsite');
// assert.equal(places[1].uri, 'http://mozilla.org');
// assert.equal(places[1].title, 'Mozilla');
// assert.equal(places[2].uri, 'http://mozilla.org/firefoxos');
// assert.equal(places[2].title, 'Firefox OS');
// done();
// });
// });
// });
suite('BrowserDB.db', function() {
setup(function(done) {
clearBrowserStores(done);
});
teardown(function(done) {
clearBrowserStores(done);
});
test('createPlace', function(done) {
BrowserDB.db.createPlace('http://mozilla.org/test1', function() {
done();
});
});
test('getPlace', function(done) {
BrowserDB.db.createPlace('http://mozilla.org/test2', function() {
BrowserDB.db.getPlace('http://mozilla.org/test2', function(place) {
done(function() {
assert.equal(place.title, 'http://mozilla.org/test2');
});
});
});
});
test('getPlace - not found', function(done) {
BrowserDB.db.getPlace('http://mozilla.org/doesnotexist',
function(place) {
done(function() {
assert.equal(place, undefined);
});
});
});
test('saveBookmark', function(done) {
var bookmark = {
uri: 'http://mozilla.org/test1',
title: 'Mozilla',
timestamp: new Date().valueOf()
};
BrowserDB.db.saveBookmark(bookmark, function() {
done();
});
});
// TODO: SHOULD FAIL
test('saveBookmarkInvalidURI', function(done) {
var bookmark = {
uri: 'notAURI',
title: 'Mozilla',
timestamp: new Date().valueOf()
};
BrowserDB.db.saveBookmark(bookmark, function() {
done();
});
});
// TODO: SHOULD FAIL
test('saveBookmarkInvalidTitle', function(done) {
var bookmark = {
uri: 'http://mozilla.org/test1',
title: '',
timestamp: new Date().valueOf()
};
BrowserDB.db.saveBookmark(bookmark, function() {
done();
});
});
test('saveBookmarkNonHTTP(S)', function(done) {
var bookmark = {
uri: 'rtsp://mozilla.org/test1',
title: '',
timestamp: new Date().valueOf()
};
BrowserDB.db.saveBookmark(bookmark, function() {
done();
});
});
test('getBookmark', function(done) {
var bookmark = {
uri: 'http://mozilla.org/test2',
title: 'Mozilla'
};
BrowserDB.db.saveBookmark(bookmark, function() {
BrowserDB.db.getBookmark('http://mozilla.org/test2',
function(bookmark) {
done(function() {
assert.equal(bookmark.title, 'Mozilla');
});
});
});
});
test('getBookmark - not found', function(done) {
BrowserDB.db.getBookmark('http://mozilla.org/doesnotexist',
function(bookmark) {
done(function() {
assert.equal(bookmark, undefined);
});
});
});
test('deleteBookmark', function(done) {
var bookmark = {
uri: 'http://mozilla.org/test3',
title: 'Mozilla'
};
BrowserDB.db.saveBookmark(bookmark, function() {
BrowserDB.db.deleteBookmark('http://mozilla.org/test3',
function() {
BrowserDB.db.getBookmark('http://mozilla.org/test3',
function(bookmark) {
done(function(bookmark) {
assert.equal(bookmark, undefined);
});
});
});
});
});
// XXX: updatePlace has been changed to visitMaxCheck. Redesign this test
// later.
// test('updatePlace', function(done) {
// var place = {
// uri: 'http://mozilla.org/test3',
// title: 'Mozilla'
// };
// BrowserDB.db.updatePlace(place, function() {
// place.title = 'Mozilla3';
// BrowserDB.db.updatePlace(place, function() {
// BrowserDB.db.getPlace('http://mozilla.org/test3',
// function(place) {
// done(function() {
// assert.equal(place.title, 'Mozilla3');
// });
// });
// });
// });
// });
test('updatePlaceScreenshot', function(done) {
var uri = 'http://mozilla.org/test4';
BrowserDB.db.updatePlaceScreenshot(uri, DATA_URI, function() {
BrowserDB.db.getPlace(uri, function(place) {
done(function() {
assert.equal(place.screenshot, DATA_URI);
});
});
});
});
// XXX: updatePlace has been changed to visitMaxCheck. Redesign this test
// later.
// test('getPlacesByFrecency', function(done) {
// var place1 = {
// uri: 'http://mozilla.org/test1',
// frecency: 3
// };
// var place2 = {
// uri: 'http://mozilla.org/test2',
// frecency: 2
// };
// var place3 = {
// uri: 'http://mozilla.org/test3',
// frecency: 1
// };
// BrowserDB.db.updatePlace(place1, function() {
// BrowserDB.db.updatePlace(place2, function() {
// BrowserDB.db.updatePlace(place3, function() {
// BrowserDB.db.getPlacesByFrecency(2, null, function(topSites) {
// done(function() {
// assert.equal(2, topSites.length);
// assert.equal(topSites[0].uri, 'http://mozilla.org/test1');
// });
// });
// });
// });
// });
// });
test('saveIcon', function(done) {
// Let's just use content-type text, a blob is a blob.
var blob = new Blob(['hello', ' world'], {type: 'text/plain'});
var iconEntry = {
uri: 'http://mozilla.org/favicon.ico',
data: blob,
expiration: new Date().valueOf()
};
BrowserDB.db.saveIcon(iconEntry, function() {
done();
});
});
// XXX: Error: TypeError: callback is not a function
// Fix this.
// test('getIcon', function(done) {
// // Let's just use content-type text, a blob is a blob.
// var blob = new Blob(['hello', ' world'], {type: 'text/plain'});
// var iconEntry = {
// uri: 'http://mozilla.org/favicon.ico',
// data: blob,
// expiration: new Date().valueOf()
// };
// BrowserDB.db.saveIcon(iconEntry, function() {
// BrowserDB.db.getIcon('http://mozilla.org/favicon.ico', function() {
// done();
// });
// });
// });
test('saveIcon', function(done) {
// Let's just use text, a blob is a blob.
var blob = new Blob(['hello', ' world'], {type: 'text/plain'});
var iconEntry = {
uri: 'http://mozilla.org/favicon.ico',
data: blob,
expiration: new Date().valueOf()
};
BrowserDB.db.saveIcon(iconEntry, function() {
done();
});
});
// XXX: Test failed on Treeherder with reason unknown.
// test('getAllBookmarks', function(done) {
// BrowserDB.addBookmark('http://mozilla.org/test1', 'Mozilla', function() {
// BrowserDB.addBookmark('http://mozilla.org/test2', 'Mozilla',
// function() {
// BrowserDB.db.getAllBookmarks(function(bookmarks) {
// done(function() {
// assert.equal(bookmarks.length, 2);
// });
// });
// });
// });
// });
// XXX: Test failed on Treeherder with reason unknown.
// test('getAllBookmarkUris', function(done) {
// BrowserDB.addBookmark('http://mozilla.org/test1', 'Mozilla', function() {
// BrowserDB.addBookmark('http://mozilla.org/test2', 'Mozilla',
// function() {
// BrowserDB.db.getAllBookmarkUris(function(uris) {
// done(function() {
// assert.equal(uris.length, 2);
// });
// });
// });
// });
// });
// XXX: Error: expected null to equal 0
// Fix this.
// test('resetPlaceFrecency', function(done) {
// BrowserDB.addPlace('http://mozilla.org/test8', function() {
// BrowserDB.updateFrecency('http://mozilla.org/test8', function() {
// BrowserDB.db.resetPlaceFrecency('http://mozilla.org/test8',
// function() {
// BrowserDB.db.getPlace('http://mozilla.org/test8', function(place) {
// done(function() {
// assert.equal(null, place.frecency);
// });
// });
// });
// });
// });
// });
test('saveSearchEngine', function(done) {
var search_engine = {
uri: 'http://google.com/',
title: 'Google',
iconUri: DATA_URI
};
BrowserDB.db.saveSearchEngine(search_engine, function() {
done();
});
});
test('getSearchEngine', function(done) {
var search_engine = {
uri: 'http://google.com/',
title: 'Google',
iconUri: DATA_URI
};
BrowserDB.db.saveSearchEngine(search_engine, function() {
BrowserDB.db.getSearchEngine('http://google.com/',
function(search_engine) {
done(function() {
assert.equal(search_engine.title, 'Google');
assert.equal(search_engine.iconUri, DATA_URI);
});
});
});
});
test('getAllSearchEngines', function(done) {
var search_engine1 = {
uri: 'http://google.com/search',
title: 'Google',
iconUri: DATA_URI
};
var search_engine2 = {
uri: 'http://yahoo.com/search',
title: 'Yahoo',
iconUri: DATA_URI
};
BrowserDB.db.saveSearchEngine(search_engine1, function() {
BrowserDB.db.saveSearchEngine(search_engine2, function() {
BrowserDB.db.getAllSearchEngines(function(engines) {
done(function() {
assert.equal(engines.length, 2);
});
});
});
});
});
});
suite('BrowserDB', function() {
setup(function(done) {
clearBrowserStores(done);
});
teardown(function(done) {
clearBrowserStores(done);
});
// XXX: Test failed on Treeherder with reason unknown.
// test('addPlace', function(done) {
// BrowserDB.addPlace('http://mozilla.org/test4', function() {
// done();
// });
// });
// XXX: Error: timeout of 10000ms exceeded
// Fix this.
// test('setPageTitle', function(done) {
// BrowserDB.addPlace('http://mozilla.org/test5', function() {
// BrowserDB.setPageTitle('http://mozilla.org/test5',
// 'Mozilla5', function() {
// BrowserDB.db.getPlace('http://mozilla.org/test5',
// function(place) {
// done(function() {
// assert.equal(place.title, 'Mozilla5');
// });
// });
// });
// });
// });
// XXX: Error: TypeError: callback is not a function
// Fix this.
// test('setAndLoadIconForPage', function(done) {
// BrowserDB.setAndLoadIconForPage('http://mozilla.org/test6',
// DATA_URI, function() {
// BrowserDB.db.getIcon(DATA_URI, function(iconEntry) {
// done(function() {
// assert.equal(true, iconEntry.expiration > new Date().valueOf());
// var twoDaysAway = new Date().valueOf() + 172800000;
// assert.equal(true, iconEntry.expiration < twoDaysAway);
// assert.equal(2550, iconEntry.data.size);
// assert.equal('image/x-icon', iconEntry.data.type);
// });
// });
// });
// });
// XXX: Error: timeout of 10000ms exceeded
// Fix this.
// test('addVisit', function(done) {
// BrowserDB.addVisit('http://mozilla.org/test8', function() {
// done();
// });
// });
// XXX: Error: timeout of 10000ms exceeded
// Fix this.
// test('addVisit - existing place', function(done) {
// BrowserDB.addPlace('http://mozilla.org/test9', function() {
// BrowserDB.addVisit('http://mozilla.org/test9', function() {
// done();
// });
// });
// });
// XXX: Test failed on Treeherder with reason unknown.
// test('addBookmark', function(done) {
// BrowserDB.addBookmark('http://mozilla.org/test7', 'Test 7', function() {
// BrowserDB.getBookmark('http://mozilla.org/test7', function(bookmark) {
// done(function() {
// assert.equal(bookmark.title, 'Test 7');
// assert.equal(true, bookmark.timestamp > 0);
// var now = new Date().valueOf();
// assert.equal(true, bookmark.timestamp <= now);
// });
// });
// });
// });
// XXX: Test failed on Treeherder with reason unknown.
// test('updateBookmark', function(done) {
// BrowserDB.addBookmark('http://mozilla.org/test7', 'Test 7', function() {
// BrowserDB.updateBookmark('http://mozilla.org/test7', 'Test 8',
// function() {
// BrowserDB.getBookmark('http://mozilla.org/test7', function(bookmark) {
// done(function() {
// assert.equal(bookmark.title, 'Test 8');
// });
// });
// });
// });
// });
// XXX: Test failed on Treeherder with reason unknown.
// test('updateBookmark - not found', function(done) {
// BrowserDB.updateBookmark('http://mozilla.org/test7', 'Test 7',
// function() {
// BrowserDB.getBookmark('http://mozilla.org/test7', function(bookmark) {
// done(function() {
// assert.equal(bookmark.title, 'Test 7');
// assert.equal(true, bookmark.timestamp > 0);
// var now = new Date().valueOf();
// assert.equal(true, bookmark.timestamp <= now);
// });
// });
// });
// });
// XXX: Test failed on Treeherder with reason unknown.
// test('updateFrecency', function(done) {
// BrowserDB.addPlace('http://mozilla.org/test8', function() {
// BrowserDB.updateFrecency('http://mozilla.org/test8', function() {
// BrowserDB.updateFrecency('http://mozilla.org/test8', function() {
// BrowserDB.db.getPlace('http://mozilla.org/test8', function(place) {
// done(function() {
// assert.equal(2, place.frecency);
// });
// });
// });
// });
// });
// });
test('addSearchEngine', function(done) {
var data = {
uri: 'http://google.com/',
title: 'Google',
iconUri: DATA_URI
};
BrowserDB.addSearchEngine(data, function() {
BrowserDB.getSearchEngine('http://google.com/',
function(search_engine) {
done(function() {
assert.equal(search_engine.title, 'Google');
assert.equal(search_engine.uri, 'http://google.com/');
assert.equal(search_engine.iconUri, DATA_URI);
});
});
});
});
test('updateSetting', function(done) {
BrowserDB.updateSetting('test_value', 'test_key', function() {
BrowserDB.getSetting('test_key', function(setting) {
done(function() {
assert.equal(setting, 'test_value');
});
});
});
});
});
});

View file

@ -0,0 +1,127 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global BrowserDialog */
/* global expect */
/* global MocksHelper */
/* global MockL10n */
'use strict';
require('/shared/test/unit/load_body_html_helper.js');
require('/shared/test/unit/mocks/mock_l10n.js');
requireApp('browser/js/browser_dialog.js');
requireApp('browser/test/unit/mocks/mock_browser.js');
requireApp('browser/test/unit/mocks/mock_awesomescreen.js');
var mocksForBrowserDialog = new MocksHelper([
'Awesomescreen',
'Browser'
]).init();
suite('Browser Dialog >', function() {
var subject;
var realL10n;
mocksForBrowserDialog.attachTestHelpers();
suiteSetup(function() {
realL10n = navigator.mozL10n;
navigator.mozL10n = MockL10n;
loadBodyHTML('fixtures/browser_dialog.html');
subject = BrowserDialog;
subject.init();
});
suiteTeardown(function() {
navigator.mozL10n = realL10n;
});
suite('Initial state', function() {
test('should init DOM elements', function() {
[
'browserDialogBase',
'browserDialog',
'browserDialogTitle',
'browserDialogMsg',
'browserDialogInput',
'browserDialogInputArea',
'browserDialogInputClear',
'browserDialogButton',
'browserDialogButton1',
'browserDialogButton2'].forEach(element => {
expect(subject[element]).to.be.an('object');
});
});
test('should not have pending deferred actions', function() {
expect(subject.deferredActions.size).to.equals(0);
});
});
suite('Sign out dialog', function() {
var promise;
setup(function() {
this.sinon.stub(subject, 'cancelDialog');
});
test('signout_confirm dialog should add a deferred action',
function(done) {
promise = subject.createDialog('signout_confirm');
expect(subject.browserDialogTitle.getAttribute('data-l10n-id'))
.to.equals('fxsync-confirm-sign-out-title');
expect(subject.browserDialogMsg.getAttribute('data-l10n-id'))
.to.equals('fxsync-confirm-sign-out-message');
expect(subject.browserDialogButton1.getAttribute('data-l10n-id'))
.to.equals('LT_CANCEL');
expect(subject.browserDialogButton1.dataset.type)
.to.equals('signout_confirm');
expect(subject.browserDialogButton1.classList.contains('visible'))
.to.equals(true);
expect(subject.browserDialogButton2.getAttribute('data-l10n-id'))
.to.equals('fxsync-sign-out');
expect(subject.browserDialogButton2.dataset.type)
.to.equals('signout_confirm');
expect(subject.browserDialogButton2.classList.contains('visible'))
.to.equals(true);
expect(subject.deferredActions.size).to.equals(1);
done();
});
test('click on signout_confirm button 2 should resolve deferred action',
function(done) {
promise.then(() => {
expect(subject.deferredActions.size).to.equals(0);
done();
});
subject.dialogButton2({
preventDefault() {},
currentTarget: {
addEventListener() {},
removeEventListener() {}
}
});
});
test('click on signout_confirm button 1 should reject deferred action',
function(done) {
subject.createDialog('signout_confirm').catch(() => {
expect(subject.deferredActions.size).to.equals(0);
done();
});
subject.dialogButton1({
preventDefault() {},
currentTarget: {
addEventListener() {},
removeEventListener() {}
}
});
});
});
});

View file

@ -0,0 +1,20 @@
<div id="browser-dialog-base">
<div id="browser-dialog">
<div id="browser-dialog-title">
<p id="browser-dialog-title-text"></p>
</div>
<div id="browser-dialog-msg">
<p id="browser-dialog-msg-text"></p>
</div>
<form id="browser-dialog-input">
<input id="browser-dialog-input-area">
<div class="input-line"></div>
<div id="browser-dialog-input-clear"></div>
</form>
<div id="browser-dialog-margin"></div>
<div id="browser-dialog-button">
<button class="browser-dialog-button" id="browser-dialog-button2"></button>
<button class="browser-dialog-button" id="browser-dialog-button1"></button>
</div>
</div>
</div>

View file

@ -0,0 +1,16 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
(function(exports) {
var MockAwesomescreen = {
focusImgFunc() {}
};
exports.MockAwesomescreen = MockAwesomescreen;
}(window));

View file

@ -0,0 +1,21 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
(function(exports) {
var MockBrowser = {
sideBlock: {
dataset: {
sidebar: 'false'
}
},
switchCursorMode() {}
};
exports.MockBrowser = MockBrowser;
}(window));

View file

@ -0,0 +1,16 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
(function(exports) {
var MockSettings = {
show() {}
};
exports.MockSettings = MockSettings;
}(window));

View file

@ -0,0 +1,5 @@
'use strict';
/* global require */
require('/shared/test/unit/mocks/mocks_helper.js');

View file

@ -0,0 +1,482 @@
'use strict';
/* global SyncBrowserDB */
/* exported Browser */
/* jshint latedef:false */
requireApp('browser/shared/test/unit/mocks/' +
'mock_navigator_moz_set_message_handler.js');
/* jshint maxlen:false */
const DATA_URI =
'data:image/x-icon;base64,AAABAAIAEBAAAAEACABoBQAAJgAAABAQAAABACAAaAQAAI4FAAAoAAAAEAAAACAAAAABAAgAAAAAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAICNgB6Pg4AajoaAHo6FgBuRioAAhJqADJCdgBmVkIAbm5eAIJCEgCGRhYAikoSAIpKFgCGShoAllYaAJJWHgCeWhoAnl4eAJJaKgCSXi4AnmYmAJZiLgCmZiIApmomALJ2LgDKjjoA1po+ANqaOgC+ikoA0qJWANquVgDeslIA5q5OAO66UgDmvl4A6sp2AOrKfgAGJooAAiaeAAIymgACHqIAAi6iAAYupgACOqYADjqmAAIyqgAGMqoABjauAAIutgACPrIACj62AAJCqgAGSq4AGlKmAAJCsgACRrIAAkq2AApOtgACQroABkK+AApKvgAOUrIAAla6AAZSvgAKWr4AFlayABZetgAiTqoARnKCAEJqpgAGRsIACkrCAAZKygAKSs4AElbOABZaygAKUtIAClbWAApa0gAOXtYADl7aABZe2gAGZs4ACmbOAA5i1gAObtYADmraAA5q3gASYtoAGm7eAAZy1gAKctoADnLiABZ24gAacuIAEnriABJ65gAaeuIAEnrqABZ+6gAqcuIAcpKGACaGwgAGiuoAFobmABqC5gASguoAEobuABaK6gASjvIAIorqACKS7gA2nuYAHqLmABqi6gAWpvoAGq76ADKq4gA6uvIARqLSAEKu4gBOrvIAdqbuADLC7gAuxv4APtb+AGbCzgBWxuYAUsruAFrW9gDmyoYA7tKKAPbengAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAJiYmJiYmAAAAAAAAAAAmJig3Nzc3NCYmAAAAAAAsMjJHTU1PT09ANSgAAAAyLDxXYWFhYV1XXVxAOgAAMjxha15aLTY+VGtpUzoAPDxVa2RZSDAnBAdndGg6OTw9a2tJSktRTCcLA3J1Wzk8VmthMTACDERGDgxFfXM5PGluMyknJwsRERAQCH58OTxtcGFxcXoqHBoZFwWBdzk8aXBrX2V7JyIhGxgJgHZBPGJwb2JkUlIGIyAVZoJDAABSa3BqaycnASQfFn95QwAAUmtSUmsqhIQlHhR4QgAAAFJSFBRSMIWFgx0UFAAAAABSAAAAFBQUFBQUAAAAAAD4HwAA4AcAAMADAACAAQAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAACAAQAAgAMAAIAHAAC4HwAAKAAAABAAAAAgAAAAAQAgAAAAAABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAAC0AAABSAQMlhQIGRLMDCVTHAwlVyAIGQbIBAyOKAAAAVQAAAC0AAAAWAAAAAAAAAAAAAAAAAAAAAAAAAEcBAyOKAR186AIym/kBQLD/AEay/wBGs/8CRbL/BESr+wUniPACBCaaAAAASgAAAAAAAAAAAAAAAAAAAAAAJV1eATKS6gM/s/8HRcL/ClPT/wtV1P8MWtP/DV7V/whb0v8HUr7/B0ms9wEkVnIAAAAAAAAAAAAAAAAAQ6o3ATqk6QdCvP8Pa9r/EXrn/xF45/8TeuL/EXvm/w9z4f8Oa93/DXDi/wty2P8DV7v3A0OPXQAAAAAAR7IKAT2yzwhBvP8QeOT/E4Dq/xZ34/8bb9z/DDin/xlQp/8OUbH/CWfP/xCH7/8Uh+b/B2TN/xBZuPElbMgYAUC0WgI3sPYNYdT/E4ft/xR96P8TYtn/CErD/wU2r/8CJp3/ejkV/zFBdv8nhsP/F6X6/weJ6v8IT7f/F1K4ggFAuK8JSL//E4ft/xOH7f8HSsr/CEvN/xBVzv8MXdn/FVvL/wImnf+GRxX/azka/x6i5/8Yrvj/BnLW/wBKtscBR7byD2zX/xOH7f8ReOH/ASy2/wIzqv96PA//ikoT/yNPqv9DaqX/h0sY/4pLFf9HcoD/Lcb//xmh6f8CTrb0AEez/hSH6P8SjvL/CDy1/wMfof8CJp3/Aiad/4FCEf+cWxr/n18e/5JXH/+VVBn/ZVZB/z/X//8wwO//AUiy/gU+r/cUiej/I5Dv/xR65f83nOX/N5zl/02s8v8CLaL/2ps7/8qPOv+wdS7/p2Yh/29GKv9Rye//Obvx/wVOtfoHM6jpF4fo/yOQ7/8Tgev/GXHi/yly4v93p+7/Aiad/+y4UP/kr0//1pg9/6RoJP9tb13/VMfm/zGq4/8IWLzSBiKczxl64f0jkO//IYrr/xp54/8Seuj/FF/a/xRf2v8CEmn/571e/9+yUP+fZCb/c5OH/1jW9f8ed8j/EWXAkQUUkZwXbtz/EoHr/yOQ7/8Yg+b/EoHr/wImnf8CJp3/AgM3/+vKdf/ar1X/l2Es/2TAz/9BruH/FVy38BZyxxgCB4dcFF/a/xKB6/8UX9r/FF/a/xKB6/8ELaX/8NSJ/+/Tiv/qy3//0qJU/5JdLP9FoNP/Flex9xNkwVYAAAAAAAAAABRf2v8UX9r/X0FThXZQRt0UX9r/BzOr//Tfnv/0357/5suG/7yJSf+hYyX/UkJZuQhPtzsAAAAAAAAAAAAAAAAUX9qsFF/aMwAAAACZZjM0Z0ZPmVtSaNeZZjPtmWYz7ZVhL82QWyuukForXQAAAAAAAAAAAAAAAAAAAADAAwAAwAMAAMADAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIADAACQDwAA';
/* jshint maxlen:80 */
const DEFAULT_FAVICON = 'style/images/default-fav.svg';
requireApp('browser/js/sync/db.js');
var clearBrowserStores = function(done) {
SyncBrowserDB.db.open(function() {
Promise.all([
new Promise(SyncBrowserDB.db.clearPlaces),
new Promise(SyncBrowserDB.db.clearVisits),
new Promise(SyncBrowserDB.db.clearIcons),
new Promise(SyncBrowserDB.db.clearBookmarks)
]).then(() => {
done();
});
});
};
var bookmarkGenerator = (amount, done, parentid) => {
var list = [];
function item(i) {
return {
id: 'FXSYNCID_00' + i,
bmkUri: 'http://mozilla.org/test' + i,
title: 'Mozilla',
parentid: parentid ? parentid : 'FXS_P_ID_00' + i,
timestamp: Date.now()
};
}
var i = 0;
function wrapper() {
if (i < amount) {
var t = item(i);
list.push(t);
SyncBrowserDB.db.saveBookmark(t, wrapper);
i++;
} else {
done(list);
}
}
wrapper();
};
var historyGenerator = (amount, done, timeOffset) => {
var list = [];
function item(i) {
return {
fxsyncId: 'FXSYNCID_00' + i,
uri: 'http://mozilla.org/test' + i,
title: 'Mozilla',
timestamp: timeOffset + i * 10
};
}
var i = 0;
function wrapper() {
if (i < amount) {
var t = item(i);
list.push(t);
SyncBrowserDB.db.createRawHistory(t, wrapper);
i++;
} else {
done(list);
}
}
wrapper();
};
window.Awesomescreen = {
DEFAULT_FAVICON: DEFAULT_FAVICON
};
suite('SyncBrowserDB', function() {
suite('SyncBrowserDB.db', function() {
setup(function(done) {
clearBrowserStores(done);
});
teardown(function(done) {
clearBrowserStores(done);
});
test('createPlace & getPlace', function(done) {
const URL = 'http://mozilla.org/test1';
SyncBrowserDB.db.createPlace(URL, () => {
SyncBrowserDB.db.getPlace(URL, place => {
assert.equal(place.title, URL);
done();
});
});
});
test('createRawHistory & getHistory', function(done) {
var example = {
fxsyncId: 'FXSYNCID_001',
uri: 'http://mozilla.org/test1',
title: 'Mozilla',
timestamp: Date.now()
};
SyncBrowserDB.db.createRawHistory(example, () => {
SyncBrowserDB.db.getHistory(10, places => {
assert.equal(places.length, 1);
example.iconUri = DEFAULT_FAVICON;
assert.deepEqual(places[0], example);
done();
});
});
});
test('getPlace - not found', function(done) {
const NONEXIST_URL = 'http://mozilla.org/doesnotexist';
SyncBrowserDB.db.getPlace(NONEXIST_URL, place => {
assert.equal(place, undefined);
done();
});
});
test('saveBookmark && getBookmark', function(done) {
var example = {
id: 'FXSYNCID_001',
bmkUri: 'http://mozilla.org/test1',
title: 'Mozilla',
parentid: 'FXS_P_ID_001',
timestamp: Date.now()
};
SyncBrowserDB.db.saveBookmark(example, () => {
SyncBrowserDB.db.getBookmark(example.id, bookmark => {
assert.deepEqual(bookmark, example);
done();
});
});
});
test('saveBookmark && getBookmarkByUri', function(done) {
var example = {
id: 'FXSYNCID_002',
bmkUri: 'http://mozilla.org/test2',
title: 'Mozilla',
parentid: 'FXS_P_ID_002',
timestamp: Date.now()
};
SyncBrowserDB.db.saveBookmark(example, () => {
SyncBrowserDB.db.getBookmarkByUri(example.bmkUri, bookmark => {
assert.deepEqual(bookmark, example);
done();
});
});
});
test('getBookmarkByParentId', function(done) {
var example = {
id: 'FXSYNCID_001',
bmkUri: 'http://mozilla.org/test1',
title: 'Mozilla',
parentid: 'FXS_P_ID_001',
timestamp: Date.now()
};
SyncBrowserDB.db.saveBookmark(example, () => {
SyncBrowserDB.db.getBookmarkByParentId(example.parentid, bookmark => {
assert.equal(bookmark.length, 1);
assert.deepEqual(bookmark[0], example);
done();
});
});
});
test('getBookmarkByUri - not found', function(done) {
const NONEXIST_URL = 'http://mozilla.org/doesnotexist';
SyncBrowserDB.db.getBookmarkByUri(NONEXIST_URL, bookmark => {
assert.equal(bookmark, undefined);
done();
});
});
test('getAllBookmarks', function(done) {
const RECORD_SIZE = 10;
bookmarkGenerator(RECORD_SIZE, records => {
SyncBrowserDB.db.getAllBookmarks(bookmarks => {
assert.equal(bookmarks.length, RECORD_SIZE);
// Sort by timestamp, so we did a reversing comparison here.
for (var i = 0; i < RECORD_SIZE; i++) {
assert.deepEqual(bookmarks[i], records[RECORD_SIZE -1 -i]);
}
done();
});
});
});
test('getAllBookmarkUris', function(done) {
const RECORD_SIZE = 10;
bookmarkGenerator(RECORD_SIZE, records => {
SyncBrowserDB.db.getAllBookmarkUris(bookmarkUris => {
assert.equal(bookmarkUris.length, RECORD_SIZE);
// Sort by timestamp, so we did a reversing comparison here.
for (var i = 0; i < RECORD_SIZE; i++) {
assert.deepEqual(bookmarkUris[i],
records[RECORD_SIZE -1 -i].bmkUri);
}
done();
});
});
});
test('deleteBookmark', function(done) {
var example = {
id: 'FXSYNCID_003',
bmkUri: 'http://mozilla.org/test3',
title: 'Mozilla',
parentid: 'FXS_P_ID_003',
timestamp: Date.now()
};
SyncBrowserDB.db.saveBookmark(example, () => {
SyncBrowserDB.db.deleteBookmark('FXSYNCID_003', () => {
SyncBrowserDB.db.getBookmark('FXSYNCID_003', bookmark => {
assert.equal(bookmark, undefined);
done();
});
});
});
});
test('updatePlaceScreenshot', function(done) {
var uri = 'http://mozilla.org/test4';
SyncBrowserDB.db.updatePlaceScreenshot(uri, DATA_URI, () => {
SyncBrowserDB.db.getPlace(uri, place => {
assert.equal(place.screenshot, DATA_URI);
done();
});
});
});
test('saveIcon', function(done) {
var blob = new Blob(['hello', ' world'], {type: 'text/plain'});
var iconEntry = {
uri: 'http://mozilla.org/favicon.ico',
data: blob,
expiration: Date.now()
};
SyncBrowserDB.db.saveIcon(iconEntry, () => {
SyncBrowserDB.db.getIcon(iconEntry.uri, null, (e) => {
assert.deepEqual(e, iconEntry);
done();
});
});
});
});
suite('SyncBrowserDB', function() {
setup(function(done) {
clearBrowserStores(done);
});
teardown(function(done) {
clearBrowserStores(done);
});
test('updateRawBookmark & getBookmark by id', function(done) {
var example = {
id: 'FXSYNCID_003',
bmkUri: 'http://mozilla.org/test3',
title: 'Mozilla',
parentid: 'FXS_P_ID_003',
timestamp: Date.now()
};
SyncBrowserDB.updateRawBookmark(example, () => {
SyncBrowserDB.getBookmark(example.id, bookmark => {
assert.deepEqual(example, bookmark);
done();
});
});
});
test('updateRawBookmark & getBookmark by {id}', function(done) {
var example = {
id: 'FXSYNCID_003',
bmkUri: 'http://mozilla.org/test3',
title: 'Mozilla',
parentid: 'FXS_P_ID_003',
timestamp: Date.now()
};
SyncBrowserDB.updateRawBookmark(example, () => {
SyncBrowserDB.getBookmark({id: example.id}, bookmark => {
assert.deepEqual(example, bookmark);
done();
});
});
});
test('updateRawBookmark & getBookmark by {bmkUri}', function(done) {
var example = {
id: 'FXSYNCID_003',
bmkUri: 'http://mozilla.org/test3',
title: 'Mozilla',
parentid: 'FXS_P_ID_003',
timestamp: Date.now()
};
SyncBrowserDB.updateRawBookmark(example, () => {
SyncBrowserDB.getBookmark({bmkUri: example.bmkUri}, bookmark => {
assert.deepEqual(example, bookmark);
done();
});
});
});
test('updateRawBookmark & getBookmark by {parentid}', function(done) {
var example = {
id: 'FXSYNCID_003',
bmkUri: 'http://mozilla.org/test3',
title: 'Mozilla',
parentid: 'FXS_P_ID_003',
timestamp: Date.now()
};
SyncBrowserDB.updateRawBookmark(example, () => {
SyncBrowserDB.getBookmark({parentid: example.parentid}, bookmarks => {
assert.equal(bookmarks.length, 1);
assert.deepEqual(example, bookmarks[0]);
done();
});
});
});
test('getBookmark by {parentid}, sorted by children array', function(done) {
var example = {
id: 'FXS_P_ID_001',
type: 'folder',
title: 'Mozilla',
children: ['FXSYNCID_003', 'FXSYNCID_001',
'FXSYNCID_000', 'FXSYNCID_002'],
parentid: 'FXS_P_ID_000',
timestamp: Date.now()
};
SyncBrowserDB.updateRawBookmark(example, () => {
bookmarkGenerator(4, rawRecords => {
SyncBrowserDB.getBookmark({parentid: example.id}, bookmarks => {
assert.deepEqual(bookmarks[0], rawRecords[3]);
assert.deepEqual(bookmarks[1], rawRecords[1]);
assert.deepEqual(bookmarks[2], rawRecords[0]);
assert.deepEqual(bookmarks[3], rawRecords[2]);
done();
});
}, 'FXS_P_ID_001');
});
});
test('removeBookmark', function(done) {
var example = {
id: 'FXSYNCID_003',
bmkUri: 'http://mozilla.org/test3',
title: 'Mozilla',
parentid: 'FXS_P_ID_003',
timestamp: Date.now()
};
SyncBrowserDB.updateRawBookmark(example, () => {
SyncBrowserDB.removeBookmark(example.id, () => {
SyncBrowserDB.getBookmark(example.id, bookmark => {
assert.equal(bookmark, undefined);
done();
});
});
});
});
test('clearBookmarks', function(done) {
bookmarkGenerator(10, (rawRecords) => {
SyncBrowserDB.clearBookmarks().then(() => {
SyncBrowserDB.db.getAllBookmarks(bookmarks => {
assert.isArray(bookmarks);
assert.equal(bookmarks.length, 0);
done();
});
});
});
});
test('updateRawHistory & removeHistory', function(done) {
var example = {
fxsyncId: 'FXSYNCID_003',
uri: 'http://mozilla.org/test3',
title: 'Mozilla',
timestamp: Date.now()
};
SyncBrowserDB.updateRawHistory(example, () => {
SyncBrowserDB.removeHistory(example.uri, bookmark => {
assert.equal(bookmark, undefined);
done();
});
});
});
test('clearHistoryDeep', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.clearHistoryDeep().then(() => {
SyncBrowserDB.db.getHistory(10000, history => {
assert.isArray(history);
assert.equal(history.length, 0);
done();
});
});
}, 10000);
});
test('getHistoryByTime', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.getHistoryByTime(10075, 10085, false, false, history => {
assert.equal(history.length, 1);
rawRecords[8].iconUri = DEFAULT_FAVICON;
assert.deepEqual(history[0], rawRecords[8]);
done();
});
}, 10000);
});
test('getHistoryByTime with timestamp equal=true', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.getHistoryByTime(10070, 10080, true, true, history => {
assert.equal(history.length, 2);
rawRecords[7].iconUri = DEFAULT_FAVICON;
rawRecords[8].iconUri = DEFAULT_FAVICON;
assert.deepEqual(history[0], rawRecords[8]);
assert.deepEqual(history[1], rawRecords[7]);
done();
});
}, 10000);
});
test('getHistoryTimestamp with equal=true / dir=prev', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.getHistoryTimestamp(10070, 'prev', true, ts => {
assert.equal(ts, 10070);
done();
});
}, 10000);
});
test('getHistoryTimestamp with equal=false / dir=prev', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.getHistoryTimestamp(10070, 'prev', false, ts => {
assert.equal(ts, 10060);
done();
});
}, 10000);
});
test('getHistoryTimestamp with equal=true / dir=next', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.getHistoryTimestamp(10075, 'next', true, ts => {
assert.equal(ts, 10080);
done();
});
}, 10000);
});
test('getHistoryTimestamp with equal=false / dir=next', function(done) {
historyGenerator(10, (rawRecords) => {
SyncBrowserDB.getHistoryTimestamp(10075, 'next', false, ts => {
assert.equal(ts, 10080);
done();
});
}, 10000);
});
});
});

View file

@ -0,0 +1,27 @@
<div id="fxsync-area">
<div id="fxsync-header">
<p data-l10n-id="fxsync-firefox-sync">Firefox Sync</p>
</div>
<div id="fxsync-disabled">
<smart-button id="fxsync-sign-in-button" type="simple-text" data-l10n-id="fxsync-create-account-or-sign-in"></smart-button>
<p id="fxsync-sign-in-description" data-l10n-id="fxsync-sign-in-to-sync-description"></p>
</div>
<div id="fxsync-enabled">
<span id="fxsync-signed-in-as" data-l10n-id="fxsync-signed-in-as"></span>
<smart-button id="fxsync-sync-now-button" type="simple-text" data-l10n-id="fxsync-sync-now"></smart-button>
<smart-button id="fxsync-sign-out-button" type="simple-text" data-l10n-id="fxsync-sign-out"></smart-button>
<ul class="settings-horizontal-list">
<li class="settings-horizontal-list-item">
<input type="checkbox" id="fxsync-collection-bookmarks" ></input>
<label for="fxsync-collection-bookmarks"></label>
<span data-l10n-id="fxsync-collection-bookmarks"></span>
</li>
<li class="settings-horizontal-list-item">
<input type="checkbox" id="fxsync-collection-history" ></input>
<label for="fxsync-collection-history"></label>
<span data-l10n-id="fxsync-collection-history"></span>
</li>
</ul>
</div>
</div>
</div>

View file

@ -0,0 +1 @@
<li id="fxsync-block"><a id="fxsync-tab" href="#" data-l10n-id="fxsync-sign-in-to-sync"></a></li>

View file

@ -0,0 +1,217 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global SyncManagerBridge */
'use strict';
requireApp('browser/js/sync/manager_bridge.js');
suite('SyncManagerBridge >', () => {
var subject;
var realMozApps;
var port;
var app;
var onmessageData;
suiteSetup(() => {
subject = SyncManagerBridge;
realMozApps = navigator.mozApps;
port = {
postMessage: function() {},
set onmessage(callback) {
setTimeout(() => {
callback({ data: onmessageData });
});
}
};
app = {
connect: function() {
return Promise.resolve([port]);
}
};
var onsuccess = {
set onsuccess(callback) {
setTimeout(() => {
callback({ target: { result: app } });
});
}
};
navigator.mozApps = {
getSelf: function() {
return onsuccess;
}
};
});
suiteTeardown(() => {
subject = null;
navigator.mozApps = realMozApps;
});
suite('Initial state', () => {
test('Integrity', () => {
assert.ok(subject != null);
assert.isNull(subject._port);
assert.equal(subject._requests.size, 0);
});
});
['enable',
'disable',
'sync'].forEach(method => {
suite(method, () => {
var getSelfSpy;
var connectSpy;
var postMessageSpy;
setup(() => {
getSelfSpy = this.sinon.spy(navigator.mozApps, 'getSelf');
connectSpy = this.sinon.spy(app, 'connect');
postMessageSpy = this.sinon.spy(port, 'postMessage');
});
teardown(() => {
getSelfSpy.restore();
connectSpy.restore();
postMessageSpy.restore();
});
suiteTeardown(() => {
subject._port = null;
});
test(method + ' - no previous connection', done => {
subject[method]();
setTimeout(() => {
this.sinon.assert.calledOnce(getSelfSpy);
this.sinon.assert.calledOnce(connectSpy);
this.sinon.assert.calledOnce(postMessageSpy);
assert.equal(postMessageSpy.getCall(0).args[0].name, method);
done();
});
});
test(method + ' - previous connection', done => {
subject[method]();
setTimeout(() => {
this.sinon.assert.notCalled(getSelfSpy);
this.sinon.assert.notCalled(connectSpy);
this.sinon.assert.calledOnce(postMessageSpy);
assert.equal(postMessageSpy.getCall(0).args[0].name, method);
done();
});
});
});
});
suite('listeners', () => {
suiteTeardown(() => {
subject._listeners.clear();
});
test('addListener', () => {
assert.equal(subject._listeners.size, 0);
this.listener = () => {};
subject.addListener(this.listener);
assert.equal(subject._listeners.size, 1);
assert.ok(subject._listeners.has(this.listener));
});
test('removeListener', () => {
assert.equal(subject._listeners.size, 1);
assert.ok(subject._listeners.has(this.listener));
subject.removeListener(this.listener);
assert.equal(subject._listeners.size, 0);
});
});
suite('getInfo', () => {
var postMessageSpy;
var dateNowStub;
var now;
var listenerCalled;
setup(() => {
postMessageSpy = this.sinon.spy(port, 'postMessage');
dateNowStub = this.sinon.stub(Date, 'now', () => {
return now;
});
subject.addListener(() => {
listenerCalled = true;
});
});
teardown(() => {
postMessageSpy.restore();
dateNowStub.restore();
});
test('getInfo', done => {
now = 'now';
var expectedMessage = {
data: {
id: now,
result: 'whatever'
}
};
subject.getInfo().then(message => {
assert.equal(message.id, expectedMessage.data.id);
assert.equal(message.result, expectedMessage.data.result);
assert.ok(!listenerCalled);
done();
});
setTimeout(() => {
this.sinon.assert.calledOnce(postMessageSpy);
assert.equal(postMessageSpy.getCall(0).args[0].name, 'getInfo');
assert.equal(postMessageSpy.getCall(0).args[0].id, now);
assert.ok(subject._requests.has(now));
subject.onmessage(expectedMessage);
});
});
});
suite('onsyncchange', () => {
var postMessageSpy;
var observedMessage;
var now;
setup(() => {
postMessageSpy = this.sinon.spy(port, 'postMessage');
var listener = (message) => {
console.log('mes', JSON.stringify(message));
observedMessage = message;
};
subject.addListener(listener);
});
teardown(() => {
postMessageSpy.restore();
});
test('getInfo', done => {
var expectedMessage = {
data: {
name: 'onsyncchange',
result: 'whatever'
}
};
subject.onmessage(expectedMessage);
setTimeout(() => {
this.sinon.assert.notCalled(postMessageSpy);
assert.ok(!(subject._requests.has(now)));
assert.deepEqual(observedMessage, expectedMessage.data);
done();
});
});
});
});

View file

@ -0,0 +1,36 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
(function(exports) {
var MockSyncManagerBridge = {
_syncInfo: null,
addListener() {},
removeListener() {},
enable() {
return Promise.resolve();
},
disable() {
return Promise.resolve();
},
sync() {
return Promise.resolve();
},
getInfo() {
return Promise.resolve(this._syncInfo);
}
};
exports.MockSyncManagerBridge = MockSyncManagerBridge;
}(window));

View file

@ -0,0 +1,525 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global ERROR_DIALOG_CLOSED_BY_USER */
/* global ERROR_INVALID_SYNC_ACCOUNT */
/* global ERROR_OFFLINE */
/* global expect */
/* global FirefoxSyncSettings */
/* global MocksHelper */
/* global MockL10n */
/* global NavigatorSettings */
/* global Settings */
/* global SettingsListener */
/* global SyncManagerBridge */
'use strict';
require('/shared/test/unit/load_body_html_helper.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/shared/test/unit/mocks/mock_l10n.js');
require('/shared/test/unit/mocks/mock_navigator_moz_settings.js');
require('/shared/test/unit/mocks/mock_settings_listener.js');
require('/shared/js/sync/errors.js');
requireApp('browser/test/unit/sync/mocks/mock_manager_bridge.js');
requireApp('browser/js/settings.js');
requireApp('browser/js/browser_dialog.js');
var mocksForSettings = new MocksHelper([
'LazyLoader',
'NavigatorSettings',
'SettingsListener',
'SyncManagerBridge'
]).init();
suite('Sync settings >', function() {
const BOOKMARKS_SETTING = 'sync.collections.bookmarks.enabled';
const HISTORY_SETTING = 'sync.collections.history.enabled';
var subject;
var realL10n;
var realMozSettings;
var observeStub;
var addListenerStub;
var addEventListenerStub;
var getInfoSpy;
var showScreenSpy;
var observers = {};
var onsyncchange;
var visibilityListener;
mocksForSettings.attachTestHelpers();
suiteSetup(function(done) {
realL10n = navigator.mozL10n;
navigator.mozL10n = MockL10n;
realMozSettings = navigator.mozSettings;
navigator.mozSettings = NavigatorSettings;
loadBodyHTML('sync/fixtures/settings.html');
getInfoSpy = sinon.spy(SyncManagerBridge, 'getInfo');
observeStub = sinon.stub(SettingsListener, 'observe',
(setting, unused, observer) => {
observers[setting] = observer;
});
addListenerStub = sinon.stub(SyncManagerBridge, 'addListener',
listener => {
onsyncchange = listener;
});
addEventListenerStub = sinon.stub(document, 'addEventListener',
(event, listener) => {
visibilityListener = listener;
});
sinon.stub(Settings, 'hide');
require('/tv_apps/browser/js/sync/settings.js').then(() => {
subject = FirefoxSyncSettings;
showScreenSpy = sinon.spy(subject, 'showScreen');
done();
});
});
suiteTeardown(function() {
navigator.mozL10n = realL10n;
navigator.mozSettings = realMozSettings;
observeStub.restore();
addListenerStub.restore();
addEventListenerStub.restore();
getInfoSpy.restore();
showScreenSpy.restore();
});
suite('Initial state', function() {
test('Integrity', function() {
expect(subject).to.be.an('object');
});
test('Initialization', function() {
expect(getInfoSpy.calledOnce).to.equal(true);
expect(addListenerStub.calledOnce).to.equal(true);
expect(addListenerStub.args[0][0]).to.be.a('function');
expect(addEventListenerStub.calledOnce).to.equal(true);
expect(onsyncchange).to.be.a('function');
expect(visibilityListener).to.be.a('function');
});
test('should observe settings', function() {
expect(observeStub.calledTwice).to.be.equal(true);
expect(observers[HISTORY_SETTING]).to.be.a('function');
expect(observers[BOOKMARKS_SETTING]).to.be.a('function');
});
test('DOM initial state', function() {
expect(subject.area).to.be.an('object');
expect(subject.elements.enabled).to.be.an('object');
expect(subject.elements.disabled).to.be.an('object');
expect(subject.listeners).to.be.an('object');
expect(subject.listeners.size).to.be.equals(8);
expect(subject.collections).to.be.an('object');
expect(subject.collections.size).to.be.equals(0);
expect(subject.screen).to.be.equals('disabled');
expect(subject.state).to.be.equals('disabled');
});
});
suite('visibilitychange', function() {
setup(function() {
getInfoSpy.reset();
});
teardown(function() {
getInfoSpy.reset();
});
test('should refresh on visibity change', function() {
expect(getInfoSpy.called).to.be.equal(false);
visibilityListener();
expect(getInfoSpy.called).to.be.equal(true);
});
});
suite('Disabled', function() {
suiteSetup(function() {
onsyncchange({
state: 'disabled'
});
});
suiteTeardown(function() {
showScreenSpy.reset();
});
test('should show disabled screen', function() {
expect(showScreenSpy.calledOnce).to.be.equal(true);
expect(showScreenSpy.args[0][0]).to.equal('disabled');
expect(subject.elements.enabled.hidden).to.be.equal(true);
expect(subject.elements.disabled.hidden).to.be.equal(false);
});
test('should have signin button', function() {
expect(subject.elements.signInButton).to.be.an('object');
expect(subject.elements.signInButton.getAttribute('data-l10n-id'))
.to.equals('fxsync-sign-in');
expect(subject.elements.signInButton.classList.contains('disabled'))
.to.equals(false);
});
});
suite('Disabled from disabling', function() {
var alertStub;
var formatValueStub;
suiteSetup(function() {
formatValueStub = sinon.stub(navigator.mozL10n, 'formatValue', key => {
return Promise.resolve(key);
});
alertStub = sinon.stub(window, 'alert');
});
suiteTeardown(function() {
showScreenSpy.reset();
formatValueStub.restore();
alertStub.restore();
});
teardown(function() {
alertStub.reset();
});
['enabled', 'syncing'].forEach(previousState => {
test('should show disabled dialog',
function(done) {
subject.previousState = previousState;
subject.state = 'disabling';
onsyncchange({
state: 'disabled',
user: 'pepito'
});
setTimeout(function() {
expect(alertStub.calledOnce).to.equal(true);
expect(alertStub.args[0][0]).to.equal('fxsync-disabled');
done();
});
});
});
});
suite('Enabled', function() {
suiteSetup(function() {
onsyncchange({
state: 'enabled',
user: 'pepito'
});
});
suiteTeardown(function() {
showScreenSpy.reset();
});
test('should show enabled screen', function() {
expect(showScreenSpy.calledOnce).to.be.equal(true);
expect(showScreenSpy.args[0][0]).to.equal('enabled');
expect(subject.elements.enabled.hidden).to.be.equal(false);
expect(subject.elements.disabled.hidden).to.be.equal(true);
});
test('should show user', function() {
expect(subject.elements.signedInAs).to.be.an('object');
expect(subject.elements.signedInAs.getAttribute('data-l10n-id'))
.to.equals('fxsync-signed-in-as');
expect(subject.elements.signedInAs.getAttribute('data-l10n-args'))
.to.equals('{"email":"pepito"}');
});
test('should show sync now button', function() {
expect(subject.elements.syncNowButton).to.be.an('object');
expect(subject.elements.syncNowButton.getAttribute('data-l10n-id'))
.to.equals('fxsync-sync-now');
});
test('should show signout button', function() {
expect(subject.elements.signOutButton).to.be.an('object');
expect(subject.elements.signOutButton.getAttribute('data-l10n-id'))
.to.equals('fxsync-sign-out');
});
test('should show collection switches', function() {
expect(subject.elements.collectionBookmarks).to.be.an('object');
expect(subject.elements.collectionHistory).to.be.an('object');
});
});
suite('Enabled from enabling', function() {
var alertStub;
var formatValueStub;
suiteSetup(function() {
formatValueStub = sinon.stub(navigator.mozL10n, 'formatValue', key => {
return Promise.resolve(key);
});
alertStub = sinon.stub(window, 'alert');
subject.state = 'enabling';
onsyncchange({
state: 'enabled',
user: 'pepito'
});
});
suiteTeardown(function() {
showScreenSpy.reset();
formatValueStub.restore();
alertStub.restore();
});
test('should show enabled dialog', function() {
expect(alertStub.calledOnce).to.equal(true);
expect(alertStub.args[0][0]).to.equal('fxsync-enabled');
});
});
suite('Enabling', function() {
suiteSetup(function() {
onsyncchange({
state: 'enabling'
});
});
test('should show signing in button', function() {
expect(subject.elements.signInButton.dataset.l10nId)
.to.equals('fxsync-signing');
});
test('should disable signin button', function() {
expect(subject.elements.signInButton.classList.contains('disabled'))
.to.equals(true);
});
});
suite('Syncing', function() {
suiteSetup(function() {
onsyncchange({
state: 'syncing',
user: 'pepito'
});
});
test('should show syncing button', function() {
expect(subject.elements.syncNowButton.dataset.l10nId)
.to.equals('fxsync-syncing');
});
test('should show user', function() {
expect(subject.elements.signedInAs).to.be.an('object');
expect(subject.elements.signedInAs.getAttribute('data-l10n-id'))
.to.equals('fxsync-signed-in-as');
expect(subject.elements.signedInAs.getAttribute('data-l10n-args'))
.to.equals('{"email":"pepito"}');
});
test('should disable sync button and collection switches', function() {
expect(subject.elements.syncNowButton.classList.contains('disabled'))
.to.equals(true);
expect(subject.elements.collectionBookmarks.disabled).to.equal(true);
expect(subject.elements.collectionHistory.disabled).to.equal(true);
});
});
suite('Errored', function() {
var alertStub;
var formatValueStub;
suiteSetup(function() {
alertStub = sinon.stub(window, 'alert');
formatValueStub = sinon.stub(navigator.mozL10n, 'formatValue', key => {
return Promise.resolve(key);
});
});
suiteTeardown(function() {
alertStub.restore();
formatValueStub.restore();
});
teardown(function() {
alertStub.reset();
});
test('should ignore ERROR_DIALOG_CLOSED_BY_USER error', function() {
onsyncchange({
state: 'errored',
error: ERROR_DIALOG_CLOSED_BY_USER
});
expect(alertStub.calledOnce).to.equal(false);
});
test('should show ERROR_INVALID_SYNC_ACCOUNT error', function(done) {
onsyncchange({
state: 'errored',
error: ERROR_INVALID_SYNC_ACCOUNT
});
setTimeout(() => {
expect(alertStub.calledOnce).to.equal(true);
expect(alertStub.args[0][0]).to.equal(ERROR_INVALID_SYNC_ACCOUNT +
'\n' +
ERROR_INVALID_SYNC_ACCOUNT +
'-explanation');
done();
});
});
test('should show ERROR_OFFLINE error', function(done) {
onsyncchange({
state: 'errored',
error: ERROR_OFFLINE
});
setTimeout(() => {
expect(alertStub.calledOnce).to.equal(true);
expect(alertStub.args[0][0]).to.equal(ERROR_OFFLINE +
'\n' +
ERROR_OFFLINE +
'-explanation');
done();
});
});
});
suite('Collections', function() {
var realMozId;
var mozIdError = null;
suiteSetup(function() {
onsyncchange({
state: 'enabled',
user: 'pepito'
});
realMozId = navigator.mozId;
navigator.mozId = {
watch(options) {
this._onlogin = options.onlogin;
this._onerror = options.onerror;
},
request() {
mozIdError ? this._onerror() : this._onlogin();
}
};
});
[{
test: 'should check bookmarks on setting enabled',
collection: 'collectionBookmarks',
setting: BOOKMARKS_SETTING,
enabled: true
}, {
test: 'should uncheck bookmarks on setting disabled',
collection: 'collectionBookmarks',
setting: BOOKMARKS_SETTING,
enabled: false
}, {
test: 'should check history on setting enabled',
collection: 'collectionHistory',
setting: HISTORY_SETTING,
enabled: true
}, {
test: 'should uncheck history on setting disabled',
collection: 'collectionHistory',
setting: HISTORY_SETTING,
enabled: false
}].forEach(config => {
test(config.test, function() {
expect(subject.elements[config.collection].checked)
.to.be.equal(!config.enabled);
observers[config.setting](config.enabled);
expect(subject.elements[config.collection].checked)
.to.be.equal(config.enabled);
});
});
[{
test: 'bookmark checked',
setting: BOOKMARKS_SETTING,
checked: true,
collection: 'collectionBookmarks',
oncheckedFunction: 'onbookmarkschecked'
}, {
test: 'bookmark unchecked',
setting: BOOKMARKS_SETTING,
checked: false,
collection: 'collectionBookmarks',
oncheckedFunction: 'onbookmarkschecked'
}, {
test: 'history checked',
setting: HISTORY_SETTING,
checked: true,
collection: 'collectionHistory',
oncheckedFunction: 'onhistorychecked'
}, {
test: 'history unchecked',
setting: HISTORY_SETTING,
checked: false,
collection: 'collectionHistory',
oncheckedFunction: 'onhistorychecked'
}].forEach(config => {
test('should enable setting on ' + config.test, function() {
expect(subject.collections.has(config.setting))
.to.be.equal(!config.checked);
subject.elements[config.collection].checked = config.checked;
subject[config.oncheckedFunction]();
expect(subject.collections.has(config.setting))
.to.be.equal(config.checked);
});
});
test('should enable/disable Sync Now button on setting enabled/disabled',
function() {
[{
setting: HISTORY_SETTING,
enabled: true
}, {
setting: HISTORY_SETTING,
enabled: false
}, {
setting: BOOKMARKS_SETTING,
enabled: true
}, {
setting: BOOKMARKS_SETTING,
enabled: false
}].forEach(config => {
observers[config.setting](config.enabled);
expect(subject.elements.syncNowButton.classList.contains('disabled'))
.to.equals(!config.enabled);
});
});
test(`should not enable collections checkboxes if refresh auth failed`,
function() {
[{
setting: HISTORY_SETTING,
element: 'collectionHistory',
onchecked: 'onhistorychecked'
}, {
setting: BOOKMARKS_SETTING,
element: 'collectionBookmarks',
onchecked: 'onbookmarkschecked'
}].forEach(config => {
mozIdError = true;
expect(subject.collections.has(config.setting))
.to.be.equal(false);
subject.elements[config.element].checked = true;
subject[config.onchecked]();
expect(subject.collections.has(config.setting))
.to.be.equal(false);
expect(subject.elements[config.element].checked)
.to.be.equal(false);
});
});
});
});

Some files were not shown because too many files have changed in this diff Show more