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
137
gaia/apps/settings/js/modules/base/dependency_graph.js
Executable file
137
gaia/apps/settings/js/modules/base/dependency_graph.js
Executable file
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* DependencyGraph is a basic data structure that helps decide the evaluation
|
||||
* order of a certain node.
|
||||
*
|
||||
* @module modules/base/dependency_graph
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var Module = require('modules/base/module');
|
||||
|
||||
/**
|
||||
* @class DependencyGraph
|
||||
* @requires module:modules/base/module
|
||||
* @params {DependencyGraph} dpGraph
|
||||
* The newly created graph will be initialized using
|
||||
* dpGraph.
|
||||
* @returns {DependencyGraph}
|
||||
*/
|
||||
var DependencyGraph = Module.create(function DependencyGraph(dpGraph) {
|
||||
this._nodes = dpGraph ? JSON.parse(JSON.stringify(dpGraph._nodes)) : {};
|
||||
});
|
||||
|
||||
/**
|
||||
* Print the content of the nodes for debugging.
|
||||
*
|
||||
* @access private
|
||||
* @memberOf DependencyGraph.prototype
|
||||
*/
|
||||
DependencyGraph.prototype._printNodes = function dg_printNodes() {
|
||||
Object.keys(this._nodes).forEach((name) => {
|
||||
var node = this._nodes[name];
|
||||
console.log('name: ' + name);
|
||||
console.log('children: ' +
|
||||
node.children.reduce((result, name) => {
|
||||
return result + ' ' + name;
|
||||
}, ''));
|
||||
console.log('dependent nodes: ' +
|
||||
node.dependentNodes.reduce((result, name) => {
|
||||
return result + ' ' + name;
|
||||
}, ''));
|
||||
console.log('======================');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Traverse the tree and add the dependent nodes to all nodes in the path.
|
||||
*
|
||||
* @access private
|
||||
* @memberOf DependencyGraph.prototype
|
||||
* @param {Object} node
|
||||
* The node that we have new dependent nodes to add to.
|
||||
* @param {Array} dependentNodes
|
||||
* New dependent nodes to add.
|
||||
*/
|
||||
DependencyGraph.prototype._addDependentNodes =
|
||||
function dg_addDependentNodes(node, dependentNodes, traversedNodes) {
|
||||
traversedNodes = traversedNodes || [];
|
||||
if (traversedNodes.indexOf(node.name) >= 0) {
|
||||
traversedNodes.push(node.name);
|
||||
var error = traversedNodes.join(' -> ');
|
||||
this.throw('circular dependency detected! ' + error);
|
||||
}
|
||||
|
||||
if (dependentNodes) {
|
||||
// add all nodes in "dependendNodes" to the current node
|
||||
dependentNodes.forEach((name) => {
|
||||
if (node.dependentNodes.indexOf(name) < 0) {
|
||||
node.dependentNodes.push(name);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Nothing to add, prepare the nodes to be added to the children.
|
||||
dependentNodes = Array.prototype.slice.call(node.dependentNodes);
|
||||
}
|
||||
|
||||
dependentNodes.push(node.name);
|
||||
traversedNodes.push(node.name);
|
||||
node.children.forEach((name) => {
|
||||
this._addDependentNodes(this._nodes[name], dependentNodes,
|
||||
traversedNodes);
|
||||
});
|
||||
dependentNodes.pop();
|
||||
traversedNodes.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Add dependency. Calling to this function adds a dependency from the first
|
||||
* parameter towards the second one.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf DependencyGraph.prototype
|
||||
* @param {String} name1
|
||||
* The name that depends on the other.
|
||||
* @param {String} name2
|
||||
* The name that is being depended on.
|
||||
*/
|
||||
DependencyGraph.prototype.addDependency = function dg_addDep(name1, name2) {
|
||||
var node1 = this._nodes[name1];
|
||||
var node2 = this._nodes[name2];
|
||||
|
||||
if (!node1) {
|
||||
node1 = this._nodes[name1] = {
|
||||
name: name1,
|
||||
children: [],
|
||||
dependentNodes: []
|
||||
};
|
||||
}
|
||||
|
||||
if (!node2) {
|
||||
node2 = this._nodes[name2] = {
|
||||
name: name2,
|
||||
children: [],
|
||||
dependentNodes: []
|
||||
};
|
||||
}
|
||||
|
||||
if (node1.children.indexOf(name2) < 0) {
|
||||
node1.children.push(name2);
|
||||
this._addDependentNodes(node1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all dependent names of a name.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf DependencyGraph.prototype
|
||||
* @param {String} name
|
||||
*/
|
||||
DependencyGraph.prototype.getAllDependent = function dg_getAllDep(name) {
|
||||
var node = this._nodes[name];
|
||||
return node && node.dependentNodes;
|
||||
};
|
||||
|
||||
return DependencyGraph;
|
||||
});
|
||||
137
gaia/apps/settings/js/modules/base/event_emitter.js
Executable file
137
gaia/apps/settings/js/modules/base/event_emitter.js
Executable file
|
|
@ -0,0 +1,137 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var Module = require('modules/base/module');
|
||||
|
||||
/**
|
||||
* EventEmitter implements basic event emitting logics. It also provides
|
||||
* function that augments the ability to other objects.
|
||||
*
|
||||
* @example
|
||||
* var eventEmitter = EventEmitter(['event1', 'event2']);
|
||||
* var eventHandler = function(event) {
|
||||
* console.log(event.detail);
|
||||
* };
|
||||
* var obj = {
|
||||
* handleEvent: function(event) {
|
||||
* console.log(event.detail);
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* eventEmitter.addEventListener('event1', eventHandler);
|
||||
* eventEmitter.addEventListener('event2', obj);
|
||||
*
|
||||
* eventEmitter._emitEvent('event1', 'value1'); // value1
|
||||
* eventEmitter._emitEvent('event2', 'value2'); // value2
|
||||
*
|
||||
* Extending from EventEmitter:
|
||||
* @example
|
||||
* var NewModule = Module.create(function() {
|
||||
* this.super(EventEmitter).call(this, ['event1', 'event2']);
|
||||
* }).extend(EventEmitter);
|
||||
*
|
||||
* var module = NewModule();
|
||||
*
|
||||
* @class EventEmitter
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
var EventEmitter = Module.create(function EventEmitter(eventNames) {
|
||||
if (eventNames && eventNames.length) {
|
||||
this._eventListeners = eventNames.reduce((result, eventName) => {
|
||||
result[eventName] = [];
|
||||
return result;
|
||||
}, {});
|
||||
} else {
|
||||
this.throw('no valid registered events');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Emit an event of a specific type and a given value.
|
||||
*
|
||||
* @access private
|
||||
* @memberOf EventEmitter.prototype
|
||||
* @param {String} eventName
|
||||
* @param {Object} value
|
||||
*/
|
||||
EventEmitter.prototype._emitEvent = function(eventName, value) {
|
||||
var listeners = this._eventListeners[eventName];
|
||||
if (!listeners) {
|
||||
this.throw('invalid event name: ' + eventName);
|
||||
}
|
||||
|
||||
this.debug('_emitEvent:' + eventName + ' ' + value);
|
||||
var eventObj = {
|
||||
type: eventName,
|
||||
detail: value
|
||||
};
|
||||
listeners.forEach((listener) => {
|
||||
listener.call(this, eventObj);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an event listener on an event. If listener is an object,
|
||||
* object.handleEvent is called when the event emits.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf EventEmitter.prototype
|
||||
* @param {String} eventName
|
||||
* @param {(Function|Object)} listener
|
||||
*/
|
||||
EventEmitter.prototype.addEventListener = function(eventName, listener) {
|
||||
var listeners = this._eventListeners[eventName];
|
||||
if (listener && listeners) {
|
||||
switch (typeof listener) {
|
||||
case 'function':
|
||||
break;
|
||||
case 'object':
|
||||
if (typeof listener.handleEvent === 'function') {
|
||||
listener = listener.handleEvent;
|
||||
} else {
|
||||
listener = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
listener = null;
|
||||
break;
|
||||
}
|
||||
if (listener && listeners.indexOf(listener) < 0) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
} else {
|
||||
this.error('addEventListener: invalid listener for ' + eventName);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the event listener from an event.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf EventEmitter.prototype
|
||||
* @param {String} eventName
|
||||
* @param {(Function|Object)} listener
|
||||
*/
|
||||
EventEmitter.prototype.removeEventListener = function(eventName, listener) {
|
||||
var listeners = this._eventListeners[eventName];
|
||||
if (listener && listeners) {
|
||||
var index = -1;
|
||||
var type = typeof listener;
|
||||
switch (type) {
|
||||
case 'function':
|
||||
index = listeners.indexOf(listener);
|
||||
break;
|
||||
case 'object':
|
||||
index = listeners.indexOf(listener.handleEvent);
|
||||
break;
|
||||
}
|
||||
if (index >= 0) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
this.error('removeEventListener: invalid listener for ' + eventName);
|
||||
}
|
||||
};
|
||||
|
||||
return EventEmitter;
|
||||
});
|
||||
152
gaia/apps/settings/js/modules/base/module.js
Executable file
152
gaia/apps/settings/js/modules/base/module.js
Executable file
|
|
@ -0,0 +1,152 @@
|
|||
/**
|
||||
* Module provides methods to create a new module. Any module created here has
|
||||
* the ability of being extended by other modules. Existing properties are
|
||||
* overridden.
|
||||
*
|
||||
* Creating a module
|
||||
* @example
|
||||
* var NewModule = Module.create(function() {
|
||||
* this.value = 100;
|
||||
* });
|
||||
* NewModule.prototype.print = function() { console.log(this.value); };
|
||||
*
|
||||
* var instance = NewModule();
|
||||
* instance.print(); // 100
|
||||
*
|
||||
* Extending a module
|
||||
* @example
|
||||
* var AnotherModule = Module.create();
|
||||
* AnotherModule.prototype.inc = function() { this.value++; };
|
||||
* var ExtendingModule = NewModule.extend(AnotherModule);
|
||||
*
|
||||
* var instance = ExtendingModule();
|
||||
* instance.inc();
|
||||
* instance.print(); // 101
|
||||
*
|
||||
* @module modules/base/module
|
||||
*/
|
||||
define(function() {
|
||||
'use strict';
|
||||
|
||||
const LOG_LEVEL = {
|
||||
NONE: 0,
|
||||
DEBUG: 1,
|
||||
INFO: 2,
|
||||
WARN: 3,
|
||||
ERROR: 4,
|
||||
ALL: 5
|
||||
};
|
||||
|
||||
var _constructorMap = (function() {
|
||||
var _ctorMap = new Map();
|
||||
var _getConstructor = function(Module) {
|
||||
return _ctorMap.get(Module) || function() {};
|
||||
};
|
||||
var _registerConstructor = function(Module, constructor) {
|
||||
_ctorMap.set(Module, constructor || function() {});
|
||||
};
|
||||
return {
|
||||
getConstructor: _getConstructor,
|
||||
registerConstructor: _registerConstructor
|
||||
};
|
||||
})();
|
||||
|
||||
var _emptyFunction = function() {};
|
||||
var _createLogger = function(name) {
|
||||
switch (name) {
|
||||
case 'DEBUG':
|
||||
return function(msg) {
|
||||
console.log(this._msgPrefix + msg);
|
||||
};
|
||||
case 'INFO':
|
||||
return function(msg) {
|
||||
console.info(this._msgPrefix + msg);
|
||||
};
|
||||
case 'WARN':
|
||||
return function(msg) {
|
||||
console.warn(this._msgPrefix + msg);
|
||||
};
|
||||
case 'ERROR':
|
||||
return function(msg) {
|
||||
console.error(this._msgPrefix + msg);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var ModulePrototype = {
|
||||
get _msgPrefix() {
|
||||
return '[' + this.$name + ']: ';
|
||||
},
|
||||
debug: _emptyFunction,
|
||||
info: _emptyFunction,
|
||||
warn: _emptyFunction,
|
||||
error: _emptyFunction,
|
||||
throw: function(msg) {
|
||||
throw new Error(this._msgPrefix + msg);
|
||||
},
|
||||
set _logLevel(value) {
|
||||
Object.keys(LOG_LEVEL).forEach((name) => {
|
||||
var level = LOG_LEVEL[name];
|
||||
if (value >= level && value > 0) {
|
||||
this[name.toLowerCase()] = _createLogger(name);
|
||||
}
|
||||
});
|
||||
},
|
||||
super: _constructorMap.getConstructor
|
||||
};
|
||||
|
||||
var _extend = function() {
|
||||
switch (arguments.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
var Module = arguments[0];
|
||||
for (var prop in Module.prototype) {
|
||||
if (prop === '$name') {
|
||||
continue;
|
||||
}
|
||||
var pd = Object.getOwnPropertyDescriptor(Module.prototype, prop);
|
||||
if (pd) {
|
||||
Object.defineProperty(this.prototype, prop, pd);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Array.prototype.forEach.call(arguments, (Module) => {
|
||||
_extend.call(this, Module);
|
||||
});
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// Returns a module function. The function returns an instance of the
|
||||
// module when it is called. The passed constructor is called using the
|
||||
// instance as "this".
|
||||
function _create(constructor) {
|
||||
if (constructor && typeof constructor !== 'function') {
|
||||
throw new Error('[Module]: Invalid constructor');
|
||||
}
|
||||
|
||||
var ModuleFunc = function() {};
|
||||
ModuleFunc.prototype = Object.create(ModulePrototype);
|
||||
ModuleFunc.prototype.$name = constructor && constructor.name || '';
|
||||
|
||||
var Module = function() {
|
||||
var instance = new ModuleFunc();
|
||||
if (constructor) {
|
||||
constructor.apply(instance, arguments);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
_constructorMap.registerConstructor(Module, constructor);
|
||||
Module.extend = _extend;
|
||||
Module.prototype = ModuleFunc.prototype;
|
||||
return Module;
|
||||
}
|
||||
|
||||
return {
|
||||
LOG_LEVEL: LOG_LEVEL,
|
||||
create: _create
|
||||
};
|
||||
});
|
||||
147
gaia/apps/settings/js/modules/base/task_scheduler.js
Executable file
147
gaia/apps/settings/js/modules/base/task_scheduler.js
Executable file
|
|
@ -0,0 +1,147 @@
|
|||
/**
|
||||
* TaskScheduler helps manage tasks and ensures they are executed in
|
||||
* sequential order. When a task of a certain type is enqueued, all pending
|
||||
* tasks of the same type in the queue are removed. This avoids redundant
|
||||
* queries and improves user perceived performance.
|
||||
*
|
||||
* @module modules/base/task_scheduler
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var Defer = require('modules/defer');
|
||||
var Module = require('modules/base/module');
|
||||
var Observable = require('modules/mvvm/observable');
|
||||
|
||||
/**
|
||||
* @class TaskScheduler
|
||||
* @returns {TaskScheduler}
|
||||
*/
|
||||
var TaskScheduler = Module.create(function TaskScheduler() {
|
||||
this.super(Observable).call(this);
|
||||
this.isLocked = false;
|
||||
this._tasks = [];
|
||||
}).extend(Observable);
|
||||
|
||||
Observable.defineObservableProperty(TaskScheduler.prototype, 'isLocked', {
|
||||
value: false
|
||||
});
|
||||
|
||||
const TASK_TYPE = {
|
||||
GENERAL: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* We will keep some constants here as a static variable
|
||||
*
|
||||
* @access public
|
||||
* @memberOf TaskScheduler
|
||||
*/
|
||||
Object.defineProperty(TaskScheduler, 'TASK_TYPE', {
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
get: function() {
|
||||
return TASK_TYPE;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Change the internal state to make sure we are locked.
|
||||
*
|
||||
* @access private
|
||||
* @memberOf TaskScheduler
|
||||
*/
|
||||
TaskScheduler.prototype._lock = function() {
|
||||
this.isLocked = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the internal state to unlocked and execute next task.
|
||||
*
|
||||
* @access private
|
||||
* @memberOf TaskScheduler
|
||||
*/
|
||||
TaskScheduler.prototype._unlock = function() {
|
||||
this.isLocked = false;
|
||||
this._executeNextTask();
|
||||
};
|
||||
|
||||
/**
|
||||
* We will remove any redundant same-type tasks and keep the remaining ones
|
||||
* including the others which are not cancelable (general use task).
|
||||
*
|
||||
* @access private
|
||||
* @memberOf TaskScheduler
|
||||
* @param {String} type
|
||||
* @return {Array} array of tasks
|
||||
*/
|
||||
TaskScheduler.prototype._removeRedundantTasks = function(type) {
|
||||
return this._tasks.filter((task) => {
|
||||
if (!task.cancelable) {
|
||||
return true;
|
||||
} else {
|
||||
return task.type !== type;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute the next task when unlocked.
|
||||
*
|
||||
* @access private
|
||||
* @returns {Promise}
|
||||
* @memberOf TaskScheduler
|
||||
*/
|
||||
TaskScheduler.prototype._executeNextTask = function() {
|
||||
if (this.isLocked) {
|
||||
return;
|
||||
}
|
||||
var nextTask = this._tasks.shift();
|
||||
if (nextTask) {
|
||||
this._lock();
|
||||
return nextTask.func().then((result) => {
|
||||
nextTask.defer.resolve(result);
|
||||
this._unlock();
|
||||
}, () => {
|
||||
nextTask.defer.reject();
|
||||
this._unlock();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the only entry point for caller, and we will enqueue all tasks
|
||||
* one by one and execute them in order.
|
||||
*
|
||||
* @access public
|
||||
* @memberOf TaskScheduler
|
||||
* @param {Object} task
|
||||
* @param {String} task.type
|
||||
* @param {Function} task.func - make sure the func would return a promise
|
||||
* @param {Boolean} task.cancelable
|
||||
* @return {Promise}
|
||||
*/
|
||||
TaskScheduler.prototype.enqueue = function(task) {
|
||||
var defer = Defer();
|
||||
|
||||
// if there is no func, let's directly resolve this task
|
||||
if (!task.func) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!task.type) {
|
||||
// copy the task and make sure we won't change the previous one
|
||||
task = Object.assign({}, task);
|
||||
task.type = TaskScheduler.TASK_TYPE.GENERAL;
|
||||
}
|
||||
|
||||
task.defer = defer;
|
||||
this._tasks = this._removeRedundantTasks(task.type);
|
||||
this._tasks.push(task);
|
||||
this._executeNextTask();
|
||||
|
||||
return defer.promise;
|
||||
};
|
||||
|
||||
return TaskScheduler;
|
||||
});
|
||||
Loading…
Reference in a new issue