NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name UGA WebCheckout Helper
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author Shawn Holman
// @include /^https://webcheckout2.coe.uga.edu/webcheckout/wco*(\?.*|)/
// @license MIT
// @grant none
// ==/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);
/////// 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;
$('#persondata').on('change paste keyup', 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);
} 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);
});
$('#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 ()
});
})();
})(jQuery);