adhara
Version:
foundation for any kind of website: microframework
1,300 lines (1,192 loc) • 307 kB
JavaScript
"use strict";
var _set = function set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent !== null) { set(parent, property, value, receiver); } } else if ("value" in desc && desc.writable) { desc.value = value; } else { var setter = desc.set; if (setter !== undefined) { setter.call(receiver, value); } } return value; };
var _AdharaListView$DEFAU;
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var _marked = /*#__PURE__*/regeneratorRuntime.mark(range);
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* @typedef {Object} ElementAttributes
* @description attributes that can be set in a element using `addAttr` helper for Handlebar files.
* */
var TemplateEngineHelpers = function () {
function TemplateEngineHelpers() {
_classCallCheck(this, TemplateEngineHelpers);
}
_createClass(TemplateEngineHelpers, null, [{
key: "getHelpers",
/**
* @namespace
* @description
* Helpers written for handlebars. Can also be used by static references.
* */
value: function getHelpers(currentHelpers) {
var if_helper = currentHelpers.if;
return {
/**
* @function
* @static
* @param {ElementAttributes} attributes - html element attributes.
* @param {String|Object} default_attributes - html element default attributes.
* @description
* attributes override default_attributes
* create attribute string and return which can be used to append
* @example
* let options = {
* attributes : { id : 'element-id', className : 'css-class' }
* }
* TemplateUtils.execute(
* '<a {{addAttr attributes "{"href":"javascript:void(0)", "route":"true"}"}}></a>',
* options
* )
* //returns <a href="javascript:void(0)" route:"true" id="element-id" class:"css-class></a>
* */
'addAttr': function addAttr(attributes, default_attributes) {
if (attributes || default_attributes) {
var attrData = [];
default_attributes = default_attributes && typeof default_attributes === "string" ? JSON.parse(default_attributes) : {};
var class_names = attributes ? attributes.className || attributes["class"] || "" : "";
class_names += default_attributes.hasOwnProperty("class") ? " " + default_attributes['class'] : "";
attributes = Object.assign(default_attributes, attributes);
if (class_names) attributes['class'] = class_names;
loop(attributes, function (key, value) {
if (key && value !== undefined) {
if (key === "style") {
var css_values = [];
loop(value, function (css_prop, css_value) {
css_values.push(css_prop + ":" + css_value + ";");
});
value = css_values.join('');
}
if (typeof value === "string") {
value = '"' + value.replace(/"/g, '\\"') + '"';
}
attrData.push(key + '=' + value);
}
});
return new window.Handlebars.SafeString(attrData.join(' '));
}
},
'addProps': function addProps() {
var properties = Array.prototype.slice.call(arguments);
return properties.splice(0, properties.length - 1).join(' ');
},
'selectedClass': function selectedClass(selected, selectedClassName) {
if (selected === true) {
return selectedClassName;
} else {
return '';
}
},
/**
* @function
* @static
* @param {String} template_name - precompiled handlebar template name.
* @param {Object} context - context with which the `template_name` hbs template to be called
* @return {String} `template_name` handlebar template contents after execution with provided context.
* @description
* includes one hbs template in another.
* @example
* //child HBS file - child-template.hbs
* `<div id="child">
* {{name}}
* </div>`
*
* // main HBS file - main-template.hbs
* `<div id="main">
* {{name}}
* {{include 'child-template' child_context}}
* </div>`
*
* Handlebars.templates['main-template']({name:"MAIN", child_context:{name:"CHILD"}})
* // returns
* //<div id="main">
* // MAIN
* // <div id="child">
* // CHILD
* // </div>
* //</div>
* */
'include': function include(template_name, context) {
return new window.Handlebars.SafeString(TemplateUtils.execute(template_name, context));
},
/**
* @function
* @static
* @param {Number} param1 - left operand / lvalue
* @param {String} operation - can be one among "+", "-", "*", "/" and "%"
* @param {Number} param2 - right operand / rvalue
* @returns {Number} - result after operation between param1 and param2 with operation
* */
'math': function math(param1, operation, param2) {
var lvalue = parseFloat(String(param1));
var rvalue = parseFloat(String(param2));
return {
"+": lvalue + rvalue,
"-": lvalue - rvalue,
"*": lvalue * rvalue,
"/": lvalue / rvalue,
"%": lvalue % rvalue
}[operation];
},
/**
* @function
* @static
* @param {String} i18nKey - application key that needs to be internationalized.
* @returns {String} internationalized application key's value
* @example
* // app.key.name = "APP Key"
* {{i18N 'app.key.name'}} //returns "APP Key"
*
* // app.key.operation = "App Operation {0} by {1}"
* {{i18N 'app.key.operation' 'operationName' 'operatedBy'}} //returns "App Operation operationName by operatedBy"
* */
'i18n': function i18n(i18nKey) {
//~ (i18nKey, ...subs)
var subs = Array.prototype.slice.call(arguments);
subs = subs.splice(1, subs.length - 2);
return Adhara.i18n.get(i18nKey, subs);
},
/**
* @function
* @static
* @param {Object} object - object in which to lookup.
* @param {String} path - dot separated keys to be looked up for in depth.
* @description
* Wrapper for {@link getValueFromJSON}
* @returns {String|Number|Boolean|Object|Array} - Value for the key.
* */
'get': function get(object, path) {
return getValueFromJSON(object, path);
},
/**
* @function
* @static
* @description
* Wrapper for {@link evaluateLogic}
* @returns
* handlebar block based on logic.
* */
'if': function _if(param1, operator, param2, options) {
if ((typeof operator === "undefined" ? "undefined" : _typeof(operator)) === "object") {
return if_helper.call(this, param1, operator);
}
if (evaluateLogic(param1, operator, param2)) {
return options.fn(this);
} else {
return options.inverse(this);
}
},
/**
* @function
* @static
* @description
* If condition with multiple equations to evaluate.
* Takes numerous arguments which will be executed in pairs.
* @returns
* handlebar block based on logic.
* */
'mIf': function mIf() {
var arr = [true, 'and', true];
var args_len = arguments.length - 1;
var options = arguments[args_len];
for (var i = 0; i < args_len; i++) {
if (i === 0) {
arr[0] = arguments[i];
} else if (i % 2 === 1) {
arr[1] = arguments[i];
} else {
arr[2] = arguments[i];
arr[0] = evaluateLogic(arr[0], arr[1], arr[2]);
}
}
if (arr[0]) {
return options.fn(this);
} else {
return options.inverse(this);
}
},
/**
* @function
* @static
* @description
* If condition with multiple equations to evaluate.
* Takes numerous arguments which will be executed in pairs.
* @returns {Boolean} result of equation created by provided params.
* @see evaluateLogic
* */
'eIf': function eIf(param1, operator, param2) {
return evaluateLogic(param1, operator, param2);
},
/**
* @function
* @static
* @returns {String|Number|Boolean|Object|Array} - Value of the global letiable.
* */
'global': function global(global_letiable) {
if (global_letiable.indexOf("Adhara.") === 0) {
return getValueFromJSON(Adhara, global_letiable.substring("Adhara.".length));
}
return getValueFromJSON(window, global_letiable);
},
'loop': function loop(looper, options) {
var structure = '';
for (var i = 0; i < looper.length; i++) {
structure += options.fn(looper[i]);
}
return structure;
},
/**
* @function
* @static
* @description Takes numerous {String} arguments and appends all those strings.
* @returns {String} arguments joined by ''.
* */
'append': function append() {
var args = Array.prototype.slice.call(arguments);
args.pop();
return args.map(function (arg) {
if ((typeof arg === "undefined" ? "undefined" : _typeof(arg)) === "object") {
return JSON.stringify(arg);
}
return arg;
}).join('');
},
/**
* @function
* @static
* @description Takes a {String} and converts it to JSON object.
* @returns {Object}
* */
'make_json': function make_json(str) {
return JSON.parse(str);
},
/**
* @function
* @static
* @description Takes a {String} and converts it to JSON object.
* @returns {Object}
* */
'make_context': function make_context() {
var context = {};
for (var i = 0; i < arguments.length - 1; i += 2) {
context[arguments[i]] = arguments[i + 1];
}
return context;
},
/**
* @function
* @static
* @param {Function} fn
* @description Takes numerous and calls the fn with arguments from 2nd position since 1st argument is fn itself.
* @returns {String|Number|Boolean|Object|Array} content returned by fn
* */
'fn_call': function fn_call(fn) {
return call_fn.apply(this, Array.prototype.slice.call(arguments).slice(0, -1));
},
/**
* @function
* @static
* @param {Object} looper
* @param {Object} options - Handlebars options that has access to blocks.
* @returns {String} Block string.
* @description blocks will be called with a context ~ {"key":k, "value":v}
* where `k` is key in the looper object and `v` is value corresponding to `k`.
* */
'loopObject': function loopObject(looper, options) {
var structure = '';
loop(looper, function (key, value) {
structure += options.fn({ key: key, value: value });
});
return structure;
},
/**
* @function
* @static
* @param {Number} start
* @param {Number} step
* @param {Number} end
* @param {Object} options - Handlebars options that has access to blocks.
* @returns {String} Block string appended n times where n is the number of times step-looped.
* @description Block will be called with just a number {Number} as context which keeps increasing in steps, where the step height is equal to step param.
* */
'iterate_range': function iterate_range(start, step, end, options) {
var str_buf = '';
for (var i = start; i <= end; i += step) {
str_buf += options.fn(i);
}
return str_buf;
},
'route': function route(url) {
return new Handlebars.SafeString("href=\"" + Adhara.router.transformURL(url) + "\" route");
}
/*
TODO handle better!
'generate': function(context, options){
let generatorInstance = context(),
ret = '', done = false, index = 0,
data = {};
function execIteration(field, index, last) {
if (data) {
data.key = field;
data.index = index;
data.first = index === 0;
data.last = !!last;
}
ret = ret + options.fn(context[field], {
data: data,
// blockParams: _utils.blockParams([context[field], field], [contextPath + field, null])
});
}
do{
let yi = generatorInstance.next();
done = yi.done;
execIteration(yi.value, ++index, done===true);
}while(done===false);
console.log(context, options);
return ret;
}*/
};
}
}, {
key: "registerHelpers",
value: function registerHelpers() {
window.Handlebars.registerHelper(TemplateEngineHelpers.getHelpers(window.Handlebars.helpers));
}
}]);
return TemplateEngineHelpers;
}();
/**------------------------------------------------------------------------------------------------------------------**/
var TAB = 9;
var ENTER = 13;
var UP_ARROW = 38;
var DOWN_ARROW = 40;
var BACKSPACE = 8;
var ESCAPE = 27;
var SHIFT = 16;
var SPACE = 32;
/**------------------------------------------------------------------------------------------------------------------**/
function handleForm(form) {
if (form.submitting) {
return;
} else {
form.submitting = true;
}
var hasFiles = !!form.querySelector('input[type="file"]');
var apiData = void 0;
if (hasFiles) {
apiData = new FormData(form);
} else {
var formData = jQuery(form).serializeArray();
apiData = {};
jQuery.each(formData, function (i, fieldData) {
apiData[fieldData.name] = fieldData.value;
});
}
var format_fn = form.getAttribute('format-data');
if (format_fn) {
apiData = call_fn(format_fn, apiData);
}
if (apiData === false) {
return;
}
RestAPI[form.getAttribute('api-method')]({
url: form.action.split(window.location.host)[1],
data: apiData,
successMessage: form.getAttribute('success-message'),
handleError: form.getAttribute('handle-error') !== "false",
success: function success(data) {
if (form.getAttribute('form-clear') === "true") {
form.reset();
}
jQuery(form).trigger('success', data);
},
failure: function failure(message) {
jQuery(form).trigger('failure', message);
}
});
}
function registerAdharaUtils() {
//Register templateEngine helpers
Adhara.templateEngine.helpersHandler.registerHelpers();
//Form listeners
jQuery(document).on('submit', 'form.api-form', function (event) {
event.preventDefault();
handleForm(this);
});
//Form listeners
jQuery(document).on('success', 'form.dialog-form', function () /*e, d*/{
this.close.click();
});
}
/**
* @function
* @global
* @param {String|Number|Boolean} param1
* @param {String} operator - Operator can be one among these.
* "in", "not_in", "contains", "not_contains", "has", "||", "&&", "|", "&", "==", "===", "!=", "!==", ">", "<", ">=", "<=", "equals", "and", "or".
* @param {String|Number|Boolean} param2
* @Returns {Boolean}
*
* "in" - param2 must be an {Array}. Whether param1's existence in that array will be checked for
*
* "not_in" - param2 must be an {Array} and param1's non-existence in that array will be checked for
*
* "contains" - param1 must be an {Array} and param2's existence in that array will be checked for
*
* "not_contains" - param1 must be an {Array} and param2's non-existence in that array will be checked for
*
* "has" - param1 must be an {Object}. Whether param2 is a key of param1
*
* All other operations will be applied as javaScript evaluates them.
* `"equals" is equivalent to "=="`,
* `"and" is equivalent to "&&"`
* and `"or" is equivalent to "||"`.
*
* */
function evaluateLogic(param1, operator, param2) {
if (operator === "in") {
return param2 && param2.indexOf(param1) !== -1;
} else if (operator === "not_in") {
return param2 && param2.indexOf(param1) === -1;
} else if (operator === "contains") {
return param1 && param1.indexOf(param2) !== -1;
} else if (operator === "not_contains") {
return param1 && param1.indexOf(param2) === -1;
} else if (operator === "has") {
return param1 && param1.hasOwnProperty(param2);
} else {
return {
"||": param1 || param2,
"&&": param1 && param2,
"|": param1 | param2,
"&": param1 & param2,
"==": param1 == param2,
"===": param1 === param2,
"!=": param1 != param2,
"!==": param1 !== param2,
">": param1 > param2,
"<": param1 < param2,
">=": param1 >= param2,
"<=": param1 <= param2,
"equals": param1 == param2,
"and": param1 && param2,
"or": param1 || param2
}[operator];
}
}
/**
* @function
* @global
* @param {Object} object - object in which to lookup.
* @param {String} path - dot separated keys to be looked up for in depth.
* @param {String} [identifier=null] - token that helps to lookup inside arrays.
* @returns {String|Number|Boolean|Object|Array} - Value for the key.
* @description
* Looks up a JSON object in depth and returns the value for the key provided.
* @example
* let obj = {
* task: {
* id: "12341234",
* status: {
* color: "#fff"
* }
* }
* };
* getValueFromJSON(obj, "task.status.color"); //returns "#fff"
*
* let objX = {
* tasks: [
* {
* id: "12341234",
* status: {
* color: "#fff"
* }
* },
* {
* id: "55424",
* status: {
* color: "#f5f5f5"
* }
* },
* {
* id: "90898080",
* status: {
* color: "#eee"
* }
* },
* ]
* };
* getValueFromJSON(objX, "task[1].status.color"); //returns "#f5f5f5"
* getValueFromJSON(objX, "task[$, ].status.color", "$"); //returns "#fff, #f5f5f5, #eee"
* // Elaborately,
* // In `[$, ]` --split into identifier and separator
* // '$'=identifier(from params).
* // Remaining part inside [] is the separator i.e., `', '` will be used to join the results from the array
* */
function getValueFromJSON(object, path, identifier) {
try {
if (!path) {
return object;
}
var keys = path.split('.');
for (var i = 0; i < keys.length; i++) {
var key_in = keys[i];
if (key_in.indexOf('[') !== -1) {
var arr = key_in.split('[');
var arrName = arr[0];
var index = arr[1].split(']')[0];
if (isNaN(index)) {
var rite = object[arrName];
var separator = index.substring(identifier.length, index.length);
var formattedVal = '';
for (var j = 0; j < rite.length; j++) {
if (j > 0) {
formattedVal += separator;
}
formattedVal += getValueFromJSON(rite[j], path.split('.').splice(i + 1).join('.'), identifier);
}
object = formattedVal;
} else {
object = object[arrName][index];
}
break;
} else {
object = object[key_in];
}
}
return object;
} catch (e) {
return undefined;
}
}
/**
* @function
* @global
* @param {Object} object - object to set value to
* @param {String} path - dot separated path.
* @param {String|Number|Boolean|Object|Array} value - value to be set fot the given key
* @description
* Sets value to provided object at specified depth in the path be using dot separators.
* Creates objects at depths if no object already exists at specified path.
* @example
* let kit = {'has_bat': true}
* setValueToJson(kit, 'has_ball', true); //let kit = {'has_bat': true, 'has_ball': true}
* setValueToJson(kit, 'has_bat', false); //let kit = {'has_bat': false, 'has_ball': true}
*
* let aeroplane = {'name': 'B747'}
* setValueToJson(aeroplane, 'tank.capacity', '4000'); //aeroplane = {'name': 'B747', 'tank': { 'capacity': '4000' }}
* setValueToJson(aeroplane, 'tank.shape', 'amoeba'); //aeroplane = {'name': 'B747', 'tank': { 'capacity': '4000', 'shape': 'amoeba' }}
* */
function setValueToJson(object, path, value) {
var keys = path.split('.');
loop(keys, function (i, key) {
if (i + 1 < keys.length) {
if (!object.hasOwnProperty(key) || !object[key] || _typeof(object[key]) !== "object") {
object[key] = {};
}
object = object[key];
} else {
object[key] = value;
}
});
}
/**
* @typedef {Object|Array|String|Boolean|Number|null|undefined} _MultiParams - numerous arguments of any kind
* @description
* A function if accepts multiple params, can use this as param type.
* @example
* //def
* function mpFn({String} param1, {_MultiParams} m_params){}
* //call
* mpFn("Str_param1", "p1", "p2", 1, {'key':'val'}, ['m1', 'm2', ...], ...);
* //def2
* function mp2Fn({String} param1, {_MultiParams} m_params, {String} param2){}
* //call2
* mp2Fn("Str_param1", "p1", "p2", 1, {'key':'val'}, ['m1', 'm2', ...], ..., "StrX_param2");
*
* */
/**
* @function
* @global
* @param {Function|String} fn - function to be called or global path to a function
* @param {_MultiParams} params - any params that to be passed to function
* @description
* calls the function with params passed
* @example
* let gv = {}; //global_letiable
* gv.sample_fn = function(param1, param2, param3){
* //Do Something...
* return "Hello from SampleFN"
* };
* call_fn('gv.sample_fn', param1, param2, param3); //returns "Hello from SampleFN"
* */
function call_fn(fn) {
if (!fn) {
return;
}
var args = Array.prototype.slice.call(arguments);
args.splice(0, 1);
if (typeof fn === "function") {
return fn.apply(fn, args);
} else {
try {
fn = getValueFromJSON(window, fn);
if (fn && fn !== window) {
return fn.apply(window[fn], args);
}
} catch (e) {
if (e.name === "TypeError" && e.message.indexOf("is not a function") !== -1) {
throw new Error("error executing function : " + fn);
} else {
throw e;
}
}
}
}
/**
* Can be used if required to call a function, and if it is unavailable, call a default fn
* Usage : call_fn_or_def(fn, arg1, arg2, arg3, def_fn)
* Result : fn(arg1, arg2, arg3) if fn is not undefined else def_fn(arg1, arg2, arg3)
* */
/**
* @function
* @global
* @param {Function|String} fn - function to be called or global path to a function
* @param {_MultiParams} params - any params that to be passed to function
* @param {Function|String} fn - function to be called or global path to a function
* @description
* calls the function with params passed
* @example
* let gv = {}; //global_letiable
* gv.sample_fn = function(param1, param2, param3){
* //Do Something...
* return "Hello from SampleFN"
* };
* call_fn('gv.sample_fn', param1, param2, param3, defaultFunction); //returns "Hello from SampleFN"
* */
function call_fn_or_def(fn) {
var args = Array.prototype.slice.call(arguments);
var def_fn = args.pop();
if (!(typeof def_fn === "function" || typeof window[def_fn] === "function")) {
args.push(def_fn);
def_fn = undefined;
}
if (fn) {
return call_fn.apply(call_fn, args);
} else if (def_fn) {
args[0] = def_fn;
return call_fn.apply(call_fn, args);
}
}
/**
* Loop - looper iterator function
* @callback LoopIteratorCallback
* @param {String|Number|RegExp} key - key will be string in case of an object and Number will be an Array while looping through an Array.
* @param {*} value - Value of iterable for key.
* @returns {Boolean}
* return `false` to stop iteration.
* */
/**
* @function
* @global
* @param {Object|Array} object - Iterable.
* @param {LoopIteratorCallback} cbk - callback for each value in iterable.
* @param {Boolean} [reverseIterate=false] - iterate in reverse if it is an array.
* */
function loop(object, cbk, reverseIterate) {
var i = void 0,
loop_size = void 0;
if (object instanceof Array) {
loop_size = object.length;
if (reverseIterate) {
for (i = loop_size - 1; i >= 0; i--) {
if (cbk(i, object[i]) === false) {
break;
}
}
} else {
for (i = 0; i < loop_size; i++) {
if (cbk(i, object[i]) === false) {
break;
}
}
}
} else {
var keys = Object.keys(object);
loop_size = keys.length;
for (i = 0; i < loop_size; i++) {
if (cbk(keys[i], object[keys[i]]) === false) {
break;
}
}
}
}
/**
* @typedef {String} HandlebarTemplate
* @description handlebar template can be an inline template or a pre compiled template that is created in a HBS file.
* */
/**
* @namespace
* @description
* TemplateUtils is a set of utilities related to handlebars
* */
var TemplateUtils = {};
(function () {
var preCompiledCache = {};
/**
* @function
* @static
* @param {HandlebarTemplate} template_or_template_string - Handlebar template name or template string.
* @param {Object} context - content to be passed t provided handlebar template/string.
* @param {Boolean} [cache=true] - whether to cache if the provided template is a Handlebar string template.
* @returns {String} compiled adn executed handlebar template
* @example
* //using template
* TemplateUtils.execute('template-file-name', {context_key1: "value1", ...});
*
* //using template string
* TemplateUtils.execute('Hello {{name}}', {name: "Adhara"}); //returns "Hello Adhara"
* */
TemplateUtils.execute = function (template_or_template_string, context, cache) {
//Check if it is a pre compiled hbs template
var template = window.Handlebars.templates[template_or_template_string];
if (!template && window.Handlebars.hasOwnProperty("compile")) {
//If template not found in precompiled hbs list => template is a handlebar string template
// check if cacheable
if (cache !== false) {
//check if the template is already cached.
template = preCompiledCache[template_or_template_string];
if (!template) {
//else compile, store it in cache and proceed to execution
template = preCompiledCache[template_or_template_string] = window.Handlebars.compile(template_or_template_string);
}
} else {
//else compile and proceed to execution
template = window.Handlebars.compile(template_or_template_string);
}
}
//execute with the provided context and return the output content...
return template(context);
};
})();
var Internationalize = function () {
/**
* @constructor
* @param {Object<String, String>} key_map - i18n key map
* */
function Internationalize(key_map) {
_classCallCheck(this, Internationalize);
this.key_map = key_map;
}
/**
* @instance
* @function
* @param {String} key - key
* @param {Array<String>} subs - substitutes
* @param {String} default_value - will be returned if key is not availalbe in the keymap
* */
_createClass(Internationalize, [{
key: "getValue",
value: function getValue(key, subs, default_value) {
if (!key) {
return;
}
var value = this.key_map[key];
if (value === undefined) {
value = getValueFromJSON(this.key_map, key);
}
if (value === undefined) {
return default_value;
}
subs = subs || [];
var placeholders = value.match(/{[0-9]+}/g) || [];
for (var i = 0; i < placeholders.length; i++) {
var sub = subs[i] || "";
try {
if (sub.indexOf('.') !== -1) {
sub = this.get(sub);
}
} catch (e) {/*Do Nothing*/}
value = value.replace(new RegExp("\\{" + i + "\\}", "g"), sub);
}
return value.trim();
}
/**
* @instance
* @function
* @param {String} key - key
* @param {Array<String>|String} [subs=[]] - substitutes
* @param {String} [default_value=null] - substitutes
* */
}, {
key: "get",
value: function get(key, subs) {
var default_value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
if (typeof subs === "string") {
default_value = subs;
}
return this.getValue(key, subs, default_value || key);
}
}]);
return Internationalize;
}();
// Enable multi extend functionality https://stackoverflow.com/a/45332959
function MutateViews(baseClass) {
for (var _len = arguments.length, mixins = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
mixins[_key - 1] = arguments[_key];
}
function copyProps(target, source) {
// this function copies all properties and symbols, filtering out some special ones
//TODO "Object.getOwnPropertyNames" and "Object.getOwnPropertySymbols" Doesn't work in IE even after transpilation to ES5...
Object.getOwnPropertyNames(source).concat(Object.getOwnPropertySymbols(source)).forEach(function (prop) {
if (!prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length|context)$/)) Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
});
}
var base = function (_baseClass) {
_inherits(base, _baseClass);
function base() {
var _ref;
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
_classCallCheck(this, base);
var _this = _possibleConstructorReturn(this, (_ref = base.__proto__ || Object.getPrototypeOf(base)).call.apply(_ref, [this].concat(args)));
mixins.forEach(function (mixin) {
copyProps(_this, new (Function.prototype.bind.apply(mixin, [null].concat(args)))());
});
return _this;
}
return base;
}(baseClass);
mixins.forEach(function (mixin) {
// outside constructor() to allow aggregation(A,B,C).staticFunction() to be called etc.
copyProps(base.prototype, mixin.prototype);
copyProps(base, mixin);
});
return base;
}
function cloneObject(obj) {
var clone = obj instanceof Array ? [] : {};
for (var i in obj) {
if (obj[i] != null && _typeof(obj[i]) === "object" && (obj[i].constructor.name === "Object" || obj[i].constructor.name === "Array")) {
clone[i] = cloneObject(obj[i]);
} else {
clone[i] = obj[i];
}
}
return clone;
}
var Time = function () {
function Time() {
_classCallCheck(this, Time);
}
_createClass(Time, null, [{
key: "sleep",
value: function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(millis) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
return _context.abrupt("return", new Promise(function (resolve, reject) {
setTimeout(resolve, millis);
}));
case 1:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
function sleep(_x2) {
return _ref2.apply(this, arguments);
}
return sleep;
}()
}]);
return Time;
}();
/**------------------------------------------------------------------------------------------------------------------**/
/**
* @class
* @classdesc Ticker class that handles repetitive, time based queueing
* @param {Number} [interval=2000] - polling interval
* @param {Number} [exponential_factor=1] - factor by which polling interval should be multiplied
* @param {Number} [min_interval=0] - minimum value configured for Poller's timer to work
* */
var AdharaTicker = function () {
function AdharaTicker(interval, exponential_factor, min_interval) {
_classCallCheck(this, AdharaTicker);
this.interval = interval === 0 ? interval : interval || 2000;
this.exponential_factor = exponential_factor || 1;
this.min_interval = min_interval || 0;
this.initial_interval = interval;
this.timeoutId = null;
}
_createClass(AdharaTicker, [{
key: "scheduleNextTick",
value: function scheduleNextTick() {
var _this2 = this;
this.pause();
if (!(this.interval <= this.min_interval)) {
this.timeoutId = window.setTimeout(function () {
_this2.onExecute();
}, this.interval);
}
}
}, {
key: "next",
value: function next() {
this.scheduleNextTick();
}
}, {
key: "onExecute",
value: function onExecute() {
this.interval *= this.exponential_factor;
this.on_execute(this.next);
}
/**
* @function
* @description
* Starts polling
* */
}, {
key: "start",
value: function start(execute) {
this.on_execute = execute;
this.scheduleNextTick();
}
/**
* @function
* @description
* stops current timeout
* doesn't call next or on-execute function
* */
}, {
key: "pause",
value: function pause() {
window.clearTimeout(this.timeoutId);
}
}, {
key: "resume",
/**
* @function
* @description
* stops current timeout
* doesn't call next or on-execute function
* start new timeout
* */
value: function resume() {
this.scheduleNextTick();
}
}, {
key: "stop",
/**
* @function
* @description
* stops current timeout
* doesn't call next or on-execute function
* reset's interval to initial interval
* */
value: function stop() {
this.pause();
this.interval = this.initial_interval;
}
}, {
key: "restart",
/**
* @function
* @description
* stops current timeout
* doesn't call next or on-execute function
* reset's interval to initial interval
* start new timeout
* */
value: function restart() {
this.stop();
this.scheduleNextTick();
}
}]);
return AdharaTicker;
}();
/**------------------------------------------------------------------------------------------------------------------**/
var CoalesceTasker = function () {
function CoalesceTasker() {
var wait_for = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
_classCallCheck(this, CoalesceTasker);
this.wait_for = wait_for;
this.timer_idx = 0;
}
_createClass(CoalesceTasker, [{
key: "execute",
value: function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(executor, terminator) {
var _this3 = this;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (this.terminator) this.terminator();
this.executor = executor;
this.terminator = terminator;
clearTimeout(this.timer_idx);
return _context2.abrupt("return", new Promise(function (resolve, reject) {
_this3.timer_idx = setTimeout(function () {
_this3.executor();
resolve();
}, _this3.wait_for);
}));
case 5:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
function execute(_x4, _x5) {
return _ref3.apply(this, arguments);
}
return execute;
}()
}]);
return CoalesceTasker;
}();
/**------------------------------------------------------------------------------------------------------------------**/
/**
* @namespace
* @description
* Client routing logic.
* All the client URL pattern's should be registered with the router.
*
* On visiting a URL, if called {@link AdharaRouter.route}, it calls the registered view function,
* which takes care of rendering the page.
*
* Any HTML element can be used as a router. For this purpose,
*
*
* > Add this attribute `href="/url/to/be/navigated/to"` and this property `route` to any html element to make behave as a router.
*
* > By default routing happening this way will execute the view function even if the current URL is same as provided href.
*
* > In order to disable this behaviour, provide the attribute `data-force="false"`
*
* > In order to use {@link AdharaRouter.goBack} functionality provide `data-force="true"`. See example below.
*
* @example
* //Registering
* AdharaRouter.register("^/adhara/{{instance_id}}([0-9]+)/{{tab}}(details|tokens|history)$", function(instance_id, tab){
* console.log(instance_id, tab);
* AdharaRouter.getPathParam("instance_id"); //Returns same as instance_id
* AdharaRouter.getPathParam("tab"); //Returns same as tab
* });
*
* //Navigating
* AdharaRouter.navigateTo("/adhara/123412341234/details");
*
* //Routing - In case if URL is already set in address bar and not via Router, call this function to execute the registered view funciton.
* this.route();
*
* //HTML Example
*
* <a href="/adhara/123412341234/tokens" />
*
* <button href="/adhara/123412341234/tokens" data-force="false">tokens</button>
*
* <div href="/adhara/123412341234/details" data-back="true"></div>
*
* */
var AdharaRouter = null;
(function () {
"use strict";
/**
* @private
* @member {Object<String, Object>}
* @description
* Stores all the registered URL's along with other view parameters.
* */
var registeredUrlPatterns = {};
/**
* @private
* @member {String}
* @description
* Stores base URI for regex matches
* */
var baseURI = "";
var defaultTitle = document.title;
/**
* @private
* @member {String}
* @description
* App Name to be used as first half of document title
* */
var appName = "";
/**
* @private
* @member {Object<String, String>}
* @description
* Stores the current URL's search query parameters.
* */
var queryParams = {};
/**
* @private
* @member {Object<String, String>}
* @description
* Stores the current URL's path variables.
* */
var pathParams = {};
/**
* @private
* @member {Array<String>}
* @description
* Stores list of visited URL's
* */
var historyStack = [];
/**
* @private
* @member {String|undefined}
* @description
* Stores current page URL.
* */
var currentUrl = undefined;
/**
* @private
* @member {RouterURLConf}
* @description
* Stores route which matches with the current URL against registered URL patterns.
* */
var currentRoute = undefined;
/**
* @private
* @member {Object<String, Function|undefined>}
* @description
* Stores listeners that will be called on routing.
* */
var listeners = {};
/**
* @typedef {Function} AdharaRouterMiddleware
* @param {Object} params - url parameters
* @param {String } params.view_name - name of the page that is being routed to
* @param {String} params.path - path that is being routed to
* @param {Object} params.query_params - url query parameters
* @param {Object} params.path_params - url path parameters
* @param {Function} route - Proceed with routing after making necessary checks in middleware
* */
/**
* @private
* @member {Array<AdharaRouterMiddleware>}
* @description
* Stores middlewares that will be called on routing.
* */
var middlewares = [];
/**
* @function
* @private
* @returns {Str