From 4e1e04e5268cdfad941fe89c0fc1cc8cb85314fa Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 16 Dec 2022 01:02:52 -0500 Subject: [PATCH] 1st commit --- .gitignore | 4 + LICENSE | 22 ++ README.md | 15 ++ core/about_bloat.txt | 3 + core/addons/ajax.js | 181 +++++++++++++++++ core/addons/cookies.js | 76 +++++++ core/addons/grapnel.js | 361 +++++++++++++++++++++++++++++++++ core/addons/load_assets.js | 115 +++++++++++ core/addons/local_storage.js | 69 +++++++ core/addons/logger.js | 143 +++++++++++++ core/addons/print_frame.js | 41 ++++ core/begin.js | 2 + core/core.js | 381 +++++++++++++++++++++++++++++++++++ core/end.js | 7 + gulp_deps/gulp-combine.js | 11 + gulp_deps/gulp-extend.js | 39 ++++ gulp_deps/gulp-when.js | 11 + gulpfile.js | 58 ++++++ old_router/router.js | 301 +++++++++++++++++++++++++++ package.json | 18 ++ 20 files changed, 1858 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 core/about_bloat.txt create mode 100644 core/addons/ajax.js create mode 100644 core/addons/cookies.js create mode 100644 core/addons/grapnel.js create mode 100644 core/addons/load_assets.js create mode 100644 core/addons/local_storage.js create mode 100644 core/addons/logger.js create mode 100644 core/addons/print_frame.js create mode 100644 core/begin.js create mode 100644 core/core.js create mode 100644 core/end.js create mode 100644 gulp_deps/gulp-combine.js create mode 100644 gulp_deps/gulp-extend.js create mode 100644 gulp_deps/gulp-when.js create mode 100644 gulpfile.js create mode 100644 old_router/router.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e7231b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +assets/dist/ +package-lock.json +nbproject/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2831971 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License + +Copyright (c) 2021 Robert Strutts + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..91bd0de --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# tts_js + +TTS Framework - JavaScript assets. + +Install node, npm, then GulpJS. +Google how to install node & npm for your OS. + +GulpJS here: +$ sudo npm install --global gulp-cli + +Goto this Repo where the package.json file exists, then run: +$ npm install + +Now, Compile all JavaScript assets into the assets/dist folders: +$ gulp diff --git a/core/about_bloat.txt b/core/about_bloat.txt new file mode 100644 index 0000000..acbde96 --- /dev/null +++ b/core/about_bloat.txt @@ -0,0 +1,3 @@ +For instance, jQuery is about 250kb (90kb if minified). +Not that bad, huh? +But, if you have 50,000 monthly visitors, jQuery will consume 4Gb! diff --git a/core/addons/ajax.js b/core/addons/ajax.js new file mode 100644 index 0000000..d3f0459 --- /dev/null +++ b/core/addons/ajax.js @@ -0,0 +1,181 @@ + /* + * @author Robert Strutts + * @copyright 2019 + * @license MIT + * 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 + */ diff --git a/core/addons/cookies.js b/core/addons/cookies.js new file mode 100644 index 0000000..8a44233 --- /dev/null +++ b/core/addons/cookies.js @@ -0,0 +1,76 @@ + /* + * 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 + */ diff --git a/core/addons/grapnel.js b/core/addons/grapnel.js new file mode 100644 index 0000000..db1d842 --- /dev/null +++ b/core/addons/grapnel.js @@ -0,0 +1,361 @@ + /* + * Grapnel Router + * @author Greg Sabia Tucker + * @copyright 2019 Greg Sabia Tucker + * @link https://github.com/baseprime/grapnel + * Released under MIT License. See http://opensource.org/licenses/MIT + */ + 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 + */ diff --git a/core/addons/load_assets.js b/core/addons/load_assets.js new file mode 100644 index 0000000..b67987b --- /dev/null +++ b/core/addons/load_assets.js @@ -0,0 +1,115 @@ + /* + * Load Assets + * @author Robert Strutts + * @copyright 2019 + * @license MIT + */ + + 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 + */ diff --git a/core/addons/local_storage.js b/core/addons/local_storage.js new file mode 100644 index 0000000..bc49777 --- /dev/null +++ b/core/addons/local_storage.js @@ -0,0 +1,69 @@ + /* + * 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 */ diff --git a/core/addons/logger.js b/core/addons/logger.js new file mode 100644 index 0000000..0025db8 --- /dev/null +++ b/core/addons/logger.js @@ -0,0 +1,143 @@ + /* + * Begin Logger + * @author Robert Strutts + * @copyright 2019 + * @license MIT + */ + + 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 + */ diff --git a/core/addons/print_frame.js b/core/addons/print_frame.js new file mode 100644 index 0000000..33370f0 --- /dev/null +++ b/core/addons/print_frame.js @@ -0,0 +1,41 @@ + /* + * Printer Support + * @author Robert Strutts + * @copyright 2019 + * @license MIT + */ + + /* 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 + */ diff --git a/core/begin.js b/core/begin.js new file mode 100644 index 0000000..1e16139 --- /dev/null +++ b/core/begin.js @@ -0,0 +1,2 @@ +var prefData = window.performance.timing; +!(function (root, window, document, pref_data, undefined) { // (immediately-invoked function expression), for Private Scope. ! means an expression diff --git a/core/core.js b/core/core.js new file mode 100644 index 0000000..0e3d68c --- /dev/null +++ b/core/core.js @@ -0,0 +1,381 @@ +/* + * Miq + @copyright 2019 Edwin Martin + @link https://github.com/edwinm/miq/blob/master/miq.js + @license MIT + * + * Miq, the micro jQuery library + */ + 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(/<(.+)>/))) { /* $('
') */ + 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); + }); + }); + }; diff --git a/core/end.js b/core/end.js new file mode 100644 index 0000000..644cf63 --- /dev/null +++ b/core/end.js @@ -0,0 +1,7 @@ + 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 */ diff --git a/gulp_deps/gulp-combine.js b/gulp_deps/gulp-combine.js new file mode 100644 index 0000000..0ed5350 --- /dev/null +++ b/gulp_deps/gulp-combine.js @@ -0,0 +1,11 @@ +combine = function (source, dest) { + + for (var i = 0; i < source.length; i++) { + dest.push(source[i]); + } + + return dest; + +}; + +module.exports = combine; \ No newline at end of file diff --git a/gulp_deps/gulp-extend.js b/gulp_deps/gulp-extend.js new file mode 100644 index 0000000..e7870ee --- /dev/null +++ b/gulp_deps/gulp-extend.js @@ -0,0 +1,39 @@ +var extend = function () { + + // Variables + var extended = {}; + var deep = false; + var i = 0; + var length = arguments.length; + + // Check if a deep merge + if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') { + deep = arguments[0]; + i++; + } + + // Merge the object into the extended object + var merge = function (obj) { + for (var prop in obj) { + if (Object.prototype.hasOwnProperty.call(obj, prop)) { + // If deep merge and property is an object, merge properties + if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') { + extended[prop] = extend(true, extended[prop], obj[prop]); + } else { + extended[prop] = obj[prop]; + } + } + } + }; + + // Loop through each object and conduct a merge + for (; i < length; i++) { + var obj = arguments[i]; + merge(obj); + } + + return extended; + +}; + +module.exports = extend; \ No newline at end of file diff --git a/gulp_deps/gulp-when.js b/gulp_deps/gulp-when.js new file mode 100644 index 0000000..c989b30 --- /dev/null +++ b/gulp_deps/gulp-when.js @@ -0,0 +1,11 @@ +when = function (arrayOfPromises) { + return new Promise(function (resolve, reject) { + Promise.all(arrayOfPromises).then(values => { + resolve(values); + }).catch(errors => { + reject(errors); + }); + }); +}; + +module.exports = when; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..ab4fd4e --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,58 @@ +/* My Plug-Ins */ +const extend = require('./gulp_deps/gulp-extend'); +const when = require('./gulp_deps/gulp-when'); +const combine = require('./gulp_deps/gulp-combine'); +/* Terser Ugilfy Settings */ +const ecma_latest = 8; +const warn_level = { warnings: true }; +const compress = { compress: { dead_code: true, drop_debugger: false, arrows: false, properties: false } }; +const mangle = { mangle: false }; // { properties: { keep_quoted: true } } +const output = { output: {comments: false} }; // Destroy Commment Blocks! +const options = { module: false, keep_classnames: true, keep_fnames: true, toplevel: false, safari10: false }; +const common = extend( warn_level, compress, mangle, options, output ); +const uglify_latest_e = { ecma: ecma_latest, ie8: false }; +const uglify_latest = extend( uglify_latest_e, common ); +/* Gulp Add-Ons */ +const { src, dest, series, parallel, watch } = require('gulp'); +const uglify = require('gulp-terser'); +const concat = require('gulp-concat'); +const rename = require('gulp-rename'); +const sourcemaps = require("gulp-sourcemaps"); +/* Core TTS JS */ +const tts_js_files = [ + 'core/begin.js', + 'core/core.js', + 'core/addons/*.js', + 'core/end.js' +]; +/* Destination Folders for JS */ +const js_dest = 'assets/dist/'; +/* Use Map instead of .js.map */ +const map = { mapFile: function(mapFilePath) { return mapFilePath.replace('.js.map', '.map'); } }; + +function tts_js() { + return when([ + new Promise(function(resolve, reject) { + src( tts_js_files ) + .pipe(sourcemaps.init({ loadMaps: true })) + .pipe(concat( 'tts.js' )) + .pipe(dest( js_dest )) + .pipe(rename( { extname: '.min.js' } )) + .pipe(uglify( uglify_latest ) ) + .pipe(sourcemaps.write(".", map )) + .pipe(dest( js_dest )) + .on('end', resolve); + }) + ]); +} + +function watch_js() { + watch(tts_js_files, tts_js); +} + +exports.js = parallel(tts_js); +exports.all = parallel(tts_js); +exports.watcher = series( parallel(tts_js), watch_js ); +//exports.css = css; +//exports.html = html; +exports.default = parallel(tts_js); diff --git a/old_router/router.js b/old_router/router.js new file mode 100644 index 0000000..0faf46a --- /dev/null +++ b/old_router/router.js @@ -0,0 +1,301 @@ + /* Robs Router Loader */ + tts.RouteObject = {}; /* This is the main Object to use for AJAX Pages */ + var include_once_files = []; /* Was this Asset loaded yet, and did the PHP Footer file find this Asset */ + + tts.AddRouterCachedFile = function(filename) { + include_once_files.push(filename); + }; + + function doesAssetExists(filename) { +// console.log(filename); + return new Promise((resolve, reject) => { + if (hasLoaded(filename) === false) { + var exists = false; + for (var i = 0; i < assets_files.length; i++) { + if (filename == assets_files[i].filename) { + tts.logger('Loading: ' + filename) + include_once_files.push(filename); + exists = true; + break; + } + } + if (exists === false) { + reject("skipped: " + filename); + } else { + resolve(assets_files[i].ts); + } + } else { + resolve("loaded"); + } + }); + } + function getClassName(obj) { + if (typeof obj.constructor.name === "undefined") { + return obj.constructor.toString().match(/^function\s(.+)\(/)[1]; + } else { + return obj.constructor.name; + } + } + function hasLoaded(file) { + return tts.inArray(file, include_once_files); + } /* Just checks if file has been loaded once yet */ + function apply_css(css_file, version) { + return new Promise((resolve, reject) => { + tts.getAsset({name: css_file, path: AJAX_Folder, version: version}).then(function () { + resolve(); + }).catch(function () { + reject(); + }); + }); + } + function hasPromise(obj, fn, text) { // tts.logger("promise"+fn, "trace"); + if (typeof text === "undefined") { + text = ""; + } + return new Promise((resolve, reject) => { + var usePromise = tts.getValue(obj.Promise, true); + if (typeof fn === "undefined" && typeof fn !== "function") { + reject(text + " Function does not exist"); + } else { + if (usePromise === true) { + tts.logger("Promise exec of " + text); + fn().then(function (out) { + resolve(out); + }).catch(function (e) { + reject(e); + }); + } else { + tts.logger("Exec of " + text); + fn(); + resolve(); + } + } + }); + } + /* Run Main method on Class File */ + function do_run_main(obj) { + var className = getClassName(obj); + return new Promise((resolve, reject) => { + hasPromise(obj, obj['Main'], className).then(function () { + resolve(); + }).catch(function (e) { + reject(e); + }); + }); + } + ; + /* This will Run JS code for Tabs! */ + function do_run(obj) { + var className = getClassName(obj); + return new Promise((resolve, reject) => { + hasPromise(obj, obj[obj.tab], className + " " + obj.tab).then(function () { + resolve(); + }).catch(function (e) { + reject(e); + }); + }); + } + ; + function is_unknown(obj) { + if (is_404(obj.tab)) { + var className = getClassName(obj); + tts.logger(className + " " + obj.tab + " tab FN not found!"); + do_404_page(); + return true; + } + return false; + } + function loadJS(scriptFile, version, obj, fn) { + var stuff = { name: scriptFile, path: AJAX_Folder, ts: version }; +// console.log(stuff); + return new Promise((resolve, reject) => { + tts.getAsset(stuff) + .then(function () { + switch (fn) { + case 'ErrorMain': + hasPromise(obj, obj.Main, "404").then(function () { + resolve(); + }).catch(function () { + reject(); + }); + break; + case 'do_run_main': + do_run_main(obj).then(function () { + resolve("js_complete"); + }).catch(function (e) { + reject(e); + }); + break; + case 'do_run': + do_run(obj).then(function () { + resolve("js_complete"); + }).catch(function (e) { + reject(e); + }); + break; + default: + window[fn](obj).then(function () { + resolve("js_complete"); + }).catch(function (e) { + reject(e); + }); + break; + } + }).catch(function (exception) { + switch (fn) { + case 'ErrorMain': + tts.logger("404 Page - does not exist", "error"); + break; + case 'do_run_main': + do_run_main(obj).catch(function () { + reject(e); + }); + break; + case 'do_run': + do_run(obj).catch(function () { + reject(e); + }); + break; + default: + window[fn](obj).catch(function () { }); + break; + } + if (fn !== 'ErrorMain') { + tts.logger("Something went wrong: " + exception, "warn"); + } + reject('Something went wrong'); + }); + }); + } + tts.JS_EXT = ".js"; + tts.CSS_EXT = ".css"; + /* Does Class StartUp, CSS, and JS - After Main JS has completed loading... */ + function do_other_FN(obj) { + return new Promise((resolve, reject) => { + var className = getClassName(obj); + var tab = tts.getValue(obj.tab, false); + hasPromise(obj, obj['StartUp'], "Start Up").catch(function () { }); + if (tab === false) { + resolve(); + } else { + var Script_File = className + "_" + tab + tts.JS_EXT; + var CSS_File = className + "_" + tab + tts.CSS_EXT; + var MainCSS_File = className + "_Main" + tts.CSS_EXT; + doesAssetExists(Script_File).then(function (versionNumber) { + if (versionNumber === 'loaded') { + do_run(obj).then(function (ok) { + resolve(ok); + }).catch(function (e) { + reject(e); + }); + } else { + loadJS(Script_File, versionNumber, obj, 'do_run').then(function (ok) { + resolve(ok); + }).catch(function (e) { + reject(e); + }); + } + }).catch(function (err) { + do_run(obj).then(function (ok) { + resolve(ok); + }).catch(function (e) { + is_unknown(obj); + reject(e); + }); + }); + doesAssetExists(MainCSS_File).then(function (versionNumber) { + if (versionNumber !== 'loaded') { + apply_css(MainCSS_File, versionNumber); + } + }).catch(function (e) { }); + doesAssetExists(CSS_File).then(function (versionNumber) { + if (versionNumber !== 'loaded') { + apply_css(CSS_File, versionNumber); + } + }).catch(function (e) { }); + } + }); + } + function mainRouting(obj) { + return new Promise((resolve, reject) => { + tts.RouteObject = obj; + var className = getClassName(obj); + var MainScript_File = className + "_Main" + tts.JS_EXT; + doesAssetExists(MainScript_File).then(function (versionNumber) { + if (versionNumber === 'loaded') { + do_run_main(obj).then(function () { + do_other_FN(obj).then(function (ok) { + resolve(ok); + }).catch(function (e) { + reject(e); + }); + }).catch(function (e) { + reject(e); + }); + } else { + loadJS(MainScript_File, versionNumber, obj, 'do_run_main').then(function () { + do_other_FN(obj).then(function (ok) { + resolve(ok); + }).catch(function (e) { + reject(e); + }); + }).catch(function (e) { + reject(e); + }); + } + }).catch(function (err) { + do_run_main(obj).then(function () { + do_other_FN(obj).then(function (ok) { + resolve(ok); + }).catch(function (e) { + reject(e); + }); + }).catch(function (e) { + reject(e); + }); + }); + }); + } + + tts.Route = function (obj) { /* This is the core loader for Tabs and Main Route */ + tts.startCodeTimer(); + return new Promise((resolve, reject) => { + mainRouting(obj).then(function (r) { + tts.endCodeTimer(); + $_.logger(r + " - Resolved Took " + tts.completedCodeTimer); + resolve(r); + }).catch(function (e) { + tts.endCodeTimer(); + $_.logger(e + " - Rejected Took " + tts.completedCodeTimer); + reject(e); + }); + }); + }; + /* Load 404 JS for doing 404 Page */ + function do_404_page() { + var ErrorScript_File = "PageNotFound_Main" + tts.JS_EXT; + var err_page = new PageNotFound(false); + doesAssetExists(ErrorScript_File).then(function (versionNumber) { + if (versionNumber === 'loaded') { + err_page.Main(); + } else { + loadJS(ErrorScript_File, versionNumber, err_page, "ErrorMain").catch(function (e) { }); + } + }).catch(function (err) { + tts.logger("404 Page - does not exist", "error"); + }); + } + /* Is 404 on, if so does Tab Method/File exists, if not was an exception made */ + tts.do_404_page_on_bad_Route = true; + tts.empty_Route_pages = []; + function is_404(tab_name) { + if (tts.do_404_page_on_bad_Route === false) + return false; /* Is 404 off?? */ + for (var i = 0; i < tts.empty_Route_pages.length; i++) { + if (tts.empty_Route_pages[i] == tab_name) { + return false; /* Found allowed empty tab page */ + } + } + return true; /* Unable to find tab page hash in allowed list */ + } + /* End of Robs Router Loader */ diff --git a/package.json b/package.json new file mode 100644 index 0000000..fa9803b --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "tts_js", + "version": "1.0.0", + "description": "TTS Framework JavaScript Assets.", + "main": "gulpfile.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Robert Strutts", + "license": "MIT", + "devDependencies": { + "gulp": "^4.0.2", + "gulp-concat": "^2.6.1", + "gulp-rename": "^2.0.0", + "gulp-sourcemaps": "^3.0.0", + "gulp-terser": "^2.1.0" + } +}