The TryingToScale PHP framework.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1362 lines
52 KiB

var prefData = window.performance.timing;
!(function (root, window, document, pref_data, undefined) { /* (immediately-invoked function expression), for Private Scope. ! means an expression */
var tts = function (arg, doc) {
doc = doc && doc.first || doc || document;
if (typeof arg == 'function') { /* $(function() {...}) */
if (doc.readyState == 'loading') {
doc.addEventListener('DOMContentLoaded', arg);
} else {
arg();
}
} else {
var ret = Object.create(tts.fn), match; /* $([domObject]) or $(ttsObject) */
if (typeof arg == 'object') {
if ('length' in arg) {
ret.length = arg.length;
for (var o = 0; o < arg.length; o++) {
ret[o] = arg[o];
}
} else { /* $(domObject) */
ret[0] = arg;
ret.length = 1;
}
} else if (!arg) { /* $() */
ret[0] = doc.createDocumentFragment();
ret.length = 1;
} else if ((match = arg.match(/<(.+)>/))) { /* $('<div>') */
ret[0] = doc.createElement(match[1]);
ret.length = 1;
} else { /* $('div.widget') */
var els = doc.querySelectorAll(arg);
ret.length = els.length;
for (var w = 0; w < els.length; w++) {
ret[w] = els[w];
}
}
return ret;
}
};
tts.version = "1.0";
tts.performanceData = pref_data;
tts.pageLoadTime = function () {
return pref_data.loadEventEnd - pref_data.navigationStart;
};
tts.connectTime = function () {
return pref_data.responseEnd - pref_data.requestStart;
};
tts.renderTime = function () {
return pref_data.domComplete - pref_data.domLoading;
};
tts.isNotSet = function (check) {
return (check === null || typeof check === "undefined" || check.length === 0) ? true : false;
};
tts.getValue = function (input, defaults) {
return (tts.isNotSet(input) === true) ? defaults : input;
};
tts.matches = ['matches', 'webkitMatchesSelector', 'mozMatchesSelector', 'msMatchesSelector'].filter(function (sel) {
return sel in document.documentElement;
})[0];
tts.fn = Object.create(Array.prototype, {
each: {value: function (callback) {
if ( ! tts.isFunction(callback) ) {
/*throw new Error("Callback should be a function");*/
}
var $this = {};
for (var index = 0; index < this.length; index++) {
$this = this[index];
$this.callback = callback;
$this.callback(index);
}
return this;
}},
first: {get: function () {
return this[0];
}},
eq: {value: function (i) {
return tts(this[i || 0]);
}},
on: {value: function (evt, fn) {
if (!tts.isFunction(fn))
tts.logger('Callback should be a function', 'warn');
var hasit = this[0].addEventListener;
for (var i = 0; i < this.length; i++) {
if (hasit) {
this[i].addEventListener(evt, fn);
} else {
this[i].attachEvent("on" + evt, fn);
}
}
return this;
}},
off: {value: function (evt, fn) {
if (!tts.isFunction(fn))
tts.logger('Callback should be a function', 'warn');
var hasit = this[0].removeEventListener;
for (var i = 0; i < this.length; i++) {
if (hasit) {
this[i].removeEventListener(evt, fn);
} else {
this[i].detachEvent("on" + evt, fn);
}
}
return this;
}},
trigger: {value: function (eventName) {
for (var i = 0; i < this.length; i++) {
var event = document.createEvent('Event');
event.initEvent(eventName, true, true);
this[i].dispatchEvent(event);
}
return this;
}},
toggleClass: {value: function (cls) {
for (var i = 0; i < this.length; i++) {
if (this[i].classList) {
this[i].classList.toggle(cls);
} else {
var classes = this[i].className.split(' ');
var existingIndex = classes.indexOf(cls);
if (existingIndex >= 0) {
classes.splice(existingIndex, 1);
} else {
classes.push(cls);
}
this[i].className = classes.join(' ');
}
}
return this;
}},
addClass: {value: function (cls) {
for (var i = 0; i < this.length; i++) {
if (!tts.fn.hasClass.call({first: this[i]}, cls)) {
this[i].className += ' ' + cls;
}
}
return this;
}},
removeClass: {value: function (cls) {
for (var i = 0; i < this.length; i++) {
this[i].className = this[i].className.replace(cls, '');
}
return this;
}},
hasClass: {value: function (cls) {
return this.first.className != '' && new RegExp('\\b' + cls + '\\b').test(this.first.className);
}},
prop: {value: function (property, value) {
if (typeof value == 'undefined') {
return this.first[property];
} else {
for (var i = 0; i < this.length; i++) {
this[i][property] = value;
}
return this;
}
}},
attr: {value: function (property, value) {
if (typeof value == 'undefined') {
return this.first.getAttribute(property);
} else {
for (var i = 0; i < this.length; i++) {
this[i].setAttribute(property, value);
}
return this;
}
}},
removeAttr: {value: function (property) {
for (var i = 0; i < this.length; i++) {
this[i].removeAttribute(property);
}
return this;
}},
val: {value: function (value) {
var el = this.first, prop = 'value';
switch (el.tagName) {
case 'SELECT':
prop = 'selectedIndex';
break;
case 'OPTION':
prop = 'selected';
break;
case 'INPUT':
if (el.type == 'checkbox' || el.type == 'radio') {
prop = 'checked';
}
break;
}
return this.prop(prop, value);
}},
append: {value: function (value) {
var t = this, v = tts(value), len = v.length;
for (var i = 0; i < len; i++) {
t.first.appendChild(v[i].first || v[i]);
}
return this;
}},
before: {value: function (value) {
this.first.parentElement.insertBefore(tts().append(value).first, this.first);
return this;
}},
parent: {value: function () {
return tts(this.first.parentNode);
}},
clone: {value: function () {
return tts(this.first.cloneNode(true));
}},
remove: {value: function () {
for (var i = 0; i < this.length; i++) {
this[i].parentNode.removeChild(this[i]);
}
return this;
}},
find: {value: function (value) {
return tts(value, this.first);
}},
closest: {value: function (selector) {
var el = this.first;
do {
if (el[tts.matches](selector)) {
return tts(el);
}
} while (el = el.parentElement);
return null;
}},
is: {value: function (selector) {
return tts(this.filter(function (el) {
return el[tts.matches](selector);
}));
}},
css: {value: function (property, value) {
if (typeof value == 'undefined') {
return this.first.style[property];
} else {
for (var i = 0; i < this.length; i++) {
this[i].style[property] = value;
}
return this;
}
}},
html: {value: function (value) {
return this.prop('innerHTML', value);
}},
text: {value: function (value) {
return this.prop('textContent', value);
}},
empty: {value: function () {
return this.prop('innerHTML', '');
}},
hide: {value: function () {
for (var i = 0; i < this.length; i++) {
this[i].style.display = 'none';
}
return this;
}},
show: {value: function (type) {
var display_type = (type) ? type : '';
for (var i = 0; i < this.length; i++) {
this[i].style.display = display_type;
}
return this;
}},
invisible: {value: function () {
for (var i = 0; i < this.length; i++) {
this[i].style.visibility = 'hidden';
}
return this;
}},
visible: {value: function (type) {
for (var i = 0; i < this.length; i++) {
this[i].style.visibility = "visible";
}
return this;
}},
fadeStop: {value: function () {
for (var i = 0; i < this.length; i++) {
this[i].style.opacity = 1;
this[i].style.filter = "alpha(opacity=1)";
this[i].style.display = "inline-block";
this[i].style.visibility = "visible";
}
}},
fadeIn: {value: function (ms, display) {
var tms = (typeof ms == 'undefined') ? 600 : ms, display_as = (typeof display == 'undefined') ? "inline-block" : display;
for (var i = 0; i < this.length; i++) {
var elem = this[i].style, opacity = {}, timer = {};
elem.opacity = 0;
elem.filter = "alpha(opacity=0)";
elem.display = display_as;
elem.visibility = "visible";
opacity.i = 0;
timer.i = setInterval(function () {
opacity.i += 50 / tms;
if (opacity.i >= 1) {
clearInterval(timer.i);
opacity.i = 1;
}
elem.opacity = opacity.i;
elem.filter = "alpha(opacity=" + opacity.i * 100 + ")";
}, 50);
}
}},
fadeOut: {value: function (ms) {
var tms = (typeof ms == 'undefined') ? 600 : ms;
for (var i = 0; i < this.length; i++) {
var opacity = {}, timer = {}, elem = this[i].style;
opacity.i = 1;
timer.i = setInterval(function () {
opacity.i -= 50 / tms;
if (opacity.i <= 0) {
clearInterval(timer.i);
opacity.i = 0;
elem.display = "none";
elem.visibility = "hidden";
}
elem.opacity = opacity.i;
elem.filter = "alpha(opacity=" + opacity.i * 100 + ")";
}, 50);
}
}}
});
tts.now = function () {
return Date.now();
};
tts.parse = function (string) {
return JSON.parse(string);
};
tts.map = function (array, callback, arg) {
return array.map(callback, arg);
};
tts.random = function (min, max) {
return Math.floor((Math.random() * max) + min);
};
tts.trim = function (string) {
return string.trim();
};
tts.inArray = function (item, array) {
return (array.indexOf(item) !== -1) ? true : false;
};
tts.isFunction = function (item) {
if (typeof item === 'function') {
return true;
}
var type = Object.prototype.toString.call(item);
return type === '[object Function]' || type === '[object GeneratorFunction]';
};
var arrayOfCalls = [];
tts.once = function (callback, id, parms) {
var fn = window[callback], found = (!tts.inArray(id, arrayOfCalls) && tts.isFunction(fn)) ? fn(parms) : false;
if (found !== false) {
arrayOfCalls.push(id);
}
return found;
};
tts.isEmptyObject = function (obj) {
return Object.keys(obj).length === 0;
};
tts.isEmpty = function (str) {
return (!str || 0 === str.length);
};
tts.isNumeric = function (n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
tts.extend = function (object1, object2) {
return Object.assign({}, object1, object2);
};
tts.when = function (arrayOfPromises) {
return new Promise(function (resolve, reject) {
Promise.all(arrayOfPromises).then(values => {
resolve(values);
}).catch(errors => {
reject(errors);
});
});
};
/*
* Begin Logger
*/
tts.time = function () {
var now = new Date(), hours = now.getHours() % 12 || 12, minutes = now.getMinutes(), seconds = now.getSeconds(), XM = (now.getHours() < 12) ? "AM" : "PM", formmated = hours + ":" + minutes + ":" + seconds + " " + XM;
return formmated;
};
tts.debugMode = true;
tts.doTrace = false;
var startTimer = [], endTimer = [], time = [], beginCodeTimer = 0, loggerData = [{message: navigator.userAgent, kind: "userAgent", option: ""}];
tts.allowedElapsedTime = 4000;
tts.completedCodeTimer = 0;
tts.startCodeTimer = function () {
beginCodeTimer = Date.now();
};
tts.endCodeTimer = function () {
tts.completedCodeTimer = Date.now() - beginCodeTimer;
loggerData.push({message: "Toal Code Time Elapsed", kind: "MainTimer", option: tts.completedCodeTimer});
if (tts.completedCodeTimer > tts.allowedElapsedTime) {
tts.sendReport();
}
};
tts.getLoggerData = loggerData;
tts.logger = function (message, level, option) {
if (typeof level === "undefined") {
level = "info";
}
if (typeof option === "undefined") {
option = "";
}
if (tts.debugMode === false || !window.console) {
return false;
}
if (typeof message === "object") {
message = `[ ${tts.time()} ] ` + JSON.stringify(message);
} else {
message = `[ ${tts.time()} ] ${message}`;
}
if (level === "microStart" || level === "start") {
console.group(message, option);
} else if (level === "microStop" || level === "stop") {
console.groupEnd(message, option);
} else {
loggerData.push({message: message, kind: level, option: option});
}
if (tts.doTrace && (level === "warn" || level === "error")) {
console.trace();
}
if (level === "info" && console.info) {
console.info(message);
} else if (level === "microStart" && performance.now) {
startTimer[option] = performance.now();
} else if (level === "microStop" && performance.now) {
endTimer[option] = performance.now();
var data = endTimer[option] - startTimer[option];
console.info(data);
loggerData.push({message: message, kind: level, option: data});
} else if (level === "warn" && console.warn) {
console.warn(message);
} else if (level === "error" && console.error) {
console.error(message);
} else if (level === "table" && console.table) {
console.table(message, option); /* option = Table Column */
} else if (level === "group" && console.group) {
console.group(message, option); /* option = Group Label */
} else if (level === "end" && console.groupEnd) {
console.groupEnd(message, option); /* option = Group Label */
} else if (level === "trace" && console.trace) {
console.trace();
} else if (level === "start" && console.time) {
console.time(option);
time[option] = Date.now();
} else if (level === "stop" && console.timeEnd) {
console.timeEnd(option);
var data = Date.now() - time[option];
loggerData.push({message: message, kind: level, option: data});
} else if (console.log) {
console.log(message); /* for Chorme Console is enabled */
}
};
tts.ReportsURL = "";
tts.sendReport = function (markComplete) {
return new Promise((resolve, reject) => {
if (tts.ReportsURL === "") {
reject();
} else {
var strValues = "&logs=" + encodeURI(JSON.stringify(loggerData));
if (sent_errors_yet === false) {
if (typeof markComplete === 'undefined') {
markComplete = false;
}
if (markComplete === true) {
sent_errors_yet = true;
}
tts.Post(tts.ReportsURL, strValues).then(values => {
resolve(values);
}).catch(errors => {
reject(errors);
});
}
}
});
};
var sent_errors_yet = false;
function errorReports(errorMsg, url, lineNumber, column, errorObj) {
if (tts.ReportsURL === "") {
return false;
}
if (errorMsg.indexOf('Script error.') > -1 || typeof errorMsg === "null") {
return; /* At the moment, we filter out the exceptions for iOS Safari and older Androids by checking if the error message is equal to “Script error.”. */
}
var strValues = "errMessage=" + encodeURI(errorMsg);
strValues += "&errLine=" + encodeURI(lineNumber);
if (typeof column !== "undeinfed" && typeof column !== "null") {
strValues += "&errColumn=" + encodeURI(column);
}
if (typeof errorObj !== "undeinfed" && typeof errorObj !== "null") {
strValues += "&errObject=" + encodeURI(errorObj);
}
strValues += "&queryString=" + encodeURI(location.search);
strValues += "&Url=" + encodeURI(url);
strValues += "&Path=" + encodeURI(location.pathname);
strValues += "&Hash=" + encodeURI(location.hash);
strValues += "&HTTPRef=" + encodeURI(document.referrer);
strValues += "&logs=" + encodeURI(JSON.stringify(loggerData));
if (sent_errors_yet === false) {
tts.Post(tts.ReportsURL, strValues);
}
sent_errors_yet = true;
}
try {
window.onerror = errorReports;
} catch (er) {
}
/*
* End of Logger
*/
/*
* Local Storage
*/
function store(temp) {
if (typeof temp === "undefined") {
this.temp = false;
} else {
this.temp = temp;
}
if (typeof (Storage) !== "undefined") {
return true;
} else {
return false;
}
}
store.prototype.set = function (name, data) {
try {
if (typeof (Storage) !== "undefined") {
var d = JSON.stringify(data);
if (this.temp === false) {
localStorage.setItem(name, d);
} else {
sessionStorage.setItem(name, d);
}
return true;
} else {
return false;
}
} catch (er) {
return false;
}
};
store.prototype.get = function (name) {
if (typeof (Storage) !== "undefined") {
if (this.temp === false) {
return JSON.parse(localStorage.getItem(name));
} else {
return JSON.parse(sessionStorage.getItem(name));
}
} else {
return false;
}
};
store.prototype.remove = function (name) {
if (typeof (Storage) !== "undefined") {
if (this.temp === false) {
localStorage.removeItem(name);
} else {
sessionStorage.removeItem(name);
}
return true;
} else {
return false;
}
};
store.prototype.clear = function () {
if (typeof (Storage) !== "undefined") {
if (this.temp === false) {
localStorage.clear();
} else {
sessionStorage.clear();
}
return true;
} else {
return false;
}
};
tts.store = store;
/* End of Local Storage */
/*
* Router
*/
class MyRouter {
constructor(opts) {
var self = this; /* Scope reference */
this.events = {}; /* Event Listeners */
this.state = null; /* Router state object */
this.options = opts || {}; /* Options */
this.options.env = this.options.env || (!!(Object.keys(root).length === 0 && process && process.browser !== true) ? 'server' : 'client');
this.options.mode = this.options.mode || (!!(this.options.env !== 'server' && this.options.pushState && root.history && root.history.pushState) ? 'pushState' : 'hashchange');
if ('function' === typeof root.addEventListener) {
root.addEventListener('hashchange', function () {
self.trigger('hashchange');
});
root.addEventListener('popstate', function (e) {
/* Make sure popstate doesn't run on init -- this is a common issue with Safari and old versions of Chrome */
if (self.state && self.state.previousState === null) {
return false;
}
self.trigger('navigate');
});
}
return this;
}
}
/**
* Create a RegExp Route from a string
* This is the heart of the router and I've made it as small as possible!
* @param {String} path - Path of route
* @param {Array} keys - Array of keys to fill
* @param {Bool} sensitive - Case sensitive comparison
* @param {Bool} strict - Strict mode
*/
MyRouter.regexRoute = function (path, keys, sensitive, strict) {
if (path instanceof RegExp) {
return path;
}
if (path instanceof Array) {
path = '(' + path.join('|') + ')';
}
/* Build route RegExp */
path = path.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/\+/g, '__plus__')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function (_, slash, format, key, capture, optional) {
keys.push({name: key, optional: !!optional});
slash = slash || '';
return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/__plus__/g, '(.+)')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
};
/**
* ForEach workaround utility
* @param {Array} a - to iterate
* @param {Function} callback
*/
MyRouter._forEach = function (a, callback) {
if (typeof Array.prototype.forEach === 'function') {
return Array.prototype.forEach.call(a, callback);
}
/* Replicate forEach() */
return function (c, next) {
for (var i = 0, n = this.length; i < n; ++i) {
c.call(next, this[i], i, this);
}
}.call(a, callback);
};
/**
* Add an route and handler
* @param {String|RegExp} route name
* @return {self} Router
*/
MyRouter.prototype.get = MyRouter.prototype.add = function (route) {
var self = this, middleware = Array.prototype.slice.call(arguments, 1, -1),
handler = Array.prototype.slice.call(arguments, -1)[0], request = new Request(route);
var invoke = function RouteHandler() {
/* Build request parameters */
var req = request.parse(self.path());
/* Check if matches are found */
if (req.match) {
/* Match found */
var extra = {route: route, params: req.params, req: req, regex: req.match};
/* Create call stack -- add middleware first, then handler */
var stack = new CallStack(self, extra).enqueue(middleware.concat(handler));
/* Trigger main event */
self.trigger('match', stack, req);
/* Continue */
if (!stack.runCallback) {
return self;
}
/* Previous state becomes current state */
stack.previousState = self.state;
/* Save new state */
self.state = stack;
/* Prevent this handler from being called if parent handler in stack has instructed not to propagate any more events */
if (stack.parent() && stack.parent().propagateEvent === false) {
stack.propagateEvent = false;
return self;
}
/* Call handler */
stack.callback();
}
/* Returns self */
return self;
};
/* Event name */
var eventName = (self.options.mode !== 'pushState' && self.options.env !== 'server') ? 'hashchange' : 'navigate';
/* Invoke when route is defined, and once again when app navigates */
return invoke().on(eventName, invoke);
};
/**
* Fire an event listener
* @param {String} event name
* @param {Mixed} [attributes] Parameters that will be applied to event handler
* @return {self} Router
*/
MyRouter.prototype.trigger = function (event) {
var self = this, params = Array.prototype.slice.call(arguments, 1);
/* Call matching events */
if (this.events[event]) {
MyRouter._forEach(this.events[event], function (fn) {
fn.apply(self, params);
});
}
return this;
};
/**
* Add an event listener
* @param {String} event name (multiple events can be called when separated by a space " ")
* @param {Function} handler - callback
* @return {self} Router
*/
MyRouter.prototype.on = MyRouter.prototype.bind = function (event, handler) {
var self = this, events = event.split(' ');
MyRouter._forEach(events, function (event) {
if (self.events[event]) {
self.events[event].push(handler);
} else {
self.events[event] = [handler];
}
});
return this;
};
/**
* Allow event to be called only once
* @param {String} event name(s)
* @param {Function} handler - callback
* @return {self} Router
*/
MyRouter.prototype.once = function (event, handler) {
var ran = false;
return this.on(event, function () {
if (ran) {
return false;
}
ran = true;
handler.apply(this, arguments);
handler = null;
return true;
});
};
/**
* @param {String} context - Route context (without trailing slash)
* param {[Function]} Middleware (optional)
* @return {Function} Adds route to context
*/
MyRouter.prototype.context = function (context) {
var self = this, middleware = Array.prototype.slice.call(arguments, 1);
return function () {
var value = arguments[0],
submiddleware = (arguments.length > 2) ? Array.prototype.slice.call(arguments, 1, -1) : [],
handler = Array.prototype.slice.call(arguments, -1)[0],
prefix = (context.slice(-1) !== '/' && value !== '/' && value !== '') ? context + '/' : context,
path = (value.substr(0, 1) !== '/') ? value : value.substr(1),
pattern = prefix + path;
return self.add.apply(self, [pattern].concat(middleware).concat(submiddleware).concat([handler]));
};
};
/**
* Navigate through history API
* @param {String} path - Pathname
* @return {self} Router
*/
MyRouter.prototype.navigate = function (path) {
return this.path(path).trigger('navigate');
};
MyRouter.prototype.path = function (pathname) {
var self = this, frag;
if ('string' === typeof pathname) {
/* Set path */
if (self.options.mode === 'pushState') {
frag = (self.options.root) ? (self.options.root + pathname) : pathname;
root.history.pushState({}, null, frag);
} else if (root.location) {
root.location.hash = (self.options.hashBang ? '!' : '') + pathname;
} else {
root._pathname = pathname || '';
}
return this;
} else if ('undefined' === typeof pathname) {
/* Get path */
if (self.options.mode === 'pushState') {
frag = root.location.pathname.replace(self.options.root, '');
} else if (self.options.mode !== 'pushState' && root.location) {
frag = (root.location.hash) ? root.location.hash.split((self.options.hashBang ? '#!' : '#'))[1] : '';
} else {
frag = root._pathname || '';
}
return frag;
} else if (pathname === false) {
/* Clear path */
if (self.options.mode === 'pushState') {
root.history.pushState({}, null, self.options.root || '/');
} else if (root.location) {
root.location.hash = (self.options.hashBang) ? '!' : '';
}
return self;
}
};
/**
* Create routes based on an object
* @param {Object} [Options, Routes]
* @param {Object Routes}
* @return {self} Router
*/
MyRouter.listen = function () {
var opts, routes;
if (arguments[0] && arguments[1]) {
opts = arguments[0];
routes = arguments[1];
} else {
routes = arguments[0];
}
/* Return a new MyRouter instance */
return (function () {
/* TODO: Accept multi-level routes */
for (var key in routes) {
this.add.call(this, key, routes[key]);
}
return this;
}).call(new MyRouter(opts || {}));
};
/**
* Create a call stack that can be enqueued by handlers and middleware
* @param {Object} router - Router
* @param {Object} extendObj - Extend
* @return {self} CallStack
*/
class CallStack {
constructor(router, extendObj) {
this.stack = CallStack.global.slice(0);
this.router = router;
this.runCallback = true;
this.callbackRan = false;
this.propagateEvent = true;
this.value = router.path();
for (var key in extendObj) {
this[key] = extendObj[key];
}
return this;
}
}
/**
* Build request parameters and allow them to be checked against a string (usually the current path)
* @param {String} route - Route
* @return {self} Request
*/
function Request(route) {
this.route = route;
this.keys = [];
this.regex = MyRouter.regexRoute(route, this.keys);
}
;
/* This allows global middleware */
CallStack.global = [];
/**
* Prevent a callback from being called
* @return {self} CallStack
*/
CallStack.prototype.preventDefault = function () {
this.runCallback = false;
};
/**
* Prevent any future callbacks from being called
* @return {self} CallStack
*/
CallStack.prototype.stopPropagation = function () {
this.propagateEvent = false;
};
/**
* Get parent state
* @return {Object} Previous state
*/
CallStack.prototype.parent = function () {
var hasParentEvents = !!(this.previousState && this.previousState.value && this.previousState.value == this.value);
return (hasParentEvents) ? this.previousState : false;
};
/**
* Run a callback (calls to next)
* @return {self} CallStack
*/
CallStack.prototype.callback = function () {
this.callbackRan = true;
this.timeStamp = Date.now();
this.next();
};
/**
* Add handler or middleware to the stack
* @param {Function|Array} handler - Handler or a array of handlers
* @param {Int} atIndex - Index to start inserting
* @return {self} CallStack
*/
CallStack.prototype.enqueue = function (handler, atIndex) {
var handlers = (!Array.isArray(handler)) ? [handler] : ((atIndex < handler.length) ? handler.reverse() : handler);
while (handlers.length) {
this.stack.splice(atIndex || this.stack.length + 1, 0, handlers.shift());
}
return this;
};
/**
* Call to next item in stack -- this adds the `req`, `event`, and `next()` arguments to all middleware
* @return {self} CallStack
*/
CallStack.prototype.next = function () {
var self = this;
return this.stack.shift().call(this.router, this.req, this, function next() {
self.next.call(self);
});
};
/**
* Match a path string -- returns a request object if there is a match -- returns false otherwise
* @param {String} path
* @return {Object} req
*/
Request.prototype.parse = function (path) {
var match = path.match(this.regex), self = this;
var req = {params: {}, keys: this.keys, matches: (match || []).slice(1), match: match};
/* Build parameters */
MyRouter._forEach(req.matches, function (value, i) {
var key = (self.keys[i] && self.keys[i].name) ? self.keys[i].name : i;
/* Parameter key will be its key or the iteration index. This is useful if a wildcard (*) is matched */
req.params[key] = (value) ? decodeURIComponent(value) : undefined;
});
return req;
};
MyRouter.CallStack = CallStack;
MyRouter.Request = Request;
tts.Router = new MyRouter();
/*
* End of MyRouter Router
*/
/*
* AJAX
*/
tts.grab_form = function (form_id) {
try {
let myForm = document.getElementById(form_id);
let arr = {};
for (var i = 0; i < myForm.elements.length; i++) {
let id = myForm.elements[i].id;
let value = myForm.elements[i].value;
let node = myForm.elements[i].nodeName;
if ((node == "INPUT" || node == "TEXTAREA" || node == "SELECT") && (typeof id !== "undefined" && id !== "")) {
arr[id] = value;
}
}
return arr;
} catch (e) {
tts.logger(e);
return false;
}
};
function json_parse(json) {
try {
var obj = JSON.parse(json);
var unfetched = obj.unfetched;
if (typeof unfetched !== "undefined") {
console.warn(`You have some unFetched JSON Vars: ${unfetched}`);
}
var err = obj.error;
if (typeof err === "undefined") {
return obj;
} else if (err !== null) {
throw err;
}
} catch (e) {
return e;
}
}
tts.send_json = function (php_script, args) {
let myPromise = new Promise(function (myResolve, myReject) {
if (args === false) {
let nodata = "No Data from Form!";
throw nodata;
}
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
xmlhttp.open("POST", php_script);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
myResolve(json_parse(this.response));
} else {
myReject(json_parse(this.response));
}
}
};
xmlhttp.send(JSON.stringify(args));
});
return myPromise;
};
tts.Post = function (url, data) {
return new Promise((resolve, reject) => {
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.onload = function (d) {
resolve(d.currentTarget.responseText);
};
try {
request.send(data);
} catch (err) {
reject(err);
}
});
};
function doProgress(eventName, evt) {
if (eventName !== false && evt.lengthComputable) {
var percentComplete = (evt.loaded / evt.total) * 100;
var pc = Math.round(percentComplete);
var event = new CustomEvent(eventName, {detail: {progress: pc}});
var el = document.getElementsByTagName('body')[0];
el.dispatchEvent(event);
}
}
function setHTML(elementID, html) {
try {
return document.getElementById(elementID).innerHTML = html;
} catch (e) {
tts.logger("ID of " + elementID + " not found...!", "warn");
}
}
tts.lastAjax = false; /* So you can use the xmlHttp Request later on... if not cached... */
let ajaxCallback = function (url, resolve, reject, options) {
var doCache = tts.getValue(options.useCache, false), eventName = tts.getValue(options.eventName, false);
var elementID = tts.getValue(options.elementID, false), ts = tts.getValue(options.ts, "");
if (doCache) {
var myCache = new tts.store();
if (myCache) {
let stored_data = myCache.get(url + ts); /* timestamp cache buster */
let done = tts.getValue(stored_data, false);
if (!tts.isEmpty(done)) {
tts.logger('Used cache, on ' + url + ' !');
tts.lastAjax = false;
doProgress(eventName, {lengthComputable: true, loaded: 100, total: 100});
if (elementID) {
setHTML(elementID, stored_data);
}
return resolve(stored_data);
} else {
tts.logger('Adding to cache, for ' + url + ' !');
}
} else {
tts.logger('No Cache Engine enabled, for ' + url + ' !');
}
} else {
tts.logger('No Caching, for ' + url);
}
var xmlHttp = new XMLHttpRequest();
tts.lastAjax = xmlHttp;
xmlHttp.upload.addEventListener("progress", function (evt) {
doProgress(eventName, evt);
});
xmlHttp.addEventListener("progress", function (evt) {
doProgress(eventName, evt);
});
xmlHttp.onreadystatechange = function () {
var result;
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
switch (options.dataType) {
case 'xml':
result = xmlHttp.responseXML;
break;
case 'json':
result = JSON.parse(xmlHttp.responseText);
break;
default:
result = xmlHttp.responseText;
break;
}
if (myCache && doCache) {
myCache.set(url + ts, result);
}
if (elementID) {
setHTML(elementID, result);
}
resolve(result);
} else if (reject) {
reject('Ajax error: ' + xmlHttp.status + ' url: ' + url);
}
}
};
xmlHttp.open(options.method || 'GET', url, true);
if (options.headers) {
for (var key in options.headers) {
xmlHttp.setRequestHeader(key, options.headers[key]);
}
}
xmlHttp.send(options.data || '');
};
tts.ajax = function (url, options) {
if (typeof options === "undefined") {
options = {};
}
return new Promise(function (resolve, reject) {
ajaxCallback(url, resolve, reject, options);
});
};
/*
* End of AJAX
*/
/*
* Load Assets
*/
var assets_loaded_once = [];
tts.AddAssetCachedFile = function (full_file) {
assets_loaded_once.push(full_file);
};
/**
* Get an StyleSheet/Script
* @param {Object} source - CSS/JavaScript File with Options
* @param {Object} options - element to use, etc...
* @returns {Promise}
*/
tts.getAsset = (source, options) => {
if (typeof options === "undefined") {
options = {};
}
return new Promise((resolve, reject) => {
var defaults_caching = tts.getValue(DO_CACHE_ON_ASSETS, true);
var file = source.name, kind = file.split('.').pop(), doCache = tts.getValue(source.useCache, defaults_caching);
var full_file = tts.getValue(source.path, "") + file;
var ts = tts.getValue(source.ts, "");
var has_loaded = (assets_loaded_once.indexOf(full_file) === -1) ? false : true;
if (has_loaded) {
resolve("Already Loaded..." + full_file);
} else {
assets_loaded_once.push(full_file);
switch (kind) {
case 'css':
var dataType = tts.getValue(source.dataType, "text/css"), style = document.createElement('style');
var elm = tts.getValue(options.element, document.getElementsByTagName('style')[0] || document.getElementsByTagName('head')[0]);
var loaded = tts.ajax(full_file, {dataType: "text/css", useCache: doCache, ts: ts});
loaded.then(function (code) {
style.type = dataType;
style.innerText = code;
elm.parentNode.insertBefore(style, elm.nextSibling);
setTimeout(function () {
resolve();
}, 12);
});
loaded.catch(function (e) {
reject(e);
});
break;
default:
var dataType = tts.getValue(source.dataType, "text/javascript");
var script = document.createElement('script');
var elm = tts.getValue(options.element, document.getElementsByTagName('script')[0] || document.getElementsByTagName('head')[0]);
var loaded = tts.ajax(full_file, {dataType: "text/javascript", useCache: doCache, ts: ts});
loaded.then(function (code) {
script.type = dataType;
script.text = code;
elm.parentNode.insertBefore(script, elm);
setTimeout(function () {
resolve();
}, 12);
});
loaded.catch(function (e) {
reject(e);
});
break;
}
}
});
};
/** Useage: to combine options on each Asset for use with getMultiAssets.
* Updates the sources Array/Objects with new data from Options.....as it is passed by Reference!!!
* @param {Array of Objects} sources - CSS/JavaScript File with Options
* @param {Array of Objects} options - path, useCache, dataType...
*/
tts.mergeOptions = function (sources, options) {
let keys = Object.keys(options);
for (let key of keys) {
for (var x = 0; x < sources.length; x++) {
if (typeof sources[x][key] === 'undefined') {
sources[x][key] = options[key];
}
}
}
};
/**
*
* @param {Array of Objects} sources - CSS/JavaScript File with Options
* @param {Object} options - element to apply to, etc...
* @returns {Promise} - All done will all Files.
*/
tts.getMultiAssets = (sources, options) => {
if (typeof options === "undefined") {
options = {};
}
var prArr = [];
sources.forEach(function (source) {
(function (source) {
prArr.push(new Promise(function (resolve, reject) {
tts.getAsset(source, options).then(function () {
resolve();
}).catch(function (e) {
reject(e);
});
}));
})(source);
});
return Promise.all(prArr, function () {
return true;
});
};
/*
* End of Assets
*/
/*
* Cookies
*/
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) { /* This is a quoted cookie as according to RFC2068, unescape... */
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
/* Replace server-side written pluses with spaces. */
/* If we can't decode the cookie, ignore it, it's unusable. */
/* If we can't parse the cookie, ignore it, it's unusable. */
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch (e) {
}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return tts.isFunction(converter) ? converter(value) : value;
}
var config = tts.cookie = function (key, value, options) {
if (arguments.length > 1 && !tts.isFunction(value)) { /* Write */
options = tts.extend(config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', /* use expires attribute, max-age is not supported by IE */
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
var result = key ? undefined : {}, /* Read */
/* To prevent the for loop in the first place assign an empty array
* in case there are no cookies at all. Also prevents odd result when
* calling $.cookie().
*/
cookies = document.cookie ? document.cookie.split('; ') : [], l = cookies.length;
for (let i = 0; i < l; i++) {
var parts = cookies[i].split('='), name = decode(parts.shift()), cookie = parts.join('=');
/* If second argument (value) is a function it's a converter... */
if (key === name) {
result = read(cookie, value);
break;
}
/* Prevent storing a cookie that we couldn't decode. */
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
tts.removeCookie = function (key, options) {
/* Must not alter options, thus extending a fresh object... */
tts.cookie(key, '', $.extend({}, options, {expires: -1}));
return !$.cookie(key);
};
/*
* End of Cookies
*/
/*
* Printer Support
*/
/* Printer Framed Window */
var array_of_frames = []; /* Needed to track open iFrames */
var printFrameID = 0;
function donePrintFrame() {
var frm = document.getElementById(printFrameID).contentWindow;
frm.focus();
frm.print(); /* set focus on contentWindow is needed on some ie versions */
}
/* id is the id of the iframe */
tts.printFrame = function (id, src) {
try {
for (var i = 0; i < array_of_frames.length; i++) {
document.body.removeChild(array_of_frames[i]); /* Delete old page when done, for new data */
array_of_frames.pop();
}
var newIframe = document.createElement('iframe');
newIframe.width = '0';
newIframe.height = '0';
newIframe.name = id;
newIframe.id = id;
newIframe.src = src;
printFrameID = id;
document.body.appendChild(newIframe);
array_of_frames.push(newIframe); /* Add frame to list to be removed next time */
newIframe.onload = donePrintFrame;
} catch (err) {
tts.logger(err.message);
}
return false;
};
/*
* End of Printer Support
*/
if (typeof module === 'object' && module.exports) {
module.exports = tts;
} else {
window.tts = tts;
}
}).call({}, ('object' === typeof window) ? window : this, window, document, prefData); /* These get passed into the Local Scope, in the top of this Script function */