From baad9b0eece372b07ebdd0ca5cd6b1ffdd8d47b1 Mon Sep 17 00:00:00 2001 From: William Mantly Date: Tue, 30 Jul 2024 20:46:37 -0400 Subject: [PATCH] moved front end JS libs to correct folder --- nodejs/public/lib/js/app-base.js | 355 ++++++++++++++++++++++++++ nodejs/public/lib/js/jq-repeat_new.js | 264 +++++++++++++++++++ nodejs/public/lib/js/val.js | 147 +++++++++++ 3 files changed, 766 insertions(+) create mode 100644 nodejs/public/lib/js/app-base.js create mode 100644 nodejs/public/lib/js/jq-repeat_new.js create mode 100755 nodejs/public/lib/js/val.js diff --git a/nodejs/public/lib/js/app-base.js b/nodejs/public/lib/js/app-base.js new file mode 100644 index 0000000..c4ec287 --- /dev/null +++ b/nodejs/public/lib/js/app-base.js @@ -0,0 +1,355 @@ +var app = {}; + +// app.pubsub = (function(){ +// app.topics = {}; + +// app.subscribe = function(topic, listener){ +// if(topic instanceof RegExp){ +// listener.match = topic; +// topic = "__REGEX__"; +// } + +// // create the topic if not yet created +// if(!app.topics[topic]) app.topics[topic] = []; + +// // add the listener +// app.topics[topic].push(listener); +// } + +// app.matchTopics = function(topic){ +// topic = topic || ''; +// var matches = [... app.topics[topic] ? app.topics[topic] : []]; + +// if(!app.topics['__REGEX__']) return matches; + +// for(var listener of app.topics['__REGEX__']){ +// if(topic.match(listener.match)) matches.push(listener); +// } + +// return matches; +// } + +// app.publish = function(topic, data){ + +// // send the event to all listeners +// app.matchTopics(topic).forEach(function(listener){ +// setTimeout(function(data, topic){ +// listener(data || {}, topic); +// }, 0, data, topic); +// }); +// } + +// return this; +// })(app); + +// app.socket = (function(app){ +// var socket = io(); +// // socket.emit('chat message', $('#m').val()); +// socket.on('P2PSub', function(msg){ +// msg.data.__noSocket = true; +// app.publish(msg.topic, msg.data); +// }); + +// app.subscribe(/./g, function(data, topic){ +// // console.log('local_pubs', data, topic) +// if(data.__noSocket) return; +// // console.log('local_pubs 2', data, topic) + +// socket.emit('P2PSub', { topic, data }) +// }); + +// return socket; + +// })(app); + +app.api = (function(app){ + var baseURL = '/api/' + + function post(url, data, callback){ + $.ajax({ + type: 'POST', + url: baseURL+url, + headers:{ + 'auth-token': app.auth.getToken() + }, + data: JSON.stringify(data), + contentType: "application/json; charset=utf-8", + dataType: "json", + complete: function(res, text){ + callback( + text !== 'success' ? res.statusText : null, + JSON.parse(res.responseText), + res.status + ) + } + }); + } + + function put(url, data, callback){ + $.ajax({ + type: 'PUT', + url: baseURL+url, + headers:{ + 'auth-token': app.auth.getToken() + }, + data: JSON.stringify(data), + contentType: "application/json; charset=utf-8", + dataType: "json", + complete: function(res, text){ + callback( + text !== 'success' ? res.statusText : null, + JSON.parse(res.responseText), + res.status + ) + } + }); + } + + function remove(url, callback, callback2){ + if(!$.isFunction(callback)) callback = callback2; + $.ajax({ + type: 'delete', + url: baseURL+url, + headers:{ + 'auth-token': app.auth.getToken() + }, + contentType: "application/json; charset=utf-8", + dataType: "json", + complete: function(res, text){ + callback( + text !== 'success' ? res.statusText : null, + JSON.parse(res.responseText), + res.status + ) + } + }); + } + + function get(url, callback){ + $.ajax({ + type: 'GET', + url: baseURL+url, + headers:{ + 'auth-token': app.auth.getToken() + }, + contentType: "application/json; charset=utf-8", + dataType: "json", + complete: function(res, text){ + callback( + text !== 'success' ? res.statusText : null, + JSON.parse(res.responseText), + res.status + ) + } + }); + } + + return {post: post, get: get, put: put, delete: remove} +})(app) + +app.auth = (function(app){ + var user = {} + function setToken(token){ + localStorage.setItem('APIToken', token); + } + + function getToken(){ + return localStorage.getItem('APIToken'); + } + + function isLoggedIn(callback){ + if(getToken()){ + return app.api.get('user/me', function(error, data){ + if(!error) app.auth.user = data; + return callback(error, data); + }); + }else{ + callback(null, false); + } + } + + function logIn(args, callback){ + app.api.post('auth/login', args, function(error, data){ + if(data.login){ + setToken(data.token); + } + callback(error, !!data.token); + }); + } + + function logOut(callback){ + localStorage.removeItem('APIToken'); + callback(); + } + + function forceLogin(){ + $.holdReady(true); + app.auth.isLoggedIn(function(error, isLoggedIn){ + if(error || !isLoggedIn){ + app.auth.logOut(function(){}) + location.replace(`/login${location.href.replace(location.origin, '')}`); + }else{ + $.holdReady(false); + } + }); + } + + function logInRedirect(){ + window.location.href = location.href.replace(location.origin+'/login', '') || '/' + } + + return { + getToken: getToken, + setToken: setToken, + isLoggedIn: isLoggedIn, + logIn: logIn, + logOut: logOut, + forceLogin, + logInRedirect, + } + +})(app); + +app.user = (function(app){ + function list(callback){ + app.api.get('user/?detail=true', function(error, data){ + callback(error, data); + }) + } + + function add(args, callback){ + app.api.post('user/', args, function(error, data){ + callback(error, data); + }); + } + + function remove(args, callback){ + app.api.delete('user/'+ args.username, function(error, data){ + callback(error, data); + }); + } + + function changePassword(args, callback){ + app.api.put('users/'+ arg.username || '', args, function(error, data){ + callback(error, data); + }); + } + + return {list, remove}; + +})(app); + +app.util = (function(app){ + + function getUrlParameter(name){ + name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); + var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); + var results = regex.exec(location.search); + return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); + }; + + function actionMessage(message, $target, type, callback){ + message = message || ''; + $target = $target.closest('div.card').find('.actionMessage'); + type = type || 'info'; + callback = callback || function(){}; + + if($target.html() === message) return; + + if($target.html()){ + $target.slideUp('fast', function(){ + $target.html('') + $target.removeClass (function(index, className){ + return (className.match (/(^|\s)bg-\S+/g) || []).join(' '); + }); + if(message) return actionMessage(message, $target, type, callback); + $target.hide() + }) + }else{ + if(type) $target.addClass('bg-' + type); + message = '' + message + '' + $target.html(message).slideDown('fast'); + } + setTimeout(callback,10) + } + + $.fn.serializeObject = function(){ + var + arr = $(this).serializeArray(), + obj = {}; + + for(var i = 0; i < arr.length; i++){ + if(obj[arr[i].name] === undefined) { + obj[arr[i].name] = arr[i].value; + } else { + if(!(obj[arr[i].name] instanceof Array)) { + obj[arr[i].name] = [obj[arr[i].name]]; + } + obj[arr[i].name].push(arr[i].value); + } + } + return obj; + }; + + return { + getUrlParameter: getUrlParameter, + actionMessage: actionMessage + } +})(app); + +$( document ).ready(function(){ + $('div.row').fadeIn('slow'); //show the page + + //panel button's + $('.fa-arrows-v').click(function(){ + $(this).closest('.card').find('.card-body').slideToggle('fast'); + }); + + $('.fa-circle-minus').click(function(){ + $(this).closest('.card').find('.card-body').slideToggle('fast'); + }); + + $('.fa-circle-xmark').click(function(){ + $(this).closest('.card').slideUp('fast'); + }); + + $('.actionMessage').on('click', 'button.action-close', function(event){ + app.util.actionMessage(null, $(this)); + }); + + setInterval(()=>{ + $('.momentFromNow').each((idx,el)=>{ + var $el = $(el); + try{ + $el.html(moment($(el).data('date')).fromNow()); + }catch{} + }) + }, 30000,); +}); + +//ajax form submit +function formAJAX(btn, del){ + event.preventDefault(); // avoid to execute the actual submit of the form. + var $form = $(btn).closest('[action]'); // gets the 'form' parent + var formData = $form.find('[name]').serializeObject(); // builds query formDataing + var method = $form.attr('method') || 'post'; + + // if( !$form.validate()){ + // app.util.actionMessage('Please fix the form errors.', $form, 'danger') + // return false; + // } + + app.util.actionMessage( + '
Loading...
', + $form, + 'info' + ); + + app.api[method]($form.attr('action'), formData, function(error, data){ + app.util.actionMessage(data.message, $form, error ? 'danger' : 'success'); //re-populate table + if(!error){ + $form.trigger("reset"); + eval($form.attr('evalAJAX')); //gets JS to run after completion + } + }); +} diff --git a/nodejs/public/lib/js/jq-repeat_new.js b/nodejs/public/lib/js/jq-repeat_new.js new file mode 100644 index 0000000..10f333e --- /dev/null +++ b/nodejs/public/lib/js/jq-repeat_new.js @@ -0,0 +1,264 @@ +/* +Author William Mantly Jr +https://github.com/wmantly/jq-repeat +MIT license +*/ + +(function($, Mustache){ +'use strict'; + if (!$.scope) { + $.scope = {}; + } + + var make = function( element ){ + var result = []; + + result.splice = function(inputValue, ...args){ + //splice does all the heavy lifting by interacting with the DOM elements. + + var toProto = [...args] + + var index; + //if a string is submitted as the index, try to match it to index number + if( typeof arguments[0] === 'string' ){ + index = this.indexOf( arguments[0] );//set where to start + if ( index === -1 ) { + return []; + } + }else{ + index = arguments[0]; //set where to start + } + + toProto.unshift(index) + + var howMany = arguments[1]; //sets the amount of fields to remove + var args = Array.prototype.slice.call( arguments ); // coverts arguments into array + var toAdd = args.slice(2); // only keeps fields to add to array + + // if the starting point is higher then the total index count, start at the end + if( index > this.length ) { + index = this.length; + } + // if the starting point is negative, start form the end of the array, minus the start point + if( index < 0 ) { + index = this.length - Math.abs( index ); + } + + // if there are things to add, figure out the how many new indexes we need + if( !howMany && howMany !== 0 ) { + howMany = this.length - index; + } + //not sure why i put this here... but it does matter! + if( howMany > this.length - index ) { + howMany = this.length - index; + } + + //figure out how many positions we need to shift the current elements + var shift = toAdd.length - howMany; + + // figure out how big the new array will be + // var newLength = this.length + shift; + + //removes fields from array based on howMany needs to be removed + for( var i = index; i < +index+howMany; i++ ) { + this.__take(this[index].__jq_$el, this[index], this); + // this.__take.apply( $( '.jq-repeat-'+ this.__jqRepeatId +'[jq-repeat-index="'+ ( i + index ) +'"]' ) ); + } + + //re-factor element index's + for(var i = 0; i < this.length; i++){ + if( i >= index){ + this[i].__jq_$el.attr( 'jq-repeat-index', i+shift ); + } + } + + //if there are fields to add to the array, add them + if( toAdd.length > 0 ){ + + //$.each( toAdd, function( key, value ){ + for(var I = 0; I < toAdd.length; I++){ + + //figure out new elements index + var key = I + index; + // apply values to template + var render = Mustache.render(this.__jqTemplate, toAdd[I] ); + + //set call name and index keys to DOM element + var $render = $( render ).addClass( 'jq-repeat-'+ this.__jqRepeatId ).attr( 'jq-repeat-index', key ); + + //if add new elements in proper stop, or after the place holder. + if( key === 0 ){ + this.$this.after( $render ); + }else{ + $( '.jq-repeat-'+ this.__jqRepeatId +'[jq-repeat-index="' + ( key -1 ) + '"]' ).after( $render ); + } + + Object.defineProperty( toAdd[I], "__jq_$el", { + value: $render, + writable: true, + enumerable: false, + configurable: true + } ); + + //animate element + this.__put($render, toAdd[I], this); + } + } + + //set and return new array + return Array.prototype.splice.apply(this, toProto); + }; + result.push = function(){ + //add one or more objects to the array + + //set the index value, if none is set make it zero + var index = this.length || 0; + + //loop each passed object and pass it to slice + for (var i = 0 ; i < arguments.length; ++i) { + this.splice( ( index + i ), 0, arguments[i] ); + } + + //return new array length + return this.length; + }; + result.pop = function(){ + //remove and return array element + + return this.splice( -1, 1 )[0]; + }; + result.reverse = function() { + var temp = this.splice( 0 ); + Array.prototype.reverse.apply( temp ); + + for( var i = 0; i < temp.length; i++ ){ + this.push( temp[i] ); + } + + return this; + }; + + result.remove = function(key, value){ + let index = this.indexOf(key, value) + if(index === -1) return; + this.splice(index, 1) + } + + result.shift = function() { + return this.splice( 0, 1 )[0]; + }; + + result.loop = function(){ + var temp = this[0]; + this.splice( 0,1 ); + this.push( temp ); + + return temp; + }; + result.loopUp = function(){ + var temp = this[this.length-1]; + this.splice( -1, 1 ); + this.splice( 0, 0, temp ); + return temp; + }; + result.indexOf = function( key, value ){ + if( typeof value !== 'string' ){ + value = arguments[0]; + key = this.__index; + } + for ( var index = 0; index < this.length; ++index ) { + if( this[index][key] === value ){ + + return index; + } + } + return -1; + }; + result.update = function( key, value, update ){ + //set variables using sting for index + + // If update is called with no index/key, assume its the 0 + if(typeof key === 'object'){ + if(this[0]){ + return this.update(0, key); + } + return this.splice(0, 1, key); + } + + if( typeof value !== 'string' ){ + update = arguments[1]; + value = arguments[0]; + key = this.__index; + } + var index = this.indexOf( key, value ); + if(index === -1) { + return []; + } + var object = $.extend( true, {}, this[index], update ); + return this.splice( index, 1, object )[0]; + }; + result.__put = function($el, item, list){ + $el.show(); + }; + result.__take = function($el, item, list){ + $el.remove(); + }; + + result.__setPut = function(fn) { + Object.defineProperty(this, '__put', { + value: fn, + writable: true, + enumerable: false, + configurable: true + }); + } + + result.__setTake = function(fn) { + Object.defineProperty(this, '__take', { + value: fn, + writable: true, + enumerable: false, + configurable: true + }); + } + + var $this = $( element ); + result.__jqRepeatId = $this.attr( 'jq-repeat' ); + $this.removeAttr('jq-repeat'); + result.__index = $this.attr('jq-repeat-index'); + result.__jqTemplate = $this[0].outerHTML; + $this.replaceWith( '