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.
31
gaia/distros/b2gdroid/apps.list
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
apps/bookmark
|
||||
apps/calendar
|
||||
apps/callscreen
|
||||
apps/clock
|
||||
apps/communications
|
||||
apps/costcontrol
|
||||
apps/default_theme
|
||||
apps/download
|
||||
apps/email
|
||||
apps/emergency-call
|
||||
apps/findmydevice
|
||||
apps/fl
|
||||
apps/gallery
|
||||
apps/homescreen
|
||||
apps/keyboard
|
||||
apps/marketplace.firefox.com
|
||||
apps/music
|
||||
apps/network-alerts
|
||||
apps/operatorvariant
|
||||
apps/pdfjs
|
||||
apps/ringtones
|
||||
apps/search
|
||||
apps/setringtone
|
||||
apps/settings
|
||||
apps/sms
|
||||
apps/sync
|
||||
apps/system
|
||||
apps/video
|
||||
apps/wallpaper
|
||||
apps/wappush
|
||||
distros/b2gdroid/apps/*
|
||||
38
gaia/distros/b2gdroid/apps/ftu/index.html
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#eeeeee">
|
||||
<link rel="stylesheet" href="style/app.css">
|
||||
|
||||
<title>Welcome to Firefox OS developer preview</title>
|
||||
|
||||
<!-- Localization -->
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<link rel="localization" href="locales/ftu-droid.{locale}.properties">
|
||||
|
||||
<script src="/shared/js/l10n.js"></script>
|
||||
<script defer src="js/app.js"></script>
|
||||
|
||||
<!-- Components -->
|
||||
<script defer src="/shared/js/component_utils.js"></script>
|
||||
<script defer src="/shared/elements/gaia_buttons/script.js"></script>
|
||||
</head>
|
||||
<body class="theme-settings">
|
||||
<section>
|
||||
<h1 data-l10n-id="welcome"></h1>
|
||||
<p data-l10n-id="welcomeBody1"></p>
|
||||
<p data-l10n-id="welcomeBody2"></p>
|
||||
<p data-l10n-id="welcomeBody3">
|
||||
<a class="external-link" href="https://www.mozilla.org/contribute"></a>
|
||||
<a class="external-link" href="https://github.com/mozilla-b2g/gaia"></a>
|
||||
</p>
|
||||
|
||||
<gaia-buttons class="nav">
|
||||
<button id="nav-done" class="recommend icon icon-next" data-l10n-id="done"></button>
|
||||
</gaia-buttons>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
19
gaia/distros/b2gdroid/apps/ftu/js/app.js
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
(function() {
|
||||
|
||||
var done = document.getElementById('nav-done');
|
||||
done.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
window.close();
|
||||
});
|
||||
|
||||
var links = document.querySelectorAll('.external-link');
|
||||
Array.slice(links).forEach(link => {
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
window.open(e.target.href, '', 'dialog');
|
||||
});
|
||||
});
|
||||
|
||||
}());
|
||||
6
gaia/distros/b2gdroid/apps/ftu/locales/ftu-droid.en-US.properties
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
welcome=Welcome
|
||||
welcomeBody1=Welcome to the Firefox OS developer preview, an experimental Android app from Mozilla that lets you experience Firefox OS.
|
||||
welcomeBody2=We would love for you to get involved in shaping the future of the Web.
|
||||
# LOCALIZATION NOTE: Keep the order of these links the same as in en-US so the hrefs do not get mixed up.
|
||||
welcomeBody3=To find out how, visit: <a>https://www.mozilla.org/contribute</a> or just grab the source code: <a>https://github.com/mozilla-b2g/gaia</a>
|
||||
done=Done
|
||||
31
gaia/distros/b2gdroid/apps/ftu/manifest.webapp
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "FTU",
|
||||
"description": "First Time Experience",
|
||||
"type": "certified",
|
||||
"launch_path": "/index.html",
|
||||
"role": "system",
|
||||
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
|
||||
"locales": {
|
||||
"en-US": {
|
||||
"name": "FTU",
|
||||
"description": "First Time Experience"
|
||||
}
|
||||
},
|
||||
|
||||
"default_locale": "en-US",
|
||||
|
||||
"permissions": {
|
||||
"themeable":{},
|
||||
"settings":{ "access": "readwrite" },
|
||||
"systemXHR": {},
|
||||
"moz-extremely-unstable-and-will-change-webcomponents":{}
|
||||
},
|
||||
|
||||
"orientation": "default"
|
||||
|
||||
}
|
||||
29
gaia/distros/b2gdroid/apps/ftu/style/app.css
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
* {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #f4f4f4 url(images/background.png) no-repeat 0 calc(100% - 7rem) / 100% auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.35rem;
|
||||
margin: 0 1.5rem 1.5rem;
|
||||
}
|
||||
BIN
gaia/distros/b2gdroid/apps/ftu/style/images/background.png
Executable file
|
After Width: | Height: | Size: 651 KiB |
1
gaia/distros/b2gdroid/distro.mk
Executable file
|
|
@ -0,0 +1 @@
|
|||
NO_LOCK_SCREEN=1
|
||||
6
gaia/distros/b2gdroid/settings.json
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"debugger.remote-mode": "adb-devtools",
|
||||
"screen.timeout": 0,
|
||||
"homescreen.appName": "homescreen",
|
||||
"ftu.manifestURL": "app://ftu.gaiamobile.org/manifest.webapp"
|
||||
}
|
||||
3
gaia/distros/raptor/apps.list
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
apps/*
|
||||
distros/raptor/apps/*
|
||||
distros/raptor/outoftree_apps/*
|
||||
23
gaia/distros/raptor/apps/test-startup-limit/index.html
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Test Startup Limit</title>
|
||||
<link rel="stylesheet" href="style/style.css">
|
||||
<script defer src="js/app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="toggle">Switch to Binary</div>
|
||||
<div class="count">
|
||||
<div class="decimal">0</div>
|
||||
<div class="binary">0</div>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div class="plus">+</div>
|
||||
<div class="minus">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
156
gaia/distros/raptor/apps/test-startup-limit/js/app.js
Executable file
|
|
@ -0,0 +1,156 @@
|
|||
var counter = {};
|
||||
|
||||
counter.component = (() => {
|
||||
'use strict';
|
||||
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Component state
|
||||
*/
|
||||
exports.base = 'decimal';
|
||||
exports.count = 0;
|
||||
exports.binary = '0';
|
||||
exports.decimal = '0';
|
||||
|
||||
exports.render = function() {
|
||||
console.log('Will render ui');
|
||||
var toggleElement = document.getElementsByClassName('toggle')[0];
|
||||
var decimalElement = document.getElementsByClassName('decimal')[0];
|
||||
var binaryElement = document.getElementsByClassName('binary')[0];
|
||||
|
||||
decimalElement.innerHTML = this.decimal;
|
||||
binaryElement.innerHTML = this.binary;
|
||||
|
||||
if (this.base === 'decimal') {
|
||||
toggleElement.innerHTML = 'Switch to binary';
|
||||
binaryElement.style.display = 'none';
|
||||
decimalElement.style.display = 'block';
|
||||
} else if (this.base === 'binary') {
|
||||
toggleElement.innerHTML = 'Switch to decimal';
|
||||
decimalElement.style.display = 'none';
|
||||
binaryElement.style.display = 'block';
|
||||
}
|
||||
};
|
||||
|
||||
return exports;
|
||||
|
||||
})();
|
||||
|
||||
counter.string = (() => {
|
||||
'use strict';
|
||||
|
||||
var exports = {};
|
||||
|
||||
exports.convertToBinary = function(value) {
|
||||
// Fake async operation.
|
||||
return Promise.resolve().then(() => {
|
||||
if (value === 0) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
var remainders = '';
|
||||
for (var quotient = value; quotient > 0; quotient = Math.floor(quotient / 2)) {
|
||||
remainders += (quotient % 2);
|
||||
}
|
||||
|
||||
return reverse('', remainders);
|
||||
});
|
||||
};
|
||||
|
||||
function reverse(str, backwards) {
|
||||
if (!backwards.length) {
|
||||
return str;
|
||||
}
|
||||
|
||||
var chr = backwards[backwards.length - 1];
|
||||
return reverse(str + chr, backwards.slice(0, -1));
|
||||
};
|
||||
|
||||
return exports;
|
||||
|
||||
})();
|
||||
|
||||
counter.app = (() => {
|
||||
'use strict';
|
||||
|
||||
var component = counter.component;
|
||||
var perf = window.performance;
|
||||
var string = counter.string;
|
||||
|
||||
var initialized = false;
|
||||
var worker;
|
||||
|
||||
var exports = {};
|
||||
|
||||
exports.main = function() {
|
||||
// Since our entire UI is in index.html, we can emit navigationLoaded.
|
||||
perf.mark('navigationLoaded');
|
||||
|
||||
console.log('Binding event handlers');
|
||||
var toggle = document.getElementsByClassName('toggle')[0];
|
||||
toggle.addEventListener('click', ontoggle);
|
||||
var plus = document.getElementsByClassName('plus')[0];
|
||||
plus.addEventListener('click', onplus);
|
||||
var minus = document.getElementsByClassName('minus')[0];
|
||||
minus.addEventListener('click', onminus);
|
||||
|
||||
component.render();
|
||||
|
||||
// Now that people can switch between bases, we can mark navigationInteractive.
|
||||
perf.mark('navigationInteractive');
|
||||
|
||||
// Start our worker and ask for the current counter count.
|
||||
console.log('Starting worker');
|
||||
worker = new Worker('/js/worker.js');
|
||||
worker.postMessage({ method: 'getCount' });
|
||||
worker.onmessage = event => {
|
||||
// We got the current counter value from the worker.
|
||||
var count = event.data;
|
||||
console.log(`Read count = ${count} from worker`);
|
||||
component.count = count;
|
||||
component.decimal = count.toString();
|
||||
initialized = true;
|
||||
component.render();
|
||||
perf.mark('visuallyLoaded');
|
||||
perf.mark('contentInteractive');
|
||||
|
||||
// Now in the background we're going to update the binary value.
|
||||
string.convertToBinary(count).then(binaryCount => {
|
||||
component.binary = binaryCount;
|
||||
perf.mark('fullyLoaded');
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
function ontoggle() {
|
||||
component.base = component.base === 'decimal' ? 'binary' : 'decimal';
|
||||
component.render();
|
||||
}
|
||||
|
||||
function add(diff) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
var count = component.count;
|
||||
count = Math.max(0, count + diff);
|
||||
return string.convertToBinary(count).then(binaryCount => {
|
||||
component.count = count;
|
||||
component.decimal = count.toString();
|
||||
component.binary = binaryCount;
|
||||
component.render();
|
||||
worker.postMessage({ method: 'setCount', params: [count] });
|
||||
});
|
||||
}
|
||||
|
||||
var onplus = add.bind(null, 1);
|
||||
var onminus = add.bind(null, -1);
|
||||
|
||||
return exports;
|
||||
|
||||
})();
|
||||
|
||||
// main
|
||||
var app = counter.app;
|
||||
app.main();
|
||||
40
gaia/distros/raptor/apps/test-startup-limit/js/worker.js
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
var db;
|
||||
|
||||
var getCount = new Promise(resolve => {
|
||||
console.log('Will open indexedDB');
|
||||
var request = indexedDB.open('counter');
|
||||
|
||||
request.onupgradeneeded = event => {
|
||||
console.log('Populating indexedDB');
|
||||
db = event.target.result;
|
||||
var store = db.createObjectStore('count');
|
||||
store.add(0, 'count');
|
||||
};
|
||||
|
||||
request.onsuccess = () => {
|
||||
console.log('Reading count from indexedDB');
|
||||
db = request.result;
|
||||
var transaction = db.transaction(['count'], 'readonly');
|
||||
var store = transaction.objectStore('count');
|
||||
var get = store.get('count');
|
||||
get.onsuccess = () => resolve(get.result);
|
||||
};
|
||||
});
|
||||
|
||||
function setCount(count) {
|
||||
var transaction = db.transaction(['count'], 'readwrite');
|
||||
var store = transaction.objectStore('count');
|
||||
store.put(count, 'count');
|
||||
}
|
||||
|
||||
self.onmessage = event => {
|
||||
console.log(`Will call ${event.data.method}`);
|
||||
switch (event.data.method) {
|
||||
case 'getCount':
|
||||
getCount.then(postMessage);
|
||||
break;
|
||||
case 'setCount':
|
||||
setCount(event.data.params[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
23
gaia/distros/raptor/apps/test-startup-limit/manifest.webapp
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "Test Startup Limit",
|
||||
"description": "Counter application that does the theoretical least amount of work on startup",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"locales": {
|
||||
"en-US": {
|
||||
"name": "Test Startup Limit",
|
||||
"description": "Counter application that does the theoretical least amount of work on startup"
|
||||
}
|
||||
},
|
||||
"default_locale": "en-US",
|
||||
"icons": {
|
||||
"84": "/style/icons/default_84.png",
|
||||
"126": "/style/icons/default_126.png",
|
||||
"142": "/style/icons/default_142.png",
|
||||
"189": "/style/icons/default_189.png",
|
||||
"284": "/style/icons/default_284.png"
|
||||
}
|
||||
}
|
||||
BIN
gaia/distros/raptor/apps/test-startup-limit/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/distros/raptor/apps/test-startup-limit/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/distros/raptor/apps/test-startup-limit/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/distros/raptor/apps/test-startup-limit/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/distros/raptor/apps/test-startup-limit/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
74
gaia/distros/raptor/apps/test-startup-limit/style/style.css
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
.container {
|
||||
background-color: black;
|
||||
bottom: 0;
|
||||
color: white;
|
||||
font-size: 64px;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.container * {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
background-color: white;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
font-size: 32px;
|
||||
float: right;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.toggle:hover {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.count {
|
||||
bottom: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.count * {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.count .binary {
|
||||
/* binary is initially hidden */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.controls {
|
||||
bottom: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.controls * {
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.controls *:hover {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.controls *:active {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.controls .plus {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.controls .minus {
|
||||
color: red;
|
||||
}
|
||||
87
gaia/distros/raptor/apps/test-startup-limit/test/marionette/counter_test.js
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
var expect = require('chai').expect;
|
||||
|
||||
const APP_ORIGIN = 'app://test-startup-limit.gaiamobile.org';
|
||||
|
||||
function Counter(client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
Counter.prototype = {
|
||||
launch: function() {
|
||||
this.client.apps.launch(APP_ORIGIN);
|
||||
this.client.apps.switchToApp(APP_ORIGIN);
|
||||
},
|
||||
|
||||
getCurrentBase: function() {
|
||||
return this.client
|
||||
.findElement('.toggle')
|
||||
.text()
|
||||
.indexOf('binary') !== -1 ? 'decimal' : 'binary';
|
||||
},
|
||||
|
||||
getCount: function() {
|
||||
return this.client
|
||||
.findElement('.count')
|
||||
.text();
|
||||
},
|
||||
|
||||
toggleView: function() {
|
||||
var base = this.getCurrentBase();
|
||||
this.client
|
||||
.findElement('.toggle')
|
||||
.click();
|
||||
this.client.waitFor(function() {
|
||||
return this.getCurrentBase() !== base;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
plus: function() {
|
||||
this.client
|
||||
.findElement('.plus')
|
||||
.click();
|
||||
},
|
||||
|
||||
minus: function() {
|
||||
this.client
|
||||
.findElement('.minus')
|
||||
.click();
|
||||
}
|
||||
};
|
||||
|
||||
marionette('counter', function() {
|
||||
var client = marionette.client({
|
||||
desiredCapabilities: { raisesAccessibilityExceptions: false }
|
||||
});
|
||||
var counter = new Counter(client);
|
||||
|
||||
setup(function() {
|
||||
counter.launch();
|
||||
});
|
||||
|
||||
test('should initially show decimal', function() {
|
||||
expect(counter.getCurrentBase()).to.equal('decimal');
|
||||
});
|
||||
|
||||
test('toggling view should show binary', function() {
|
||||
counter.toggleView();
|
||||
expect(counter.getCurrentBase()).to.equal('binary');
|
||||
counter.plus();
|
||||
counter.plus();
|
||||
expect(counter.getCount()).to.equal('10');
|
||||
});
|
||||
|
||||
test('+ should increment count', function() {
|
||||
expect(counter.getCount()).to.equal('0');
|
||||
counter.plus();
|
||||
counter.plus();
|
||||
expect(counter.getCount()).to.equal('2');
|
||||
});
|
||||
|
||||
test('- should decrement count', function() {
|
||||
expect(counter.getCount()).to.equal('0');
|
||||
counter.plus();
|
||||
counter.plus();
|
||||
counter.minus();
|
||||
expect(counter.getCount()).to.equal('1');
|
||||
});
|
||||
});
|
||||
3
gaia/distros/raptor/distro.mk
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
RAPTOR=1
|
||||
PERF_LOGGING=1
|
||||
GAIA_OPTIMIZE=1
|
||||
5
gaia/distros/raptor/partner-prefs.js
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
/*global user_pref*/
|
||||
user_pref('b2g.adb.timeout', 0);
|
||||
user_pref('dom.serviceWorkers.enabled', true);
|
||||
// Remove this pref once bug 1125916 and bug 1125961 are fixed.
|
||||
user_pref('network.disable.ipc.security', true);
|
||||
1
gaia/distros/raptor/remote.list
Executable file
|
|
@ -0,0 +1 @@
|
|||
fxos-performance,https://fxos-performance.github.io/package.webapp
|
||||
6
gaia/distros/raptor/settings.json
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"screen.timeout": 0,
|
||||
"ftu.manifestURL": null,
|
||||
"lockscreen.enabled": false,
|
||||
"dom.serviceWorkers.interception.enabled": true
|
||||
}
|
||||
36
gaia/distros/spark/apps.list
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
apps/bluetooth
|
||||
apps/bookmark
|
||||
apps/calendar
|
||||
apps/callscreen
|
||||
apps/camera
|
||||
apps/clock
|
||||
apps/communications
|
||||
apps/costcontrol
|
||||
apps/default_theme
|
||||
apps/download
|
||||
apps/email
|
||||
apps/emergency-call
|
||||
apps/findmydevice
|
||||
apps/fl
|
||||
apps/ftu
|
||||
apps/gallery
|
||||
apps/homescreen
|
||||
apps/keyboard
|
||||
apps/marketplace.firefox.com
|
||||
apps/music
|
||||
apps/network-alerts
|
||||
apps/operatorvariant
|
||||
apps/pdfjs
|
||||
apps/ringtones
|
||||
apps/search
|
||||
apps/setringtone
|
||||
apps/settings
|
||||
apps/sms
|
||||
apps/sync
|
||||
apps/system
|
||||
apps/verticalhome
|
||||
apps/video
|
||||
apps/wallpaper
|
||||
apps/wappush
|
||||
distros/spark/apps/*
|
||||
distros/spark/outoftree_apps/*
|
||||
227
gaia/distros/spark/apps/customizer-launcher/components/base/base.css
Executable file
|
|
@ -0,0 +1,227 @@
|
|||
|
||||
/** Variables
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:root {
|
||||
--dim-micro: 6px;
|
||||
--dim-small: 12px;
|
||||
--dim-medium: 24px;
|
||||
--dim-mega: 48px;
|
||||
|
||||
--base-xs: 6px;
|
||||
--base-s: 18px;
|
||||
--base-m: 24px;
|
||||
--base-l: 30px;
|
||||
--base-xl: 42px;
|
||||
--base-xxl: 60px;
|
||||
|
||||
--base-font-xs: 10px;
|
||||
--base-font-s: 14px;
|
||||
--base-font-m: 17px;
|
||||
--base-font-l: 23px;
|
||||
--base-font-xl: 60px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Apply a natural box layout
|
||||
* model to all elements
|
||||
*/
|
||||
|
||||
*,
|
||||
*:after,
|
||||
*:before {
|
||||
box-sizing: border-box; /* 1 */
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Document
|
||||
---------------------------------------------------------*/
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Body
|
||||
---------------------------------------------------------*/
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
font: 300 17px/21px 'FiraSans';
|
||||
background-color: var(--background);
|
||||
color: var(--text-color);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/** Tags
|
||||
---------------------------------------------------------*/
|
||||
|
||||
a {
|
||||
color: var(--highlight-color, inherit);
|
||||
text-decoration: none;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
margin: var(--dim-small) 0 var(--dim-small) 0;
|
||||
border: 0;
|
||||
background:
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
rgba(0,0,0,0.2)));
|
||||
}
|
||||
|
||||
em {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5 {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.alpha {
|
||||
font-size: 23px;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
line-height: 26px;
|
||||
margin: 6px 0 24px 0;
|
||||
}
|
||||
|
||||
.beta {
|
||||
font-size: 17px;
|
||||
font-weight: 400;
|
||||
margin: 32px 0 16px 0;
|
||||
}
|
||||
|
||||
.gamma {
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
font-weight: normal;
|
||||
margin: 32px 0 16px 0;
|
||||
}
|
||||
|
||||
.milli {
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 23px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.mega {
|
||||
font-size: 60px;
|
||||
line-height: 60px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.giga {}
|
||||
.kilo {}
|
||||
|
||||
/* alignment */
|
||||
.l-align-right { float: right; }
|
||||
.l-align-left { float: left; }
|
||||
.l-align-center { text-align: center; }
|
||||
.l-text-align-left { text-align: left; }
|
||||
.l-text-align-right { text-align: right; }
|
||||
.l-text-valign-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.l-width-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/** Flexbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.l-flex { display: flex; }
|
||||
.l-flex-col { display: flex; flex-direction: column; }
|
||||
|
||||
.l-flex-col-v-align {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.l-flex-v-align { align-items: center; }
|
||||
.l-flex-h-align { justify-content: center; }
|
||||
.l-flex-grow { flex: 1; }
|
||||
|
||||
/** Margin
|
||||
---------------------------------------------------------*/
|
||||
|
||||
/* Top */
|
||||
|
||||
.l-mt-small { margin-top: var(--dim-small); }
|
||||
.l-mt-med { margin-top: var(--dim-medium); }
|
||||
|
||||
/* Bottom */
|
||||
|
||||
.l-mb-small { margin-bottom: var(--dim-small); }
|
||||
.l-mb-med { margin-bottom: var(--dim-medium); }
|
||||
.l-mb-large {}
|
||||
.l-mb-mega { margin-bottom: var(--dim-mega); }
|
||||
|
||||
/* Left */
|
||||
|
||||
.l-ml-small { margin-left: var(--dim-small); }
|
||||
|
||||
/* Right */
|
||||
|
||||
.l-mr-small { margin-right: var(--dim-small); }
|
||||
|
||||
/* Auto */
|
||||
|
||||
.l-mlr-auto { margin-left: auto; margin-right: auto; }
|
||||
.l-m-auto { margin: auto }
|
||||
|
||||
/* Margin */
|
||||
|
||||
.l-m-small { margin: var(--dim-small) }
|
||||
.l-m-med { margin: var(--dim-medium) }
|
||||
.l-m-0 { margin: 0 }
|
||||
|
||||
/** Padding
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.l-p-small { padding: var(--dim-small); }
|
||||
.l-pl-small { padding-left: var(--dim-small); }
|
||||
.l-pr-small { padding-right: var(--dim-small); }
|
||||
.l-plr-small {
|
||||
padding-right: var(--dim-small);
|
||||
padding-left: var(--dim-small);
|
||||
}
|
||||
.l-pb-small { padding-bottom: var(--dim-small); }
|
||||
.l-pt-small { padding-top: var(--dim-small); }
|
||||
.l-pt-mega { padding-top: var(--dim-mega); }
|
||||
.l-pt-micro { padding-top: var(--dim-micro); }
|
||||
.l-pb-micro { padding-bottom: var(--dim-micro); }
|
||||
.l-p-0 { padding: 0 ;}
|
||||
|
||||
/** Helpers
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.l-clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.l-inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.is-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.is-invisible {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
16
gaia/distros/spark/apps/customizer-launcher/components/base/bower.json
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "base",
|
||||
"version": "0.0.0",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "base.css",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
18
gaia/distros/spark/apps/customizer-launcher/components/font-fit/bower.json
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "font-fit",
|
||||
"main": "font-fit.js",
|
||||
"version": "0.3.1",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"README.md",
|
||||
"index.html",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
132
gaia/distros/spark/apps/customizer-launcher/components/font-fit/font-fit.js
Executable file
|
|
@ -0,0 +1,132 @@
|
|||
;(function(define){define(function(require,exports,module){
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Simple logger.
|
||||
*
|
||||
* @return {Function}
|
||||
*/
|
||||
var debug = 0 ? console.log.bind(console) : function(){};
|
||||
|
||||
/**
|
||||
* Global canvas cache.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Default min/max font-size.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
var MIN = 16;
|
||||
var MAX = 24;
|
||||
|
||||
/**
|
||||
* The number of pixels to subtract from
|
||||
* the given `config.space` to ensure
|
||||
* HTML text doesn't overflow container.
|
||||
*
|
||||
* Ideally we would use 1px, but in some
|
||||
* cases italicised text in canvas is ~2px
|
||||
* longer than the same text in HTML.
|
||||
*
|
||||
* http://bugzil.la/1126391
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
var BUFFER = 3;
|
||||
|
||||
/**
|
||||
* Get the font-size that closest fits
|
||||
* the given space with the given font.
|
||||
*
|
||||
* Config:
|
||||
*
|
||||
* - {String} `text` The text string
|
||||
* - {String} `font` Font shorthand string
|
||||
* - {Number} `space` Width (px) to fit the text into
|
||||
* - {Number} `min` Min font-size (px) (optional)
|
||||
* - {Number} `max` Max font-size (px) (optional)
|
||||
*
|
||||
* @param {Object} config
|
||||
* @return {Object} {fontSize,overflowing,textWidth}
|
||||
*/
|
||||
module.exports = function(config) {
|
||||
debug('font fit', config);
|
||||
var space = config.space - BUFFER;
|
||||
var min = config.min || MIN;
|
||||
var max = config.max || MAX;
|
||||
var text = trim(config.text);
|
||||
var fontSize = max;
|
||||
var textWidth;
|
||||
var font;
|
||||
|
||||
do {
|
||||
font = config.font.replace(/\d+px/, fontSize + 'px');
|
||||
textWidth = getTextWidth(text, font);
|
||||
} while (textWidth > space && fontSize !== min && fontSize--);
|
||||
|
||||
return {
|
||||
textWidth: textWidth,
|
||||
fontSize: fontSize,
|
||||
overflowing: textWidth > space
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the width of the given text
|
||||
* with the given font style.
|
||||
*
|
||||
* @param {String} text
|
||||
* @param {String} font (CSS shorthand)
|
||||
* @return {Number} (px)
|
||||
*/
|
||||
function getTextWidth(text, font) {
|
||||
var ctx = getCanvasContext(font);
|
||||
var width = ctx.measureText(text).width;
|
||||
debug('got text width', width);
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a canvas context configured
|
||||
* to the given font style.
|
||||
*
|
||||
* @param {String} font
|
||||
* @return {CanvasRenderingContext2D}
|
||||
*/
|
||||
function getCanvasContext(font) {
|
||||
debug('get canvas context', font);
|
||||
|
||||
var cached = cache[font];
|
||||
if (cached) { return cached; }
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.setAttribute('moz-opaque', 'true');
|
||||
canvas.setAttribute('width', '1px');
|
||||
canvas.setAttribute('height', '1px');
|
||||
debug('created canvas', canvas);
|
||||
|
||||
var ctx = canvas.getContext('2d', { willReadFrequently: true });
|
||||
ctx.font = font;
|
||||
|
||||
return cache[font] = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim leading, trailing
|
||||
* and excess whitespace.
|
||||
*
|
||||
* @param {String} text
|
||||
* @return {String}
|
||||
*/
|
||||
function trim(text) {
|
||||
return text.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('font-fit',this));
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
'use strict';
|
||||
|
||||
/* global Notification, console */
|
||||
|
||||
const DEFAULT_IMAGE_SIZE = 64;
|
||||
const MOZ_SETTINGS_NOT_AVAILABLE_MSG = 'navigator.mozSettings is not available';
|
||||
|
||||
class ImageHelper {
|
||||
static getImage(aSrc) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let image = new Image();
|
||||
image.src = aSrc;
|
||||
image.onload = () => resolve(image);
|
||||
image.onerror = reason => reject(reason);
|
||||
}).catch(reason => console.warn('Could not load an achievement image:',
|
||||
reason));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a Data URL for an image from source.
|
||||
* @param {String} aSrc source path to the image
|
||||
* @return {Promise} a promise of Data URL.
|
||||
*/
|
||||
static generateImageDataURL(aSrc) {
|
||||
return ImageHelper.getImage(aSrc).then(image => {
|
||||
try {
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.height = canvas.width = DEFAULT_IMAGE_SIZE;
|
||||
let context = canvas.getContext('2d');
|
||||
let dataUrl;
|
||||
|
||||
context.drawImage(image, 0, 0, DEFAULT_IMAGE_SIZE, DEFAULT_IMAGE_SIZE);
|
||||
dataUrl = canvas.toDataURL();
|
||||
|
||||
// Clean up.
|
||||
canvas.width = canvas.height = 0;
|
||||
canvas = null;
|
||||
|
||||
return dataUrl;
|
||||
} catch(e) {
|
||||
return Promise.reject('Could not convert image to Data URL.');
|
||||
}
|
||||
}).catch(reason => console.warn(reason));
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsHelper {
|
||||
static get(name, defaultValue) {
|
||||
if (!name) {
|
||||
return Promise.reject('Setting name is missing');
|
||||
}
|
||||
|
||||
if (!navigator.mozSettings) {
|
||||
console.warn(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
return Promise.reject(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let setting = navigator.mozSettings.createLock().get(name, defaultValue);
|
||||
setting.onsuccess = () => {
|
||||
let settingValue = setting.result[name] || defaultValue;
|
||||
resolve(settingValue);
|
||||
};
|
||||
setting.onerror = () => { reject(setting.error); };
|
||||
});
|
||||
}
|
||||
|
||||
static set(settings) {
|
||||
if (!settings) {
|
||||
return Promise.reject('Settings are missing');
|
||||
}
|
||||
|
||||
if (!navigator.mozSettings) {
|
||||
console.warn(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
return Promise.reject(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let result = navigator.mozSettings.createLock().set(settings);
|
||||
result.onsuccess = () => { resolve(result.result); };
|
||||
result.onerror = () => { reject(result.error); };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default class AchievementsService {
|
||||
/**
|
||||
* Reward an achievement and store a record in 'achievements' setting.
|
||||
* @param {JSON} options attributes for the achievement that is awarded:
|
||||
* {String} criteria URL of the criteria for earning
|
||||
* the achievement
|
||||
* {String} evidence A URN of the evidence of
|
||||
* achievement unlocked
|
||||
* {String} name Achievement name
|
||||
* {String} description Achievement description
|
||||
* {String} image Achievement image
|
||||
*/
|
||||
reward({criteria, evidence, name, description, image}) {
|
||||
if (!evidence) {
|
||||
return Promise.reject('Evidence is not provided.');
|
||||
}
|
||||
|
||||
let issuedOn;
|
||||
return SettingsHelper.get('achievements', []).then(achievements => {
|
||||
let achievement = achievements.find(
|
||||
achievement => achievement.criteria === criteria);
|
||||
|
||||
if (!achievement) {
|
||||
return Promise.reject('Achievement is not registered.');
|
||||
}
|
||||
if (achievement.evidence) {
|
||||
return Promise.reject('Achievement is already awarded.');
|
||||
}
|
||||
|
||||
achievement.evidence = evidence;
|
||||
achievement.uid = 'achievement' + Math.round(Math.random() * 100000000);
|
||||
achievement.issuedOn = issuedOn = Date.now();
|
||||
achievement.recipient = {}; // TODO
|
||||
|
||||
return achievements;
|
||||
}).then(achievements => Promise.all([
|
||||
ImageHelper.generateImageDataURL(image),
|
||||
SettingsHelper.set({ 'achievements': achievements })
|
||||
])).then(([image]) => {
|
||||
// Send a Notification via WebAPI to be handled by the Gaia::System
|
||||
let notification = new Notification(name, {
|
||||
body: description,
|
||||
icon: image,
|
||||
tag: issuedOn
|
||||
});
|
||||
|
||||
notification.onclick = () => {
|
||||
let activity = new window.MozActivity({
|
||||
name: 'configure',
|
||||
data: {
|
||||
target: 'device',
|
||||
section: 'achievements'
|
||||
}
|
||||
});
|
||||
activity.onsuccess = activity.onerror = () => { notification.close(); };
|
||||
};
|
||||
}).catch(reason => console.warn(reason));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "fxos-achievements-service",
|
||||
"version": "0.0.14",
|
||||
"description": "Achievements service for embedding achievements support into Gaia apps",
|
||||
"homepage": "https://github.com/fxos/fxos-achievements-service",
|
||||
"license": "MPL",
|
||||
"main": "achievements-service.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"example",
|
||||
"componenets",
|
||||
"node_modules",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
175
gaia/distros/spark/apps/customizer-launcher/components/fxos-achievements-service/dist/achievements-service.js
vendored
Executable file
|
|
@ -0,0 +1,175 @@
|
|||
define(["exports"], function (exports) {
|
||||
"use strict";
|
||||
|
||||
var _toArray = function (arr) {
|
||||
return Array.isArray(arr) ? arr : Array.from(arr);
|
||||
};
|
||||
|
||||
"use strict";
|
||||
|
||||
/* global Notification, console */
|
||||
|
||||
var DEFAULT_IMAGE_SIZE = 64;
|
||||
var MOZ_SETTINGS_NOT_AVAILABLE_MSG = "navigator.mozSettings is not available";
|
||||
|
||||
var ImageHelper = (function () {
|
||||
var ImageHelper = function ImageHelper() {};
|
||||
|
||||
ImageHelper.getImage = function (aSrc) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var image = new Image();
|
||||
image.src = aSrc;
|
||||
image.onload = function () {
|
||||
return resolve(image);
|
||||
};
|
||||
image.onerror = function (reason) {
|
||||
return reject(reason);
|
||||
};
|
||||
})["catch"](function (reason) {
|
||||
return console.warn("Could not load an achievement image:", reason);
|
||||
});
|
||||
};
|
||||
|
||||
ImageHelper.generateImageDataURL = function (aSrc) {
|
||||
return ImageHelper.getImage(aSrc).then(function (image) {
|
||||
try {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.height = canvas.width = DEFAULT_IMAGE_SIZE;
|
||||
var context = canvas.getContext("2d");
|
||||
var dataUrl;
|
||||
|
||||
context.drawImage(image, 0, 0, DEFAULT_IMAGE_SIZE, DEFAULT_IMAGE_SIZE);
|
||||
dataUrl = canvas.toDataURL();
|
||||
|
||||
// Clean up.
|
||||
canvas.width = canvas.height = 0;
|
||||
canvas = null;
|
||||
|
||||
return dataUrl;
|
||||
} catch (e) {
|
||||
return Promise.reject("Could not convert image to Data URL.");
|
||||
}
|
||||
})["catch"](function (reason) {
|
||||
return console.warn(reason);
|
||||
});
|
||||
};
|
||||
|
||||
return ImageHelper;
|
||||
})();
|
||||
|
||||
var SettingsHelper = (function () {
|
||||
var SettingsHelper = function SettingsHelper() {};
|
||||
|
||||
SettingsHelper.get = function (name, defaultValue) {
|
||||
if (!name) {
|
||||
return Promise.reject("Setting name is missing");
|
||||
}
|
||||
|
||||
if (!navigator.mozSettings) {
|
||||
console.warn(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
return Promise.reject(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var setting = navigator.mozSettings.createLock().get(name, defaultValue);
|
||||
setting.onsuccess = function () {
|
||||
var settingValue = setting.result[name] || defaultValue;
|
||||
resolve(settingValue);
|
||||
};
|
||||
setting.onerror = function () {
|
||||
reject(setting.error);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
SettingsHelper.set = function (settings) {
|
||||
if (!settings) {
|
||||
return Promise.reject("Settings are missing");
|
||||
}
|
||||
|
||||
if (!navigator.mozSettings) {
|
||||
console.warn(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
return Promise.reject(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var result = navigator.mozSettings.createLock().set(settings);
|
||||
result.onsuccess = function () {
|
||||
resolve(result.result);
|
||||
};
|
||||
result.onerror = function () {
|
||||
reject(result.error);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
return SettingsHelper;
|
||||
})();
|
||||
|
||||
var AchievementsService = (function () {
|
||||
var AchievementsService = function AchievementsService() {};
|
||||
|
||||
AchievementsService.prototype.reward = function (_ref) {
|
||||
var criteria = _ref.criteria;
|
||||
var evidence = _ref.evidence;
|
||||
var name = _ref.name;
|
||||
var description = _ref.description;
|
||||
var image = _ref.image;
|
||||
if (!evidence) {
|
||||
return Promise.reject("Evidence is not provided.");
|
||||
}
|
||||
|
||||
var issuedOn;
|
||||
return SettingsHelper.get("achievements", []).then(function (achievements) {
|
||||
var achievement = achievements.find(function (achievement) {
|
||||
return achievement.criteria === criteria;
|
||||
});
|
||||
|
||||
if (!achievement) {
|
||||
return Promise.reject("Achievement is not registered.");
|
||||
}
|
||||
if (achievement.evidence) {
|
||||
return Promise.reject("Achievement is already awarded.");
|
||||
}
|
||||
|
||||
achievement.evidence = evidence;
|
||||
achievement.uid = "achievement" + Math.round(Math.random() * 100000000);
|
||||
achievement.issuedOn = issuedOn = Date.now();
|
||||
achievement.recipient = {}; // TODO
|
||||
|
||||
return achievements;
|
||||
}).then(function (achievements) {
|
||||
return Promise.all([ImageHelper.generateImageDataURL(image), SettingsHelper.set({ achievements: achievements })]);
|
||||
}).then(function (_ref2) {
|
||||
var _ref3 = _toArray(_ref2);
|
||||
|
||||
var image = _ref3[0];
|
||||
// Send a Notification via WebAPI to be handled by the Gaia::System
|
||||
var notification = new Notification(name, {
|
||||
body: description,
|
||||
icon: image,
|
||||
tag: issuedOn
|
||||
});
|
||||
|
||||
notification.onclick = function () {
|
||||
var activity = new window.MozActivity({
|
||||
name: "configure",
|
||||
data: {
|
||||
target: "device",
|
||||
section: "achievements"
|
||||
}
|
||||
});
|
||||
activity.onsuccess = activity.onerror = function () {
|
||||
notification.close();
|
||||
};
|
||||
};
|
||||
})["catch"](function (reason) {
|
||||
return console.warn(reason);
|
||||
});
|
||||
};
|
||||
|
||||
return AchievementsService;
|
||||
})();
|
||||
|
||||
exports["default"] = AchievementsService;
|
||||
});
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
/* global require, console */
|
||||
|
||||
var gulp = require('gulp');
|
||||
var to5 = require('gulp-6to5');
|
||||
|
||||
/**
|
||||
* converts javascript to es5.
|
||||
*/
|
||||
gulp.task('to5', function () {
|
||||
try {
|
||||
return gulp.src('./achievements-service.js')
|
||||
.pipe(to5({ modules: 'amd' }).on('error', function(e) {
|
||||
console.log('error running 6to5', e);
|
||||
}))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
} catch(e) {
|
||||
console.log('Got error in 6to5', e);
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task('default', ['to5']);
|
||||
|
||||
/**
|
||||
* Runs travis tests
|
||||
*/
|
||||
gulp.task('travis', ['to5']);
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "fxos-dev-mode-dialog",
|
||||
"version": "0.0.3",
|
||||
"description": "Developer Mode prompt for Gaia apps.",
|
||||
"homepage": "https://github.com/fxos/fxos-dev-mode-dialog",
|
||||
"license": "MPL",
|
||||
"main": "fxos-dev-mode-dialog.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"package.json",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
var template = `<style>
|
||||
.modal-dialog {
|
||||
background: #2d2d2d;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
z-index: 100;
|
||||
}
|
||||
.modal-dialog > section {
|
||||
color: #FAFAFA;
|
||||
padding: 80px 25px 0;
|
||||
-moz-box-sizing: padding-box;
|
||||
font-size: 22px;
|
||||
line-height: 30px;
|
||||
font-weight: 300;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
overflow-y: scroll;
|
||||
max-height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.modal-dialog h1 {
|
||||
font-size: 19px;
|
||||
font-weight: 400;
|
||||
line-height: 28px;
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
padding-top: 10px;
|
||||
}
|
||||
/* Menu & buttons setup */
|
||||
.modal-dialog menu {
|
||||
padding: 15px;
|
||||
background: #4d4d4d;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.modal-dialog p {
|
||||
word-wrap: break-word;
|
||||
margin: 10px 0 0;
|
||||
padding: 10px 0;
|
||||
border-top: 0.1rem solid #686868;
|
||||
line-height: 30px;
|
||||
}
|
||||
.modal-dialog p > span {
|
||||
padding-top: 25px;
|
||||
display: block;
|
||||
}
|
||||
.modal-dialog menu button {
|
||||
font-family: sans-serif;
|
||||
font-style: italic;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin: 0 0 10px;
|
||||
padding: 0 2px;
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
-moz-box-sizing: border-box;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background: #d8d8d8;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
/* Pressed */
|
||||
.modal-dialog menu button:active {
|
||||
background: #00aacc;
|
||||
color: #fff;
|
||||
}
|
||||
.modal-dialog menu button:last-child {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<div class="modal-dialog hidden">
|
||||
<section>
|
||||
<h1>Developer Mode not enabled</h1>
|
||||
<p>To gain access to this and other customization features,
|
||||
you must enable Developer Mode.
|
||||
<span>Click Continue to go to Settings app and enable Developer Mode.</span>
|
||||
</p>
|
||||
</section>
|
||||
<menu>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="continue">Continue</button>
|
||||
</menu>
|
||||
</div>`;
|
||||
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
this.shadow = this.createShadowRoot();
|
||||
this.shadow.innerHTML = template;
|
||||
this.modalDialog = this.shadow.querySelector('.modal-dialog');
|
||||
this.cancelButton = this.shadow.querySelector('.cancel');
|
||||
this.continueButton = this.shadow.querySelector('.continue');
|
||||
|
||||
this.cancelButton.addEventListener(
|
||||
'click', this.handleCancel.bind(this));
|
||||
this.continueButton.addEventListener(
|
||||
'click', this.handleContinue.bind(this));
|
||||
|
||||
// If dev mode perf is enabled emit 'enabled' event else
|
||||
// show the confirm modal dialog
|
||||
navigator.getFeature('dom.apps.developer_mode').then(enabled => {
|
||||
if (enabled) {
|
||||
// Emit Enabled Event
|
||||
this.dispatchEvent(new CustomEvent('enabled'));
|
||||
} else {
|
||||
this.modalDialog.classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
proto.handleCancel = function(e) {
|
||||
window.close();
|
||||
};
|
||||
|
||||
proto.handleContinue = function(e) {
|
||||
// Invoke Settings activity to enable developer mode
|
||||
// XXX: Bug 1163889
|
||||
var activity = new window.MozActivity({
|
||||
name: 'configure',
|
||||
data: {
|
||||
target: 'device',
|
||||
section: 'full-developer-mode'
|
||||
}
|
||||
});
|
||||
activity.onerror = function() {
|
||||
console.log('Settings configure activity error:', activity.error.name);
|
||||
};
|
||||
};
|
||||
|
||||
try {
|
||||
document.registerElement('fxos-dev-mode-dialog', { prototype: proto });
|
||||
} catch (e) {
|
||||
if (e.name !== 'NotSupportedError') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
})(window);
|
||||
15
gaia/distros/spark/apps/customizer-launcher/components/fxos-mvc/bower.json
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "fxos-mvc",
|
||||
"version": "0.0.7",
|
||||
"homepage": "https://github.com/fxos/mvc",
|
||||
"license": "MPL",
|
||||
"main": "mvc.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"example",
|
||||
"node_modules",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
1660
gaia/distros/spark/apps/customizer-launcher/components/fxos-mvc/dist/mvc.js
vendored
Executable file
44
gaia/distros/spark/apps/customizer-launcher/components/fxos-mvc/gulpfile.js
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
var gulp = require('gulp');
|
||||
var merge = require('gulp-merge');
|
||||
var concat = require('gulp-concat');
|
||||
var wrapper = require('gulp-wrapper');
|
||||
var to5 = require('gulp-6to5');
|
||||
|
||||
/**
|
||||
* converts javascript to es5.
|
||||
*/
|
||||
gulp.task('to5', function () {
|
||||
try {
|
||||
return merge(
|
||||
gulp
|
||||
.src([
|
||||
'./node_modules/observe-shim/lib/observe-shim.js',
|
||||
'./node_modules/observe-utils/lib/observe-utils.js'
|
||||
])
|
||||
.pipe(concat('shim.js')),
|
||||
gulp
|
||||
.src([
|
||||
'./node_modules/sanitizer/sanitizer.js'
|
||||
])
|
||||
.pipe(wrapper({
|
||||
header: '(function(){var define,exports;',
|
||||
footer: '})(window);'
|
||||
}))
|
||||
.pipe(concat('deps.js')),
|
||||
gulp
|
||||
.src('./mvc.js')
|
||||
.pipe(to5({
|
||||
modules: 'amd'
|
||||
}).on('error', function(e) {
|
||||
console.log('error running 6to5', e);
|
||||
})
|
||||
)
|
||||
)
|
||||
.pipe(concat('mvc.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
} catch(e) {
|
||||
console.log('Got error in 6to5', e);
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task('default', ['to5']);
|
||||
312
gaia/distros/spark/apps/customizer-launcher/components/fxos-mvc/mvc.js
Executable file
|
|
@ -0,0 +1,312 @@
|
|||
/**
|
||||
* Model
|
||||
*/
|
||||
export class Model {
|
||||
constructor(properties) {
|
||||
properties = properties || {};
|
||||
|
||||
for (var key in properties) {
|
||||
this[key] = properties[key];
|
||||
}
|
||||
|
||||
this.observableProperties = {};
|
||||
|
||||
Object.observe(this, (changes) => {
|
||||
changes.forEach((change) => {
|
||||
var handlers = this.observableProperties[change.name];
|
||||
if (handlers) {
|
||||
handlers.forEach((handler) => {
|
||||
handler(change);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
on(property, handler) {
|
||||
if (typeof handler !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.observableProperties[property]) {
|
||||
ObserveUtils.defineObservableProperties(this, property);
|
||||
this.observableProperties[property] = [];
|
||||
}
|
||||
|
||||
this.observableProperties[property].push(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View
|
||||
*/
|
||||
var events = {};
|
||||
|
||||
export class View {
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
|
||||
for (var key in options) {
|
||||
this[key] = options[key];
|
||||
}
|
||||
|
||||
if (!this.el) {
|
||||
this.el = document.createElement('div');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an instance with the specified controller.
|
||||
*
|
||||
* @param {Controller} controller
|
||||
* @return {View}
|
||||
*/
|
||||
init(controller) {
|
||||
this.controller = controller;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the layout wrapper for the template.
|
||||
*
|
||||
* @param {Template} Inner template
|
||||
* @return {String} Rendered layout with template
|
||||
*/
|
||||
layout(template) {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the default template.
|
||||
*/
|
||||
render(params) {
|
||||
var innerHTML = '';
|
||||
|
||||
if (params) {
|
||||
if (typeof params === 'object') {
|
||||
for (var index in params) {
|
||||
var param = params[index];
|
||||
innerHTML += this.template(param);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
innerHTML += this.template(param);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
innerHTML = this.template();
|
||||
}
|
||||
|
||||
this.el.innerHTML = this.layout(innerHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to provide a function that returns the template string.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
template() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a single child element using the specified selector.
|
||||
*
|
||||
* @param {String} query
|
||||
* @return {Element | null}
|
||||
*/
|
||||
$(selector) {
|
||||
return this.el.querySelector(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all child elements using the specified selector.
|
||||
*
|
||||
* @param {String} query
|
||||
* @return {NodeList}
|
||||
*/
|
||||
$$(selector) {
|
||||
return this.el.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
on(type, selector, handler, scope) {
|
||||
var controller = this.controller;
|
||||
scope = scope || this.el;
|
||||
|
||||
if (!events[type]) {
|
||||
events[type] = [];
|
||||
window.addEventListener(type, delegateHandler, true);
|
||||
}
|
||||
|
||||
events[type].push({
|
||||
selector: selector,
|
||||
handler: handler,
|
||||
controller: controller,
|
||||
scope: scope
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
off(type, selector, handler) {
|
||||
if (!events[type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
events[type] = events[type].filter((delegate) => {
|
||||
if (typeof handler === 'function') {
|
||||
return delegate.selector !== selector ||
|
||||
delegate.handler !== handler;
|
||||
}
|
||||
|
||||
return delegate.selector !== selector;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward an event based on the target's `[data-action]` attr to the controller.
|
||||
* e.g. "click" on a `<button data-action="cancel">` goes to controller.cancel()
|
||||
*/
|
||||
function handleAction(event, controller) {
|
||||
var action = event.target.dataset.action;
|
||||
if (controller && controller[action]) {
|
||||
controller[action](event);
|
||||
}
|
||||
}
|
||||
|
||||
function delegateHandler(event) {
|
||||
var target = event.target;
|
||||
|
||||
events[event.type].forEach((delegate) => {
|
||||
if (delegate.scope.contains(target) && target.matches(delegate.selector)) {
|
||||
if (delegate.handler) {
|
||||
delegate.handler.call(target, event);
|
||||
} else {
|
||||
handleAction(event, delegate.controller);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller
|
||||
*/
|
||||
export class Controller {
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
|
||||
for (var key in options) {
|
||||
this[key] = options[key];
|
||||
}
|
||||
|
||||
// Initialize the view (if applicable) when the
|
||||
// controller is instantiated.
|
||||
if (this.view && typeof this.view.init === 'function') {
|
||||
this.view.init(this);
|
||||
}
|
||||
}
|
||||
|
||||
teardown() {
|
||||
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class RoutingController extends Controller {
|
||||
constructor(controllers) {
|
||||
if (window.routingController) {
|
||||
console.error('Document can only contain one RoutingController');
|
||||
return;
|
||||
}
|
||||
|
||||
super();
|
||||
this._controllers = controllers;
|
||||
this.activeController = null;
|
||||
window.routingController = this;
|
||||
window.addEventListener('hashchange', this.route.bind(this));
|
||||
}
|
||||
|
||||
route() {
|
||||
var route = window.location.hash.slice(1);
|
||||
var controller = this._controllers[route];
|
||||
if (controller) {
|
||||
if (this.activeController) {
|
||||
this.activeController.teardown();
|
||||
}
|
||||
|
||||
this.activeController = controller;
|
||||
controller.main();
|
||||
}
|
||||
}
|
||||
|
||||
controller(id) {
|
||||
return this._controllers[id];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Service
|
||||
*/
|
||||
export class Service {
|
||||
constructor() {
|
||||
this._listeners = {};
|
||||
this._dispatchedEvents = {};
|
||||
}
|
||||
|
||||
addEventListener(name, callback, trigger) {
|
||||
if (!this._listeners[name]) {
|
||||
this._listeners[name] = [callback];
|
||||
} else {
|
||||
this._listeners[name].push(callback);
|
||||
}
|
||||
|
||||
if (trigger && this._dispatchedEvents[name] !== undefined) {
|
||||
setTimeout(() => {
|
||||
callback(this._dispatchedEvents[name]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(name, callback) {
|
||||
if (!this._listeners[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var listenerIndex;
|
||||
this._listeners[name].find((listener, index) => {
|
||||
if (listener === callback) {
|
||||
listenerIndex = index;
|
||||
}
|
||||
|
||||
return listenerIndex !== undefined;
|
||||
});
|
||||
|
||||
if (listenerIndex !== undefined) {
|
||||
this._listeners[name].splice(listenerIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
_dispatchEvent(name, params) {
|
||||
if (!this._listeners[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatchedEvents[name] = params || null;
|
||||
|
||||
this._listeners[name].forEach((listener) => {
|
||||
listener(params);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "fxos-web-server",
|
||||
"version": "0.0.7",
|
||||
"homepage": "https://github.com/justindarc/fxos-web-server",
|
||||
"authors": [
|
||||
"Justin D'Arcangelo <justindarc@gmail.com>"
|
||||
],
|
||||
"main": "dist/fxos-web-server.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"example",
|
||||
"node_modules",
|
||||
"src",
|
||||
"test",
|
||||
"bower.json",
|
||||
"LICENSE",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
710
gaia/distros/spark/apps/customizer-launcher/components/fxos-web-server/dist/fxos-web-server.js
vendored
Executable file
|
|
@ -0,0 +1,710 @@
|
|||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.HTTPServer=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported BinaryUtils*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.BinaryUtils = (function() {
|
||||
|
||||
var BinaryUtils = {
|
||||
stringToArrayBuffer: function(string) {
|
||||
var length = (string || '').length;
|
||||
var arrayBuffer = new ArrayBuffer(length);
|
||||
var uint8Array = new Uint8Array(arrayBuffer);
|
||||
for (var i = 0; i < length; i++) {
|
||||
uint8Array[i] = string.charCodeAt(i);
|
||||
}
|
||||
|
||||
return arrayBuffer;
|
||||
},
|
||||
|
||||
arrayBufferToString: function(arrayBuffer) {
|
||||
var results = [];
|
||||
var uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
for (var i = 0, length = uint8Array.length; i < length; i += 200000) {
|
||||
results.push(String.fromCharCode.apply(null, uint8Array.subarray(i, i + 200000)));
|
||||
}
|
||||
|
||||
return results.join('');
|
||||
},
|
||||
|
||||
blobToArrayBuffer: function(blob, callback) {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
if (typeof callback === 'function') {
|
||||
callback(fileReader.result);
|
||||
}
|
||||
};
|
||||
fileReader.readAsArrayBuffer(blob);
|
||||
|
||||
return fileReader.result;
|
||||
},
|
||||
|
||||
mergeArrayBuffers: function(arrayBuffers, callback) {
|
||||
return BinaryUtils.blobToArrayBuffer(new Blob(arrayBuffers), callback);
|
||||
}
|
||||
};
|
||||
|
||||
return BinaryUtils;
|
||||
|
||||
})();
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported EventTarget*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.EventTarget = (function() {
|
||||
|
||||
function EventTarget(object) {
|
||||
if (typeof object !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var property in object) {
|
||||
this[property] = object[property];
|
||||
}
|
||||
}
|
||||
|
||||
EventTarget.prototype.constructor = EventTarget;
|
||||
|
||||
EventTarget.prototype.dispatchEvent = function(name, data) {
|
||||
var events = this._events || {};
|
||||
var listeners = events[name] || [];
|
||||
listeners.forEach((listener) => {
|
||||
listener.call(this, data);
|
||||
});
|
||||
};
|
||||
|
||||
EventTarget.prototype.addEventListener = function(name, listener) {
|
||||
var events = this._events = this._events || {};
|
||||
var listeners = events[name] = events[name] || [];
|
||||
if (listeners.find(fn => fn === listener)) {
|
||||
return;
|
||||
}
|
||||
|
||||
listeners.push(listener);
|
||||
};
|
||||
|
||||
EventTarget.prototype.removeEventListener = function(name, listener) {
|
||||
var events = this._events || {};
|
||||
var listeners = events[name] || [];
|
||||
for (var i = listeners.length - 1; i >= 0; i--) {
|
||||
if (listeners[i] === listener) {
|
||||
listeners.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return EventTarget;
|
||||
|
||||
})();
|
||||
|
||||
},{}],3:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported HTTPRequest*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.HTTPRequest = (function() {
|
||||
|
||||
var EventTarget = require('./event-target');
|
||||
var BinaryUtils = require('./binary-utils');
|
||||
|
||||
const CRLF = '\r\n';
|
||||
|
||||
function HTTPRequest(socket) {
|
||||
var parts = [];
|
||||
var receivedLength = 0;
|
||||
|
||||
var checkRequestComplete = () => {
|
||||
var contentLength = parseInt(this.headers['Content-Length'], 10);
|
||||
if (isNaN(contentLength)) {
|
||||
this.complete = true;
|
||||
this.dispatchEvent('complete', this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (receivedLength < contentLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
BinaryUtils.mergeArrayBuffers(parts, (data) => {
|
||||
this.body = parseBody(this.headers['Content-Type'], data);
|
||||
this.complete = true;
|
||||
this.dispatchEvent('complete', this);
|
||||
});
|
||||
|
||||
socket.ondata = null;
|
||||
};
|
||||
|
||||
socket.ondata = (event) => {
|
||||
var data = event.data;
|
||||
|
||||
if (parts.length > 0) {
|
||||
parts.push(data);
|
||||
receivedLength += data.byteLength;
|
||||
checkRequestComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
var firstPart = parseHeader(this, data);
|
||||
if (this.invalid) {
|
||||
this.dispatchEvent('error', this);
|
||||
|
||||
socket.close();
|
||||
socket.ondata = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPart) {
|
||||
parts.push(firstPart);
|
||||
receivedLength += firstPart.byteLength;
|
||||
}
|
||||
|
||||
checkRequestComplete();
|
||||
};
|
||||
}
|
||||
|
||||
HTTPRequest.prototype = new EventTarget();
|
||||
|
||||
HTTPRequest.prototype.constructor = HTTPRequest;
|
||||
|
||||
function parseHeader(request, data) {
|
||||
if (!data) {
|
||||
request.invalid = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
data = BinaryUtils.arrayBufferToString(data);
|
||||
|
||||
var requestParts = data.split(CRLF + CRLF);
|
||||
|
||||
var header = requestParts.shift();
|
||||
var body = requestParts.join(CRLF + CRLF);
|
||||
|
||||
var headerLines = header.split(CRLF);
|
||||
var requestLine = headerLines.shift().split(' ');
|
||||
|
||||
var method = requestLine[0];
|
||||
var uri = requestLine[1];
|
||||
var version = requestLine[2];
|
||||
|
||||
if (version !== HTTPServer.HTTP_VERSION) {
|
||||
request.invalid = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
var uriParts = uri.split('?');
|
||||
|
||||
var path = uriParts.shift();
|
||||
var params = parseURLEncodedString(uriParts.join('?'));
|
||||
|
||||
var headers = {};
|
||||
headerLines.forEach((headerLine) => {
|
||||
var parts = headerLine.split(': ');
|
||||
if (parts.length !== 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = parts[0];
|
||||
var value = parts[1];
|
||||
|
||||
headers[name] = value;
|
||||
});
|
||||
|
||||
request.method = method;
|
||||
request.path = path;
|
||||
request.params = params;
|
||||
request.headers = headers;
|
||||
|
||||
if (headers['Content-Length']) {
|
||||
// request.body = parseBody(headers['Content-Type'], body);
|
||||
return BinaryUtils.stringToArrayBuffer(body);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function setOrAppendValue(object, name, value) {
|
||||
var existingValue = object[name];
|
||||
if (existingValue === undefined) {
|
||||
object[name] = value;
|
||||
} else {
|
||||
if (Array.isArray(existingValue)) {
|
||||
existingValue.push(value);
|
||||
} else {
|
||||
object[name] = [existingValue, value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseURLEncodedString(string) {
|
||||
var values = {};
|
||||
|
||||
string.split('&').forEach((pair) => {
|
||||
if (!pair) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parts = decodeURIComponent(pair).split('=');
|
||||
|
||||
var name = parts.shift();
|
||||
var value = parts.join('=');
|
||||
|
||||
setOrAppendValue(values, name, value);
|
||||
});
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
function parseMultipartFormDataString(string, boundary) {
|
||||
var values = {};
|
||||
|
||||
string.split('--' + boundary).forEach((data) => {
|
||||
data = data.replace(/^\r\n/, '').replace(/\r\n$/, '');
|
||||
|
||||
if (!data || data === '--') {
|
||||
return;
|
||||
}
|
||||
|
||||
var parts = data.split(CRLF + CRLF);
|
||||
|
||||
var header = parts.shift();
|
||||
var value = {
|
||||
headers: {},
|
||||
metadata: {},
|
||||
value: parts.join(CRLF + CRLF)
|
||||
};
|
||||
|
||||
var name;
|
||||
|
||||
var headers = header.split(CRLF);
|
||||
headers.forEach((header) => {
|
||||
var headerParams = header.split(';');
|
||||
var headerParts = headerParams.shift().split(': ');
|
||||
|
||||
var headerName = headerParts[0];
|
||||
var headerValue = headerParts[1];
|
||||
|
||||
if (headerName !== 'Content-Disposition' ||
|
||||
headerValue !== 'form-data') {
|
||||
value.headers[headerName] = headerValue;
|
||||
return;
|
||||
}
|
||||
|
||||
headerParams.forEach((param) => {
|
||||
var paramParts = param.trim().split('=');
|
||||
|
||||
var paramName = paramParts[0];
|
||||
var paramValue = paramParts[1];
|
||||
|
||||
paramValue = paramValue.replace(/\"(.*?)\"/, '$1') || paramValue;
|
||||
|
||||
if (paramName === 'name') {
|
||||
name = paramValue;
|
||||
}
|
||||
|
||||
else {
|
||||
value.metadata[paramName] = paramValue;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (name) {
|
||||
setOrAppendValue(values, name, value);
|
||||
}
|
||||
});
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
function parseBody(contentType, data) {
|
||||
contentType = contentType || 'text/plain';
|
||||
|
||||
var contentTypeParams = contentType.replace(/\s/g, '').split(';');
|
||||
var mimeType = contentTypeParams.shift();
|
||||
|
||||
var body = BinaryUtils.arrayBufferToString(data);
|
||||
|
||||
var result;
|
||||
|
||||
try {
|
||||
switch (mimeType) {
|
||||
case 'application/x-www-form-urlencoded':
|
||||
result = parseURLEncodedString(body);
|
||||
break;
|
||||
case 'multipart/form-data':
|
||||
contentTypeParams.forEach((contentTypeParam) => {
|
||||
var parts = contentTypeParam.split('=');
|
||||
|
||||
var name = parts[0];
|
||||
var value = parts[1];
|
||||
|
||||
if (name === 'boundary') {
|
||||
result = parseMultipartFormDataString(body, value);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'application/json':
|
||||
result = JSON.parse(body);
|
||||
break;
|
||||
case 'application/xml':
|
||||
result = new DOMParser().parseFromString(body, 'text/xml');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (exception) {
|
||||
console.log('Unable to parse HTTP request body with Content-Type: ' + contentType);
|
||||
}
|
||||
|
||||
return result || body;
|
||||
}
|
||||
|
||||
return HTTPRequest;
|
||||
|
||||
})();
|
||||
|
||||
},{"./binary-utils":1,"./event-target":2}],4:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported HTTPResponse*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.HTTPResponse = (function() {
|
||||
|
||||
var EventTarget = require('./event-target');
|
||||
var BinaryUtils = require('./binary-utils');
|
||||
var HTTPStatus = require('./http-status');
|
||||
|
||||
const CRLF = '\r\n';
|
||||
const BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
function HTTPResponse(socket, timeout) {
|
||||
this.socket = socket;
|
||||
this.timeout = timeout;
|
||||
|
||||
this.headers = {};
|
||||
this.headers['Content-Type'] = 'text/html';
|
||||
this.headers['Connection'] = 'close';
|
||||
|
||||
if (this.timeout) {
|
||||
this.timeoutHandler = setTimeout(() => {
|
||||
this.send(null, 500);
|
||||
}, this.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
HTTPResponse.prototype = new EventTarget();
|
||||
|
||||
HTTPResponse.prototype.constructor = HTTPResponse;
|
||||
|
||||
HTTPResponse.prototype.send = function(body, status) {
|
||||
return createResponse(body, status, this.headers, (response) => {
|
||||
var offset = 0;
|
||||
var remaining = response.byteLength;
|
||||
|
||||
var sendNextPart = () => {
|
||||
var length = Math.min(remaining, BUFFER_SIZE);
|
||||
|
||||
var bufferFull = this.socket.send(response, offset, length);
|
||||
|
||||
offset += length;
|
||||
remaining -= length;
|
||||
|
||||
if (remaining > 0) {
|
||||
if (!bufferFull) {
|
||||
sendNextPart();
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
clearTimeout(this.timeoutHandler);
|
||||
|
||||
this.socket.close();
|
||||
this.dispatchEvent('complete');
|
||||
}
|
||||
};
|
||||
|
||||
this.socket.ondrain = sendNextPart;
|
||||
|
||||
sendNextPart();
|
||||
});
|
||||
};
|
||||
|
||||
HTTPResponse.prototype.sendFile = function(fileOrPath, status) {
|
||||
if (fileOrPath instanceof File) {
|
||||
BinaryUtils.blobToArrayBuffer(fileOrPath, (arrayBuffer) => {
|
||||
this.send(arrayBuffer, status);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', fileOrPath, true);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onload = () => {
|
||||
this.send(xhr.response, status);
|
||||
};
|
||||
|
||||
xhr.send(null);
|
||||
};
|
||||
|
||||
function createResponseHeader(status, headers) {
|
||||
var header = HTTPStatus.getStatusLine(status);
|
||||
|
||||
for (var name in headers) {
|
||||
header += name + ': ' + headers[name] + CRLF;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
function createResponse(body, status, headers, callback) {
|
||||
body = body || '';
|
||||
status = status || 200;
|
||||
headers = headers || {};
|
||||
|
||||
headers['Content-Length'] = body.length || body.byteLength;
|
||||
|
||||
var response = new Blob([
|
||||
createResponseHeader(status, headers),
|
||||
CRLF,
|
||||
body
|
||||
]);
|
||||
|
||||
return BinaryUtils.blobToArrayBuffer(response, callback);
|
||||
}
|
||||
|
||||
return HTTPResponse;
|
||||
|
||||
})();
|
||||
|
||||
},{"./binary-utils":1,"./event-target":2,"./http-status":6}],5:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported HTTPServer*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.HTTPServer = (function() {
|
||||
|
||||
var EventTarget = require('./event-target');
|
||||
var HTTPRequest = require('./http-request');
|
||||
var HTTPResponse = require('./http-response');
|
||||
var IPUtils = require('./ip-utils');
|
||||
|
||||
const DEFAULT_PORT = 8080;
|
||||
const DEFAULT_TIMEOUT = 20000;
|
||||
|
||||
const CRLF = '\r\n';
|
||||
|
||||
function HTTPServer(port, options) {
|
||||
this.port = port || DEFAULT_PORT;
|
||||
|
||||
options = options || {};
|
||||
for (var option in options) {
|
||||
this[option] = options[option];
|
||||
}
|
||||
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
HTTPServer.HTTP_VERSION = 'HTTP/1.1';
|
||||
|
||||
HTTPServer.prototype = new EventTarget();
|
||||
|
||||
HTTPServer.prototype.constructor = HTTPServer;
|
||||
|
||||
HTTPServer.prototype.timeout = DEFAULT_TIMEOUT;
|
||||
|
||||
HTTPServer.prototype.start = function() {
|
||||
if (this.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Starting HTTP server on port ' + this.port);
|
||||
|
||||
var socket = navigator.mozTCPSocket.listen(this.port, {
|
||||
binaryType: 'arraybuffer'
|
||||
});
|
||||
|
||||
socket.onconnect = (connectEvent) => {
|
||||
var request = new HTTPRequest(connectEvent);
|
||||
|
||||
request.addEventListener('complete', () => {
|
||||
var response = new HTTPResponse(connectEvent, this.timeout);
|
||||
|
||||
this.dispatchEvent('request', {
|
||||
request: request,
|
||||
response: response
|
||||
});
|
||||
});
|
||||
|
||||
request.addEventListener('error', () => {
|
||||
console.warn('Invalid request received');
|
||||
});
|
||||
};
|
||||
|
||||
this.socket = socket;
|
||||
this.running = true;
|
||||
};
|
||||
|
||||
HTTPServer.prototype.stop = function() {
|
||||
if (!this.running) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Shutting down HTTP server on port ' + this.port);
|
||||
|
||||
this.socket.close();
|
||||
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
return HTTPServer;
|
||||
|
||||
})();
|
||||
|
||||
},{"./event-target":2,"./http-request":3,"./http-response":4,"./ip-utils":7}],6:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported HTTPStatus*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.HTTPStatus = (function() {
|
||||
|
||||
const CRLF = '\r\n';
|
||||
|
||||
var HTTPStatus = {};
|
||||
|
||||
HTTPStatus.STATUS_CODES = {
|
||||
100: 'Continue',
|
||||
101: 'Switching Protocols',
|
||||
102: 'Processing',
|
||||
200: 'OK',
|
||||
201: 'Created',
|
||||
202: 'Accepted',
|
||||
203: 'Non Authoritative Information',
|
||||
204: 'No Content',
|
||||
205: 'Reset Content',
|
||||
206: 'Partial Content',
|
||||
207: 'Multi-Status',
|
||||
300: 'Mutliple Choices',
|
||||
301: 'Moved Permanently',
|
||||
302: 'Moved Temporarily',
|
||||
303: 'See Other',
|
||||
304: 'Not Modified',
|
||||
305: 'Use Proxy',
|
||||
307: 'Temporary Redirect',
|
||||
400: 'Bad Request',
|
||||
401: 'Unauthorized',
|
||||
402: 'Payment Required',
|
||||
403: 'Forbidden',
|
||||
404: 'Not Found',
|
||||
405: 'Method Not Allowed',
|
||||
406: 'Not Acceptable',
|
||||
407: 'Proxy Authentication Required',
|
||||
408: 'Request Timeout',
|
||||
409: 'Conflict',
|
||||
410: 'Gone',
|
||||
411: 'Length Required',
|
||||
412: 'Precondition Failed',
|
||||
413: 'Request Entity Too Large',
|
||||
414: 'Request-URI Too Long',
|
||||
415: 'Unsupported Media Type',
|
||||
416: 'Requested Range Not Satisfiable',
|
||||
417: 'Expectation Failed',
|
||||
419: 'Insufficient Space on Resource',
|
||||
420: 'Method Failure',
|
||||
422: 'Unprocessable Entity',
|
||||
423: 'Locked',
|
||||
424: 'Failed Dependency',
|
||||
500: 'Server Error',
|
||||
501: 'Not Implemented',
|
||||
502: 'Bad Gateway',
|
||||
503: 'Service Unavailable',
|
||||
504: 'Gateway Timeout',
|
||||
505: 'HTTP Version Not Supported',
|
||||
507: 'Insufficient Storage'
|
||||
};
|
||||
|
||||
HTTPStatus.getStatusLine = function(status) {
|
||||
var reason = HTTPStatus.STATUS_CODES[status] || 'Unknown';
|
||||
|
||||
return [HTTPServer.HTTP_VERSION, status, reason].join(' ') + CRLF;
|
||||
};
|
||||
|
||||
return HTTPStatus;
|
||||
|
||||
})();
|
||||
|
||||
},{}],7:[function(require,module,exports){
|
||||
/*jshint esnext:true*/
|
||||
/*exported IPUtils*/
|
||||
'use strict';
|
||||
|
||||
module.exports = window.IPUtils = (function() {
|
||||
|
||||
const CRLF = '\r\n';
|
||||
|
||||
var IPUtils = {
|
||||
getAddresses: function(callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
console.warn('No callback provided');
|
||||
return;
|
||||
}
|
||||
|
||||
var addresses = {
|
||||
'0.0.0.0': true
|
||||
};
|
||||
|
||||
var rtc = new mozRTCPeerConnection({ iceServers: [] });
|
||||
rtc.createDataChannel('', { reliable: false });
|
||||
|
||||
rtc.onicecandidate = function(evt) {
|
||||
if (evt.candidate) {
|
||||
parseSDP('a=' + evt.candidate.candidate);
|
||||
}
|
||||
};
|
||||
|
||||
rtc.createOffer((description) => {
|
||||
parseSDP(description.sdp);
|
||||
rtc.setLocalDescription(description, noop, noop);
|
||||
}, (error) => {
|
||||
console.warn('Unable to create offer', error);
|
||||
});
|
||||
|
||||
function addAddress(address) {
|
||||
if (addresses[address]) {
|
||||
return;
|
||||
}
|
||||
|
||||
addresses[address] = true;
|
||||
callback(address);
|
||||
}
|
||||
|
||||
function parseSDP(sdp) {
|
||||
sdp.split(CRLF).forEach((line) => {
|
||||
var parts = line.split(' ');
|
||||
|
||||
if (line.indexOf('a=candidate') !== -1) {
|
||||
if (parts[7] === 'host') {
|
||||
addAddress(parts[4]);
|
||||
}
|
||||
}
|
||||
|
||||
else if (line.indexOf('c=') !== -1) {
|
||||
addAddress(parts[2]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function noop() {}
|
||||
|
||||
return IPUtils;
|
||||
|
||||
})();
|
||||
|
||||
},{}]},{},[5])(5)
|
||||
});
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-button",
|
||||
"version": "0.0.3",
|
||||
"main": "gaia-button.js",
|
||||
"homepage": "https://github.com/gaia-components/gaia-button",
|
||||
"authors": [
|
||||
"cyee@mozilla.com"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.7.1",
|
||||
"base": "gaia-components/base",
|
||||
"gaia-theme": "gaia-components/gaia-theme#~0.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-button', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
content: this.shadowRoot.querySelector('.content')
|
||||
};
|
||||
|
||||
this.circular = this.hasAttribute('circular');
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.setAttribute('role', 'button');
|
||||
this.tabIndex = 0;
|
||||
},
|
||||
|
||||
attrs: {
|
||||
circular: {
|
||||
get: function() { this.getAttribute('circular'); },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
if (value) {
|
||||
this.setAttribute('circular', '');
|
||||
this.els.inner.setAttribute('circular', '');
|
||||
} else {
|
||||
this.removeAttribute('circular');
|
||||
this.els.inner.removeAttribute('circular');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { this.getAttribute('disabled'); },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
if (value) {
|
||||
this.setAttribute('disabled', '');
|
||||
this.els.inner.setAttribute('disabled', '');
|
||||
} else {
|
||||
this.removeAttribute('disabled');
|
||||
this.els.inner.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<div class="background"></div>
|
||||
<div class="content"><content></content></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
height: 50px;
|
||||
min-width: 50%;
|
||||
margin: var(--base-m, 18px);
|
||||
outline: 0;
|
||||
font-style: italic;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
@media(min-width:500px) {
|
||||
:host { min-width: 140px; }
|
||||
}
|
||||
|
||||
:host([circular]) {
|
||||
width: 50px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
border-radius: 50px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
line-height: 1;
|
||||
transition: color 0ms 300ms;
|
||||
|
||||
background:
|
||||
var(--button-background,
|
||||
var(--input-background,
|
||||
var(--background-plus,
|
||||
#fff)));
|
||||
|
||||
color:
|
||||
var(--button-color,
|
||||
var(--text-color,
|
||||
inherit));
|
||||
|
||||
box-shadow:
|
||||
var(--button-box-shadow,
|
||||
var(--box-shadow,
|
||||
none));
|
||||
}
|
||||
|
||||
/**
|
||||
* [circular]
|
||||
*/
|
||||
|
||||
.inner[circular] {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/**
|
||||
* .pressed
|
||||
*/
|
||||
|
||||
.inner:active {
|
||||
transition: none;
|
||||
color: var(--button-color-active, #fff);
|
||||
box-shadow: var(--button-box-shadow-active, none);
|
||||
}
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.background {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
|
||||
transition: opacity 500ms 200ms;
|
||||
|
||||
background:
|
||||
var(--button-background-active,
|
||||
var(--highlight-color,
|
||||
#333));
|
||||
}
|
||||
|
||||
:active .background {
|
||||
transition: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.released .background {
|
||||
transition: opacity 500ms;
|
||||
}
|
||||
|
||||
i:before {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
::content i {
|
||||
margin-left: -2px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
::content i + span,
|
||||
::content span + i {
|
||||
-moz-margin-start: 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Content
|
||||
---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* 1. In some cases events seems to be getting
|
||||
* swallowed by text-nodes. Ignoring pointer-
|
||||
* events means we can listen on parent nodes
|
||||
* instead.
|
||||
*/
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: 100%;
|
||||
padding: 0 18px;
|
||||
pointer-events: none; /* 1 */
|
||||
}
|
||||
|
||||
[circular] .content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-button',this));
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-button></title>
|
||||
<meta name="description" content="gaia-text-input demo" />
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/gaia-icons.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="gaia-button.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding-top: 48px;
|
||||
background-color: var(--background);
|
||||
}
|
||||
/*
|
||||
[data-icon=back-light] {
|
||||
margin-left: -9px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
[data-icon=forward-light] {
|
||||
margin-left: 10px;
|
||||
margin-right: -9px;
|
||||
}*/
|
||||
|
||||
[flex] {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body role="application" class="l-align-center">
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
<h1 class="large l-align-center l-mb-mega"><gaia-button></h1>
|
||||
|
||||
<section>
|
||||
<gaia-button>Gaia button 1</gaia-button>
|
||||
<gaia-button disabled>Gaia button 1</gaia-button>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
|
||||
<section>
|
||||
<gaia-button><i data-icon="back-light"></i><span>Back</span></gaia-button>
|
||||
<gaia-button><span>Forward</span><i data-icon="forward-light"></i></gaia-button>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
|
||||
<section flex>
|
||||
<gaia-button circular><i data-icon="camera"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="bug"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="video"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="camera"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="reload"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="airplane"></i></gaia-button>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "gaia-component",
|
||||
"version": "0.3.8",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-component.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"README.md",
|
||||
"package.json",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,420 @@
|
|||
/* globals define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
var textContent = Object.getOwnPropertyDescriptor(Node.prototype,
|
||||
'textContent');
|
||||
var innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
|
||||
var removeAttribute = Element.prototype.removeAttribute;
|
||||
var setAttribute = Element.prototype.setAttribute;
|
||||
var noop = function() {};
|
||||
|
||||
/**
|
||||
* Register a new component.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} props
|
||||
* @return {constructor}
|
||||
* @public
|
||||
*/
|
||||
exports.register = function(name, props) {
|
||||
var baseProto = getBaseProto(props.extends);
|
||||
var template = props.template || baseProto.templateString;
|
||||
|
||||
// Components are extensible by default but can be declared
|
||||
// as non extensible as an optimization to avoid
|
||||
// storing the template strings
|
||||
var extensible = props.extensible = props.hasOwnProperty('extensible')?
|
||||
props.extensible : true;
|
||||
|
||||
// Clean up
|
||||
delete props.extends;
|
||||
|
||||
// Pull out CSS that needs to be in the light-dom
|
||||
if (template) {
|
||||
// Stores the string to be reprocessed when
|
||||
// a new component extends this one
|
||||
if (extensible && props.template) {
|
||||
props.templateString = props.template;
|
||||
}
|
||||
|
||||
var output = processCss(template, name);
|
||||
|
||||
props.template = document.createElement('template');
|
||||
props.template.innerHTML = output.template;
|
||||
props.lightCss = output.lightCss;
|
||||
|
||||
props.globalCss = props.globalCss || '';
|
||||
props.globalCss += output.globalCss;
|
||||
}
|
||||
|
||||
// Inject global CSS into the document,
|
||||
// and delete as no longer needed
|
||||
injectGlobalCss(props.globalCss);
|
||||
delete props.globalCss;
|
||||
|
||||
// Merge base getter/setter attributes with the user's,
|
||||
// then define the property descriptors on the prototype.
|
||||
var descriptors = mixin(props.attrs || {}, base.descriptors);
|
||||
|
||||
// Store the orginal descriptors somewhere
|
||||
// a little more private and delete the original
|
||||
props._attrs = props.attrs;
|
||||
delete props.attrs;
|
||||
|
||||
// Create the prototype, extended from base and
|
||||
// define the descriptors directly on the prototype
|
||||
var proto = createProto(baseProto, props);
|
||||
Object.defineProperties(proto, descriptors);
|
||||
|
||||
// Register the custom-element and return the constructor
|
||||
try {
|
||||
return document.registerElement(name, { prototype: proto });
|
||||
} catch (e) {
|
||||
if (e.name !== 'NotSupportedError') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var base = {
|
||||
properties: {
|
||||
GaiaComponent: true,
|
||||
attributeChanged: noop,
|
||||
attached: noop,
|
||||
detached: noop,
|
||||
created: noop,
|
||||
|
||||
createdCallback: function() {
|
||||
if (this.rtl) { addDirObserver(); }
|
||||
injectLightCss(this);
|
||||
this.created();
|
||||
},
|
||||
|
||||
/**
|
||||
* It is very common to want to keep object
|
||||
* properties in-sync with attributes,
|
||||
* for example:
|
||||
*
|
||||
* el.value = 'foo';
|
||||
* el.setAttribute('value', 'foo');
|
||||
*
|
||||
* So we support an object on the prototype
|
||||
* named 'attrs' to provide a consistent
|
||||
* way for component authors to define
|
||||
* these properties. When an attribute
|
||||
* changes we keep the attr[name]
|
||||
* up-to-date.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String||null} from
|
||||
* @param {String||null} to
|
||||
*/
|
||||
attributeChangedCallback: function(name, from, to) {
|
||||
var prop = toCamelCase(name);
|
||||
if (this._attrs && this._attrs[prop]) { this[prop] = to; }
|
||||
this.attributeChanged(name, from, to);
|
||||
},
|
||||
|
||||
attachedCallback: function() { this.attached(); },
|
||||
detachedCallback: function() { this.detached(); },
|
||||
|
||||
/**
|
||||
* A convenient method for setting up
|
||||
* a shadow-root using the defined template.
|
||||
*
|
||||
* @return {ShadowRoot}
|
||||
*/
|
||||
setupShadowRoot: function() {
|
||||
if (!this.template) { return; }
|
||||
var node = document.importNode(this.template.content, true);
|
||||
this.createShadowRoot().appendChild(node);
|
||||
return this.shadowRoot;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
setAttr: function(name, value) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
setAttribute.call(internal, name, value);
|
||||
setAttribute.call(this, name, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
removeAttr: function(name) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
removeAttribute.call(internal, name);
|
||||
removeAttribute.call(this, name);
|
||||
}
|
||||
},
|
||||
|
||||
descriptors: {
|
||||
textContent: {
|
||||
set: function(value) {
|
||||
textContent.set.call(this, value);
|
||||
if (this.lightStyle) { this.appendChild(this.lightStyle); }
|
||||
},
|
||||
|
||||
get: function() {
|
||||
return textContent.get();
|
||||
}
|
||||
},
|
||||
|
||||
innerHTML: {
|
||||
set: function(value) {
|
||||
innerHTML.set.call(this, value);
|
||||
if (this.lightStyle) { this.appendChild(this.lightStyle); }
|
||||
},
|
||||
|
||||
get: innerHTML.get
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The default base prototype to use
|
||||
* when `extends` is undefined.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var defaultPrototype = createProto(HTMLElement.prototype, base.properties);
|
||||
|
||||
/**
|
||||
* Returns a suitable prototype based
|
||||
* on the object passed.
|
||||
*
|
||||
* @private
|
||||
* @param {HTMLElementPrototype|undefined} proto
|
||||
* @return {HTMLElementPrototype}
|
||||
*/
|
||||
function getBaseProto(proto) {
|
||||
if (!proto) { return defaultPrototype; }
|
||||
proto = proto.prototype || proto;
|
||||
return !proto.GaiaComponent ?
|
||||
createProto(proto, base.properties) : proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the given proto and mixes
|
||||
* in the given properties.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} proto
|
||||
* @param {Object} props
|
||||
* @return {Object}
|
||||
*/
|
||||
function createProto(proto, props) {
|
||||
return mixin(Object.create(proto), props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects presence of shadow-dom
|
||||
* CSS selectors.
|
||||
*
|
||||
* @private
|
||||
* @return {Boolean}
|
||||
*/
|
||||
var hasShadowCSS = (function() {
|
||||
var div = document.createElement('div');
|
||||
try { div.querySelector(':host'); div.querySelector('::content'); return true; }
|
||||
catch (e) { return false; }
|
||||
})();
|
||||
|
||||
/**
|
||||
* Regexs used to extract shadow-css
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var regex = {
|
||||
shadowCss: /(?:\:host|\:\:content)[^{]*\{[^}]*\}/g,
|
||||
':host': /(?:\:host)/g,
|
||||
':host()': /\:host\((.+)\)(?: \:\:content)?/g,
|
||||
':host-context': /\:host-context\((.+)\)([^{,]+)?/g,
|
||||
'::content': /(?:\:\:content)/g
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the :host and ::content rules
|
||||
* from the shadow-dom CSS and rewrites
|
||||
* them to work from the <style scoped>
|
||||
* injected at the root of the component.
|
||||
*
|
||||
* @private
|
||||
* @return {String}
|
||||
*/
|
||||
function processCss(template, name) {
|
||||
var globalCss = '';
|
||||
var lightCss = '';
|
||||
|
||||
if (!hasShadowCSS) {
|
||||
template = template.replace(regex.shadowCss, function(match) {
|
||||
var hostContext = regex[':host-context'].exec(match);
|
||||
|
||||
if (hostContext) {
|
||||
globalCss += match
|
||||
.replace(regex['::content'], '')
|
||||
.replace(regex[':host-context'], '$1 ' + name + '$2')
|
||||
.replace(/ +/g, ' '); // excess whitespace
|
||||
} else {
|
||||
lightCss += match
|
||||
.replace(regex[':host()'], name + '$1')
|
||||
.replace(regex[':host'], name)
|
||||
.replace(regex['::content'], name);
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
template: template,
|
||||
lightCss: lightCss,
|
||||
globalCss: globalCss
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Some CSS rules, such as @keyframes
|
||||
* and @font-face don't work inside
|
||||
* scoped or shadow <style>. So we
|
||||
* have to put them into 'global'
|
||||
* <style> in the head of the
|
||||
* document.
|
||||
*
|
||||
* @private
|
||||
* @param {String} css
|
||||
*/
|
||||
function injectGlobalCss(css) {
|
||||
if (!css) {return;}
|
||||
var style = document.createElement('style');
|
||||
style.innerHTML = css.trim();
|
||||
headReady().then(function() {
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves a promise once document.head is ready.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function headReady() {
|
||||
return new Promise(function(resolve) {
|
||||
if (document.head) { return resolve(); }
|
||||
window.addEventListener('load', function fn() {
|
||||
window.removeEventListener('load', fn);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The Gecko platform doesn't yet have
|
||||
* `::content` or `:host`, selectors,
|
||||
* without these we are unable to style
|
||||
* user-content in the light-dom from
|
||||
* within our shadow-dom style-sheet.
|
||||
*
|
||||
* To workaround this, we clone the <style>
|
||||
* node into the root of the component,
|
||||
* so our selectors are able to target
|
||||
* light-dom content.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function injectLightCss(el) {
|
||||
if (hasShadowCSS) { return; }
|
||||
el.lightStyle = document.createElement('style');
|
||||
el.lightStyle.setAttribute('scoped', '');
|
||||
el.lightStyle.innerHTML = el.lightCss;
|
||||
el.appendChild(el.lightStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hyphen separated
|
||||
* string to camel-case.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* toCamelCase('foo-bar'); //=> 'fooBar'
|
||||
*
|
||||
* @private
|
||||
* @param {Sring} string
|
||||
* @return {String}
|
||||
*/
|
||||
function toCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function replacer(string, p1) {
|
||||
return p1.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer (singleton)
|
||||
*
|
||||
* @type {MutationObserver|undefined}
|
||||
*/
|
||||
var dirObserver;
|
||||
|
||||
/**
|
||||
* Observes the document `dir` (direction)
|
||||
* attribute and dispatches a global event
|
||||
* when it changes.
|
||||
*
|
||||
* Components can listen to this event and
|
||||
* make internal changes if need be.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addDirObserver() {
|
||||
if (dirObserver) { return; }
|
||||
|
||||
dirObserver = new MutationObserver(onChanged);
|
||||
dirObserver.observe(document.documentElement, {
|
||||
attributeFilter: ['dir'],
|
||||
attributes: true
|
||||
});
|
||||
|
||||
function onChanged(mutations) {
|
||||
document.dispatchEvent(new Event('dirchanged'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the values of all properties from
|
||||
* source object `target` to a target object `source`.
|
||||
* It will return the target object.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} target
|
||||
* @param {Object} source
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mixin(target, source) {
|
||||
for (var key in source) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-component',this));
|
||||
16
gaia/distros/spark/apps/customizer-launcher/components/gaia-fonts/bower.json
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "gaia-fonts",
|
||||
"version": "0.2.1",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "style.css",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
54
gaia/distros/spark/apps/customizer-launcher/components/gaia-fonts/style.css
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Light.woff") format("woff");
|
||||
font-weight: 300; /* lighter */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-LightItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 300; /* lighter */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: normal; /* 400 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-RegularItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: normal; /* 400 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Medium.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: bold; /* 700 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-MediumItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: bold; /* 700 */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-Bold.woff") format("woff");
|
||||
font-weight: 800; /* bolder */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FiraSans";
|
||||
src: url("fonts/FiraSans-BoldItalic.woff") format("woff");
|
||||
font-style: italic;
|
||||
font-weight: 800; /* bolder */
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "gaia-header",
|
||||
"version": "0.8.1",
|
||||
"homepage": "https://github.com/gaia-components/gaia-header",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-header.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"index.html",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.7.11",
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.0",
|
||||
"font-fit": "gaia-components/font-fit#~0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gaia-theme": "gaia-components/gaia-theme",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"base": "gaia-components/base"
|
||||
}
|
||||
}
|
||||
1580
gaia/distros/spark/apps/customizer-launcher/components/gaia-header/dist/gaia-header.js
vendored
Executable file
1015
gaia/distros/spark/apps/customizer-launcher/components/gaia-header/gaia-header.js
Executable file
118
gaia/distros/spark/apps/customizer-launcher/components/gaia-icons/bin/report.js
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
// Create a report about unused icons in a project.
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
var optimist = require('optimist');
|
||||
|
||||
var cli = optimist
|
||||
.usage('Create a report about unused icons in a project.' + '\n' +
|
||||
'Usage: $0 path/to/your/project/');
|
||||
var projectDir = cli.argv._[0];
|
||||
|
||||
// No folder passed? Show help message then.
|
||||
if (!projectDir) {
|
||||
cli.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check if the directory exist.
|
||||
var stats = fs.lstatSync(projectDir);
|
||||
if (!stats.isDirectory()) {
|
||||
console.log('\x1b[31mPlease provide a valid folder.\x1b[0m\n');
|
||||
cli.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all the icons in the font.
|
||||
* @returns {Array}
|
||||
*/
|
||||
function getIcons() {
|
||||
var icons = fs.readdirSync('./images/');
|
||||
|
||||
icons = icons.map(function(icon) {
|
||||
return path.basename(icon, '.svg');
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a grep pattern to extract used icons from files.
|
||||
* @param {string} grep
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function getUsedIcons(grep, callback) {
|
||||
exec(grep, function(err, stdout, stderr) {
|
||||
var usedIcons = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(function(icon) {
|
||||
// Take only the icon name.
|
||||
return icon.split(/["']/)[1];
|
||||
})
|
||||
.filter(function(icon) {
|
||||
// Remove non string items.
|
||||
return icon && icon.match(/^[a-z0-9-]+$/);
|
||||
});
|
||||
|
||||
callback(usedIcons);
|
||||
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of unused icons in a folder. The patterns of extraction are:
|
||||
* * data-icon="[^"]+"
|
||||
* * .dataset.icon ?= ?.+
|
||||
*/
|
||||
function getUnusedIcons() {
|
||||
var usedIcons = [];
|
||||
var length = 2;
|
||||
|
||||
var cb = function(icons) {
|
||||
usedIcons = usedIcons.concat(icons);
|
||||
length--;
|
||||
|
||||
if (length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var allIcons = getIcons();
|
||||
var unusedIcons = [];
|
||||
|
||||
allIcons.forEach(function(icon) {
|
||||
if (usedIcons.indexOf(icon) === -1) {
|
||||
unusedIcons.push(icon);
|
||||
}
|
||||
});
|
||||
|
||||
outputUnusedIcons(allIcons, unusedIcons);
|
||||
};
|
||||
|
||||
getUsedIcons('grep -rhoP \'data-icon="[^"]+"\' ' + projectDir, cb);
|
||||
getUsedIcons('grep -rhoP \'.dataset.icon ?= ?.+\' ' + projectDir, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of unused icons to the screen.
|
||||
* @param {Array.<string>} icons
|
||||
* @param {Array.<string>} unusedIcons
|
||||
*/
|
||||
function outputUnusedIcons(icons, unusedIcons) {
|
||||
console.log('\x1b[36mList of unused icons in %s (%d/%d):\x1b[0m',
|
||||
projectDir, unusedIcons.length, icons.length);
|
||||
|
||||
unusedIcons.forEach(function(icon) {
|
||||
console.log('* ' + icon);
|
||||
});
|
||||
}
|
||||
|
||||
getUnusedIcons();
|
||||
30
gaia/distros/spark/apps/customizer-launcher/components/gaia-icons/bower.json
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "gaia-icons",
|
||||
"version": "0.7.12",
|
||||
"homepage": "https://github.com/wilsonpage/gaia-icons",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": [
|
||||
"gaia-icons.js",
|
||||
"gaia-icons.css",
|
||||
"fonts/gaia-icons.ttf",
|
||||
"gaia-icons-embedded.css"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"templates",
|
||||
"images",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"create-svg-icon-set-file.py",
|
||||
"Gruntfile.js",
|
||||
"README.md",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
|
|
@ -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: "gaia-icons";
|
||||
src: url("fonts/gaia-icons.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
[data-icon]:before,
|
||||
.ligature-icons {
|
||||
font-family: "gaia-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;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint laxbreak:true*/
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
var base = window.GAIA_ICONS_BASE_URL
|
||||
|| window.COMPONENTS_BASE_URL
|
||||
|| 'bower_components/';
|
||||
|
||||
if (!document.documentElement) {
|
||||
window.addEventListener('load', load);
|
||||
} else {
|
||||
load();
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (isLoaded()) { return; }
|
||||
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = base + 'gaia-icons/gaia-icons.css';
|
||||
document.head.appendChild(link);
|
||||
exports.loaded = true;
|
||||
}
|
||||
|
||||
function isLoaded() {
|
||||
return exports.loaded ||
|
||||
document.querySelector('link[href*=gaia-icons]') ||
|
||||
document.documentElement.classList.contains('gaia-icons-loaded');
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-icons',this));
|
||||
26
gaia/distros/spark/apps/customizer-launcher/components/gaia-list/bower.json
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-list",
|
||||
"version": "0.1.7",
|
||||
"homepage": "https://github.com/gaia-components/gaia-list",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-list.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-theme": "gaia-components/gaia-theme#dev",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.0",
|
||||
"base": "gaia-components/base"
|
||||
}
|
||||
}
|
||||
311
gaia/distros/spark/apps/customizer-launcher/components/gaia-list/gaia-list.js
Executable file
|
|
@ -0,0 +1,311 @@
|
|||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Pointer event abstraction to make
|
||||
* it work for touch and mouse.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var pointer = [
|
||||
{ down: 'touchstart', up: 'touchend', move: 'touchmove' },
|
||||
{ down: 'mousedown', up: 'mouseup', move: 'mousemove' }
|
||||
]['ontouchstart' in window ? 0 : 1];
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-list', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.els = { inner: this.shadowRoot.querySelector('.inner') };
|
||||
this.addEventListener('click', this.onPointerDown);
|
||||
this.makeAccessible();
|
||||
},
|
||||
|
||||
makeAccessible: function() {
|
||||
[].forEach.call(this.children, (el) => { el.tabIndex = 0; });
|
||||
},
|
||||
|
||||
itemShouldRipple: function(el) {
|
||||
if (scrolling) { return false; }
|
||||
else if (el.classList.contains('ripple')) { return true; }
|
||||
else if (el.classList.contains('no-ripple')) { return false; }
|
||||
else if (this.classList.contains('ripple')){ return true; }
|
||||
else if (this.classList.contains('no-ripple')){ return false; }
|
||||
else if (el.tagName === 'A') { return true; }
|
||||
else { return false; }
|
||||
},
|
||||
|
||||
onPointerDown: function(e) {
|
||||
var point = e.touches ? e.changedTouches[0] : e;
|
||||
var target = this.getChild(e.target);
|
||||
|
||||
if (!this.itemShouldRipple(target)) { return; }
|
||||
|
||||
var pos = {
|
||||
list: this.getBoundingClientRect(),
|
||||
item: target.getBoundingClientRect()
|
||||
};
|
||||
|
||||
var els = {
|
||||
container: document.createElement('div'),
|
||||
ripple: document.createElement('div')
|
||||
};
|
||||
|
||||
els.container.className = 'ripple-container';
|
||||
els.container.style.left = (pos.item.left - pos.list.left) + 'px';
|
||||
els.container.style.top = (pos.item.top - pos.list.top) + 'px';
|
||||
els.container.style.width = pos.item.width + 'px';
|
||||
els.container.style.height = pos.item.height + 'px';
|
||||
|
||||
var offset = {
|
||||
x: point.clientX - pos.item.left,
|
||||
y: point.clientY - pos.item.top
|
||||
};
|
||||
|
||||
els.ripple.className = 'ripple';
|
||||
els.ripple.style.left = offset.x + 'px';
|
||||
els.ripple.style.top = offset.y + 'px';
|
||||
els.ripple.style.visibility = 'hidden';
|
||||
|
||||
els.container.appendChild(els.ripple);
|
||||
this.els.inner.appendChild(els.container);
|
||||
|
||||
// var reflow = els.ripple.offsetTop;
|
||||
var scale = pos.item.width / 1.2;
|
||||
var duration = 500;
|
||||
|
||||
setTimeout(function() {
|
||||
els.ripple.style.visibility = '';
|
||||
els.ripple.style.transform = 'scale(' + scale + ')';
|
||||
els.ripple.style.transitionDuration = duration + 'ms';
|
||||
setTimeout(function() {
|
||||
els.ripple.style.transitionDuration = '1000ms';
|
||||
els.ripple.style.opacity = '0';
|
||||
setTimeout(function() {
|
||||
els.container.remove();
|
||||
}, 1000);
|
||||
}, duration);
|
||||
});
|
||||
},
|
||||
|
||||
getChild: function(el) {
|
||||
return el && (el.parentNode === this ? el : this.getChild(el.parentNode));
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content></content>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label { background: none; }
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/** Children
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > *:not(style) {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 60px;
|
||||
padding: 9px 16px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
background: transparent;
|
||||
align-items: center;
|
||||
list-style-type: none;
|
||||
|
||||
color:
|
||||
var(--text-color);
|
||||
}
|
||||
|
||||
::content > a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/** Titles
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content h1,
|
||||
::content h2,
|
||||
::content h3,
|
||||
::content h4 {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/** Layout Helpers
|
||||
---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* [flexbox]
|
||||
*
|
||||
* A helper attribute to allow users to
|
||||
* quickly define content as a flexbox.
|
||||
*/
|
||||
|
||||
::content [flexbox] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/**
|
||||
* [flex]
|
||||
*
|
||||
* A helper attribute to allow users to
|
||||
* quickly define area as flexible.
|
||||
*/
|
||||
|
||||
::content [flex] {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/** Border
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > *:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
height: 1px;
|
||||
|
||||
background:
|
||||
var(--border-color,
|
||||
var(--background-plus));
|
||||
}
|
||||
|
||||
/* Hack: Hide the line before the second element, since the first element is
|
||||
* the <style scoped> element */
|
||||
::content > :first-child:before,
|
||||
::content > style:first-child ~ :nth-child(2):before,
|
||||
::content > gaia-header:first-child ~ :nth-child(2):before,
|
||||
::content > gaia-sub-header:first-child ~ :nth-child(2):before,
|
||||
::content > h1:first-child ~ :nth-child(2):before,
|
||||
::content > h2:first-child ~ :nth-child(2):before,
|
||||
::content > .borderless:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/** Titles
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content small,
|
||||
::content p {
|
||||
font-size: 0.7em;
|
||||
line-height: 1.35em;
|
||||
}
|
||||
|
||||
/** Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content i {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
::content i:before {
|
||||
display: block;
|
||||
}
|
||||
|
||||
::content > * > i:last-child {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the icons when the document is RTL mode
|
||||
*/
|
||||
|
||||
:host-context([dir=rtl]) ::content i:before {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
/** Divided
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content .divided {
|
||||
-moz-border-start: solid 1px;
|
||||
-moz-padding-start: 14px;
|
||||
|
||||
border-color:
|
||||
var(--border-color,
|
||||
var(--background-plus));
|
||||
}
|
||||
|
||||
/** Ripple Container
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.ripple-container.ripple-container {
|
||||
box-sizing: content-box;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
padding-top: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/** Ripple
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.ripple-container > .ripple {
|
||||
background: var(--border-color);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
margin: -1px;
|
||||
border-radius: 50%;
|
||||
transition-property: transform, opacity;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
var scrolling = false;
|
||||
var scrollTimeout;
|
||||
|
||||
addEventListener('scroll', function() {
|
||||
scrolling = true;
|
||||
clearTimeout(scrollTimeout);
|
||||
scrollTimeout = setTimeout(function() {
|
||||
scrolling = false;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-list',this));
|
||||
167
gaia/distros/spark/apps/customizer-launcher/components/gaia-list/index.html
Executable file
|
|
@ -0,0 +1,167 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-list></title>
|
||||
<meta name="description" content="gaia-list example" />
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-icons/gaia-icons.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="gaia-list.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding: 16px;
|
||||
padding-top: 48px;
|
||||
}
|
||||
|
||||
gaia-list.settings [data-icon='forward'] {
|
||||
color: var(--text-color-minus);
|
||||
}
|
||||
|
||||
gaia-list .divided {
|
||||
border-left: solid 1px;
|
||||
padding-left: 14px;
|
||||
|
||||
border-color:
|
||||
var(--border-color,
|
||||
var(--background-plus));
|
||||
}
|
||||
|
||||
gaia-list.contacts .face {
|
||||
position: absolute;
|
||||
top: 50%; right: 16px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: -20px;
|
||||
border-radius: 50%;
|
||||
border: solid 2px;
|
||||
|
||||
border-color:
|
||||
var(--border-color,
|
||||
var(--background-minus));
|
||||
background: var(--background-plus);
|
||||
}
|
||||
|
||||
gaia-list.email > * {
|
||||
padding-left: 32px !important;
|
||||
}
|
||||
|
||||
gaia-list.email time {
|
||||
position: absolute;
|
||||
right: 0; top: 0;
|
||||
margin: 9px 16px;
|
||||
font-size: 0.7em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
gaia-list.email p {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
gaia-list.email .unread:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 16px; top: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-top: -4px;
|
||||
border-radius: 50%;
|
||||
|
||||
background:
|
||||
var(--highlight-color);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body role="application">
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
<h1 class="large l-align-center l-mb-mega"><gaia-list></h1>
|
||||
<section>
|
||||
<gaia-list class="settings l-mb-mega">
|
||||
<a>
|
||||
<i data-icon="brightness"></i><h3>Menu 1</h3><i data-icon="forward-light"></i></a>
|
||||
<a><i data-icon="location"></i><h3>Menu 2</h3><i data-icon="forward-light"></i></a>
|
||||
<a><i data-icon="settings"></i>Menu 3<i data-icon="forward-light"></i></a>
|
||||
<li>
|
||||
<label class="l-flex l-flex-grow" for="wifi-switch">
|
||||
<i data-icon="wifi-4"></i><h3>Wifi</h3>
|
||||
</label>
|
||||
<gaia-switch id="wifi-switch" class="divided"></gaia-switch>
|
||||
</li>
|
||||
</gaia-list>
|
||||
|
||||
<gaia-list class="contacts l-mb-mega">
|
||||
<a>
|
||||
<div>
|
||||
<h3>Noah Green</h3>
|
||||
<p>Atsara Kitchens</p>
|
||||
<div class="face"></div>
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
<div>
|
||||
<h3>Will Grand</h3>
|
||||
<p>CBN Studio</p>
|
||||
<div class="face"></div>
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
<div>
|
||||
<h3>Carolina Grey</h3>
|
||||
<p>Mozilla</p>
|
||||
<div class="face"></div>
|
||||
</div>
|
||||
</a>
|
||||
</gaia-list>
|
||||
|
||||
<gaia-list class="email">
|
||||
<a class="unread">
|
||||
<div>
|
||||
<h3>Will Gordan</h3>
|
||||
<p>Send photos please!</p>
|
||||
<p>You're the best, thank you so much for all</p><time>11:30AM</time>
|
||||
</div>
|
||||
</a>
|
||||
<a class="unread">
|
||||
<div>
|
||||
<h3>Jennifer Liu</h3>
|
||||
<p>Road trip next weekend</p>
|
||||
<p>I've been wanting to visit that place for a</p>
|
||||
<time>11:30AM</time>
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
<div>
|
||||
<h3>Michael Stanford</h3>
|
||||
<p>You might like this or not?</p>
|
||||
<p>Great find, I definitely check with Brian if</p>
|
||||
<time>11:30AM</time>
|
||||
</div>
|
||||
</a>
|
||||
<a class="unread">
|
||||
<div>
|
||||
<h3>Jennifer Liu</h3>
|
||||
<p>Road trip next weekend</p>
|
||||
<p>I'vee been wanting to visit that place for a</p>
|
||||
<time>11:30AM</time>
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
<div>
|
||||
<h3>Michael Stanford</h3>
|
||||
<p>You might like this or not?</p>
|
||||
<p>Great find, I definitely check with Brian if</p>
|
||||
<time>11:30AM</time>
|
||||
</div>
|
||||
</a>
|
||||
</gaia-list>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
26
gaia/distros/spark/apps/customizer-launcher/components/gaia-theme/bower.json
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-theme",
|
||||
"version": "0.4.5",
|
||||
"homepage": "https://github.com/gaia-components/gaia-theme",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons",
|
||||
"gaia-header": "gaia-components/gaia-header",
|
||||
"gaia-button": "gaia-components/gaia-button",
|
||||
"gaia-switch": "gaia-components/gaia-switch",
|
||||
"gaia-checkbox": "gaia-components/gaia-checkbox"
|
||||
}
|
||||
}
|
||||
234
gaia/distros/spark/apps/customizer-launcher/components/gaia-theme/gaia-theme.css
Executable file
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
Gaia theme variables
|
||||
*/
|
||||
|
||||
|
||||
:root {
|
||||
|
||||
/** Grey Colors
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--color-alpha: #333333;
|
||||
--color-beta: #ffffff;
|
||||
--color-gamma: #4d4d4d;
|
||||
--color-delta: #5f5f5f;
|
||||
--color-epsilon: #858585;
|
||||
--color-zeta: #a6a6a6;
|
||||
--color-eta: #c7c7c7;
|
||||
--color-theta: #e7e7e7;
|
||||
--color-iota: #f4f4f4;
|
||||
|
||||
/** Brand Colors
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--color-darkblue: #00539f;
|
||||
--color-blue: #00caf2;
|
||||
--color-turquoise: #27c8c2;
|
||||
--color-darkorange: #e66000;
|
||||
--color-orange: #ff9500;
|
||||
--color-yellow: #ffcb00;
|
||||
--color-violet: #c40c84;
|
||||
|
||||
--color-warning: #fbbd3c;
|
||||
--color-destructive: #e2443a;
|
||||
--color-preffered: #00ba91;
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-beta);
|
||||
--background-plus: var(--color-theta);
|
||||
--background-minus: var(--color-zeta);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-theta);
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-gamma);
|
||||
--text-color-minus: var(--color-eta);
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--color-iota);
|
||||
|
||||
/** Links
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--link-color: var(--highlight-color);
|
||||
|
||||
/** Inputs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--input-background: var(--color-beta);
|
||||
--input-color: var(--color-alpha);
|
||||
--input-clear-background: #909ca7;
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-box-shadow:
|
||||
inset 0 -1px 0 #d8d8d8,
|
||||
inset 0 1px 0 #eeeeee;
|
||||
--button-box-shadow-active: var(--button-box-shadow);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-disabled-button-color: rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
|
||||
.theme-productivity {
|
||||
|
||||
/** Brand Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-orange);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--highlight-color);
|
||||
--header-color: var(--color-beta);
|
||||
}
|
||||
|
||||
.theme-communications {
|
||||
|
||||
/** Brand Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-turquoise);
|
||||
|
||||
/** Links
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--link-color: #177874;
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--highlight-color);
|
||||
--header-color: var(--color-beta);
|
||||
--header-icon-color: var(--color-beta);
|
||||
--header-button-color: var(--link-color);
|
||||
}
|
||||
|
||||
.theme-settings {
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-iota);
|
||||
--background-plus: var(--color-beta);
|
||||
--background-minus: var(--color-epsilon);
|
||||
--background-minus-minus: var(--color-zeta);
|
||||
|
||||
/** Highlight
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-blue);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-theta);
|
||||
|
||||
/** Titles
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--title-color: var(--background-minus);
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--background-plus);
|
||||
|
||||
/** Switch
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--switch-background: var(--background-minus-minus);
|
||||
|
||||
/** Checkbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--checkbox-border-color: var(--background-minus-minus);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-color: var(--title-color);
|
||||
--header-background: var(--background);
|
||||
--header-button-color: var(--highlight-color);
|
||||
--header-disabled-button-color: var(--color-theta);
|
||||
--header-action-button-color: var(--title-color);
|
||||
}
|
||||
|
||||
.theme-media {
|
||||
|
||||
/** Highlight Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-blue);
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-alpha);
|
||||
--background-plus: var(--color-gamma);
|
||||
--background-minus: #2B2B2B;
|
||||
--background-minus-minus: #1a1a1a;
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-beta);
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--background-plus);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--background);
|
||||
--header-icon-color: var(--text-color);
|
||||
--header-button-color: var(--highlight-color);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-gamma);
|
||||
|
||||
/** Inputs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--input-background: var(--background-plus);
|
||||
|
||||
/** Text Input
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-input-background: var(--background-minus);
|
||||
|
||||
/** Switch
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--switch-head-border-color: var(--background-minus-minus);
|
||||
--switch-background: var(--background-minus-minus);
|
||||
|
||||
/** Checkbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--checkbox-border-color: var(--background-minus-minus);
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-box-shadow: none;
|
||||
--button-box-shadow-active: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
(function(define){'use strict';define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
|
||||
/**
|
||||
* Extend from the `HTMLElement` prototype
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
this.createShadowRoot().innerHTML = template;
|
||||
|
||||
this.els = {
|
||||
themes: this.shadowRoot.querySelector('.themes'),
|
||||
rtl: this.shadowRoot.querySelector('.toggle-rtl')
|
||||
};
|
||||
|
||||
this.els.rtl.addEventListener('click', this.onRtlClick.bind(this));
|
||||
this.els.themes.addEventListener('click', this.onThemeClick.bind(this));
|
||||
this.styleHack();
|
||||
this.set(localStorage.theme || 'settings');
|
||||
};
|
||||
|
||||
proto.styleHack = function() {
|
||||
var style = this.shadowRoot.querySelector('style');
|
||||
style.setAttribute('scoped', '');
|
||||
this.appendChild(style.cloneNode(true));
|
||||
};
|
||||
|
||||
proto.onThemeClick = function(e) {
|
||||
var theme = e.target.value;
|
||||
if (theme) { this.set(theme); }
|
||||
};
|
||||
|
||||
proto.onRtlClick = function() {
|
||||
document.dir = this.els.rtl.checked ? 'rtl' : 'ltr';
|
||||
};
|
||||
|
||||
proto.set = function(theme) {
|
||||
var radio = this.shadowRoot.querySelector('[value="' + theme + '"]');
|
||||
document.body.classList.remove('theme-' + this.theme);
|
||||
document.body.classList.add('theme-' + theme);
|
||||
radio.checked = true;
|
||||
this.theme = theme;
|
||||
localStorage.theme = theme;
|
||||
};
|
||||
|
||||
var template = `
|
||||
<style>
|
||||
|
||||
* { margin: 0; padding: 0; }
|
||||
|
||||
gaia-theme-selector {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
z-index: 101;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
background: rgba(255,255,255,0.8);
|
||||
color: #000;
|
||||
font-size: 9px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
form label {
|
||||
-moz-margin-start: 9px;
|
||||
}
|
||||
|
||||
form input {
|
||||
-moz-margin-end: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.rtl {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<form>
|
||||
<label class="rtl"><input type="checkbox" class="toggle-rtl" />RTL</label>
|
||||
<span class="themes">
|
||||
<label><input type="radio" name="theme" value="productivity"/>Prod</label>
|
||||
<label><input type="radio" name="theme" value="communications"/>Comms</label>
|
||||
<label><input type="radio" name="theme" value="media"/>Media</label>
|
||||
<label><input type="radio" name="theme" value="settings"/>Settings</label>
|
||||
</span>
|
||||
</form>`;
|
||||
|
||||
document.registerElement('gaia-theme-selector', { prototype: proto });
|
||||
|
||||
});})((function(n,w){'use strict';return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:
|
||||
function(c){var m={exports:{}},r=function(n){return w[n];};
|
||||
w[n]=c(r,m.exports,m)||m.exports;};})('gaia-theme-selector',this));
|
||||
BIN
gaia/distros/spark/apps/customizer-launcher/img/customize-champ.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/distros/spark/apps/customizer-launcher/img/default_icon.png
Executable file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
gaia/distros/spark/apps/customizer-launcher/img/icons/customizer_126.png
Executable file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
gaia/distros/spark/apps/customizer-launcher/img/icons/customizer_142.png
Executable file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
gaia/distros/spark/apps/customizer-launcher/img/icons/customizer_189.png
Executable file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
gaia/distros/spark/apps/customizer-launcher/img/icons/customizer_84.png
Executable file
|
After Width: | Height: | Size: 5.5 KiB |
15
gaia/distros/spark/apps/customizer-launcher/index.html
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#9ab0c0">
|
||||
<title>Customizer Launcher</title>
|
||||
<link rel="stylesheet" href="./components/gaia-fonts/style.css">
|
||||
<link rel="stylesheet" href="./components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" href="./style/app.css">
|
||||
</head>
|
||||
<body class="theme-settings">
|
||||
<script src="js/initapp.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
9
gaia/distros/spark/apps/customizer-launcher/js/app.js
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
define(["exports", "js/globals", "js/controller/main_controller"], function (exports, _jsGlobals, _jsControllerMainController) {
|
||||
"use strict";
|
||||
|
||||
var MainController = _jsControllerMainController["default"];
|
||||
|
||||
|
||||
var mainController = new MainController();
|
||||
mainController.main();
|
||||
});
|
||||
88
gaia/distros/spark/apps/customizer-launcher/js/controller/list_controller.js
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
define(["exports", "components/fxos-mvc/dist/mvc", "js/model/list_model", "js/view/list_view", "js/lib/web_server"], function (exports, _componentsFxosMvcDistMvc, _jsModelListModel, _jsViewListView, _jsLibWebServer) {
|
||||
"use strict";
|
||||
|
||||
var _extends = function (child, parent) {
|
||||
child.prototype = Object.create(parent.prototype, {
|
||||
constructor: {
|
||||
value: child,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
child.__proto__ = parent;
|
||||
};
|
||||
|
||||
var Controller = _componentsFxosMvcDistMvc.Controller;
|
||||
var ListModel = _jsModelListModel["default"];
|
||||
var ListView = _jsViewListView["default"];
|
||||
var WebServer = _jsLibWebServer["default"];
|
||||
var ListController = (function (Controller) {
|
||||
var ListController = function ListController() {
|
||||
this.model = new ListModel();
|
||||
this.listView = new ListView();
|
||||
this.webServer = new WebServer();
|
||||
};
|
||||
|
||||
_extends(ListController, Controller);
|
||||
|
||||
ListController.prototype.main = function () {
|
||||
var _this = this;
|
||||
this.model.getAllApps().then(function (allApps) {
|
||||
_this.enableCustomizerAddOn(allApps).then(function () {
|
||||
return _this.createList(allApps);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ListController.prototype.enableCustomizerAddOn = function (allApps) {
|
||||
var _this2 = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
_this2.model.getCustomizerAddOn(allApps).then(function (addon) {
|
||||
if (addon && !addon.enabled) {
|
||||
navigator.mozApps.mgmt.setEnabled(addon, true);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ListController.prototype.createList = function (allApps) {
|
||||
var _this3 = this;
|
||||
this.listView.render();
|
||||
document.body.appendChild(this.listView.el);
|
||||
|
||||
this.model.getAppList(allApps).then(function (appsList) {
|
||||
_this3.listView.update(appsList);
|
||||
_this3.listView.setOpenHandler(_this3.handleOpen.bind(_this3));
|
||||
});
|
||||
};
|
||||
|
||||
ListController.prototype.handleOpen = function (data) {
|
||||
var _this4 = this;
|
||||
if (data.app) {
|
||||
this.webServer.startServer().then(function (result) {
|
||||
if (result) {
|
||||
_this4.launchApp(data);
|
||||
_this4.webServer.setData(data.manifestURL);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Error("Could not open app: " + data);
|
||||
}
|
||||
};
|
||||
|
||||
ListController.prototype.launchApp = function (data) {
|
||||
// Use entry_point to launch app, if entry_point exists
|
||||
if (data.entry_point) {
|
||||
data.app.launch(data.entry_point);
|
||||
} else {
|
||||
data.app.launch();
|
||||
}
|
||||
};
|
||||
|
||||
return ListController;
|
||||
})(Controller);
|
||||
|
||||
exports["default"] = ListController;
|
||||
});
|
||||
46
gaia/distros/spark/apps/customizer-launcher/js/controller/main_controller.js
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
define(["exports", "components/fxos-mvc/dist/mvc", "gaia-component", "js/view/main_view", "js/controller/list_controller", "js/lib/helpers"], function (exports, _componentsFxosMvcDistMvc, _gaiaComponent, _jsViewMainView, _jsControllerListController, _jsLibHelpers) {
|
||||
"use strict";
|
||||
|
||||
var _extends = function (child, parent) {
|
||||
child.prototype = Object.create(parent.prototype, {
|
||||
constructor: {
|
||||
value: child,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
child.__proto__ = parent;
|
||||
};
|
||||
|
||||
var Controller = _componentsFxosMvcDistMvc.Controller;
|
||||
var MainView = _jsViewMainView["default"];
|
||||
var ListController = _jsControllerListController["default"];
|
||||
var AchievementsHelper = _jsLibHelpers.AchievementsHelper;
|
||||
var MainController = (function (Controller) {
|
||||
var MainController = function MainController() {
|
||||
this.achievementsHelper = new AchievementsHelper();
|
||||
this.view = new MainView({ el: document.body });
|
||||
this.listController = new ListController();
|
||||
Controller.call(this);
|
||||
};
|
||||
|
||||
_extends(MainController, Controller);
|
||||
|
||||
MainController.prototype.main = function () {
|
||||
this.view.render();
|
||||
this.dialog = document.querySelector("fxos-dev-mode-dialog");
|
||||
|
||||
// fxos-dev-mode-dialog checks and emit event 'enabled' when
|
||||
// device dev mode perf is set to true. Continue to load
|
||||
// list of apps inside dialog enabled event handler.
|
||||
this.dialog.addEventListener("enabled", function () {
|
||||
this.listController.main();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
return MainController;
|
||||
})(Controller);
|
||||
|
||||
exports["default"] = MainController;
|
||||
});
|
||||
12
gaia/distros/spark/apps/customizer-launcher/js/globals.js
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
define(["exports"], function (exports) {
|
||||
"use strict";
|
||||
|
||||
window.COMPONENTS_BASE_URL = "./components/";
|
||||
window.DEFAULT_ICON_URL = "./img/default_icon.png";
|
||||
require.config({
|
||||
baseUrl: "/",
|
||||
paths: {
|
||||
"gaia-component": "components/gaia-component/gaia-component"
|
||||
}
|
||||
});
|
||||
});
|
||||
1416
gaia/distros/spark/apps/customizer-launcher/js/initapp.js
Executable file
96
gaia/distros/spark/apps/customizer-launcher/js/lib/helpers.js
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
define(["exports", "components/fxos-achievements-service/dist/achievements-service"], function (exports, _componentsFxosAchievementsServiceDistAchievementsService) {
|
||||
"use strict";
|
||||
|
||||
var AchievementsService = _componentsFxosAchievementsServiceDistAchievementsService["default"];
|
||||
var IconHelper = (function () {
|
||||
var IconHelper = function IconHelper() {};
|
||||
|
||||
IconHelper.setImage = function (imageElement, imagePath) {
|
||||
imageElement.src = imagePath || window.DEFAULT_ICON_URL;
|
||||
imageElement.onerror = function (e) {
|
||||
console.warn("Warning, failed to load icon url", imageElement.src, e);
|
||||
imageElement.src = window.DEFAULT_ICON_URL;
|
||||
};
|
||||
};
|
||||
|
||||
IconHelper.getIconURL = function (app, icons) {
|
||||
if (!icons || !Object.keys(icons).length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// The preferred size is 30 by the default. If we use HDPI device, we may
|
||||
// use the image larger than 30 * 1.5 = 45 pixels.
|
||||
var preferredIconSize = 30 * (window.devicePixelRatio || 1);
|
||||
var preferredSize = Number.MAX_VALUE;
|
||||
var max = 0;
|
||||
|
||||
for (var size in icons) {
|
||||
size = parseInt(size, 10);
|
||||
if (size > max) {
|
||||
max = size;
|
||||
}
|
||||
|
||||
if (size >= preferredIconSize && size < preferredSize) {
|
||||
preferredSize = size;
|
||||
}
|
||||
}
|
||||
// If there is an icon matching the preferred size, we return the result,
|
||||
// if there isn't, we will return the maximum available size.
|
||||
if (preferredSize === Number.MAX_VALUE) {
|
||||
preferredSize = max;
|
||||
}
|
||||
|
||||
var url = icons[preferredSize];
|
||||
|
||||
if (url) {
|
||||
return !(/^(http|https|data):/.test(url)) ? app.origin + url : url;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
return IconHelper;
|
||||
})();
|
||||
|
||||
exports.IconHelper = IconHelper;
|
||||
var AppsHelper = (function () {
|
||||
var AppsHelper = function AppsHelper() {};
|
||||
|
||||
AppsHelper.getAllApps = function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var mgmt = navigator.mozApps.mgmt;
|
||||
if (!mgmt) {
|
||||
reject(new Error("Cannot fetch apps, no permissions"));
|
||||
}
|
||||
|
||||
var req = mgmt.getAll();
|
||||
req.onsuccess = function () {
|
||||
resolve(req.result);
|
||||
};
|
||||
req.onerror = function (e) {
|
||||
reject(e);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
return AppsHelper;
|
||||
})();
|
||||
|
||||
exports.AppsHelper = AppsHelper;
|
||||
var AchievementsHelper = (function () {
|
||||
var AchievementsHelper = function AchievementsHelper() {
|
||||
// Create an achievements service
|
||||
this.achievementsService = new AchievementsService();
|
||||
|
||||
window.addEventListener("achievement-rewarded", this);
|
||||
};
|
||||
|
||||
AchievementsHelper.prototype.handleEvent = function (aEvent) {
|
||||
this.achievementsService.reward(aEvent.detail);
|
||||
};
|
||||
|
||||
return AchievementsHelper;
|
||||
})();
|
||||
|
||||
exports.AchievementsHelper = AchievementsHelper;
|
||||
});
|
||||
71
gaia/distros/spark/apps/customizer-launcher/js/lib/web_server.js
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
define(["exports", "components/fxos-web-server/dist/fxos-web-server"], function (exports, _componentsFxosWebServerDistFxosWebServer) {
|
||||
"use strict";
|
||||
|
||||
var WebServer = (function () {
|
||||
var WebServer = function WebServer() {
|
||||
var _this = this;
|
||||
this.lastLaunchedManifestURL = null;
|
||||
if (!this.httpServer) {
|
||||
this.httpServer = new HTTPServer(3215);
|
||||
}
|
||||
|
||||
this.httpServer.addEventListener("request", function (evt) {
|
||||
var request = evt.request;
|
||||
var response = evt.response;
|
||||
response.headers["Access-Control-Allow-Origin"] = "*";
|
||||
response.headers["Cache-Control"] = "no-cache";
|
||||
|
||||
if (request.path === "/request") {
|
||||
response.send(_this.lastLaunchedManifestURL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.path === "/confirm") {
|
||||
var url = (request.params && request.params.url) || "";
|
||||
if (url && url === _this.lastLaunchedManifestURL) {
|
||||
response.send("STOP_SERVER_INVOKED");
|
||||
_this.stopServer();
|
||||
window.dispatchEvent(new CustomEvent("achievement-rewarded", {
|
||||
detail: {
|
||||
criteria: "achievements/customize-champ",
|
||||
evidence: "urn:fxos-customizer-launcher:customizer:launched",
|
||||
name: "Customize Champ",
|
||||
description: "Open Customizer in an app",
|
||||
image: "./img/customize-champ.png"
|
||||
}
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Default response for all other requests
|
||||
response.send(null, 404);
|
||||
});
|
||||
};
|
||||
|
||||
WebServer.prototype.setData = function (url) {
|
||||
this.lastLaunchedManifestURL = url;
|
||||
};
|
||||
|
||||
WebServer.prototype.startServer = function () {
|
||||
var _this2 = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
_this2.httpServer.start();
|
||||
console.log("WebServer Started");
|
||||
resolve(true);
|
||||
});
|
||||
};
|
||||
|
||||
WebServer.prototype.stopServer = function () {
|
||||
if (!this.httpServer) {
|
||||
return;
|
||||
}
|
||||
this.httpServer.stop();
|
||||
this.lastLaunchedManifestURL = null;
|
||||
console.log("WebServer Stopped");
|
||||
};
|
||||
|
||||
return WebServer;
|
||||
})();
|
||||
|
||||
exports["default"] = WebServer;
|
||||
});
|
||||
109
gaia/distros/spark/apps/customizer-launcher/js/model/list_model.js
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
define(["exports", "components/fxos-mvc/dist/mvc", "js/lib/helpers"], function (exports, _componentsFxosMvcDistMvc, _jsLibHelpers) {
|
||||
"use strict";
|
||||
|
||||
var _extends = function (child, parent) {
|
||||
child.prototype = Object.create(parent.prototype, {
|
||||
constructor: {
|
||||
value: child,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
child.__proto__ = parent;
|
||||
};
|
||||
|
||||
var Model = _componentsFxosMvcDistMvc.Model;
|
||||
var AppsHelper = _jsLibHelpers.AppsHelper;
|
||||
var IconHelper = _jsLibHelpers.IconHelper;
|
||||
var ListModel = (function (Model) {
|
||||
var ListModel = function ListModel() {
|
||||
Model.apply(this, arguments);
|
||||
};
|
||||
|
||||
_extends(ListModel, Model);
|
||||
|
||||
ListModel.prototype.getAllApps = function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
AppsHelper.getAllApps().then(function (allApps) {
|
||||
resolve(allApps);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ListModel.prototype.filterCustomizerAddon = function (apps) {
|
||||
return apps.filter(function (app) {
|
||||
return app.manifestURL == "app://customizer.gaiamobile.org/manifest.webapp";
|
||||
});
|
||||
};
|
||||
|
||||
ListModel.prototype.getCustomizerAddOn = function (allApps) {
|
||||
var _this = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
var addOnList = _this.filterCustomizerAddon(allApps);
|
||||
if (addOnList && addOnList.length == 1) {
|
||||
resolve(addOnList[0]);
|
||||
} else {
|
||||
reject(new Error("Cannot fetch customizer add on"));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ListModel.prototype.filterApps = function (apps) {
|
||||
var excludedApps = ["app://keyboard.gaiamobile.org/manifest.webapp", "app://customizer-launcher.gaiamobile.org/manifest.webapp"];
|
||||
|
||||
return apps.filter(function (app) {
|
||||
return app.manifest.role !== "addon" && app.manifest.role !== "theme" && app.manifest.role !== "system" && excludedApps.indexOf(app.manifestURL) === -1;
|
||||
});
|
||||
};
|
||||
|
||||
ListModel.prototype.fillAppDetails = function (app) {
|
||||
var detail = Object.create(null);
|
||||
detail.manifestURL = app.manifestURL;
|
||||
detail.name = app.manifest.name;
|
||||
detail.description = app.manifest.description;
|
||||
detail.icon = IconHelper.getIconURL(app, app.manifest.icons);
|
||||
detail.author = app.manifest.developer ? app.manifest.developer.name : "";
|
||||
detail.app = app;
|
||||
return detail;
|
||||
};
|
||||
|
||||
ListModel.prototype.fillAppDetailsFromEntryPoint = function (app, entry_point) {
|
||||
var detail = Object.create(null);
|
||||
detail.manifestURL = app.manifestURL;
|
||||
detail.description = app.manifest.description;
|
||||
detail.author = app.manifest.developer ? app.manifest.developer.name : "";
|
||||
detail.app = app;
|
||||
detail.name = app.manifest.entry_points[entry_point].name;
|
||||
detail.icon = IconHelper.getIconURL(app, app.manifest.entry_points[entry_point].icons);
|
||||
detail.entry_point = entry_point;
|
||||
return detail;
|
||||
};
|
||||
|
||||
ListModel.prototype.getAppList = function (allApps) {
|
||||
var _this2 = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
var installedApps = Object.create(null);
|
||||
var filterList = _this2.filterApps(allApps);
|
||||
filterList.forEach(function (app) {
|
||||
// Check for Communications app, only app that uses
|
||||
// multiple entry_points in manifest
|
||||
if (app.manifest.entry_points) {
|
||||
// Iterate manifest.entry_points to fill dialer and
|
||||
// contacts app details
|
||||
for (var entry_point in app.manifest.entry_points) {
|
||||
installedApps[app.manifestURL + "/" + entry_point] = _this2.fillAppDetailsFromEntryPoint(app, entry_point);
|
||||
}
|
||||
} else {
|
||||
installedApps[app.manifestURL] = _this2.fillAppDetails(app);
|
||||
}
|
||||
});
|
||||
resolve(installedApps);
|
||||
});
|
||||
};
|
||||
|
||||
return ListModel;
|
||||
})(Model);
|
||||
|
||||
exports["default"] = ListModel;
|
||||
});
|
||||
82
gaia/distros/spark/apps/customizer-launcher/js/view/list_view.js
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
define(["exports", "components/fxos-mvc/dist/mvc", "components/gaia-list/gaia-list", "components/gaia-button/gaia-button", "js/lib/helpers"], function (exports, _componentsFxosMvcDistMvc, _componentsGaiaListGaiaList, _componentsGaiaButtonGaiaButton, _jsLibHelpers) {
|
||||
"use strict";
|
||||
|
||||
var _taggedTemplateLiteral = function (strings, raw) {
|
||||
return Object.defineProperties(strings, {
|
||||
raw: {
|
||||
value: raw
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _extends = function (child, parent) {
|
||||
child.prototype = Object.create(parent.prototype, {
|
||||
constructor: {
|
||||
value: child,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
child.__proto__ = parent;
|
||||
};
|
||||
|
||||
var View = _componentsFxosMvcDistMvc.View;
|
||||
var IconHelper = _jsLibHelpers.IconHelper;
|
||||
|
||||
|
||||
function capitalize(string) {
|
||||
return string[0].toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
var ListView = (function (View) {
|
||||
var ListView = function ListView() {
|
||||
this.el = document.createElement("gaia-list");
|
||||
this.el.className = "app-list";
|
||||
|
||||
this.elements = Object.create(null);
|
||||
};
|
||||
|
||||
_extends(ListView, View);
|
||||
|
||||
ListView.prototype.update = function (list) {
|
||||
for (var key in list) {
|
||||
var data = list[key];
|
||||
if (!this.elements[key]) {
|
||||
this.elements[key] = this.addElement(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ListView.prototype.setOpenHandler = function (handler) {
|
||||
if (!this.openHandler) {
|
||||
this.openHandler = handler;
|
||||
}
|
||||
};
|
||||
|
||||
ListView.prototype.addElement = function (data) {
|
||||
var item = document.createElement("li");
|
||||
item.classList.add("app");
|
||||
item.innerHTML = Sanitizer.unwrapSafeHTML(this.listItemTemplate(data));
|
||||
IconHelper.setImage(item.querySelector(".icon"), data.icon);
|
||||
this.el.appendChild(item);
|
||||
|
||||
item.querySelector(".open-button").addEventListener("click", function (data) {
|
||||
this.openHandler(data);
|
||||
}.bind(this, data));
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
ListView.prototype.listItemTemplate = function (_ref) {
|
||||
var name = _ref.name;
|
||||
var author = _ref.author;
|
||||
var string = Sanitizer.createSafeHTML(_taggedTemplateLiteral(["\n <img class=\"icon\" />\n <div flex class=\"description\">\n <p class=\"name\">", "</p>\n <p class=\"author\">", "</p>\n </div>\n <gaia-button class=\"open-button\">Open</gaia-button>"], ["\n <img class=\"icon\" />\n <div flex class=\"description\">\n <p class=\"name\">", "</p>\n <p class=\"author\">", "</p>\n </div>\n <gaia-button class=\"open-button\">Open</gaia-button>"]), capitalize(name), author);
|
||||
return string;
|
||||
};
|
||||
|
||||
return ListView;
|
||||
})(View);
|
||||
|
||||
exports["default"] = ListView;
|
||||
});
|
||||
37
gaia/distros/spark/apps/customizer-launcher/js/view/main_view.js
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
define(["exports", "components/fxos-mvc/dist/mvc", "components/gaia-header/dist/gaia-header", "components/fxos-dev-mode-dialog/fxos-dev-mode-dialog"], function (exports, _componentsFxosMvcDistMvc, _componentsGaiaHeaderDistGaiaHeader, _componentsFxosDevModeDialogFxosDevModeDialog) {
|
||||
"use strict";
|
||||
|
||||
var _extends = function (child, parent) {
|
||||
child.prototype = Object.create(parent.prototype, {
|
||||
constructor: {
|
||||
value: child,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
child.__proto__ = parent;
|
||||
};
|
||||
|
||||
var View = _componentsFxosMvcDistMvc.View;
|
||||
var MainView = (function (View) {
|
||||
var MainView = function MainView() {
|
||||
View.apply(this, arguments);
|
||||
};
|
||||
|
||||
_extends(MainView, View);
|
||||
|
||||
MainView.prototype.render = function () {
|
||||
View.prototype.render.call(this);
|
||||
};
|
||||
|
||||
MainView.prototype.template = function () {
|
||||
var string = "\n <gaia-header>\n <h1>Customizer Launcher</h1>\n </gaia-header>\n <fxos-dev-mode-dialog></fxos-dev-mode-dialog>";
|
||||
return string;
|
||||
};
|
||||
|
||||
return MainView;
|
||||
})(View);
|
||||
|
||||
exports["default"] = MainView;
|
||||
});
|
||||
25
gaia/distros/spark/apps/customizer-launcher/manifest.webapp
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "Customizer",
|
||||
"description": "Launcher App for Customizer",
|
||||
"type": "certified",
|
||||
"launch_path": "/index.html",
|
||||
"icons": {
|
||||
"84": "/img/icons/customizer_84.png",
|
||||
"126": "/img/icons/customizer_126.png",
|
||||
"142": "/img/icons/customizer_142.png",
|
||||
"189": "/img/icons/customizer_189.png"
|
||||
},
|
||||
"permissions": {
|
||||
"webapps-manage": {},
|
||||
"tcp-socket": {},
|
||||
"feature-detection": {},
|
||||
"settings": {
|
||||
"access": "readwrite",
|
||||
"description": "For reading and writing achievements settings"
|
||||
},
|
||||
"desktop-notification": {
|
||||
"description": "For sending achievements notifications to Gaia::System"
|
||||
},
|
||||
"moz-extremely-unstable-and-will-change-webcomponents":{}
|
||||
}
|
||||
}
|
||||
63
gaia/distros/spark/apps/customizer-launcher/style/app.css
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
body {
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
font-family: "FiraSans";
|
||||
overflow-x: hidden;
|
||||
background-color: var(--background);
|
||||
color: var(--title-color);
|
||||
}
|
||||
|
||||
gaia-header {
|
||||
--header-background: #9ab0c0;
|
||||
--header-icon-color: #ffffff;
|
||||
--header-title-color: #ffffff;
|
||||
|
||||
}
|
||||
|
||||
.app-list {
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.app-list .icon {
|
||||
max-height: 100%;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
.app-list .name {
|
||||
margin: 0;
|
||||
font-size: 19px !important;
|
||||
color: var(--text-color);
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
.author {
|
||||
margin: 0;
|
||||
font-size: 15px !important;
|
||||
color: var(--title-color);
|
||||
}
|
||||
|
||||
.app-list li i {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.app-list .open-button {
|
||||
width: 20%;
|
||||
font-size: 12px !important;
|
||||
font-weight: bold !important;
|
||||
height: 32px !important;
|
||||
min-width: 40px !important;
|
||||
margin: 15px 0 !important;
|
||||
-moz-user-select: none;
|
||||
--button-background: var(--color-blue);
|
||||
--button-color: white;
|
||||
--button-background-active: white;
|
||||
--button-color-active: var(--title-color);
|
||||
}
|
||||
|
||||
.app-list .open-button:active {
|
||||
background-color: transparent;
|
||||
}
|
||||
82
gaia/distros/spark/apps/customizer/components/esprima/ChangeLog
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
2015-02-06: Version 2.0.0
|
||||
|
||||
* Support ES6 arrow function (issue 517)
|
||||
* Support ES6 Unicode code point escape (issue 521)
|
||||
* Improve the speed and accuracy of comment attachment (issue 522)
|
||||
* Support ES6 default parameter (issue 519)
|
||||
* Support ES6 regular expression flags (issue 557)
|
||||
* Fix scanning of implicit octal literals (issue 565)
|
||||
* Fix the handling of automatic semicolon insertion (issue 574)
|
||||
* Support ES6 method definition (issue 620)
|
||||
* Support ES6 octal integer literal (issue 621)
|
||||
* Support ES6 binary integer literal (issue 622)
|
||||
* Support ES6 object literal property value shorthand (issue 624)
|
||||
|
||||
2015-01-18: Version 1.2.3
|
||||
|
||||
* Fix division by this (issue 616)
|
||||
|
||||
2014-05-18: Version 1.2.2
|
||||
|
||||
* Fix duplicated tokens when collecting comments (issue 537)
|
||||
|
||||
2014-05-04: Version 1.2.1
|
||||
|
||||
* Ensure that Program node may still have leading comments (issue 536)
|
||||
|
||||
2014-04-29: Version 1.2.0
|
||||
|
||||
* Fix semicolon handling for expression statement (issue 462, 533)
|
||||
* Disallow escaped characters in regular expression flags (issue 503)
|
||||
* Performance improvement for location tracking (issue 520)
|
||||
* Improve the speed of comment attachment (issue 522)
|
||||
|
||||
2014-03-26: Version 1.1.1
|
||||
|
||||
* Fix token handling of forward slash after an array literal (issue 512)
|
||||
|
||||
2014-03-23: Version 1.1.0
|
||||
|
||||
* Optionally attach comments to the owning syntax nodes (issue 197)
|
||||
* Simplify binary parsing with stack-based shift reduce (issue 352)
|
||||
* Always include the raw source of literals (issue 376)
|
||||
* Add optional input source information (issue 386)
|
||||
* Tokenizer API for pure lexical scanning (issue 398)
|
||||
* Improve the web site and its online demos (issue 337, 400, 404)
|
||||
* Performance improvement for location tracking (issue 417, 424)
|
||||
* Support HTML comment syntax (issue 451)
|
||||
* Drop support for legacy browsers (issue 474)
|
||||
|
||||
2013-08-27: Version 1.0.4
|
||||
|
||||
* Minimize the payload for packages (issue 362)
|
||||
* Fix missing cases on an empty switch statement (issue 436)
|
||||
* Support escaped ] in regexp literal character classes (issue 442)
|
||||
* Tolerate invalid left-hand side expression (issue 130)
|
||||
|
||||
2013-05-17: Version 1.0.3
|
||||
|
||||
* Variable declaration needs at least one declarator (issue 391)
|
||||
* Fix benchmark's variance unit conversion (issue 397)
|
||||
* IE < 9: \v should be treated as vertical tab (issue 405)
|
||||
* Unary expressions should always have prefix: true (issue 418)
|
||||
* Catch clause should only accept an identifier (issue 423)
|
||||
* Tolerate setters without parameter (issue 426)
|
||||
|
||||
2012-11-02: Version 1.0.2
|
||||
|
||||
Improvement:
|
||||
|
||||
* Fix esvalidate JUnit output upon a syntax error (issue 374)
|
||||
|
||||
2012-10-28: Version 1.0.1
|
||||
|
||||
Improvements:
|
||||
|
||||
* esvalidate understands shebang in a Unix shell script (issue 361)
|
||||
* esvalidate treats fatal parsing failure as an error (issue 361)
|
||||
* Reduce Node.js package via .npmignore (issue 362)
|
||||
|
||||
2012-10-22: Version 1.0.0
|
||||
|
||||
Initial release.
|
||||
19
gaia/distros/spark/apps/customizer/components/esprima/LICENSE.BSD
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
127
gaia/distros/spark/apps/customizer/components/esprima/bin/esparse.js
Executable file
|
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint sloppy:true node:true rhino:true */
|
||||
|
||||
var fs, esprima, fname, content, options, syntax;
|
||||
|
||||
if (typeof require === 'function') {
|
||||
fs = require('fs');
|
||||
esprima = require('esprima');
|
||||
} else if (typeof load === 'function') {
|
||||
try {
|
||||
load('esprima.js');
|
||||
} catch (e) {
|
||||
load('../esprima.js');
|
||||
}
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under Rhino.
|
||||
if (typeof console === 'undefined' && typeof process === 'undefined') {
|
||||
console = { log: print };
|
||||
fs = { readFileSync: readFile };
|
||||
process = { argv: arguments, exit: quit };
|
||||
process.argv.unshift('esparse.js');
|
||||
process.argv.unshift('rhino');
|
||||
}
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage:');
|
||||
console.log(' esparse [options] file.js');
|
||||
console.log();
|
||||
console.log('Available options:');
|
||||
console.log();
|
||||
console.log(' --comment Gather all line and block comments in an array');
|
||||
console.log(' --loc Include line-column location info for each syntax node');
|
||||
console.log(' --range Include index-based range for each syntax node');
|
||||
console.log(' --raw Display the raw value of literals');
|
||||
console.log(' --tokens List all tokens in an array');
|
||||
console.log(' --tolerant Tolerate errors on a best-effort basis (experimental)');
|
||||
console.log(' -v, --version Shows program version');
|
||||
console.log();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (process.argv.length <= 2) {
|
||||
showUsage();
|
||||
}
|
||||
|
||||
options = {};
|
||||
|
||||
process.argv.splice(2).forEach(function (entry) {
|
||||
|
||||
if (entry === '-h' || entry === '--help') {
|
||||
showUsage();
|
||||
} else if (entry === '-v' || entry === '--version') {
|
||||
console.log('ECMAScript Parser (using Esprima version', esprima.version, ')');
|
||||
console.log();
|
||||
process.exit(0);
|
||||
} else if (entry === '--comment') {
|
||||
options.comment = true;
|
||||
} else if (entry === '--loc') {
|
||||
options.loc = true;
|
||||
} else if (entry === '--range') {
|
||||
options.range = true;
|
||||
} else if (entry === '--raw') {
|
||||
options.raw = true;
|
||||
} else if (entry === '--tokens') {
|
||||
options.tokens = true;
|
||||
} else if (entry === '--tolerant') {
|
||||
options.tolerant = true;
|
||||
} else if (entry.slice(0, 2) === '--') {
|
||||
console.log('Error: unknown option ' + entry + '.');
|
||||
process.exit(1);
|
||||
} else if (typeof fname === 'string') {
|
||||
console.log('Error: more than one input file.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
fname = entry;
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof fname !== 'string') {
|
||||
console.log('Error: no input file.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Special handling for regular expression literal since we need to
|
||||
// convert it to a string literal, otherwise it will be decoded
|
||||
// as object "{}" and the regular expression would be lost.
|
||||
function adjustRegexLiteral(key, value) {
|
||||
if (key === 'value' && value instanceof RegExp) {
|
||||
value = value.toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
try {
|
||||
content = fs.readFileSync(fname, 'utf-8');
|
||||
syntax = esprima.parse(content, options);
|
||||
console.log(JSON.stringify(syntax, adjustRegexLiteral, 4));
|
||||
} catch (e) {
|
||||
console.log('Error: ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
199
gaia/distros/spark/apps/customizer/components/esprima/bin/esvalidate.js
Executable file
|
|
@ -0,0 +1,199 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint sloppy:true plusplus:true node:true rhino:true */
|
||||
/*global phantom:true */
|
||||
|
||||
var fs, system, esprima, options, fnames, count;
|
||||
|
||||
if (typeof esprima === 'undefined') {
|
||||
// PhantomJS can only require() relative files
|
||||
if (typeof phantom === 'object') {
|
||||
fs = require('fs');
|
||||
system = require('system');
|
||||
esprima = require('./esprima');
|
||||
} else if (typeof require === 'function') {
|
||||
fs = require('fs');
|
||||
esprima = require('esprima');
|
||||
} else if (typeof load === 'function') {
|
||||
try {
|
||||
load('esprima.js');
|
||||
} catch (e) {
|
||||
load('../esprima.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under PhantomJS 1.7+.
|
||||
if (typeof phantom === 'object') {
|
||||
fs.readFileSync = fs.read;
|
||||
process = {
|
||||
argv: [].slice.call(system.args),
|
||||
exit: phantom.exit
|
||||
};
|
||||
process.argv.unshift('phantomjs');
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under Rhino.
|
||||
if (typeof console === 'undefined' && typeof process === 'undefined') {
|
||||
console = { log: print };
|
||||
fs = { readFileSync: readFile };
|
||||
process = { argv: arguments, exit: quit };
|
||||
process.argv.unshift('esvalidate.js');
|
||||
process.argv.unshift('rhino');
|
||||
}
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage:');
|
||||
console.log(' esvalidate [options] file.js');
|
||||
console.log();
|
||||
console.log('Available options:');
|
||||
console.log();
|
||||
console.log(' --format=type Set the report format, plain (default) or junit');
|
||||
console.log(' -v, --version Print program version');
|
||||
console.log();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (process.argv.length <= 2) {
|
||||
showUsage();
|
||||
}
|
||||
|
||||
options = {
|
||||
format: 'plain'
|
||||
};
|
||||
|
||||
fnames = [];
|
||||
|
||||
process.argv.splice(2).forEach(function (entry) {
|
||||
|
||||
if (entry === '-h' || entry === '--help') {
|
||||
showUsage();
|
||||
} else if (entry === '-v' || entry === '--version') {
|
||||
console.log('ECMAScript Validator (using Esprima version', esprima.version, ')');
|
||||
console.log();
|
||||
process.exit(0);
|
||||
} else if (entry.slice(0, 9) === '--format=') {
|
||||
options.format = entry.slice(9);
|
||||
if (options.format !== 'plain' && options.format !== 'junit') {
|
||||
console.log('Error: unknown report format ' + options.format + '.');
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (entry.slice(0, 2) === '--') {
|
||||
console.log('Error: unknown option ' + entry + '.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
fnames.push(entry);
|
||||
}
|
||||
});
|
||||
|
||||
if (fnames.length === 0) {
|
||||
console.log('Error: no input file.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (options.format === 'junit') {
|
||||
console.log('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
console.log('<testsuites>');
|
||||
}
|
||||
|
||||
count = 0;
|
||||
fnames.forEach(function (fname) {
|
||||
var content, timestamp, syntax, name;
|
||||
try {
|
||||
content = fs.readFileSync(fname, 'utf-8');
|
||||
|
||||
if (content[0] === '#' && content[1] === '!') {
|
||||
content = '//' + content.substr(2, content.length);
|
||||
}
|
||||
|
||||
timestamp = Date.now();
|
||||
syntax = esprima.parse(content, { tolerant: true });
|
||||
|
||||
if (options.format === 'junit') {
|
||||
|
||||
name = fname;
|
||||
if (name.lastIndexOf('/') >= 0) {
|
||||
name = name.slice(name.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
console.log('<testsuite name="' + fname + '" errors="0" ' +
|
||||
' failures="' + syntax.errors.length + '" ' +
|
||||
' tests="' + syntax.errors.length + '" ' +
|
||||
' time="' + Math.round((Date.now() - timestamp) / 1000) +
|
||||
'">');
|
||||
|
||||
syntax.errors.forEach(function (error) {
|
||||
var msg = error.message;
|
||||
msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
||||
console.log(' <testcase name="Line ' + error.lineNumber + ': ' + msg + '" ' +
|
||||
' time="0">');
|
||||
console.log(' <error type="SyntaxError" message="' + error.message + '">' +
|
||||
error.message + '(' + name + ':' + error.lineNumber + ')' +
|
||||
'</error>');
|
||||
console.log(' </testcase>');
|
||||
});
|
||||
|
||||
console.log('</testsuite>');
|
||||
|
||||
} else if (options.format === 'plain') {
|
||||
|
||||
syntax.errors.forEach(function (error) {
|
||||
var msg = error.message;
|
||||
msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
||||
msg = fname + ':' + error.lineNumber + ': ' + msg;
|
||||
console.log(msg);
|
||||
++count;
|
||||
});
|
||||
|
||||
}
|
||||
} catch (e) {
|
||||
++count;
|
||||
if (options.format === 'junit') {
|
||||
console.log('<testsuite name="' + fname + '" errors="1" failures="0" tests="1" ' +
|
||||
' time="' + Math.round((Date.now() - timestamp) / 1000) + '">');
|
||||
console.log(' <testcase name="' + e.message + '" ' + ' time="0">');
|
||||
console.log(' <error type="ParseError" message="' + e.message + '">' +
|
||||
e.message + '(' + fname + ((e.lineNumber) ? ':' + e.lineNumber : '') +
|
||||
')</error>');
|
||||
console.log(' </testcase>');
|
||||
console.log('</testsuite>');
|
||||
} else {
|
||||
console.log('Error: ' + e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (options.format === 'junit') {
|
||||
console.log('</testsuites>');
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (count === 0 && typeof phantom === 'object') {
|
||||
process.exit(0);
|
||||
}
|
||||
29
gaia/distros/spark/apps/customizer/components/esprima/bower.json
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "esprima",
|
||||
"version": "2.0.0",
|
||||
"main": "./esprima.js",
|
||||
"scripts": [
|
||||
"esprima.js"
|
||||
],
|
||||
"dependencies": {},
|
||||
"ignore": [
|
||||
"examples",
|
||||
"test",
|
||||
"tools"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/jquery/esprima.git"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "BSD",
|
||||
"url": "http://github.com/jquery/esprima/raw/master/LICENSE.BSD"
|
||||
}],
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"parser",
|
||||
"syntax"
|
||||
]
|
||||
}
|
||||
24
gaia/distros/spark/apps/customizer/components/esprima/component.json
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "esprima",
|
||||
"version": "2.0.0",
|
||||
"main": "./esprima.js",
|
||||
"scripts": [
|
||||
"esprima.js"
|
||||
],
|
||||
"dependencies": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/jquery/esprima.git"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "BSD",
|
||||
"url": "http://github.com/jquery/esprima/raw/master/LICENSE.BSD"
|
||||
}],
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"parser",
|
||||
"syntax"
|
||||
]
|
||||
}
|
||||