/**
* @file Volt Core Library - plug-in registration
*
* @license
* (c) 2017 NS BASIC Corporation. All rights reserved.
*/
window.$volt = (function () {
'use strict';
var plugins = {}, pluginNames = [];
// static object to manage internal state
var state = {
// clear all state items except for appId
clear: function () {
var key;
for (key in this) {
if (typeof this[key] !== 'function' && key !== 'appId') {
delete this[key];
}
}
this.save();
},
// loads the state (given) an appId, from localStorage
load: function (appId) {
var key, state = window.localStorage.getItem('$volt_' + appId);
try {
state = JSON.parse(state);
} catch (e) {
state = null;
}
if (state && typeof state === 'object') {
for (key in state) {
if (state.hasOwnProperty(key)) {
this[key] = state[key];
}
}
}
this.appId = appId;
},
// saves the state to localStorage - assumes appId is set in the state
save: function () {
window.localStorage.setItem('$volt_' + this.appId, JSON.stringify(this));
}
};
/**
* Volt Core Library
*
* Provides plugin registratoin, and basic authentication and user management.
*
* @namespace
* @alias $volt
*/
var ns = { // jscs:ignore requireVarDeclFirst
/**
* Register a Volt plug-in
*
* More details are available in the plug-in spec - this is
* private for now as it is only needed by plug-in authors
*
* @private
*
* @param {string} name - the name of the mount point for the plug-in in the `$volt` namespace - can contain periods which represent hierarchy
* @param {function} init - the callback function with the params (core, state) that inits the plug-in
*/
register: function (name, init) {
if (!plugins.hasOwnProperty(name)) {
plugins[name] = init;
pluginNames.push(name);
} else {
throw new Error('Plug-in "' + name + '" already registered.');
}
},
/**
* Init Volt and registered plug-ins
*
* @param {string} appId - the appId to init Volt with
* @param {string} [domain] - the API domain
*/
init: function (appId, domain) {
var i, name, init, mount, part;
state.load(appId);
state.domain = domain;
// make sure parent namespaces are created prior to children
pluginNames = pluginNames.sort();
for (i = 0; i < pluginNames.length; i++) {
name = pluginNames[i].split('.');
init = plugins[pluginNames[i]];
// walk the dots down
mount = ns;
part = name.shift();
while (name.length) {
mount[part] = mount[part] || {}; // create missing namespaces
mount = mount[part];
part = name.shift();
}
mount[part] = init(ns, state);
}
},
/**
* Helper method to allow callback methods to also use promises if
* support exists in the browser
*
* @private
*
* @example
* function callbackOrPromise(callback) {
* callback = methodAsPromised(callback);
*
* // do stuff
*
* return callback.promise;
* }
*
* @param {voltCallback} [callback] the callback parameter from
* the calling function, or undefined if it wasn't passed
*
* @returns {voltCallback} either the original or newly created
* callback - if the callback was created, it has an additional
* property `promise` which is a reference to the promise to
* return
*/
methodAsPromised: function (callback) {
var promise;
var resolve, reject;
if (!callback) {
if (!window.Promise) {
throw new Error("This browser doesn't support promises.");
}
promise = new window.Promise(function (res, rej) {
resolve = res;
reject = rej;
});
callback = function (error, data) {
if (error) {
error.data = data;
reject(error);
} else {
resolve(data);
}
};
callback.promise = promise;
}
return callback;
}
};
return ns;
})();