NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name COE's OIT at UGA WebCheckout Helper // @namespace http://tampermonkey.net/ // @version 0.2 // @description This script is used by the University of Georgia to better help service our custermers. // By working with web checkout and modifying it, we make a smoother experience. // @author Shawn Holman // @author Shawn Holman // @include /^https://webcheckout2.coe.uga.edu/webcheckout/wco*(\?.*|)/ // @grant none // @license MIT // @updateURL https://openuserjs.org/meta/the-ikick/COEs_OIT_at_UGA_WebCheckout_Helper.meta.js // ==/UserScript== (function($) { 'use strict'; /////// BEIGIN EXTERNAL JS SECTION *******//////// /** * Featherlight - ultra slim jQuery lightbox * Version 1.4.0 - http://noelboss.github.io/featherlight/ * * Copyright 2016, Noël Raoul Bossart (http://www.noelboss.com) * MIT Licensed. **/ !function(e){"use strict";if(void 0!==e){var t=[],n=function(n){return t=e.grep(t,function(e){return e!==n&&e.$instance.closest("body").length>0})},r={keyup:"onKeyUp",resize:"onResize"},i=function(t){e.each(o.opened().reverse(),function(){if(!t.isDefaultPrevented()&&!1===this[r[t.type]](t))return t.preventDefault(),t.stopPropagation(),!1})},a=function(t){if(t!==o._globalHandlerInstalled){o._globalHandlerInstalled=t;var n=e.map(r,function(e,t){return t+"."+o.prototype.namespace}).join(" ");e(window)[t?"on":"off"](n,i)}};o.prototype={constructor:o,namespace:"featherlight",targetAttr:"data-featherlight",variant:null,resetCss:!1,background:null,openTrigger:"click",closeTrigger:"click",filter:null,root:"body",fadeInOnly:!1,openSpeed:150,closeSpeed:150,closeOnClick:"background",closeOnEsc:!0,closeIcon:"✕",loading:"",persist:!1,otherClose:null,beforeOpen:e.noop,beforeContent:e.noop,beforeClose:e.noop,afterOpen:e.noop,afterContent:e.noop,afterClose:e.noop,onKeyUp:e.noop,onResize:e.noop,type:null,contentFilters:["jquery","image","html","ajax","iframe","text"],setup:function(t,n){"object"!=typeof t||t instanceof e!=!1||n||(n=t,t=void 0);var r=e.extend(this,n,{target:t}),i=r.resetCss?r.namespace+"-reset":r.namespace,a=e(r.background||['<div class="'+i+"-loading "+i+'">','<div class="'+i+'-content">','<span class="'+i+"-close-icon "+r.namespace+'-close" title="Press ESC to close">',r.closeIcon,"</span>",'<div class="'+r.namespace+'-inner">'+r.loading+"</div>","</div>","</div>"].join("")),o="."+r.namespace+"-close"+(r.otherClose?","+r.otherClose:"");return r.$instance=a.clone().addClass(r.variant),r.$instance.on(r.closeTrigger+"."+r.namespace,function(t){var n=e(t.target);("background"===r.closeOnClick&&n.is("."+r.namespace)||"anywhere"===r.closeOnClick||n.closest(o).length)&&(r.close(t),t.preventDefault())}),this},getContent:function(){if(this.$currentTarget&&this.$currentTarget[0].classList.contains("disabled"))return!1;if(!1!==this.persist&&this.$content)return this.$content;var t=this,n=this.constructor.contentFilters,r=function(e){return t.$currentTarget&&t.$currentTarget.attr(e)},i=r(t.targetAttr),a=t.target||i||"";t.$currentTarget&&t.$currentTarget[0].hasAttribute("data-unique")&&(e.featherlight.close(),t.$currentTarget[0].classList.add("disabled"));var o=n[t.type];if(!o&&a in n&&(o=n[a],a=t.target&&i),a=a||r("href")||"",!o)for(var s in n)t[s]&&(o=n[s],a=t[s]);if(!o){var c=a;if(a=null,e.each(t.contentFilters,function(){return(o=n[this]).test&&(a=o.test(c)),!a&&o.regex&&c.match&&c.match(o.regex)&&(a=c),!a}),!a)return"console"in window&&window.console.error("Featherlight: no content filter found "+(c?' for "'+c+'"':" (no target specified)")),!1}return o.process.call(t,a)},setContent:function(t){var n=this;return(t.is("iframe")||e("iframe",t).length>0)&&n.$instance.addClass(n.namespace+"-iframe"),n.$instance.removeClass(n.namespace+"-loading"),n.$instance.find("."+n.namespace+"-inner").not(t).slice(1).remove().end().replaceWith(e.contains(n.$instance[0],t[0])?"":t),n.$content=t.addClass(n.namespace+"-inner"),n},open:function(n){var r=this;if(r.$instance.hide().appendTo(r.root),!(n&&n.isDefaultPrevented()||!1===r.beforeOpen(n))){n&&n.preventDefault();var i=r.getContent();if(i){t.push(r),a(!0);var o=!1;return r.$currentTarget&&(o=r.$currentTarget.data("featherlight-fadeinonly")),r.beforeContent(n),e.when(i).always(function(e){r.setContent(e),(r.fadeInOnly||o)&&r.$instance.fadeIn(r.openSpeed),r.afterContent(n)}).then(r.$instance.promise()).done(function(){if(r.afterOpen(n),!r.fadeInOnly&&1!=o){var e=r.$instance.children(".featherlight-content");r.$instance.show();e[0].clientWidth,e[0].clientHeight;r.$instance.hide(),e.css("top",-700),r.$instance.fadeIn(r.openSpeed,function(){e.show().animate({top:0},r.openSpeed+500,function(){e.css("overflow","visible")})})}})}}return r.$instance.detach(),e.Deferred().reject().promise()},close:function(t){this.$currentTarget&&this.$currentTarget[0].classList.contains("disabled")&&e(".disabled").removeClass("disabled");var r=this,i=e.Deferred();return!1===r.beforeClose(t)?i.reject():(0===n(r).length&&a(!1),r.$instance.fadeOut(r.closeSpeed,function(){r.$instance.detach(),r.afterClose(t),i.resolve()})),i.promise()},resize:function(e,t){if(e&&t){this.$content.css("width","").css("height","");var n=Math.max(e/parseInt(this.$content.parent().css("width"),10),t/parseInt(this.$content.parent().css("height"),10));n>1&&this.$content.css("width",e/n+"px").css("height",t/n+"px")}},chainCallbacks:function(t){for(var n in t)this[n]=e.proxy(t[n],this,e.proxy(this[n],this))}},e.extend(o,{id:0,autoBind:"[data-featherlight]",defaults:o.prototype,contentFilters:{jquery:{regex:/^[#.]\w/,test:function(t){return t instanceof e&&t},process:function(t){return!1!==this.persist?e(t):e(t).clone(!0)}},image:{regex:/\.(png|jpg|jpeg|gif|tiff|bmp|svg)(\?\S*)?$/i,process:function(t){var n=e.Deferred(),r=new Image,i=e('<img src="'+t+'" alt="" class="'+this.namespace+'-image" />');return r.onload=function(){i.naturalWidth=r.width,i.naturalHeight=r.height,n.resolve(i)},r.onerror=function(){n.reject(i)},r.src=t,n.promise()}},html:{regex:/^\s*<[\w!][^<]*>/,process:function(t){return e(t)}},ajax:{regex:/./,process:function(t){var n=e.Deferred();e.get(t).then(function(t,r){n.resolve(e(t))},function(){n.fail()});return n.promise()}},iframe:{process:function(t){var n=new e.Deferred,r=e("<iframe/>").hide().attr("src",t).css(function(e,t){var n={},r=new RegExp("^"+t+"([A-Z])(.*)");for(var i in e){var a=i.match(r);a&&(n[(a[1]+a[2].replace(/([A-Z])/g,"-$1")).toLowerCase()]=e[i])}return n}(this,"iframe")).on("load",function(){n.resolve(r.show())}).appendTo(this.$instance.find("."+this.namespace+"-content"));return n.promise()}},text:{process:function(t){return e("<div>",{text:t})}}},functionAttributes:["beforeOpen","afterOpen","beforeContent","afterContent","beforeClose","afterClose"],readElementConfig:function(t,n){var r=this,i=new RegExp("^data-"+n+"-(.*)"),a={};return t&&t.attributes&&e.each(t.attributes,function(){var t=this.name.match(i);if(t){var n=this.value,o=e.camelCase(t[1]);if(e.inArray(o,r.functionAttributes)>=0)n=new Function(n);else try{n=e.parseJSON(n)}catch(e){}a[o]=n}}),a},extend:function(t,n){var r=function(){this.constructor=t};return r.prototype=this.prototype,t.prototype=new r,t.__super__=this.prototype,e.extend(t,this,n),t.defaults=t.prototype,t},attach:function(t,n,r){var i=this;"object"!=typeof n||n instanceof e!=!1||r||(r=n,n=void 0);var a,o=(r=e.extend({},r)).namespace||i.defaults.namespace,s=e.extend({},i.defaults,i.readElementConfig(t[0],o),r);return t.on(s.openTrigger+"."+s.namespace,s.filter,function(o){var c=e.extend({$source:t,$currentTarget:e(this)},i.readElementConfig(t[0],s.namespace),i.readElementConfig(this,s.namespace),r),l=a||e(this).data("featherlight-persisted")||new i(n,c);"shared"===l.persist?a=l:!1!==l.persist&&e(this).data("featherlight-persisted",l),c.$currentTarget.blur(),l.open(o)}),t},current:function(){var e=this.opened();return e[e.length-1]||{close:function(){}}},prev:function(){var e=this.opened();return e[e.length-2]||{close:function(){}}},opened:function(){var r=this;return n(),e.grep(t,function(e){return e instanceof r})},close:function(e){var t=this.current();if(t)return t.close(e)},closeAll:function(e){for(var t=this.opened(),n=0,r=t.length;n<r;n++)t[n]&&t[n].close(e)},_onReady:function(){var t=this;t.autoBind&&(e(t.autoBind).each(function(){t.attach(e(this))}),e(document).on("click",t.autoBind,function(n){n.isDefaultPrevented()||"featherlight"===n.namespace||(n.preventDefault(),t.attach(e(n.currentTarget)),e(n.target).trigger("click.featherlight"))}))},_callbackChain:{onKeyUp:function(t,n){return 27===n.keyCode?(this.closeOnEsc&&e.featherlight.close(n),!1):t(n)},onResize:function(e,t){return this.resize(this.$content.naturalWidth,this.$content.naturalHeight),e(t)},afterContent:function(e,t){var n=e(t);return this.onResize(t),n}}}),e.featherlight=o,e.fn.featherlight=function(e,t){return o.attach(this,e,t)},e(document).ready(function(){o._onReady()})}else"console"in window&&window.console.info("Too much lightness, Featherlight needs jQuery.");function o(e,t){if(!(this instanceof o)){var n=new o(e,t);return n.open(),n}this.id=o.id++,this.setup(e,t),this.chainCallbacks(o._callbackChain)}}(jQuery); /** * */ (function(a){a.fn.codeScanner=function(b){var c=a.extend({},a.fn.codeScanner.defaults,b);return this.each(function(){var d=!1,f=[],g=a(this);return a(window).keypress(function(h){var i=h.which?h.which:h.keyCode;(65<=i&&90>=i||97<=i&&122>=i||48<=i&&57>=i)&&f.push(String.fromCharCode(h.which)),!1==d&&setTimeout(function(){if(f.length>=c.minEntryChars){var j=f.join('');c.onScan(g,j)}f=[],d=!1},c.maxEntryTime),d=!0}),a(this).keypress(function(h){13===h.which&&h.preventDefault()}),a(this)})},a.fn.codeScanner.defaults={minEntryChars:4,maxEntryTime:140,onScan:function(b,c){b.val(c)}}})(jQuery); /////// END EXTERNAL JS SECTION *******//////// let styles = { featherlight: "@media all{.featherlight{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:400;text-align:center;white-space:nowrap;cursor:pointer;background:rgba(0,0,0,.8)}.featherlight:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-.25em}.featherlight .featherlight-content{position:relative;text-align:left;vertical-align:middle;display:inline-block;overflow:hidden;padding:25px 0 0 0;margin-left:5%;margin-right:5%;max-height:95%;background:#fff;cursor:auto;white-space:normal;}.featherlight .featherlight-inner{display:block;min-width:400px}.featherlight .featherlight-close-icon{position:absolute;z-index:9999;top:0;right:0;line-height:25px;width:25px;cursor:pointer;text-align:center;font-family:Arial,sans-serif;background:#fff;background:rgba(255,255,255,.3);color:#000}li.nav-item.disabled,li.nav-item.disabled:hover{color:grey!important;background:#e4e4e4!important}.featherlight .featherlight-image{width:100%}.featherlight-iframe .featherlight-content{border-bottom:0;padding:0}.featherlight iframe{border:0}li.nav-item.disabled{cursor:not-allowed}}@media only screen and (max-width:1024px){.featherlight .featherlight-content{margin-left:10px;margin-right:10px;max-height:98%}}.lightbox-bottom-banner{background:#f2f2f2;margin:15px -25px -25px;padding:15px 25px;text-align:center;display:block;text-transform:capitalize}", main: ` .featherlight-inner h1 { font-size: 20px; padding: 5px 10px; margin: 0; background: transparent; color: #b93b40; text-align: center; font-weight: bold; margin-top: -22px; letter-spacing: -1px; } .featherlight-inner .content { padding: 10px 25px; background: #f6f6f6; } .featherlight-inner .content textarea, div#progress-prompt { resize: none; width: 100%; height: 90px; outline: none; padding: 10px 15px 5px; color: #4a4949; border-radius: 4px; border-color: #afafaf; transition: 0.3s box-shadow, border-color; } #progress-prompt { background: white; border-color: white !important; border: 1px solid; overflow-y: auto; max-width: 310px; } #progress-prompt div { padding: 5px; margin-bottom: 0; } #progress-prompt div.success { color: green; } .featherlight-inner .content textarea:focus { box-shadow: inset 0 0px 1px grey; border-color: #b7b7b7; } .featherlight-inner .content textarea.error { border-color: #e00000; color: red; } .featherlight-inner input.form-control:focus { box-shadow: inset 0 0px 1px grey; border-color: #b7b7b7; } .featherlight-inner input.form-control.autocompleted { background: #e4e4e4; color: #004802a8; } .featherlight-inner .footer-area { font-size: 0; } .autocomplete { list-style: none; margin: 5px 0 0 0; padding: 0; background: white; position: absolute; z-index: 233; border: 1px solid #c7c7c7; } .autocomplete li:hover { background: #eaeaea; color: #b93b40; cursor: pointer; } .autocomplete li { padding: 5px 10px; user-select: none; } .row { margin: 0; } .content .row { margin-bottom: 5px; } .content .row .remove-row { text-align: center; background: #c90000; color: #ffeaea; border-radius: 4px; border: 1px solid #750000; padding: 3px; } .content .row .remove-row:hover { background: red; cursor: pointer; } .featherlight-inner .footer-area .btn { color: #fff; border-radius: 0; height: 40px; outline:none; } .featherlight-inner .well.person-verification, .featherlight-inner .well.person-verification ul { margin:0; } .featherlight-inner .well.person-verification .list-group-item strong { float:right; } ` } function objectContainsAll (obj, contains) { for (let contain of contains) { if (!(contain in obj)) return false; } return true; } /** * Parses the data string * @param {String:encoded in base64} data An encoded string which when decoded has the format: name:value,name2:value2 ....etc */ function parseToDataString (data) { try { let unencode = window.atob(data); // parse string let dataPoints = unencode.split(/\s*,\s*/); //split into data points let parsedData = {}; for (let dataPoint of dataPoints) { // run through each datapoint let dataComponents = dataPoint.split(/\s*:\s*/); // and split into its components let dataName = dataComponents[0]; let dataValue = dataComponents[1]; parsedData[dataName] = dataValue; } return parsedData; } catch (e) { return false; } } function average (numbers) { if (numbers == null || numbers.length == 0) return 0; let sum = 0; let len = numbers.length; for (let i = 0; i < len; i++) { sum += numbers[i]; } return sum/len; } /** * Allows us to create a timeline of requests which contains many frames. For the case of webcheckout, this is nice way * of getting an action done since they require frames of requests * @param {Array} frames The frames that will be executed through a post request * @return {Promise} */ function makeFrameRequest(frames) { let cancelled = false; let totalFrames = frames.length; let framesCompleted = 1; let progress = null; let globalTimes = []; // keep track of all of the times let avgTime = average(globalTimes); // keep track of the average execution time let startTime = performance.now(); let promise = new Promise(function(resolve, reject) { let frame = frames[0]; // get the first frame if (frames.length == 0) { // resolve when all frames have been used resolve(); } else { return $.post(frame.url, frame.hasOwnProperty('data') ? frame.data : null).done(() => { // run the request frames.shift(); // shift the frames // if the user has cancelled and we aren't on the last frame if (cancelled && frames.length != 0) reject('cancelled'); else { // else continue making frame requests if (progress != null && typeof progress == "function") { let progressData = { // set progress data completed: framesCompleted + 1, total: totalFrames, percent: (framesCompleted + 1) / totalFrames, // calculate the time remaining by multiplying the frames left by the average execution time remaining: (totalFrames - (framesCompleted + 1)) * avgTime / 1000 }; progress.call(this, progressData, frames[0] != undefined ? frames[0] : null); } //push the execution time for the purpose of generating an average globalTimes.push(performance.now() - startTime); return makeFrameRequest(frames).then(resolve, reject).progress(progress, totalFrames, ++framesCompleted, globalTimes) // we run the requests } }).error(function () { // if something goes wrong then we will default back to the checkout page $.post('?method=checkout-jump'); reject('error'); }); } }); Promise.prototype.progress = function (progressFunction, total, completed, times) { // keep track of progress totalFrames = total || frames.length; framesCompleted = completed || 0; progress = progressFunction || $.noop; globalTimes = times || []; avgTime = average(times); } Promise.prototype.cancel = function () { cancelled = true; $.post('?method=checkout-jump'); } return promise; } /** * Adds all of the extra external css to the webpage */ function addExternalStyling () { let css = ''; for (let style in styles) { css += styles[style]; } $('head').append(`<style>${css}</style>`); } // holds different types of requests that we will be pulling let Requests = { /** * Adds a person the WebCheckout database * @param {Array} data A set of data of the person */ addPerson: function (data) { // delete: // 1111111111, // delete resource: 135797,123,124,125,126,127,128 return makeFrameRequest([ { url: '?method=new-person-wizard' }, { url: '?method=new-userid-forward', data: { "new-userid-form.userid": data.ugaid, "new-userid-form.first-name": data.firstname, "new-userid-form.other-name": '', "new-userid-form.last-name": data.lastname, "new-userid-form.patron-class": data.class, "new-userid-form.department": data.department } }, { url: '?method=new-person-contact-forward', data: { "new-person-contact-form.street": '', "new-person-contact-form.street2": '', "new-person-contact-form.city": '', "new-person-contact-form.state": '', "new-person-contact-form.postal-code": '', "new-person-contact-form.country": '', "new-person-contact-form.telephone": data.phone, "new-person-contact-form.email": data.email } }, { url: '?method=new-person-create-finish', finishing: true } ]); }, /** * Find the autocomplete resources * @param {String} string String to search for an autocompletion * @return {Promise} */ autocomplete: function (string) { return new Promise (function (resolve, reject) { $.ajax({ url: '/webcheckout/rest/resourceType/autocomplete', type: "POST", dataType: "json", data: `{"string": "${string}", "properties": ["name", "description"]}`, contentType: "application/json", headers: { Accept: "application/json, text/plain, */*" }, xhrFields: { withCredentials: true }, success: function (d) { if (d == null || d.payload == null) resolve([]); else { let resources = []; let results = d.payload; for (let result of results) { if (result.label == "OIT") { for (let value of result.values) { resources.push({ oid: value.oid, name: value.name }); } } } resolve(resources); } } }); }); }, /** * Adds a set of resources to WebCheckout * @param {Array} resources An array of resources with formate [{ id: 12, type: "oid|type"}, ...] */ addResources: function (resources) { // remove 123456, let masterFrame = []; let ajaxSet = function (id, type) { return [ { url: '?method=new-resource-wizard' }, { url: '?method=choose-resource-id-forward', data: { "choose-resource-id-form.resource-id": id, "choose-resource-id-form.circulating": true } }, { url: '?method=choose-resource-type-forward', data: { "choose-resource-type-form.search-field": type } }, { url: '?method=new-resource-wizard-finish', finishing: true } ] } for (let resource of resources) { masterFrame = masterFrame.concat(ajaxSet(resource.id, resource.type)); } return makeFrameRequest(masterFrame); } } function modifiedNewPerson () { let createPersonWell = function (persondata) { // skip a spot here since the values start at 1 let classes = [null, 'Other', 'Continuing education', 'Undergraduate freshman', 'Undergraduate sophomore', 'Undergraduate junior', 'Undergraduate senior', 'Graduate 1', 'Graduate 2', 'Employee', 'Faculty']; let formatedNumber = persondata.phone.replace(/([0-9]{3})([0-9]{3})([0-9]{4})/, function (full, $1, $2, $3) { return "(" + $1 + ") " + $2 + "-" + $3; }); return `<div id='person-ticket' class="well person-verification"> <ul class="list-group list-group-flush"> <li class="list-group-item">UGA ID: <strong>${persondata.ugaid}</strong></li> <li class="list-group-item">Name: <strong>${persondata.firstname} ${persondata.lastname}</strong></li> <li class="list-group-item">Class: <strong>${classes[persondata.class]}</strong></li> <li class="list-group-item">Department: <strong>${persondata.department}</strong></li> <li class="list-group-item">Email: <strong>${persondata.email}</strong></li> <li class="list-group-item">Phone: <strong>${formatedNumber}</strong></li> </ul> <div class="progress" style="margin-bottom: 0;margin-top: 10px;display:none"> <div class="progress-bar" role="progressbar" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" style="width:10%"></div> </div> </div>` } $.featherlight(null, { html: ` <div> <h1>Add Person</h1> <div class="content"> <textarea id='persondata' placeholder="Enter unique user code.."></textarea> </div> <div class="footer-area row"> <input id='addperson' type="button" class="col-sm-6 btn btn-primary" value="Add Person" disabled> <input id='cancel' type="button" class="col-sm-3 btn btn-danger" value="Cancel" disabled> <input id='originalform' type="button" class="col-sm-3 btn btn-info" value="Original Form"> </div> </div>`, afterOpen: function () { let person = null; $(document).on('change paste keyup', '#persondata', function (e) { setTimeout(() => { // add a timeout here so that we can get the proper value of the paste event person = parseToDataString($(this).val()); $('.error-message').remove(); // if the person contains all of the correct data if (person && objectContainsAll(person, ['ugaid', 'firstname', 'lastname', 'class', 'department', 'email', 'phone'])) { $(this).parent().html(createPersonWell(person)); $('#addperson').attr('disabled', false); $('#cancel').attr('disabled', false).off('click').on('click', function () { $(this).attr('disabled', true).parent().prev().html('<textarea id="persondata" placeholder="Enter unique user code.."></textarea>'); }); } else { // if not we will give an error person = null; $(this).addClass('error').before('<div class="error-message" style="margin-bottom: 4px;text-align: center;color: #e00000;">Incorrect Code</div>') } }, 5); }); $('#originalform').on('click', function () { document.location = '?method=new-person-wizard'; }); $('#addperson').on('click', function () { // when we add the person if (person != null) { // if we have a person then.. $('#cancel').attr('disabled', false); // open up the cancel button $('#person-ticket .progress').show(); $(this).val("Adding...").add('#originalform').attr('disabled', true); let req = Requests.addPerson(person).then(() => { // create the request $(this).val("Added").removeClass('btn-primary').addClass('btn-success').parent().prev().prepend('<div class="alert alert-success"><strong>Success!</strong> User has been added!</div>'); $('#person-ticket .progress').hide(); setTimeout(() => { $.featherlight.close(); }, 2000); }); req.progress(function (prog, frame) { let cantCancel = (frame != null && frame.hasOwnProperty('finishing') && frame.finishing == true) || prog.total - prog.completed == 1; $('#cancel').attr('disabled', cantCancel); $('#person-ticket .progress-bar').attr('aria-valuenow', prog.percent*100).width(prog.percent*100 + '%'); }); $("#cancel").off('click').on('click', () => { req.cancel(); $(this).val("Add Person").add('#originalform').attr('disabled', false); $('#cancel').attr('disabled', true); $('#person-ticket .progress').hide(); }); } }); } }); } function modifiedResourceAdder () { let inputRow = `<div class='row'> <div class='col-sm-5' style='padding: 0;'> <input type="text" class='numbers form-control' placeholder="11111, 22222, 33333,..." /> </div> <div class='col-sm-5' style='padding: 0 0 0 5px;'> <input type="text" class='type form-control' placeholder='Resource Type' /> <ul class='autocomplete'></ul> </div> <div class='col-sm-2' style='padding: 0 0 0 5px;'> <div class='remove-row'>Remove</div> </div> </div>`; $.featherlight(null, { html: ` <div> <h1>Add Resources</h1> <div class="content"> <div class='well' style='margin-bottom:0'> ${inputRow} </div> </div> <div class="footer-area row"> <input id='finishadding' type="button" class="col-sm-3 btn btn-success" value="Finish" disabled> <input id='addresource' type="button" class="col-sm-4 btn btn-primary" value="New Resource"> <input id='cancel' type="button" class="col-sm-2 btn btn-danger" value="Cancel" disabled> <input id='originalform' type="button" class="col-sm-3 btn btn-info" value="Original Form"> </div> </div>`, afterOpen: function () { function cons (mess, type) { let classes = type || 'default' document.getElementById('progress-prompt').innerHTML += `<div class='${classes}'>${mess}</div>`; document.getElementById('progress-prompt').scrollTop = document.getElementById('progress-prompt').scrollHeight; } function checkFinishDisability () { let numberOfInputs = $('.featherlight-inner .content .well .row .form-control').length; let numberOfCompletedInputs = $('.featherlight-inner .content .well .row .form-control').filter(function () { return ($(this).hasClass('type') && $(this).hasClass('autocompleted')) || ($(this).hasClass('numbers') && $(this).val().length > 0) }).length; $("#finishadding").attr("disabled", !(numberOfInputs == numberOfCompletedInputs)); } $('#originalform').on('click', function () { document.location = '?method=new-resource-wizard' }); $('.featherlight-inner').on('click', '.remove-row', function () { // remove a resource row $(this).closest('.row').slideUp(600, function () { $(this).remove(); checkFinishDisability (); }); }).on('click', function (e) { // clear the autocomplete when you click somewhere on the inner $('.featherlight-inner .autocomplete').empty(); }).on('click', '.autocomplete li', function () { // assign the autocompleted item to an input let oid = $(this).data('oid'); let value = $(this).text(); $(this).parent().prev().data('oid', oid).val(value).addClass('autocompleted'); $(this).parent().empty(); checkFinishDisability (); }).on('keyup', '.type.form-control', function () { // look up auto complete values let value = $(this).val(); $(this).removeClass('autocompleted'); Requests.autocomplete(value).then((results) => { if ($(this).is(':focus')) { // only show the results if we are still focuses on the input let list = ''; for (let result of results) { list += `<li data-oid="${result.oid}">${result.name}</li>`; } $(this).next().html(list); // add the list of items } }); }).on('blur', '.type.form-control', function (){ // if we click off the input and have no auto completed if (!$(this).hasClass('autocompleted')) { let value = $(this).val(); Requests.autocomplete(value).then((results) => { // check the current value of the input and see if we can derivate an auto completed value anyways if (results.length == 1) { // if the input only gives one autocorrected result then we can use that result to finish the completion let result = results[0]; $(this).data('oid', result.oid).val(result.name).addClass('autocompleted'); } else { // however, even if we get multiple results, if the input value matches one of the autocompleted ones exactly, // we can choose that one as the autocorrect for (let result of results) { if (result.name == value) { $(this).data('oid', result.oid).addClass('autocompleted'); break; } } } checkFinishDisability (); }); } }).on('keyup change', '.form-control', checkFinishDisability); $("#addresource").on('click', function () { $('.featherlight-inner .content .well').append(inputRow); checkFinishDisability (); }); $("#finishadding").on('click', function () { // Add Resources // collect together all of the resources from the input let allResources = []; $('#finishadding, #addresource').attr('disabled', true); $('.featherlight-inner .content .row').each(function () { let type = $(this).find('.type').data('oid') + '|' + $(this).find('.type').val(); let resources = $(this).find('.numbers').val().split(/\s*,\s*/); console.log(resources); for (let resource of resources) { allResources.push({"id": resource, type }); } $(this).remove(); }); $('.featherlight-inner .content .well').html(`<div id='progress-prompt'><div>Opening resource creator</div></div><div style=" margin-top: 2px;margin-bottom: -6px;display:none;">Time Remaining: <strong>0 seconds</strong></div><div class="progress" style="margin-bottom: 0;margin-top: 10px;"> <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%"></div> </div>`); // add the resources let req = Requests.addResources(allResources).then(function () { $('#cancel, #finishadding, #addresource').attr('disabled', true); cons('All Resources have been added.', 'success'); }); req.progress(function (prog, frame) { // progress as the resources are added let cantCancel = (frame != null && frame.hasOwnProperty('finishing') && frame.finishing == true) || prog.total - prog.completed == 1; let progressBar = $('.featherlight-inner .content .progress-bar'); $('#cancel').attr('disabled', cantCancel); switch (prog.completed % 4) { case 0: cons('Resetting resource creator..'); break; case 1: let id = frame.data["choose-resource-id-form.resource-id"]; cons(`Creating resource ${id} ..`); break; case 2: let type = frame.data["choose-resource-type-form.search-field"]; cons(`Connecting type ${type} ..`); break case 3: cons('Finishing Resource Creation..'); break; } if (prog.remaining == 0) { progressBar.parent().prev().hide() } else { progressBar.parent().prev().show().find('strong').text(Math.round(prog.remaining) + ' seconds'); } progressBar.attr('aria-valuenow', prog.percent*100).width(prog.percent*100 + '%'); }); $("#cancel").off('click').on('click', () => { req.cancel(); $('#cancel, #finishadding, #addresource').attr('disabled', true); $('.featherlight-inner .content .progress').hide().parent().prev().hide(); cons('Cancelled. Current Resource will be revoked and any pending resources will be ignored.', 'error'); }); }); } }); } (function main () { window.onload = function () { console.log(document.location); } addExternalStyling (); $('#new-person-wizard').removeAttr('href').on('click', function () { modifiedNewPerson(); }); $('#new-resource-wizard').removeAttr('href').on('click', function () { modifiedResourceAdder () }); // Fixes barcode issues /*$("#input-barcode").off("keypress keyup keydown").codeScanner({ onScan: function ($element, code) { $("#input-barcode").val(code.replace(/OIT(-|)/, '')).parent().next().find('a').click(); } });*/ $("#input-barcode").on("keydown", function () { $(this).val($(this).val().replace(/OIT-/, '')) }); })(); })(jQuery);