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.
24
gaia/dev_apps/contacts-ds-provider1/index.html
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Provider 1</title>
|
||||
<script defer src="/js/google.js"></script>
|
||||
<script defer src="/js/app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<section>
|
||||
<header>
|
||||
<h1>Google contacts provider</h1>
|
||||
</header>
|
||||
<article>
|
||||
This test app will allow you to log in into your google account and store your contacts into an 'contacts' datastore.
|
||||
</article>
|
||||
</section>
|
||||
<section id="info"></section>
|
||||
<section id="commands">
|
||||
<button id="fillDS">Fill DataStore</button>
|
||||
<button id="resetDS">Clean DataStore</button>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
87
gaia/dev_apps/contacts-ds-provider1/js/app.js
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
/* global Google */
|
||||
|
||||
'use strict';
|
||||
|
||||
var App = function App() {
|
||||
|
||||
var store = null;
|
||||
var info = null;
|
||||
var fillButton, resetButton;
|
||||
|
||||
var DS_NAME = 'contacts';
|
||||
|
||||
var init = function init() {
|
||||
info = document.getElementById('info');
|
||||
fillButton = document.getElementById('fillDS');
|
||||
resetButton = document.getElementById('resetDS');
|
||||
|
||||
fillButton.addEventListener('click', handleEvent);
|
||||
resetButton.addEventListener('click', handleEvent);
|
||||
|
||||
initDS();
|
||||
};
|
||||
|
||||
function handleEvent(evt) {
|
||||
var btn = evt.target.id;
|
||||
|
||||
switch (btn) {
|
||||
case 'fillDS':
|
||||
fillButton.disabled = true;
|
||||
Google.initLogin(store, function(t) {
|
||||
Google.importContacts(function() {
|
||||
fillButton.disabled = false;
|
||||
store.getLength().then(function(count) {
|
||||
info.textContent = count + ' elements';
|
||||
});
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'resetDS':
|
||||
store.clear().then(function() {
|
||||
store.getLength().then(function(count) {
|
||||
info.textContent = count + ' elements';
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function initDS() {
|
||||
function storeError() {
|
||||
info.textContent = 'Error getting store';
|
||||
}
|
||||
|
||||
if (!navigator.getDataStores) {
|
||||
info.textContent = 'NO DataStore API!';
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.getDataStores(DS_NAME).then(function(ds) {
|
||||
if (!ds || ds.length < 1) {
|
||||
storeError();
|
||||
return;
|
||||
}
|
||||
ds.forEach(function onDs(datastore) {
|
||||
if (datastore.owner.indexOf('provider1')) {
|
||||
store = datastore;
|
||||
console.log('Got store ' + store.owner);
|
||||
}
|
||||
});
|
||||
|
||||
store.getLength().then(function(count) {
|
||||
info.textContent = count + ' elements';
|
||||
});
|
||||
}, function() {
|
||||
storeError();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
App.init();
|
||||
343
gaia/dev_apps/contacts-ds-provider1/js/google.js
Executable file
|
|
@ -0,0 +1,343 @@
|
|||
'use strict';
|
||||
|
||||
var googleAuth = 'https://accounts.google.com/o/oauth2/auth?scope=' +
|
||||
'https://www.google.com/m8/feeds/&response_type=token&redirect_uri=' +
|
||||
'http://postmessageitor.eu01.aws.af.cm/&approval_prompt=force&' +
|
||||
'client_id=206115911344.apps.googleusercontent.com';
|
||||
|
||||
var Google = function Google() {
|
||||
|
||||
var authWindow;
|
||||
var accessToken;
|
||||
var datastore;
|
||||
|
||||
var initLogin = function initLogin(ds, cb) {
|
||||
accessToken = localStorage.accessToken;
|
||||
datastore = ds;
|
||||
if (accessToken) {
|
||||
cb(accessToken);
|
||||
return;
|
||||
}
|
||||
authWindow = window.open(googleAuth);
|
||||
window.addEventListener('message', function(evt) {
|
||||
authWindow.close();
|
||||
accessToken = evt.data.access_token;
|
||||
localStorage.accessToken = accessToken;
|
||||
if (typeof cb === 'function') {
|
||||
cb(accessToken);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var getContacts = function getContacts(cb) {
|
||||
var parser = ContactsParser(accessToken, function() {
|
||||
var contacts = parser.getContacts();
|
||||
cb(contacts);
|
||||
});
|
||||
parser.fetchContacts();
|
||||
};
|
||||
|
||||
var importContacts = function importContacts(cb) {
|
||||
this.getContacts(function(contacts) {
|
||||
doImportContacts(contacts, cb);
|
||||
});
|
||||
};
|
||||
|
||||
function doImportContacts(contacts, cb) {
|
||||
if (!contacts || contacts.length === 0) {
|
||||
if (typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var contact = prepareForDS(contacts[0]);
|
||||
|
||||
function continuee() {
|
||||
var rest = contacts.slice(1);
|
||||
if (rest && rest.length > -1) {
|
||||
doImportContacts(rest, cb);
|
||||
}
|
||||
}
|
||||
|
||||
datastore.add(contact).then(function(id) {
|
||||
console.add('Added contact with id ' + id);
|
||||
continuee();
|
||||
|
||||
}, function() {
|
||||
console.add('Error saving contact ');
|
||||
continuee();
|
||||
});
|
||||
}
|
||||
|
||||
function prepareForDS(contact) {
|
||||
// Initialy dont do any extra processing
|
||||
return contact;
|
||||
}
|
||||
|
||||
return {
|
||||
initLogin: initLogin,
|
||||
getContacts: getContacts,
|
||||
importContacts: importContacts
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
|
||||
|
||||
var ContactsParser = function contacts(t, cb) {
|
||||
|
||||
var token = t;
|
||||
|
||||
var contacts = [];
|
||||
var contactsToImport = [];
|
||||
var GOOGLE_URL = 'https://www.google.com/m8/feeds/contacts/default/full?max-results=10000';
|
||||
var GROUPS_END_POINT = 'https://www.google.com/m8/feeds/groups/default/full/';
|
||||
var GD_NAMESPACE = 'http://schemas.google.com/g/2005';
|
||||
var CATEGORY = 'gmail';
|
||||
var URN_IDENTIFIER = 'urn:service:gmail:uid:';
|
||||
|
||||
var fetchContacts = function fetchContact() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', GROUPS_END_POINT, true);
|
||||
xhr.setRequestHeader('Authorization', 'OAuth ' + token);
|
||||
xhr.setRequestHeader('Gdata-version', '3.0');
|
||||
xhr.addEventListener('load', function dataLoaded(e) {
|
||||
if (xhr.status == 200 || xhr.status == 0) {
|
||||
var feed = xhr.responseXML.getElementsByTagName('feed')[0];
|
||||
if (feed === null) {
|
||||
getContactsByGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
var sgc = feed.querySelector('systemGroup[id="Contacts"]');
|
||||
if (sgc !== null) {
|
||||
var id = sgc.parentNode.querySelector('id').textContent;
|
||||
getContactsByGroup(id);
|
||||
} else {
|
||||
getContactsByGroup();
|
||||
}
|
||||
} else {
|
||||
getContactsByGroup();
|
||||
}
|
||||
});
|
||||
xhr.send(null);
|
||||
};
|
||||
|
||||
var getContactsByGroup = function getContactsByGroup(groupId) {
|
||||
var url = GOOGLE_URL;
|
||||
if (groupId) {
|
||||
url += '&group=' + groupId;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', url, true);
|
||||
xhr.setRequestHeader('Authorization', 'OAuth ' + token);
|
||||
xhr.setRequestHeader('Gdata-version', '3.0');
|
||||
xhr.addEventListener('load', function dataLoaded(e) {
|
||||
if (xhr.status == 200 || xhr.status == 0) {
|
||||
parseContacts(xhr.responseXML);
|
||||
cb(contacts);
|
||||
} else {
|
||||
// TODO : Handle error
|
||||
console.error('----->> Pete');
|
||||
delete localStorage.accessToken;
|
||||
}
|
||||
});
|
||||
xhr.send(null);
|
||||
};
|
||||
|
||||
var parseContacts = function parseContacts(responseXML) {
|
||||
contacts = [];
|
||||
var contactsEntries = responseXML.querySelectorAll('entry');
|
||||
for (var i = 0; i < contactsEntries.length; i++) {
|
||||
var entry = contactsEntries[i];
|
||||
contacts.push(gContactToJson(entry));
|
||||
}
|
||||
};
|
||||
|
||||
var getValueForNode = function getValueForNode(doc, name, def) {
|
||||
var defaultValue = def || '';
|
||||
|
||||
if (doc == null || name == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
var node = doc.querySelector(name);
|
||||
|
||||
if (node && node.textContent) {
|
||||
return node.textContent;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
var gContactToJson = function gContactToJson(googleContact) {
|
||||
var output = {};
|
||||
|
||||
// This field will be needed for indexing within the
|
||||
// import process, not for the api
|
||||
output.uid = getUid(googleContact);
|
||||
|
||||
output.name = getValueForNode(googleContact, 'title');
|
||||
|
||||
// Store the photo url, not in the contact itself
|
||||
var photoUrl = googleContact.querySelector('link[type="image/*"]');
|
||||
if (photoUrl) {
|
||||
photoUrl = photoUrl.getAttribute('href');
|
||||
} else {
|
||||
// No image link
|
||||
photoUrl = '';
|
||||
}
|
||||
output.photoUrl = photoUrl;
|
||||
|
||||
var name = googleContact.querySelector('name');
|
||||
if (name) {
|
||||
var contactName = getValueForNode(name, 'givenName');
|
||||
if (contactName) {
|
||||
output.givenName = [contactName];
|
||||
}
|
||||
var contactFamilyName = getValueForNode(name, 'familyName');
|
||||
if (contactFamilyName) {
|
||||
output.familyName = [contactFamilyName];
|
||||
}
|
||||
var contactSuffix = getValueForNode(name, 'additionalName');
|
||||
if (contactSuffix) {
|
||||
output.additionalName = [contactSuffix];
|
||||
}
|
||||
}
|
||||
|
||||
output.email = parseEmails(googleContact);
|
||||
|
||||
output.adr = parseAddress(googleContact);
|
||||
|
||||
output.tel = parsePhones(googleContact);
|
||||
|
||||
var org = googleContact.querySelector('organization');
|
||||
if (org) {
|
||||
output.org = [getValueForNode(org, 'orgName')];
|
||||
output.jobTitle = [getValueForNode(org, 'orgTitle')];
|
||||
}
|
||||
|
||||
var bday = googleContact.querySelector('birthday');
|
||||
if (bday) {
|
||||
output.bday = new Date(bday.getAttribute('when'));
|
||||
}
|
||||
|
||||
var content = googleContact.querySelector('content');
|
||||
if (content) {
|
||||
output.note = [content.textContent];
|
||||
}
|
||||
|
||||
output.category = [CATEGORY];
|
||||
output.url = [{
|
||||
type: ['source'],
|
||||
value: getContactURI(output)
|
||||
}];
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
var getContactURI = function getContactURI(contact) {
|
||||
return URN_IDENTIFIER + contact.uid;
|
||||
};
|
||||
|
||||
// This will be a full url like:
|
||||
// http://www.google.com/m8/feeds/contacts/<email>/base/<contact_id>
|
||||
// for a specific contact node
|
||||
var getUid = function getUid(contact) {
|
||||
return contact.querySelector('id').textContent;
|
||||
};
|
||||
|
||||
// Returns an array with the possible emails found in a contact
|
||||
// as a ContactField format
|
||||
var parseEmails = function parseEmails(googleContact) {
|
||||
var DEFAULT_EMAIL_TYPE = 'personal';
|
||||
var emails = [];
|
||||
var fields = googleContact.getElementsByTagNameNS(GD_NAMESPACE,
|
||||
'email');
|
||||
if (fields && fields.length > 0) {
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var emailField = fields.item(i);
|
||||
|
||||
// Type format: rel="http://schemas.google.com/g/2005#home"
|
||||
var type = emailField.getAttribute('rel') || DEFAULT_EMAIL_TYPE;
|
||||
if (type.indexOf('#') > -1) {
|
||||
type = type.substr(type.indexOf('#') + 1);
|
||||
}
|
||||
|
||||
emails.push({
|
||||
'type': type,
|
||||
'value': emailField.getAttribute('address')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return emails;
|
||||
};
|
||||
|
||||
// Given a google contact returns an array of ContactAddress
|
||||
var parseAddress = function parseAddress(googleContact) {
|
||||
var addresses = [];
|
||||
var fields = googleContact.getElementsByTagNameNS(GD_NAMESPACE,
|
||||
'structuredPostalAddress');
|
||||
if (fields && fields.length > 0) {
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var field = fields.item(i);
|
||||
var address = {};
|
||||
|
||||
address.streetAddress = getValueForNode(field, 'street');
|
||||
address.locality = getValueForNode(field, 'city');
|
||||
address.region = getValueForNode(field, 'region');
|
||||
address.postalCode = getValueForNode(field, 'postcode');
|
||||
address.countryName = getValueForNode(field, 'country');
|
||||
|
||||
addresses.push(address);
|
||||
}
|
||||
}
|
||||
return addresses;
|
||||
};
|
||||
|
||||
// Given a google contact this function returns an array of
|
||||
// ContactField with the pones stored for that contact
|
||||
var parsePhones = function parsePhones(googleContact) {
|
||||
var DEFAULT_PHONE_TYPE = 'personal';
|
||||
var phones = [];
|
||||
var fields = googleContact.getElementsByTagNameNS(GD_NAMESPACE,
|
||||
'phoneNumber');
|
||||
if (fields && fields.length > 0) {
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
var field = fields.item(i);
|
||||
|
||||
// Type format: rel="http://schemas.google.com/g/2005#home"
|
||||
var type = field.getAttribute('rel') || DEFAULT_PHONE_TYPE;
|
||||
if (type.indexOf('#') > -1) {
|
||||
type = type.substr(type.indexOf('#') + 1);
|
||||
}
|
||||
|
||||
phones.push({
|
||||
'type': type,
|
||||
'value': field.textContent
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return phones;
|
||||
};
|
||||
|
||||
// All contacts
|
||||
var getContacts = function getContacts() {
|
||||
return contacts;
|
||||
};
|
||||
|
||||
var cancelImport = function cancelImport() {
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
'parseContacts': parseContacts,
|
||||
'fetchContacts': fetchContacts,
|
||||
'getContacts': getContacts,
|
||||
'cancelImport': cancelImport
|
||||
};
|
||||
};
|
||||
36
gaia/dev_apps/contacts-ds-provider1/js/redirect.js
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
var Redirect = function Redirect() {
|
||||
|
||||
var ORIGIN = document.location.protocol + '//' +
|
||||
document.location.host;
|
||||
|
||||
var init = function init() {
|
||||
var hash = document.location.hash.substring(1);
|
||||
var parameters = {};
|
||||
|
||||
var dataStart = hash.indexOf('access_token');
|
||||
|
||||
if (dataStart !== -1) {
|
||||
var elements = hash.split('&');
|
||||
|
||||
elements.forEach(function(p) {
|
||||
var values = p.split('=');
|
||||
parameters[values[0]] = values[1];
|
||||
});
|
||||
console.log('-----> Post message:');
|
||||
console.log(JSON.stringify(parameters));
|
||||
|
||||
window.opener.postMessage(parameters, ORIGIN);
|
||||
window.close();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
'init': init
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
Redirect.init();
|
||||
27
gaia/dev_apps/contacts-ds-provider1/manifest.webapp
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "Google Contacts DS",
|
||||
"type": "certified",
|
||||
"launch_path": "/index.html",
|
||||
"datastores-owned": {
|
||||
"contacts": {
|
||||
"access": "readwrite",
|
||||
"description": "Provider 1 contacts"
|
||||
}
|
||||
},
|
||||
"redirects": [
|
||||
{"from": "http://postmessageitor.eu01.aws.af.cm/",
|
||||
"to": "/redirect.html"}
|
||||
],
|
||||
"permissions": {
|
||||
"systemXHR": {
|
||||
"description": "This permission is require to contact Google serves"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
11
gaia/dev_apps/contacts-ds-provider1/redirect.html
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OAuth Redirection</title>
|
||||
<script defer src="js/redirect.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
gaia/dev_apps/contacts-ds-provider1/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/contacts-ds-provider1/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/contacts-ds-provider1/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/contacts-ds-provider1/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/dev_apps/contacts-ds-provider1/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
24
gaia/dev_apps/contacts-ds-provider2/index.html
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Provider 2</title>
|
||||
<script defer src="/js/linkedin.js"></script>
|
||||
<script defer src="/js/app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<section>
|
||||
<header>
|
||||
<h1>Linked In contacts provider</h1>
|
||||
</header>
|
||||
<article>
|
||||
This test app will allow you to log in into your linked in account and store your contacts into an 'contacts' datastore.
|
||||
</article>
|
||||
</section>
|
||||
<section id="info"></section>
|
||||
<section id="commands">
|
||||
<button id="fillDS">Fill DataStore</button>
|
||||
<button id="resetDS">Clean DataStore</button>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
85
gaia/dev_apps/contacts-ds-provider2/js/app.js
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
'use strict';
|
||||
|
||||
var App = function App() {
|
||||
|
||||
var store = null;
|
||||
var info = null;
|
||||
var fillButton, resetButton;
|
||||
|
||||
var DS_NAME = 'contacts';
|
||||
|
||||
var init = function init() {
|
||||
info = document.getElementById('info');
|
||||
fillButton = document.getElementById('fillDS');
|
||||
resetButton = document.getElementById('resetDS');
|
||||
|
||||
fillButton.addEventListener('click', handleEvent);
|
||||
resetButton.addEventListener('click', handleEvent);
|
||||
|
||||
initDS();
|
||||
};
|
||||
|
||||
function handleEvent(evt) {
|
||||
var btn = evt.target.id;
|
||||
|
||||
switch (btn) {
|
||||
case 'fillDS':
|
||||
fillButton.disabled = true;
|
||||
LinkedIn.initLogin(store, function() {
|
||||
LinkedIn.importContacts(function() {
|
||||
store.getLength().then(function(count) {
|
||||
info.textContent = count + ' elements';
|
||||
});
|
||||
fillButton.disabled = false;
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'resetDS':
|
||||
store.clear().then(function() {
|
||||
store.getLength().then(function(count) {
|
||||
info.textContent = count + ' elements';
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function initDS() {
|
||||
function storeError() {
|
||||
info.textContent = 'Error getting store';
|
||||
}
|
||||
|
||||
if (!navigator.getDataStores) {
|
||||
info.textContent = 'NO DataStore API!';
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.getDataStores(DS_NAME).then(function(ds) {
|
||||
if (!ds || ds.length < 1) {
|
||||
storeError();
|
||||
return;
|
||||
}
|
||||
ds.forEach(function onDs(datastore) {
|
||||
if (datastore.owner.indexOf('provider2')) {
|
||||
store = datastore;
|
||||
console.log('Got store ' + store.owner);
|
||||
}
|
||||
});
|
||||
|
||||
store.getLength().then(function(count) {
|
||||
info.textContent = count + ' elements';
|
||||
});
|
||||
}, function() {
|
||||
storeError();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
App.init();
|
||||
177
gaia/dev_apps/contacts-ds-provider2/js/linkedin.js
Executable file
|
|
@ -0,0 +1,177 @@
|
|||
'use strict';
|
||||
|
||||
var accessURI = 'https://www.linkedin.com/uas/oauth2/authorization?response_type=code' +
|
||||
'&client_id=773tsorjqd8pqw' +
|
||||
'&scope=r_fullprofile%20r_emailaddress%20r_network' +
|
||||
'&state=' + (new Date()) +
|
||||
'&redirect_uri=http://127.0.0.1/li';
|
||||
|
||||
var LinkedIn = function LinkedIn() {
|
||||
|
||||
var accessToken = null;
|
||||
var datastore = null;
|
||||
|
||||
var initLogin = function(ds, cb) {
|
||||
datastore = ds;
|
||||
accessToken = localStorage.accessToken;
|
||||
|
||||
if (accessToken) {
|
||||
cb(accessToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var authWindow = window.open(accessURI);
|
||||
window.addEventListener('message', function(evt) {
|
||||
authWindow.close();
|
||||
var code = evt.data.code;
|
||||
|
||||
exchangeAuthCode(code, cb);
|
||||
});
|
||||
};
|
||||
|
||||
var getContacts = function getContacts(cb) {
|
||||
getLinkedinPeople(cb);
|
||||
};
|
||||
|
||||
var importContacts = function importContacts(cb) {
|
||||
getContacts(function(contacts) {
|
||||
// Save contacts to local ds
|
||||
doImportContacts(contacts, cb);
|
||||
});
|
||||
};
|
||||
|
||||
function doImportContacts(contacts, cb) {
|
||||
if (!contacts || contacts.length === 0) {
|
||||
if (typeof cb === 'function') {
|
||||
cb();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var contact = prepareForDS(contacts[0]);
|
||||
|
||||
function continuee() {
|
||||
var rest = contacts.slice(1);
|
||||
if (rest && rest.length > -1) {
|
||||
doImportContacts(rest, cb);
|
||||
}
|
||||
}
|
||||
|
||||
datastore.add(contact).then(function(id) {
|
||||
console.add('Added contact with id ' + id);
|
||||
continuee();
|
||||
|
||||
}, function() {
|
||||
console.add('Error saving contact ');
|
||||
continuee();
|
||||
});
|
||||
}
|
||||
|
||||
function prepareForDS(contact) {
|
||||
// Initialy dont do any extra processing
|
||||
return contact;
|
||||
}
|
||||
|
||||
function getLinkedinPeople(cb) {
|
||||
var url = 'https://api.linkedin.com/v1/people/~/connections?oauth2_access_token=' + accessToken;
|
||||
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', url, true);
|
||||
xhr.addEventListener('load', function dataLoaded(e) {
|
||||
if (xhr.status === 200 || xhr.status === 0) {
|
||||
parseContacts(xhr.responseXML, cb);
|
||||
}
|
||||
});
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function parseContacts(xml, cb) {
|
||||
var contactsElements = xml.querySelectorAll('person');
|
||||
contactsElements = Array.prototype.slice.call(contactsElements);
|
||||
parseIterative(contactsElements, [], cb);
|
||||
}
|
||||
|
||||
function parseIterative(unparsedList, parsedList, cb) {
|
||||
if (!unparsedList || unparsedList.length === 0) {
|
||||
cb(parsedList);
|
||||
return;
|
||||
}
|
||||
|
||||
var unparsed = unparsedList[0];
|
||||
var rest = unparsedList.slice(1);
|
||||
|
||||
parseContact(unparsed, function(contact) {
|
||||
parsedList.push(contact);
|
||||
parseIterative(rest, parsedList, cb);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function parseContact(raw, cb) {
|
||||
var contact = {};
|
||||
|
||||
contact.uid = raw.querySelector('id').textContent;
|
||||
contact.givenName = [];
|
||||
contact.givenName[0] = raw.querySelector('first-name') ?
|
||||
raw.querySelector('first-name').textContent || '' : '';
|
||||
contact.familyName = [];
|
||||
contact.familyName[0] = raw.querySelector('last-name') ?
|
||||
raw.querySelector('last-name').textContent || '' : '';
|
||||
contact.name = [contact.givenName[0] + ' ' + contact.familyName[0]];
|
||||
contact.org = [];
|
||||
contact.org[0] = raw.querySelector('headline') ?
|
||||
raw.querySelector('headline').textContent || '' : '';
|
||||
|
||||
// Parse photo here
|
||||
var photoUrl = raw.querySelector('picture-url');
|
||||
if (photoUrl) {
|
||||
photoUrl = photoUrl.textContent;
|
||||
var xhr = new XMLHttpRequest({mozSystem: true});
|
||||
xhr.open('GET', photoUrl, true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.addEventListener('load', function onImageLoaded(e) {
|
||||
if (xhr.status === 0 || xhr.status === 200) {
|
||||
contact.photo = [xhr.response];
|
||||
}
|
||||
cb(contact);
|
||||
});
|
||||
xhr.send();
|
||||
} else {
|
||||
cb(contact);
|
||||
}
|
||||
}
|
||||
|
||||
function exchangeAuthCode(code, cb) {
|
||||
var url = 'https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code' +
|
||||
'&code=' + code +
|
||||
'&redirect_uri=http://127.0.0.1/li' +
|
||||
'&client_id=773tsorjqd8pqw' +
|
||||
'&client_secret=oX6W3js86FIfNtZH';
|
||||
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('POST', url, true);
|
||||
xhr.addEventListener('load', function dataLoaded(e) {
|
||||
if (xhr.status === 200 || xhr.status === 0) {
|
||||
var response = xhr.response;
|
||||
if (typeof response === 'string') {
|
||||
response = JSON.parse(response);
|
||||
}
|
||||
|
||||
accessToken = response.access_token;
|
||||
localStorage.accessToken = accessToken;
|
||||
cb(accessToken);
|
||||
} else {
|
||||
console.error('Could not get an access token from url ' + url);
|
||||
}
|
||||
});
|
||||
xhr.send();
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
initLogin: initLogin,
|
||||
getContacts: getContacts,
|
||||
importContacts: importContacts
|
||||
};
|
||||
|
||||
}();
|
||||
36
gaia/dev_apps/contacts-ds-provider2/js/redirect.js
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
var Redirect = function Redirect() {
|
||||
|
||||
var ORIGIN = document.location.protocol + '//' +
|
||||
document.location.host;
|
||||
|
||||
var init = function init() {
|
||||
var parameters = {};
|
||||
|
||||
var dataStart = document.location.href.indexOf('?');
|
||||
var params = document.location.href.substring(dataStart + 1);
|
||||
|
||||
if (dataStart !== -1) {
|
||||
var elements = params.split('&');
|
||||
|
||||
elements.forEach(function(p) {
|
||||
var values = p.split('=');
|
||||
parameters[values[0]] = values[1];
|
||||
});
|
||||
console.log('-----> Post message:');
|
||||
console.log(JSON.stringify(parameters));
|
||||
|
||||
window.opener.postMessage(parameters, ORIGIN);
|
||||
window.close();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
'init': init
|
||||
};
|
||||
|
||||
}();
|
||||
|
||||
Redirect.init();
|
||||
27
gaia/dev_apps/contacts-ds-provider2/manifest.webapp
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "LI Contacts DS",
|
||||
"type": "certified",
|
||||
"launch_path": "/index.html",
|
||||
"datastores-owned": {
|
||||
"contacts": {
|
||||
"access": "readwrite",
|
||||
"description": "Provider 2 contacts"
|
||||
}
|
||||
},
|
||||
"redirects": [
|
||||
{"from": "http://127.0.0.1/li",
|
||||
"to": "/redirect.html"}
|
||||
],
|
||||
"permissions": {
|
||||
"systemXHR": {
|
||||
"description": "This permission is require to contact Linked In serves"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
11
gaia/dev_apps/contacts-ds-provider2/redirect.html
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OAuth Redirection</title>
|
||||
<script defer src="js/redirect.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
gaia/dev_apps/contacts-ds-provider2/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/contacts-ds-provider2/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/contacts-ds-provider2/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/contacts-ds-provider2/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/dev_apps/contacts-ds-provider2/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
27
gaia/dev_apps/contacts-manager/README
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
Contacts Manager
|
||||
================
|
||||
|
||||
History
|
||||
-------
|
||||
Traditionally we have been using and abusing mozContacts[1], each certified app that uses contacts has been putting their requirements (indexes, search options, etc.) directly on the API, making it a bit unmaintable.
|
||||
|
||||
Also this API has been designed as a mapping with the vcard format, which is great to define a single contact but lacks of all the fields necessary to track modern requirements (contacts merging, data visibility, searching, etc.)
|
||||
|
||||
Despite of that in the certified Contacts application we have been adding more and more functionality to try to fix this (the merging is added, different sources of contacts are available just as input), but the requirements continue growing and we move the problem from the API to the app.
|
||||
|
||||
Future
|
||||
------
|
||||
In a no so distant future, now with current technologies like Datastore, that enable us to share information across domains we can bypass the mozContacts restrictions.
|
||||
|
||||
We want to create an app that aggregates and manipulates contacts data sources, not just mozContacts, but also any other possible provider of contacts. As well as consumers will use this data and create local copies with simplified, optimized and specific view of that data per app.
|
||||
|
||||
Key points
|
||||
----------
|
||||
- Remember a contact is not just an entry: it could be a merged contact, we do have logic to pick information and prioritizing the view of a contact from different entries.
|
||||
- Datasources should be pluggable: removing a contacts data source would clean all the contacts coming from it, in case of merged contacts being able to unmerge the changes.
|
||||
- Security and access: By contract some contacts data sources wont be available to everyone or the user may decide to not to grant access from and to different apps.
|
||||
- Each app will need to have their specific view: an example of this, contacts needs to make the contact list superfast, contacts app should create a storage from this global one with the requirements needed by contacts app.
|
||||
|
||||
Links
|
||||
-----
|
||||
[1] https://wiki.mozilla.org/WebAPI/ContactsAPI
|
||||
36
gaia/dev_apps/contacts-manager/manifest.webapp
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "ContactsManager",
|
||||
"description": "Contacts Provider App",
|
||||
"version": "1.5",
|
||||
"type": "certified",
|
||||
"role": "system",
|
||||
"developer": {
|
||||
"name": "Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"permissions": {
|
||||
"contacts":{ "access": "readwrite" },
|
||||
"alarms": {},
|
||||
"systemXHR": {},
|
||||
"phonenumberservice": {}
|
||||
},
|
||||
"locales": {
|
||||
"en-US": {
|
||||
"name": "Contacts Provider",
|
||||
"description": "Contacts Provider App"
|
||||
}
|
||||
},
|
||||
"default_locale": "en-US",
|
||||
"messages": [
|
||||
{ "alarm": "/periodic_sync.html" }
|
||||
],
|
||||
"connections": {
|
||||
"contacts-sync": {
|
||||
"description": "Contacts DataBase synchronization",
|
||||
"rules": {
|
||||
"manifestURLs": ["*"]
|
||||
},
|
||||
"handler_path": "/on_demand_sync.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
17
gaia/dev_apps/contacts-manager/on_demand_sync.html
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title> Contacts Database On Demand Sync </title>
|
||||
<script defer src="/shared/js/simple_phone_matcher.js"></script>
|
||||
<script defer src="/shared/js/fb/fb_tel_index.js"></script>
|
||||
<script defer src="/shared/js/async_storage.js"></script>
|
||||
<script defer src="js/gcdsops.js"></script>
|
||||
<script defer src="js/sync.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
12
gaia/dev_apps/contacts-manager/periodic_sync.html
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title> Contacts Database Periodic Sync </title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
78
gaia/dev_apps/ds-test/index.html
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<title>Device Storage Test</title>
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/buttons.css">
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/headers.css">
|
||||
<link rel="stylesheet" type="text/css" href="style/ds-test.css">
|
||||
<script src="js/ds-test.js"></script>
|
||||
</head>
|
||||
<body role="application">
|
||||
<section role="region">
|
||||
<header>
|
||||
<h1 data-l10n-id="dstest-title">Device Storage Test</h1>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
<section role="region">
|
||||
<table>
|
||||
<tr>
|
||||
<td align="right">Command:</td>
|
||||
<td>
|
||||
<select class="fake-select" id="ds.cmd" name="ds.cmd">
|
||||
<option value="getDeviceStorage">GetDeviceStorage</option>
|
||||
<option value="getDeviceStorages">GetDeviceStorages</option>
|
||||
<option value="free-space">Free Space</option>
|
||||
<option value="used-space">Used Space</option>
|
||||
<option value="available">Available</option>
|
||||
<option value="enumerate">Enumerate</option>
|
||||
<option value="enumerate-dcim">Enumerate DCIM</option>
|
||||
<option value="enumerate-filesizes">Enum File Sizes</option>
|
||||
<option value="enumerate-all">Enumerate ALL</option>
|
||||
<option value="add-unnamed-file">Add & Del Unnamed File</option>
|
||||
<option value="add-file">Add File</option>
|
||||
<option value="del-file">Del File</option>
|
||||
<option value="mod-file">Mod File</option>
|
||||
<option value="show-file">Show File</option>
|
||||
<option value="add-listener">Add Listener</option>
|
||||
<option value="remove-listener">Remove Listener</option>
|
||||
<option value="test" selected>Test</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">Storage Type:</td>
|
||||
<td>
|
||||
<select class="fake-select" id="ds.type" name="ds.type">
|
||||
<option value="sdcard" selected>sdcard</option>
|
||||
<option value="pictures">pictures</option>
|
||||
<option value="music">music</option>
|
||||
<option value="videos">videos</option>
|
||||
<option value="apps">apps</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
</section>
|
||||
|
||||
<section role="region">
|
||||
<div class="bb-docs">
|
||||
<button id="doit">Do It</button>
|
||||
<button id="clear-log">Clear Log</button>
|
||||
</div>
|
||||
</section
|
||||
|
||||
<section role="region">
|
||||
<header>
|
||||
<h1 data-l10n-id="dstest-debug-log" id="h1-debuglog" data-hide="debuglog">Debug Log</h1>
|
||||
</header>
|
||||
<div class="bb-docs" id="debuglog">
|
||||
<span id="log"></span>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1010
gaia/dev_apps/ds-test/js/ds-test.js
Executable file
38
gaia/dev_apps/ds-test/manifest.webapp
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "Device Storage Test",
|
||||
"launch_path": "/index.html",
|
||||
"description": "Test app for Device Storage",
|
||||
"type": "certified",
|
||||
"fullscreen": "false",
|
||||
"developer": {
|
||||
"name": "dhylands",
|
||||
"url": "https://github.com/dhylands/ds-test"
|
||||
},
|
||||
"permissions": {
|
||||
"systemXHR":{},
|
||||
"device-storage:apps":{ "access": "readwrite" },
|
||||
"device-storage:sdcard":{ "access": "readwrite" },
|
||||
"device-storage:music":{ "access": "readwrite" },
|
||||
"device-storage:pictures":{ "access": "readwrite" },
|
||||
"device-storage:videos":{ "access": "readwrite" },
|
||||
"settings":{ "access": "readonly" },
|
||||
"webapps-manage":{}
|
||||
},
|
||||
"activities": {
|
||||
"share": {
|
||||
"filters": {
|
||||
"type": "image/*"
|
||||
},
|
||||
"href": "/index.html",
|
||||
"returnValue": true,
|
||||
"disposition": "window"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
22
gaia/dev_apps/ds-test/style/ds-test.css
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 10px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
select {
|
||||
font-size: 18px;
|
||||
}
|
||||
BIN
gaia/dev_apps/ds-test/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/ds-test/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/ds-test/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/ds-test/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/dev_apps/ds-test/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
107
gaia/dev_apps/geoloc/index.html
Executable file
|
|
@ -0,0 +1,107 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8" />
|
||||
<title>Geolocation Debug</title>
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/buttons.css" />
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/headers.css" />
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/input_areas.css" />
|
||||
<link rel="stylesheet" type="text/css" href="shared/elements/gaia-theme/gaia-theme.css /">
|
||||
<link rel="stylesheet" type="text/css" href="style/geoloc.css" />
|
||||
<script type="application/javascript" src="js/geoloc.js"></script>
|
||||
|
||||
<!-- localization -->
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<link rel="localization" href="locales/geoloc.{locale}.properties">
|
||||
<link rel="localization" href="/shared/locales/date/date.{locale}.properties">
|
||||
<script src="shared/js/l10n.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script defer src="shared/js/component_utils.js"></script>
|
||||
<script defer src="shared/elements/gaia_switch/script.js"></script>
|
||||
</head>
|
||||
<body role="application">
|
||||
<section role="region">
|
||||
<header>
|
||||
<h1 data-l10n-id="geolocation-tracker">Geolocation tracker</h1>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
<section role="region">
|
||||
<div class="bb-docs">
|
||||
<button id="btnGet" data-l10n-id="geoloc-get">Get</button>
|
||||
<button id="btnStart" data-l10n-id="geoloc-start">Start</button>
|
||||
<button id="btnStop" data-l10n-id="geoloc-stop">Stop</button>
|
||||
<button id="btnClear" data-l10n-id="geoloc-clear">Clear</button>
|
||||
<button id="btnSave" data-l10n-id="geoloc-save">Save as a file</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section role="region">
|
||||
<header>
|
||||
<h1 data-l10n-id="geoloc-parameters" id="h1-parameters" data-hide="parameters" class="bb-docs">Parameters</h1>
|
||||
</header>
|
||||
<div class="bb-docs" id="parameters">
|
||||
<fieldset>
|
||||
<legend data-l10n-id="geoloc-timeout">Timeout</legend>
|
||||
<section>
|
||||
<input type="number" id="geoloc-timeout" value="0" />
|
||||
</section>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend data-l10n-id="geoloc-maxage">Max. age</legend>
|
||||
<section>
|
||||
<input type="number" id="geoloc-maxage" value="0" />
|
||||
</section>
|
||||
</fieldset>
|
||||
<span class="desc" data-l10n-id="geoloc-msecs">Timeout and Max. age are specified in miliseconds.</span>
|
||||
<ul>
|
||||
<li>
|
||||
<gaia-switch id="geoloc-highaccuracy" checked>
|
||||
<label data-l10n-id="geoloc-highaccuracy">High accuracy</label>
|
||||
</gaia-switch>
|
||||
</li>
|
||||
<li>
|
||||
<gaia-switch id="geoloc-debug" checked>
|
||||
<label data-l10n-id="geoloc-debug">Show debug traces</label>
|
||||
</gaia-switch>
|
||||
</li>
|
||||
<li>
|
||||
<gaia-switch id="geoloc-keep" checked>
|
||||
<label data-l10n-id="geoloc-keep">Keep locations</label>
|
||||
</gaia-switch>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section role="region">
|
||||
<header>
|
||||
<h1 data-l10n-id="geoloc-status" id="h1-status" data-hide="status">Status</h1>
|
||||
</header>
|
||||
<div class="bb-docs" id="status">
|
||||
<fieldset>
|
||||
<legend data-l10n-id="gps-fixes">Fixes</legend>
|
||||
<section>
|
||||
<input type="text" disabled="disabled" id="nbr-gps-fixes" placeholder="0" />
|
||||
</section>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend data-l10n-id="last-fix">Last</legend>
|
||||
<section>
|
||||
<input type="text" disabled="disabled" data-l10n-id="date-last-fix" id="date-last-fix" placeholder="None" />
|
||||
</section>
|
||||
</fieldset>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section role="region">
|
||||
<header>
|
||||
<h1 data-l10n-id="geoloc-debug-log" id="h1-debuglog" data-hide="debuglog">Debug log</h1>
|
||||
</header>
|
||||
<div class="bb-docs" id="debuglog">
|
||||
<span id="log"></span>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
325
gaia/dev_apps/geoloc/js/geoloc.js
Executable file
|
|
@ -0,0 +1,325 @@
|
|||
var running = false;
|
||||
var watchId = undefined;
|
||||
var sep = "<br />************<br />";
|
||||
|
||||
var _ = undefined;
|
||||
|
||||
var locations = undefined;
|
||||
|
||||
function successWatch(position) {
|
||||
var debug = document.getElementById('geoloc-debug').checked;
|
||||
var s = document.querySelector('#log');
|
||||
|
||||
if (!debug) {
|
||||
s.innerHTML = "";
|
||||
}
|
||||
|
||||
if (keep()) {
|
||||
locations.push(position);
|
||||
}
|
||||
|
||||
s.innerHTML = sep + s.innerHTML;
|
||||
for (var i in position.coords) {
|
||||
var e = position.coords[i];
|
||||
if (typeof e == 'number') {
|
||||
s.innerHTML = i + ":" + position.coords[i] + "<br />" + s.innerHTML;
|
||||
}
|
||||
}
|
||||
var link = '<a href="http://www.openstreetmap.org/?mlat=' + position.coords.latitude + '&mlon=' + position.coords.longitude + '&zoom=16">Show on map</a><br />';
|
||||
s.innerHTML = link + s.innerHTML;
|
||||
|
||||
var nbfixes = document.getElementById('nbr-gps-fixes');
|
||||
nbfixes.value = parseInt(nbfixes.value) + 1;
|
||||
|
||||
var datefix = document.getElementById('date-last-fix');
|
||||
var cdate = new Date();
|
||||
var localeFormat = cdate.toLocaleString(navigator.languages, {
|
||||
month: 'numeric',
|
||||
day: 'numeric',
|
||||
year: 'numeric'
|
||||
});
|
||||
datefix.value = localeFormat;
|
||||
}
|
||||
|
||||
function errorWatch(msg) {
|
||||
var s = document.querySelector('#log');
|
||||
if (typeof msg == "object") {
|
||||
if (msg.code == 1) {
|
||||
msg = "Permission denied";
|
||||
}
|
||||
if (msg.code == 2) {
|
||||
msg = "Position unavailable";
|
||||
}
|
||||
if (msg.code == 3) {
|
||||
msg = "Timed out";
|
||||
}
|
||||
}
|
||||
s.innerHTML = sep + msg + sep + s.innerHTML;
|
||||
}
|
||||
|
||||
function successGet(position) {
|
||||
successWatch(position);
|
||||
enable('btnGet');
|
||||
enable('btnStart');
|
||||
enable('btnClear');
|
||||
enable('btnSave');
|
||||
}
|
||||
|
||||
function errorGet(msg) {
|
||||
errorWatch(msg);
|
||||
enable('btnGet');
|
||||
enable('btnStart');
|
||||
enable('btnClear');
|
||||
}
|
||||
|
||||
function getOptions() {
|
||||
if (navigator.geolocation) {
|
||||
locations = new Array();
|
||||
document.getElementById('nbr-gps-fixes').value = "0";
|
||||
document.getElementById('date-last-fix').value = "";
|
||||
show('status');
|
||||
if (document.getElementById('geoloc-debug').checked) {
|
||||
show('debuglog');
|
||||
}
|
||||
running = true;
|
||||
return {
|
||||
enableHighAccuracy: document.getElementById('geoloc-highaccuracy').checked ? true : false,
|
||||
timeout: parseInt(document.getElementById('geoloc-timeout').value),
|
||||
maximumAge: parseInt(document.getElementById('geoloc-maxage').value)
|
||||
};
|
||||
}
|
||||
errorWatch('not supported');
|
||||
return null;
|
||||
}
|
||||
|
||||
function getGeoloc() {
|
||||
errorWatch("getting current position");
|
||||
options = getOptions();
|
||||
if (options) {
|
||||
navigator.geolocation.getCurrentPosition(successGet, errorGet, options);
|
||||
disable('btnGet');
|
||||
disable('btnStart');
|
||||
disable('btnStop');
|
||||
disable('btnClear');
|
||||
disable('btnSave');
|
||||
}
|
||||
}
|
||||
|
||||
function startGeoloc() {
|
||||
errorWatch("Starting watchPosition");
|
||||
options = getOptions();
|
||||
if (options) {
|
||||
watchId = navigator.geolocation.watchPosition(successWatch, errorWatch, options);
|
||||
enable('btnStop');
|
||||
enable('btnClear');
|
||||
disable('btnGet');
|
||||
disable('btnStart');
|
||||
disable('btnSave');
|
||||
}
|
||||
}
|
||||
|
||||
function stopGeoloc() {
|
||||
if (watchId != undefined) {
|
||||
errorWatch("Stopping watchPosition");
|
||||
navigator.geolocation.clearWatch(watchId);
|
||||
disable('btnStop');
|
||||
enable('btnGet');
|
||||
enable('btnClear');
|
||||
enable('btnStart');
|
||||
if (keep()) {
|
||||
enable('btnSave');
|
||||
}
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
function clearGeoloc() {
|
||||
var s = document.querySelector('#log');
|
||||
s.innerHTML = "";
|
||||
}
|
||||
|
||||
function locationsToGPX() {
|
||||
var xmldoc = document.implementation.createDocument("", "", null);
|
||||
var doc = xmldoc.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');
|
||||
doc.setAttribute('creator', 'FirefoxOS geotracker');
|
||||
doc.setAttribute('version', '1.1');
|
||||
xmldoc.appendChild(doc);
|
||||
|
||||
var time = xmldoc.createElement('time');
|
||||
|
||||
var dtf = Intl.DateTimeFormat(navigator.languages, {
|
||||
year: 'numeric',
|
||||
moth: 'numeric',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
second: 'numeric',
|
||||
timeZoneName: 'short'
|
||||
});
|
||||
var ts = xmldoc.createTextNode(dtf.format(new Date()));
|
||||
time.appendChild(ts);
|
||||
doc.appendChild(time);
|
||||
|
||||
var createSimpleNode = function(name, value) {
|
||||
var e = xmldoc.createElement(name);
|
||||
e.appendChild(xmldoc.createTextNode(value));
|
||||
return e;
|
||||
};
|
||||
|
||||
for (var ei in locations) {
|
||||
var e = locations[ei];
|
||||
var x = xmldoc.createElement('wpt');
|
||||
x.setAttribute('lat', e.coords.latitude);
|
||||
x.setAttribute('lon', e.coords.longitude);
|
||||
|
||||
var ele = createSimpleNode('ele', e.coords.altitude);
|
||||
x.appendChild(ele);
|
||||
|
||||
var time = createSimpleNode('time', dtf.format(new Date(e.timestamp)));
|
||||
x.appendChild(time);
|
||||
|
||||
var ext = xmldoc.createElement('extensions');
|
||||
x.appendChild(ext);
|
||||
var accuracy = createSimpleNode('accuracy', e.coords.accuracy);
|
||||
ext.appendChild(accuracy);
|
||||
|
||||
var altitudeAccuracy = createSimpleNode('altitudeAccuracy', e.coords.altitudeAccuracy);
|
||||
ext.appendChild(altitudeAccuracy);
|
||||
|
||||
if (!isNaN(e.coords.speed)) {
|
||||
var speed = createSimpleNode('speed', e.coords.speed);
|
||||
ext.appendChild(speed);
|
||||
}
|
||||
|
||||
if (!isNaN(e.coords.heading)) {
|
||||
var heading = createSimpleNode('heading', e.coords.heading);
|
||||
ext.appendChild(heading);
|
||||
}
|
||||
|
||||
doc.appendChild(x);
|
||||
}
|
||||
|
||||
return xmldoc;
|
||||
}
|
||||
|
||||
function locationsToFile(format) {
|
||||
var xmldoc = undefined;
|
||||
if (format == "gpx") {
|
||||
xmldoc = locationsToGPX();
|
||||
}
|
||||
|
||||
var oSerializer = new XMLSerializer();
|
||||
return '<?xml version="1.0" ?>'
|
||||
+ oSerializer.serializeToString(xmldoc);
|
||||
}
|
||||
|
||||
function saveGeoloc() {
|
||||
var date = (new Date()).toLocaleFormat("%Y%m%d%H%M%S");
|
||||
var file = locationsToFile("gpx");
|
||||
var blob = new Blob([file], {type: 'application/gpx+xml'});
|
||||
var fname = "geoloc/geoloc-" + date + ".gpx";
|
||||
var storage = navigator.getDeviceStorage('sdcard');
|
||||
if (!storage) {
|
||||
console.log("No storage available!");
|
||||
console.log(file);
|
||||
return;
|
||||
}
|
||||
var save = storage.addNamed(blob, fname);
|
||||
save.onsuccess = function() {
|
||||
alert("Successfully saved " + fname);
|
||||
};
|
||||
save.onerror = function() {
|
||||
alert("Error while saving to " + fname + ": " + this.error.name);
|
||||
};
|
||||
}
|
||||
|
||||
function enable(id) {
|
||||
var e = document.getElementById(id);
|
||||
if (e) {
|
||||
e.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function disable(id) {
|
||||
var e = document.getElementById(id);
|
||||
if (e) {
|
||||
e.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function show(id) {
|
||||
var e = document.getElementById(id);
|
||||
if (e) {
|
||||
e.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
function hide(id) {
|
||||
var e = document.getElementById(id);
|
||||
if (e) {
|
||||
e.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function keep() {
|
||||
var e = document.getElementById('geoloc-keep');
|
||||
if (e) {
|
||||
return e.checked;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
_ = navigator.mozL10n.get;
|
||||
disable('btnStop');
|
||||
disable('btnClear');
|
||||
disable('btnSave');
|
||||
hide('parameters');
|
||||
hide('status');
|
||||
hide('debuglog');
|
||||
var keep = document.getElementById('geoloc-keep');
|
||||
keep.addEventListener('change', function(ev) {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.target.checked) {
|
||||
enable('btnSave');
|
||||
} else {
|
||||
disable('btnSave');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('geoloc-debug').addEventListener('change', function(ev) {
|
||||
if (ev.target.checked) {
|
||||
show('debuglog');
|
||||
} else {
|
||||
hide('debuglog');
|
||||
}
|
||||
});
|
||||
|
||||
var showHideDiv = function(ev, tgt) {
|
||||
var clicktarget = document.getElementById(tgt);
|
||||
clicktarget.addEventListener(ev, function(ev) {
|
||||
var target = ev.target.dataset['hide'];
|
||||
var el = document.getElementById(target);
|
||||
if (el) {
|
||||
if (el.style.display == "" || el.style.display == "block") {
|
||||
hide(target);
|
||||
} else {
|
||||
show(target);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
showHideDiv('click', 'h1-parameters');
|
||||
showHideDiv('click', 'h1-status');
|
||||
showHideDiv('click', 'h1-debuglog');
|
||||
|
||||
document.getElementById('btnGet').addEventListener('click', getGeoloc);
|
||||
document.getElementById('btnStart').addEventListener('click', startGeoloc);
|
||||
document.getElementById('btnStop').addEventListener('click', stopGeoloc);
|
||||
document.getElementById('btnClear').addEventListener('click', clearGeoloc);
|
||||
document.getElementById('btnSave').addEventListener('click', saveGeoloc);
|
||||
});
|
||||
20
gaia/dev_apps/geoloc/locales/geoloc.en-US.properties
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
geolocation-tracker = Geolocation tracker
|
||||
|
||||
geoloc-get = Get current
|
||||
geoloc-start = Start
|
||||
geoloc-stop = Stop
|
||||
geoloc-clear = Clear
|
||||
geoloc-debug = Show debug traces
|
||||
geoloc-keep = Keep locations
|
||||
geoloc-save = Save as a file
|
||||
geoloc-parameters = Parameters
|
||||
geoloc-status = Status
|
||||
geoloc-debug-log = Debug log
|
||||
geoloc-timeout = Timeout
|
||||
geoloc-maxage = Max. age
|
||||
geoloc-highaccuracy = High accuracy
|
||||
geoloc-msecs = Timeout and max. age are specified in milliseconds.
|
||||
|
||||
gps-fixes = Fixes
|
||||
last-fix = Last
|
||||
date-last-fix.placeholder = None
|
||||
41
gaia/dev_apps/geoloc/manifest.webapp
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "Geoloc",
|
||||
"description": "Geolocation Tracker",
|
||||
"type": "certified",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "lissyx",
|
||||
"url": "https://github.com/lissyx/gaia-geoloc"
|
||||
},
|
||||
"permissions": {
|
||||
"geolocation":{},
|
||||
"device-storage:sdcard":{ "access": "readonly" }
|
||||
},
|
||||
"locales": {
|
||||
"ar": {
|
||||
"name": "Geoloc",
|
||||
"description": "Geolocation Tracker"
|
||||
},
|
||||
"en-US": {
|
||||
"name": "Geoloc",
|
||||
"description": "Geolocation Tracker"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Geoloc",
|
||||
"description": "Enregistrement de géolocalisation"
|
||||
},
|
||||
"zh-TW": {
|
||||
"name": "Geoloc",
|
||||
"description": "Geolocation Tracker"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"default_locale": "en-US",
|
||||
"orientation": "portrait-primary"
|
||||
}
|
||||
27
gaia/dev_apps/geoloc/style/geoloc.css
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
background: none;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
margin-left: -2em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
li span {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
fieldset legend {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
span.desc {
|
||||
padding: 1em;
|
||||
}
|
||||
BIN
gaia/dev_apps/geoloc/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/geoloc/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/geoloc/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/geoloc/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/dev_apps/geoloc/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
10
gaia/dev_apps/in_app_pay_test/index.html
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>In-App Payments Tester</title>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="app" src="http://inapp-pay-test.paas.allizom.org"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
18
gaia/dev_apps/in_app_pay_test/manifest.webapp
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "In-app Payment Tester",
|
||||
"description": "Utility app to test in-app payments.",
|
||||
"version": "1.0",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"default_locale": "en",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
10
gaia/dev_apps/in_app_pay_test/style.css
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
#app {
|
||||
position: fixed;
|
||||
border: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
BIN
gaia/dev_apps/in_app_pay_test/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/in_app_pay_test/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/in_app_pay_test/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/in_app_pay_test/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/dev_apps/in_app_pay_test/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
33
gaia/dev_apps/l20n-app/index.html
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<script defer src="shared/js/intl/l20n.js"></script>
|
||||
<link rel="localization" href="locales/example.{locale}.l20n">
|
||||
|
||||
<title>L20n</title>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #dff;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 data-l10n-id="hello"></h1>
|
||||
<p data-l10n-id="name">
|
||||
<input type="text">
|
||||
<input type="submit">
|
||||
</p>
|
||||
<div data-l10n-id="unreadEmails" data-l10n-args='{"emailCount": 5}'/>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1
gaia/dev_apps/l20n-app/js/template.js
Executable file
|
|
@ -0,0 +1 @@
|
|||
// App script goes here.
|
||||
8
gaia/dev_apps/l20n-app/locales/example.en-US.l20n
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
<hello "Hello, <em>world</em>!">
|
||||
<name 'Type <input placeholder="your name"> and <input value="send">'>
|
||||
|
||||
<unreadEmails[@cldr.plural($emailCount)] {
|
||||
one: "You have one unread email",
|
||||
other: "You have {{ $emailCount }} unread emails"
|
||||
}>
|
||||
|
||||
17
gaia/dev_apps/l20n-app/manifest.webapp
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "L20n Example App",
|
||||
"description": "Example app using l20n file format",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"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/dev_apps/l20n-app/style/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/l20n-app/style/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/l20n-app/style/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/l20n-app/style/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/dev_apps/l20n-app/style/icons/default_84.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
gaia/dev_apps/marketplace-dev.allizom.org/application.zip
Executable file
9
gaia/dev_apps/marketplace-dev.allizom.org/metadata.json
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"external": true,
|
||||
"etag": "\"82c95e39e46ee556037d41177df63766f6c8229b6ad7ee67ec56db17ce29ef8e\"",
|
||||
"manifestURL": "https://marketplace.firefox.com/app/bee10fbb-7829-4d99-8a9f-a6d0a905138e/manifest.webapp",
|
||||
"packageEtag": "\"e5dcfbb758ef085adab393464d92ccbd0de7bfc0fab94e0e7d3dc2c1aa07f39f\"",
|
||||
"installOrigin": "https://marketplace.firefox.com",
|
||||
"removable": true,
|
||||
"type": "privileged"
|
||||
}
|
||||
17
gaia/dev_apps/marketplace-dev.allizom.org/update.webapp
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "Dev",
|
||||
"description": "Firefox Marketplace Dev",
|
||||
"developer": {
|
||||
"name": "Mozilla",
|
||||
"url": "http://mozilla.org"
|
||||
},
|
||||
"icons": {
|
||||
"60": "/60.png",
|
||||
"90": "/90.png",
|
||||
"120": "/120.png",
|
||||
"128": "/128.png",
|
||||
"256": "/256.png"
|
||||
},
|
||||
"launch_path": "/index.html",
|
||||
"package_path": "/application.zip"
|
||||
}
|
||||
BIN
gaia/dev_apps/marketplace.allizom.org/application.zip
Executable file
9
gaia/dev_apps/marketplace.allizom.org/metadata.json
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"external": true,
|
||||
"etag": "\"2fe3dfe988d1bce334a4697ef2fcf4a736fb539ed1dd141b74d72d9d50abbfa2\"",
|
||||
"manifestURL": "https://marketplace.firefox.com/app/3cf61cd6-7ab6-4329-83dc-275b47c8c873/manifest.webapp",
|
||||
"packageEtag": "\"a9f9981c467a42a53e4009590e9c3123d9ac8b56b4587d31856fddafce054c72\"",
|
||||
"installOrigin": "https://marketplace.firefox.com",
|
||||
"removable": true,
|
||||
"type": "privileged"
|
||||
}
|
||||
17
gaia/dev_apps/marketplace.allizom.org/update.webapp
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "Stage",
|
||||
"description": "Firefox Marketplace Stage",
|
||||
"developer": {
|
||||
"name": "Mozilla",
|
||||
"url": "http://mozilla.org"
|
||||
},
|
||||
"icons": {
|
||||
"60": "/60.png",
|
||||
"90": "/90.png",
|
||||
"120": "/120.png",
|
||||
"128": "/128.png",
|
||||
"256": "/256.png"
|
||||
},
|
||||
"launch_path": "/index.html",
|
||||
"package_path": "/application.zip"
|
||||
}
|
||||
33
gaia/dev_apps/membuster/index.html
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Template</title>
|
||||
|
||||
<style>
|
||||
#canvases {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0px;
|
||||
}
|
||||
canvas {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
</style>
|
||||
<script src="membuster.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<button id="sys">Bust system memory</button>
|
||||
<button id="gfx">Bust graphics memory</button>
|
||||
</div>
|
||||
<div><span id="log"></span></div>
|
||||
<div id="canvases"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
63
gaia/dev_apps/membuster/manifest.webapp
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory",
|
||||
"launch_path": "/index.html",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"locales": {
|
||||
"ar": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"de": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"el": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"en-US": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"es": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"it": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"pt-BR": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"ru": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"tr": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
},
|
||||
"zh-TW": {
|
||||
"name": "Membuster",
|
||||
"description": "Busts your memory"
|
||||
}
|
||||
},
|
||||
"default_locale": "en-US",
|
||||
"icons": {
|
||||
"84": "/style/icons/membuster_84.png",
|
||||
"126": "/style/icons/membuster_126.png",
|
||||
"142": "/style/icons/membuster_142.png",
|
||||
"189": "/style/icons/membuster_189.png",
|
||||
"284": "/style/icons/membuster_284.png"
|
||||
}
|
||||
}
|
||||
66
gaia/dev_apps/membuster/membuster.js
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
var arr = [];
|
||||
function bustSysmem() {
|
||||
setInterval(allocChunk, 1000);
|
||||
}
|
||||
|
||||
var chunks = [ ]; // root the chunks
|
||||
var nextChunkMB = 32;
|
||||
var totalAllocMB = 0;
|
||||
function allocChunk() {
|
||||
var allocSizeMB = nextChunkMB * 1024 * 1024;
|
||||
var array = new ArrayBuffer(allocSizeMB);
|
||||
|
||||
// Ensure all pages are committed.
|
||||
var view = new Int32Array(array);
|
||||
for (var j = 0; j < view.length; j += 1024) {
|
||||
view[j] = 42;
|
||||
}
|
||||
|
||||
totalAllocMB += nextChunkMB;
|
||||
log("Allocated "+ nextChunkMB +"MB; total so far is "+ totalAllocMB+ "MB");
|
||||
|
||||
if (nextChunkMB > 1) {
|
||||
nextChunkMB >>= 1
|
||||
}
|
||||
|
||||
chunks.push(array);
|
||||
}
|
||||
|
||||
function bustGfxmem() {
|
||||
setInterval(allocCanvas, 1000);
|
||||
}
|
||||
|
||||
var totalGfxMB = 0;
|
||||
function allocCanvas() {
|
||||
var c = document.createElement("canvas");
|
||||
// We want to allocate 1MB of gfx mem. Canvases are double buffered
|
||||
// and default to RGBA. So we create one with 128K pixels.
|
||||
var w = 128, h = 1024;
|
||||
c.width = w;
|
||||
c.height = h;
|
||||
|
||||
var ctx = c.getContext('2d');
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
ctx.fillStyle = 'rgba(0, 0, 255, 0.1)';
|
||||
ctx.rect(0, 0, w, h);
|
||||
ctx.fill();
|
||||
|
||||
++totalGfxMB;
|
||||
log("Allocated 1MB gfx memory; total so far is ~"+ totalGfxMB +"MB");
|
||||
|
||||
document.getElementById("canvases").appendChild(c);
|
||||
}
|
||||
|
||||
var logElt;
|
||||
function log(msg) {
|
||||
if (!logElt) {
|
||||
logElt = document.getElementById("log");
|
||||
}
|
||||
logElt.textContent = msg;
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
document.getElementById("sys").onclick = function() { bustSysmem(); };
|
||||
document.getElementById("gfx").onclick = function() { bustGfxmem(); };
|
||||
};
|
||||
BIN
gaia/dev_apps/membuster/style/icons/membuster_126.png
Executable file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
gaia/dev_apps/membuster/style/icons/membuster_142.png
Executable file
|
After Width: | Height: | Size: 2 KiB |
BIN
gaia/dev_apps/membuster/style/icons/membuster_189.png
Executable file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
gaia/dev_apps/membuster/style/icons/membuster_284.png
Executable file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
gaia/dev_apps/membuster/style/icons/membuster_84.png
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
202
gaia/dev_apps/mobile-wallet/LICENSE
Executable file
|
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 Deutsche Telekom, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
364
gaia/dev_apps/mobile-wallet/css/app.css
Executable file
|
|
@ -0,0 +1,364 @@
|
|||
html {
|
||||
font-size: 10px;
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
[role="toolbar"] {
|
||||
position: static;
|
||||
}
|
||||
|
||||
ul {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.gaia-icon::before {
|
||||
font-style: normal;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon-settings::before {
|
||||
color: white;
|
||||
top: 2px;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
.note {
|
||||
font-size: 0.7em;
|
||||
padding-left: 15px;
|
||||
padding-bottom: 5px;
|
||||
background-color: rgb(248, 246, 246);
|
||||
display: none;
|
||||
}
|
||||
|
||||
#main article > header {
|
||||
background-color: rgb(248, 246, 246);
|
||||
color: #F97C17;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px white solid;
|
||||
border-top: 1px white solid;
|
||||
/* box-shadow: 0px 1px 5px 0px rgba(50, 50, 50, 0.1);*/
|
||||
font-size: 12px;
|
||||
box-shadow: 0px 1px 1px 0px rgba(33, 33, 33, 0.1);
|
||||
}
|
||||
|
||||
.bottom-article > header {
|
||||
z-index: 3;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hide, .listview-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#settings p {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child h1:nth-child(2) {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
#hci-notification {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 300;
|
||||
transition: all 0.6s ease;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
#hci-notification img {
|
||||
width: 240px;
|
||||
box-shadow: 0px 1px 4px 1px #7B7B7B;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#hci-notification.show {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 300;
|
||||
transition: all 0.6s ease;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
article.notification {
|
||||
color: #9C9C9C;
|
||||
font-size: 0.7em;
|
||||
font-style: italic;
|
||||
opacity: 0.95;
|
||||
background: black;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.hci-card {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hci-container {
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
padding: 0px 20px;
|
||||
color: rgb(77, 78, 83);
|
||||
background: transparent linear-gradient(to bottom, rgb(234, 239, 242), rgb(212, 221, 228));
|
||||
}
|
||||
|
||||
.hci-container p {
|
||||
line-height: 3em;
|
||||
font-weight: 300;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
@keyframes show-card {
|
||||
0% { z-index: 2; transform: rotate(0deg); top: 0px; left: 0px; width: 240px;}
|
||||
50% { z-index: 10; transform: rotate(0deg); top: -30px; left: -2px; width: 244px;}
|
||||
100% { z-index: 10; transform: rotate(0deg); top: -8px; left: 0px; width: 240px;}
|
||||
}
|
||||
|
||||
@keyframes hide-card {
|
||||
0% { z-index: 10; transform: rotate(0deg); top: -8px; left: 0px; width: 240px;}
|
||||
50% { z-index: 10; transform: rotate(0deg); top: -30px; left: -2px; width: 244px;}
|
||||
100% { z-index: 2; transform: rotate(0deg); top: 0px; left: 0px; width: 240px;}
|
||||
}
|
||||
|
||||
ul.swipeable > li.deselected > img {
|
||||
animation-name: hide-card;
|
||||
animation-duration: 0.5s;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
ul.swipeable > li.selected > img {
|
||||
z-index: 10;
|
||||
transform: rotate(0deg);
|
||||
position: relative;
|
||||
top: -8px;
|
||||
animation-name: show-card;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
ul.details > li {
|
||||
display: block;
|
||||
padding: 15px 10px;
|
||||
}
|
||||
|
||||
ul.details > li > p.label {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.details span.date {
|
||||
display: inline-block;
|
||||
width: 67%;
|
||||
}
|
||||
|
||||
li.details-more {
|
||||
text-align: center;
|
||||
vertical-align: bottom;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
li.details-more > .details-note {
|
||||
font-style: italic;
|
||||
font-size: 0.8em;
|
||||
color: rgb(133, 133, 133);
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
/*.details-oneline p {
|
||||
display: inline-block;
|
||||
}*/
|
||||
|
||||
.active > header {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.slider {
|
||||
background-color: rgb(248, 246, 246);
|
||||
/* transform: translate3d(0, -131px, 0);
|
||||
box-shadow: inset 0px 1px 5px 0px rgba(50, 50, 50, 0.1);
|
||||
box-shadow: 0px 5px 5px 0px rgba(33, 33, 33, 0.1) inset; */
|
||||
padding-top: 1rem;
|
||||
height: 25rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bottom-slide .slider {
|
||||
box-shadow: 0px 2px 2px 0px rgba(33, 33, 33, 0.1) inset;
|
||||
}
|
||||
|
||||
.bottom-slide > header {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.top-slide {
|
||||
margin-top: -26rem;
|
||||
transition: transform 0.75s, margin-top 0.75s ease;
|
||||
}
|
||||
|
||||
.details-visible .top-slide {
|
||||
margin-top: 0px;
|
||||
overflow: auto;
|
||||
transform: translate3d(0,0,0)
|
||||
}
|
||||
|
||||
.bottom-slide {
|
||||
z-index: 3;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
transition: transform 0.75s, top 0.75s ease;
|
||||
}
|
||||
|
||||
.bottom-slide.details-visible {
|
||||
top: -253px;
|
||||
transform: translate3d(0,0,0)
|
||||
}
|
||||
|
||||
section[role="region"] > header:first-child .t-logo {
|
||||
background: url(../img/icons/t_logo_white.png) center center / 5rem auto no-repeat;
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.pocket, .listview-element-pocket {
|
||||
width: 260px;
|
||||
height: 40px;
|
||||
border-radius: 12px;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
top: 150px;
|
||||
left: 0px;
|
||||
background: linear-gradient(to bottom, rgb(200, 200, 200) 0%, #F4F4F4 77%, #F4F4F4 100%) repeat scroll 0% 0% transparent;
|
||||
border-top: 1px solid #808080;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/*.nonpayment*/ .details li {
|
||||
min-height: 0px
|
||||
}
|
||||
|
||||
/*.nonpayment*/ .details p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/*.nonpayment*/ .details p.val {
|
||||
float: right;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.details .price {
|
||||
font-family: "Fira Mono";
|
||||
font-size: 13px;
|
||||
width: 21%;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.details .currency {
|
||||
font-family: "Fira Mono";
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sew, .listview-element-sew {
|
||||
width: 92%;
|
||||
height: 10px;
|
||||
margin: 2px 0px 0px 5px;
|
||||
border-radius: 12px;
|
||||
padding-right: 10px;
|
||||
border-top: 1px dashed #8C8C8C;
|
||||
}
|
||||
|
||||
ul.transaction-list > li.transaction {
|
||||
padding: 4px 0px 1px 10px;
|
||||
color: rgb(133, 133, 133);
|
||||
}
|
||||
|
||||
ul.transaction-list > li.transaction:after {
|
||||
border: 0px none;
|
||||
}
|
||||
|
||||
ul.details > li p {
|
||||
font-size: 1em;
|
||||
margin-left: 10px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
ul.details > li p.value {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.error-view {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
margin-top: -2em;
|
||||
}
|
||||
|
||||
.error-view h2.error {
|
||||
font-weight: normal;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.error-view button {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.error-img {
|
||||
width: 5em;
|
||||
height: 5em;
|
||||
background-image: url(../img/errors/error.png);
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.error-api {
|
||||
background-image: url(../img/errors/api-error.png);
|
||||
}
|
||||
|
||||
.error-no-sim {
|
||||
background-image: url(../img/errors/no-sim.png);
|
||||
}
|
||||
|
||||
.error-sim {
|
||||
background-image: url(../img/errors/sim-error.png);
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
margin: 10px 10px 0px 10px;
|
||||
}
|
||||
|
||||
@media (min-width: 360px) {
|
||||
.bottom-slide {
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.bottom-slide.details-visible {
|
||||
top: -26rem;
|
||||
}
|
||||
|
||||
ul.details > li.details-more {
|
||||
padding-right: 20px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
131
gaia/dev_apps/mobile-wallet/css/pin.css
Executable file
|
|
@ -0,0 +1,131 @@
|
|||
section#pin {
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
.pin-unblocked {
|
||||
font-weight: 300;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.pin-view h2 {
|
||||
font-size: 1.2em;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pin-view:not(hide) {
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.pin-top {
|
||||
/*font-style: italic;*/
|
||||
height: 7.3em;
|
||||
}
|
||||
|
||||
.pin-input {
|
||||
text-align: center;
|
||||
margin: 35px 0px 30px;
|
||||
}
|
||||
|
||||
.pin-input > div {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 1.5px solid #ccc;
|
||||
vertical-align: baseline;
|
||||
margin: 0px 5px;
|
||||
}
|
||||
|
||||
.pin-input > div.pin-digit-entered {
|
||||
background: linear-gradient(to bottom, #f4f4f4 0%,#333333 100%);
|
||||
border: 1.5px solid #333;
|
||||
}
|
||||
|
||||
.pin-keypad {
|
||||
display: table;
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
margin: 0px 0px 25px 0px;
|
||||
}
|
||||
|
||||
.pin-keypad-row {
|
||||
border-width: 0px 0px 1px 0px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
/*border-image: linear-gradient(45deg, #f4f4f4, #ccc, #f4f4f4) 1;*/
|
||||
border-image: linear-gradient(to right, #f4f4f4 0%,#cccccc 30%,#cccccc 70%,#f4f4f4 100%) 1;
|
||||
}
|
||||
|
||||
.pin-keypad-row:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.pin-key {
|
||||
display: table-cell;
|
||||
width: 2.7em;
|
||||
height: 2.7em;
|
||||
vertical-align: middle;
|
||||
border-right: 1px solid #ccc;
|
||||
font-size: 1.7em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pin-key.clear-key::after {
|
||||
content: "clear";
|
||||
font-size: 0.5em;
|
||||
vertical-align: 35%;
|
||||
}
|
||||
|
||||
.pin-key:active {
|
||||
color: #F97C17;
|
||||
/*background-color: #ccc;*/
|
||||
}
|
||||
|
||||
.pin-key.gaia-icon::before {
|
||||
position: relative;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.pin-key.icon-clearcancel-cross::before {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
.pin-keypad-row:first-child .pin-key {
|
||||
background: linear-gradient(to bottom, #f4f4f4, #ccc);
|
||||
background-origin: border-box;
|
||||
border-right: 1px solid transparent;
|
||||
box-shadow: inset -999px 0 0 #f4f4f4;
|
||||
}
|
||||
|
||||
.pin-keypad-row:last-child .pin-key {
|
||||
background: linear-gradient(to top, #f4f4f4, #ccc);
|
||||
background-origin: border-box;
|
||||
border-right: 1px solid transparent;
|
||||
box-shadow: inset -999px 0 0 #f4f4f4;
|
||||
}
|
||||
|
||||
.pin-keypad-row .pin-key:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.pin-warning {
|
||||
margin-bottom: -39px;
|
||||
position: relative;
|
||||
top: -13px;
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pin-enable-warning {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.error-pin-enable {
|
||||
background-image: url(../img/errors/pin-enable-fail.png);
|
||||
}
|
||||
|
||||
.error-locked {
|
||||
background-image: url(../img/errors/locked.png);
|
||||
}
|
||||
|
||||
172
gaia/dev_apps/mobile-wallet/css/settings.css
Executable file
|
|
@ -0,0 +1,172 @@
|
|||
#settings {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
opacity: 1;
|
||||
transition: all 0.6s ease;
|
||||
background-color: #F4F4F4;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
#settings.edit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
opacity: 1;
|
||||
transition: all 0.6s ease;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.settings-subpage {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 101;
|
||||
opacity: 1;
|
||||
background-color: #F4F4F4;
|
||||
transition: transform 0.6s ease;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.settings-subpage.slide-in {
|
||||
transition: transform 0.6s ease;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.settings-disabled {
|
||||
pointer-events: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.settings-disabled .gaia-icon::before {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.settings-disclaimer {
|
||||
font-size: 0.6em;
|
||||
padding: 0px 15px 10px 15px;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.settings-forward div {
|
||||
width: 100%;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.settings-forward .gaia-icon {
|
||||
text-align: right;
|
||||
color: #868692;
|
||||
}
|
||||
|
||||
.settings-forward .gaia-icon::before {
|
||||
position: relative;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
#settings-status {
|
||||
opacity: 0;
|
||||
transition: opacity 600ms ease 0s;
|
||||
}
|
||||
|
||||
#settings-status.visible {
|
||||
opacity: 1;
|
||||
transition: opacity 1000ms ease 0s;
|
||||
}
|
||||
|
||||
#settings-status p{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#settings-about section > div {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #E7E7E7;
|
||||
padding: 10px;
|
||||
margin: 0px 15px;
|
||||
}
|
||||
|
||||
#settings-about div:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#settings-about div:first-child {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.about-logo img {
|
||||
max-width: 9em;
|
||||
}
|
||||
|
||||
.about-logo p {
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
.about-logo p:first-child {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.about-logo p:nth-child(2) {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.about-logo p:nth-child(4) {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.about-authors p, .about-contributors p {
|
||||
font-size: 0.8em;
|
||||
color: #a6a6a6;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.about-authors strong, .about-contributors strong {
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.about-authors p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.about-authors strong {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.about-contributors div {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.about-contributors h3 {
|
||||
font-size: 0.8em;
|
||||
margin-bottom: 2px;
|
||||
margin-top: 1px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.about-contributors div p:nth-child(2) {
|
||||
line-height: 1em;
|
||||
margin: 5px 0px;
|
||||
}
|
||||
|
||||
.about-contributors div p:nth-child(3) {
|
||||
line-height: 1em;
|
||||
font-size: 0.6em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* ugly hacks to override header.css, TODO migrate to proper gaia header */
|
||||
section[role="region"].settings-subpage > header:first-child h1:nth-child(2) {
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
section.skin-organic.settings-subpage[role="region"] > header:first-child .gaia-icon {
|
||||
color: #868692;
|
||||
background: none;
|
||||
}
|
||||
70
gaia/dev_apps/mobile-wallet/css/swipeable.css
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
ul.swipeable {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: 0px;
|
||||
}
|
||||
|
||||
ul.swipeable > li {
|
||||
display: inline-block;
|
||||
width: 260px;
|
||||
height: 206px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
ul.swipeable > li > img, .listview-element-img {
|
||||
width: 240px;
|
||||
padding: 20px 10px 25px;
|
||||
margin-top: -35px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
ul.swipeable > li:first-child {
|
||||
margin-left: 3rem;
|
||||
}
|
||||
|
||||
.swipeable-container {
|
||||
z-index: 2;
|
||||
background-color: #f4f4f4;
|
||||
border-bottom: 1px solid #FBFBFB;
|
||||
box-shadow: 0px 2px 2px 0px rgba(33, 33, 33, 0.1);
|
||||
}
|
||||
|
||||
.swipeable-progress {
|
||||
text-align: center;
|
||||
height: 1.6rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.swipeable-progress div{
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border: 2px solid #aeaeae;
|
||||
vertical-align: baseline;
|
||||
margin: 0px 2px;
|
||||
}
|
||||
|
||||
.swipeable-progress div.swipeable-progress-selected {
|
||||
background: #aeaeae;
|
||||
}
|
||||
|
||||
.swipeable-progress div.swipeable-progress-active {
|
||||
/* background-color: #e20074; */
|
||||
border: 2px solid #F97C17;
|
||||
}
|
||||
|
||||
.swipeable-progress div.swipeable-progress-active.swipeable-progress-selected {
|
||||
background: #F97C17;
|
||||
}
|
||||
|
||||
@media (min-width: 360px) {
|
||||
ul.swipeable > li:first-child {
|
||||
margin-left: 5rem;
|
||||
}
|
||||
|
||||
.swipeable-container {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
BIN
gaia/dev_apps/mobile-wallet/img/cards/no-cards-other.png
Executable file
|
After Width: | Height: | Size: 11 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/no-cards-payment.png
Executable file
|
After Width: | Height: | Size: 12 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/other-1.png
Executable file
|
After Width: | Height: | Size: 25 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/other-2.png
Executable file
|
After Width: | Height: | Size: 24 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/other-3.png
Executable file
|
After Width: | Height: | Size: 23 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/payment-1.png
Executable file
|
After Width: | Height: | Size: 21 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/payment-2.png
Executable file
|
After Width: | Height: | Size: 22 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/payment-3.png
Executable file
|
After Width: | Height: | Size: 22 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/cards/unknown.png
Executable file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/errors/api-error.png
Executable file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/errors/error.png
Executable file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/errors/locked.png
Executable file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/errors/no-sim.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/errors/pin-enable-fail.png
Executable file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/errors/sim-error.png
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/icons/default_126.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/icons/default_142.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/icons/default_189.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
gaia/dev_apps/mobile-wallet/img/icons/default_284.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |