Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
193
gaia/shared/js/everythingme/api.js
Executable file
193
gaia/shared/js/everythingme/api.js
Executable file
|
|
@ -0,0 +1,193 @@
|
|||
'use strict';
|
||||
/* global Promise */
|
||||
|
||||
(function(eme) {
|
||||
|
||||
const NETWORK_ERROR = 'network error';
|
||||
const API_KEY = '79011a035b40ef3d7baeabc8f85b862f';
|
||||
|
||||
const ICON_FORMAT = 20;
|
||||
|
||||
var device = eme.device;
|
||||
|
||||
function getCtx() {
|
||||
var w = device.screen.width;
|
||||
var h = device.screen.height;
|
||||
|
||||
// default to undefined's so that JSON.stringify will drop them
|
||||
return {
|
||||
lc: device.language || undefined,
|
||||
tz: device.timezone || undefined,
|
||||
v: device.osVersion || undefined,
|
||||
dn: device.deviceName || undefined,
|
||||
cr: device.carrier || undefined,
|
||||
ct: device.dataConnectionType || undefined,
|
||||
mcc: device.mcc || undefined,
|
||||
mnc: device.mnc || undefined,
|
||||
sr: (w && h) ? [w, h].join('x') : undefined
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an async httpRequest to resource with given options.
|
||||
* Returns a promise which will be resolved/reject on success/error
|
||||
* respectively
|
||||
*/
|
||||
function Request(service, method, options) {
|
||||
|
||||
if (!eme.config.apiUrl) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
reject('eme.config.apiUrl not defined');
|
||||
});
|
||||
}
|
||||
|
||||
var resource = service + '/' + method;
|
||||
var url = eme.config.apiUrl.replace('{resource}', resource);
|
||||
var payload = '';
|
||||
|
||||
options = options ? options : {};
|
||||
|
||||
options.apiKey = API_KEY;
|
||||
options.deviceId = eme.device.deviceId;
|
||||
|
||||
options.ctx = getCtx();
|
||||
|
||||
for (var opt in options) {
|
||||
var value = options[opt];
|
||||
if (value !== null && value !== undefined) {
|
||||
if (typeof value === 'object') {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
|
||||
payload += opt + '=' + encodeURIComponent(value) + '&';
|
||||
}
|
||||
}
|
||||
|
||||
eme.log('API request:', decodeURIComponent(url + '?' + payload));
|
||||
|
||||
var httpRequest;
|
||||
var promise = new Promise(function done(resolve, reject) {
|
||||
httpRequest = new XMLHttpRequest({mozSystem: true});
|
||||
httpRequest.open('POST', url, true);
|
||||
httpRequest.setRequestHeader(
|
||||
'Content-Type', 'application/x-www-form-urlencoded');
|
||||
|
||||
httpRequest.onload = function onload(e) {
|
||||
var response = null;
|
||||
|
||||
try {
|
||||
response = JSON.parse(httpRequest.responseText);
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
|
||||
if (response && response.errorCode > 0) {
|
||||
resolve(response);
|
||||
} else {
|
||||
reject(response ?
|
||||
'errorCode: ' + response.errorCode : 'invalid response');
|
||||
}
|
||||
};
|
||||
|
||||
httpRequest.onerror = function onError(e) {
|
||||
reject(NETWORK_ERROR);
|
||||
};
|
||||
|
||||
httpRequest.send(payload);
|
||||
});
|
||||
|
||||
promise.abort = function() {
|
||||
if (httpRequest.abort) {
|
||||
httpRequest.abort();
|
||||
}
|
||||
};
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function SanitizeAppSearch(result) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// Sanitize app URLs returned from e.me
|
||||
var apps = result.response.apps;
|
||||
if (apps.length) {
|
||||
var a = document.createElement('a');
|
||||
for (var i = 0, iLen = apps.length; i < iLen; i++) {
|
||||
a.href = apps[i].appUrl;
|
||||
apps[i].appUrl = a.href;
|
||||
}
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
}
|
||||
|
||||
function PartnersAPI() {
|
||||
|
||||
this.Apps = {
|
||||
MAX_QUERY_LENGTH : 128,
|
||||
|
||||
nativeInfo: function nativeInfo(options) {
|
||||
if (options.guids && options.guids.length) {
|
||||
// string together ids like so:
|
||||
// Apps/nativeInfo/?guids=["guid1","guid2","guid3", ...]
|
||||
options.guids = JSON.stringify(options.guids);
|
||||
}
|
||||
|
||||
return Request('Apps', 'nativeInfo', options);
|
||||
},
|
||||
|
||||
search: function search(options) {
|
||||
if (!!options.query && options.query.length > this.MAX_QUERY_LENGTH) {
|
||||
options.query = options.query.substr(0, this.MAX_QUERY_LENGTH);
|
||||
}
|
||||
|
||||
options.iconFormat = ICON_FORMAT;
|
||||
|
||||
return Request('Apps', 'search', options).then(SanitizeAppSearch);
|
||||
}
|
||||
};
|
||||
|
||||
this.Search = {
|
||||
suggestions: function suggestions(options) {
|
||||
return Request('Search', 'suggestions', options);
|
||||
},
|
||||
bgimage: function bgimage(options) {
|
||||
// Some devices contain fractions in dimensions
|
||||
// which the eme api server does not accept
|
||||
// so Math.ceil (http://bugzil.la/1023312)
|
||||
options.width = Math.ceil(options.width || eme.device.screen.width);
|
||||
options.height = Math.ceil(options.height || eme.device.screen.height);
|
||||
|
||||
return Request('Search', 'bgimage', options);
|
||||
}
|
||||
};
|
||||
|
||||
/** Make a Request and
|
||||
* 1. on success: cache the response
|
||||
* 2. on error: get response from cache
|
||||
* 2.1 on error: reject with NETWORK_ERROR
|
||||
*/
|
||||
this.Categories = {
|
||||
list: function list(options) {
|
||||
var request = Request('Categories', 'list', options);
|
||||
|
||||
return request.then(
|
||||
response => {
|
||||
eme.Cache.addRequest('Categories', 'list', options, response);
|
||||
return response;
|
||||
},
|
||||
() => {
|
||||
return eme.Cache.getRequest('Categories', 'list', options)
|
||||
.then(response => {
|
||||
eme.log('using cached response (Categories/list)');
|
||||
return response;
|
||||
})
|
||||
.catch(() => Promise.reject(NETWORK_ERROR));
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
eme.api = new PartnersAPI();
|
||||
|
||||
})(window.eme);
|
||||
44
gaia/shared/js/everythingme/cache.js
Executable file
44
gaia/shared/js/everythingme/cache.js
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
'use strict';
|
||||
/* global Promise*/
|
||||
/* global asyncStorage*/
|
||||
|
||||
(function(eme) {
|
||||
var PREFIX = 'eme-cache';
|
||||
var slice = Function.call.bind(Array.prototype.slice);
|
||||
|
||||
|
||||
function Cache() { }
|
||||
|
||||
Cache.prototype = {
|
||||
generateKey: function cache_generateKey() {
|
||||
return slice(arguments).map(JSON.stringify).join('|');
|
||||
},
|
||||
|
||||
add: function cache_add(key, value) {
|
||||
return new Promise(function ready(resolve, reject) {
|
||||
asyncStorage.setItem(PREFIX + key, value);
|
||||
});
|
||||
},
|
||||
get: function cache_get(key) {
|
||||
return new Promise(function ready(resolve, reject) {
|
||||
asyncStorage.getItem(PREFIX + key, function onValue(value) {
|
||||
if (value === null) {
|
||||
reject(null);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
addRequest: function cache_addRequest(service, method, options, response) {
|
||||
this.add(this.generateKey(service, method, options), response);
|
||||
},
|
||||
getRequest: function cache_getRequest(service, method, options) {
|
||||
return this.get(this.generateKey(service, method, options));
|
||||
}
|
||||
};
|
||||
|
||||
eme.Cache = new Cache();
|
||||
|
||||
})(window.eme);
|
||||
112
gaia/shared/js/everythingme/device.js
Executable file
112
gaia/shared/js/everythingme/device.js
Executable file
|
|
@ -0,0 +1,112 @@
|
|||
'use strict';
|
||||
/* global Promise */
|
||||
|
||||
(function(eme) {
|
||||
|
||||
const mozSettings = navigator.mozSettings;
|
||||
const mozWifiManager = navigator.mozWifiManager;
|
||||
const mozMobileConnections = navigator.mozMobileConnections;
|
||||
|
||||
const dataConnectionNames = {
|
||||
'hspa+': 'H+',
|
||||
'lte': '4G', 'ehrpd': '4G',
|
||||
'hsdpa': '3G', 'hsupa': '3G', 'hspa': '3G', 'evdo0': '3G', 'evdoa': '3G',
|
||||
'evdob': '3G', '1xrtt': '3G', 'umts': '3G',
|
||||
'edge': '2G', 'is95a': '2G', 'is95b': '2G', 'gprs': '2G'
|
||||
};
|
||||
|
||||
function Device() {
|
||||
// set async. from settings when calling init()
|
||||
this.osVersion = null;
|
||||
this.deviceId = null;
|
||||
this.deviceName = null;
|
||||
|
||||
this.screen = {
|
||||
width: window.screen.width * window.devicePixelRatio,
|
||||
height: window.screen.height * window.devicePixelRatio
|
||||
};
|
||||
}
|
||||
|
||||
Device.prototype = {
|
||||
init: function init(settings) {
|
||||
var deviceId = settings['search.deviceId'];
|
||||
|
||||
if (!deviceId) {
|
||||
deviceId = this.generateDeviceId();
|
||||
mozSettings.createLock().set({
|
||||
'search.deviceId': deviceId
|
||||
});
|
||||
}
|
||||
|
||||
this.deviceId = deviceId;
|
||||
this.deviceName = settings['deviceinfo.product_model'];
|
||||
this.osVersion = settings['deviceinfo.os'];
|
||||
|
||||
// Return a successful promise for back-compat.
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
// see duplicate in homescreen/everything.me.js
|
||||
generateDeviceId: function generateDeviceId() {
|
||||
var url = window.URL.createObjectURL(new Blob());
|
||||
var id = url.replace('blob:', '');
|
||||
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
return 'fxos-' + id;
|
||||
},
|
||||
|
||||
get language() {
|
||||
return navigator.language;
|
||||
},
|
||||
|
||||
get timezone() {
|
||||
return (new Date().getTimezoneOffset() / -60).toString();
|
||||
},
|
||||
|
||||
// mobile connection
|
||||
get connection() {
|
||||
if (!this._connection) {
|
||||
this._connection = mozMobileConnections &&
|
||||
mozMobileConnections.length && mozMobileConnections[0];
|
||||
}
|
||||
return this._connection;
|
||||
},
|
||||
|
||||
// voice network
|
||||
get voiceNet() {
|
||||
return (this.connection && this.connection.voice) ?
|
||||
this.connection.voice.network : null;
|
||||
},
|
||||
|
||||
// data connection type
|
||||
get dataConnectionType() {
|
||||
if (mozWifiManager && mozWifiManager.enabled) {
|
||||
return 'wifi';
|
||||
}
|
||||
|
||||
if (this.connection && this.connection.data) {
|
||||
var type = this.connection.data.type;
|
||||
return dataConnectionNames[type] || type;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
get carrier() {
|
||||
return this.voiceNet ?
|
||||
(this.voiceNet.shortName || this.voiceNet.longName) : null;
|
||||
},
|
||||
|
||||
get mcc() {
|
||||
return this.voiceNet ? this.voiceNet.mcc : null;
|
||||
},
|
||||
|
||||
get mnc() {
|
||||
return this.voiceNet ? this.voiceNet.mnc : null;
|
||||
}
|
||||
};
|
||||
|
||||
eme.device = new Device();
|
||||
|
||||
})(window.eme);
|
||||
88
gaia/shared/js/everythingme/eme.js
Executable file
88
gaia/shared/js/everythingme/eme.js
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
'use strict';
|
||||
/* global eme */
|
||||
/* global Promise */
|
||||
|
||||
(function(exports) {
|
||||
|
||||
const mozSettings = navigator.mozSettings;
|
||||
|
||||
const DEBUG = true;
|
||||
|
||||
var initPromise = null;
|
||||
var slice = Function.call.bind(Array.prototype.slice);
|
||||
|
||||
exports.eme = {
|
||||
config: {
|
||||
apiUrl: null
|
||||
},
|
||||
|
||||
init: function init() {
|
||||
if (initPromise) {
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
initPromise = this.readSettings()
|
||||
.then(
|
||||
function success(settings) {
|
||||
// config overrides
|
||||
if (settings['appsearch.url']) {
|
||||
this.config.apiUrl = settings['appsearch.url'];
|
||||
}
|
||||
|
||||
// wait for device init
|
||||
return this.device.init(settings);
|
||||
}.bind(this),
|
||||
|
||||
function error(e) {
|
||||
eme.log('fatal error accessing device settings', e);
|
||||
}
|
||||
|
||||
).catch(function(e) {
|
||||
eme.log('init failed', e);
|
||||
});
|
||||
|
||||
// avoid multiple init calls
|
||||
this.init = function noop() {
|
||||
eme.log('init: noop');
|
||||
return initPromise;
|
||||
};
|
||||
|
||||
return initPromise;
|
||||
},
|
||||
|
||||
readSettings: function readSettings() {
|
||||
return new Promise(function ready(resolve, reject) {
|
||||
var lock = mozSettings.createLock();
|
||||
var request = lock.get('*');
|
||||
|
||||
request.onsuccess = function onsuccess() {
|
||||
resolve(request.result);
|
||||
};
|
||||
request.onerror = function onerror() {
|
||||
reject(request.error);
|
||||
};
|
||||
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
log: function log() {
|
||||
if (DEBUG) {
|
||||
var args = slice(arguments);
|
||||
args.unshift('evme');
|
||||
console.log.apply(console, args);
|
||||
}
|
||||
},
|
||||
warn: function warn() {
|
||||
var args = slice(arguments);
|
||||
args.unshift('evme', 'WARNING');
|
||||
console.warn.apply(console, args);
|
||||
},
|
||||
error: function error() {
|
||||
var args = slice(arguments);
|
||||
args.unshift('evme', 'ERROR');
|
||||
console.error.apply(console, args);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})(window);
|
||||
Loading…
Reference in a new issue