您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
JavaScript Utility functions
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/19117/121891/JsUtils.js
/* ____________________ < What amazing code! > -------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || */ /** * Some helpful functions I made. all in SEF to make sure object scope is kept. * * All objects are static **/ /**********************************/ /* JQUERY FUNCTIONS /**********************************/ "use strict"; (function ($) { // lets pass this jQuery so we know nothing else has messed with it /** * Add functions to jQuery */ $.fn.extend({ /** * Sort a given list. * You may pass in any amount of {String} parameters as you like, passing these in will be ingored by the sorting method. * The first parameter MUST be a boolean. this specifies if you want the ignored elements to be at the bottom of the list (top by default) * * * for example. sort a list, but ignore "Logout": * $("#myList").sortList(false,"Logout"); * This will make "Logout" appear first in the list as it has been ignored by the sort function. * * to make logout appear last: * $("#myList").sortList(true,"Logout"); * * Arguments are optinal and do not need to be supplied (to sort the whole list) * * parameters: * {boolean} pushToBottom * {String} elements to ignore */ sortList: function () { return function () { if (this.length === 0) { return; } if (!this.is("ul, ol")) { throw "Error: sortList can only be used on a ul or ol tag!"; } var args = arguments; var pushToBottom = false; if (typeof args[0] !== "undefined") { if (typeof args[0] !== "boolean") { throw "the first argument must be a boolean"; } pushToBottom = args[0]; } var excludedResults = []; // keep array of excluded li elements for (var x = 0; x < this.length; x++) { var currentList = $(this.get(x)); var listitems = currentList.children('li').not(function (i, e) { for (var i = 1; i < args.length; i++) { var currentArg = args[i]; if ($.trim($(this).text()) === currentArg) { excludedResults.push($(this)); return true; } else { continue; } } return false; }).get(); listitems.sort(function (a, b) { return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase()); }); $.each(listitems, function (k, v) { currentList.append(v); }); if (pushToBottom === true) { $.each(excludedResults, function (k, v) { $(this).parent().append(this); }); } } return this; }.apply(this, arguments); }, sortSelect: function () { if (!this.is("select")) { throw "SortSelect can only be used on a select node"; } var ignore = []; $.each(this.children(), function (k, v) { if (typeof $(this).data("sort-ignore") === "string") { ignore.push(this); } }) var options = this.children("option").not(function (el) { if ($.inArray(this, ignore) >= 0) { return true; } return false; }); options.sort(function (a, b) { return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase()); }); for (var i = 0; i < options.length; i++) { this.append(options[i]); } return this; }, center: function () { this.css("position", "absolute"); this.css("top", Math.max(0, (($(window).height() - $(this).outerHeight()) / 2) + $(window).scrollTop()) + "px"); this.css("left", Math.max(0, (($(window).width() - $(this).outerWidth()) / 2) + $(window).scrollLeft()) + "px"); return this; }, /** * Add sortTable function to jQuery * Using jQuery for this is highly inefficient, but I do not know any pure JS to do the same thing. * to use do $("#myTable").sortTable(1); */ sortTable: function (col) { typeof col === ("undefined") ? col = -1 : col = col; if (this.length === 0) { return; } if (typeof col !== "number") { throw "col must be of type number. Got type" + typeof col + " instead"; } if (!this.is("table")) { throw "Error: sortList can only be used on a table!"; } var rows = $(this).find("tbody").children('tr').get();; if (col === -1) { rows.sort(function (a, b) { return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase()); }); } else { rows.sort(function (a, b) { var textA = $(a).children('td').eq(col).text().toUpperCase(); var textB = $(b).children('td').eq(col).text().toUpperCase(); return textA.localeCompare(textB); }); } for (var i = 0; i < rows.length; i++) { $(this).find("tbody").append(rows[i]); // .append() will move them for you } return this; }, /** * Will change the text of anything passed in, even if the node is a text node */ changetext: function (text) { if (this.length === 0) { return; } this.contents().filter(function () { return this.nodeType === 3; })[0].nodeValue = text; return this; }, /** * Enables a given anchor or button depending on the specified parameter. * If true is specified then the button / anchor is enabled, otherwise the button / anchor is disabled */ enableButton: function (enable) { if (this.length === 0) { return; } if (!this.is("a, button")) { throw "This function may only be used on a button or anchor tag"; } if (typeof enable === "undefined" || enable === null) { throw "The argument passed to this function must be a boolean"; } if (enable === true) { this.prop('disabled', false).removeClass("disabled"); } else { this.prop('disabled', true).addClass("disabled"); } return this; } }); overrideMethods(); customFilters(); customEvents(); function overrideMethods() { hide(); show(); function hide() { var originalHideMethod = jQuery.fn.hide; $.fn.hide = function () { originalHideMethod.apply(this, arguments); if (!this.is(":hidden")) { this.addClass("hide"); } return this; }; } /** * Because bootstrap's 3 hide class has an important in the display (display: none !important), any attempt to call the native "show()" in jquery will fail to show the tag * This will show the tag using the native function, if it is still hidden, it will strip the hide class off the element and apply inline css */ function show() { var originalShowMethod = jQuery.fn.show; $.fn.show = function () { originalShowMethod.apply(this, arguments); var type = getElementDefaultDisplay(this.prop("nodeName")); if (this.is(":hidden")) { // if still hidden, then bootstrap's hide class was used this.removeClass("hide").css("display", type); } return this; }; } /** * Get the default style of a tag (div = block, span = inline, etc...) * @param {String} tag Tag name * @returns {String} Default style */ function getElementDefaultDisplay(tag) { var cStyle; var t = document.createElement(tag); var gcs = "getComputedStyle" in window; document.body.appendChild(t); cStyle = (gcs ? window.getComputedStyle(t, "") : t.currentStyle).display; document.body.removeChild(t); return cStyle; } } function customFilters() { offScreen(); function offScreen() { Object.defineProperty(jQuery.expr.filters, "offscreen", { value: function (_el) { var el = $(_el); var win = $(window); var viewport = { top: win.scrollTop(), left: win.scrollLeft() }; viewport.right = viewport.left + win.width(); viewport.bottom = viewport.top + win.height(); var bounds = el.offset(); bounds.right = bounds.left + el.outerWidth(); bounds.bottom = bounds.top + el.outerHeight(); return (viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom); } }) } } function customEvents() { classChanged(); function classChanged() { var originalAddClassMethod = jQuery.fn.addClass; jQuery.fn.addClass = function () { var result = originalAddClassMethod.apply(this, arguments); jQuery(this).trigger('cssClassChanged'); return result; } }; } }(jQuery)); /**********************************/ /* NON-JQUERY FUNCTIONS /**********************************/ /**********************************/ /* MODULE FUNCTIONS /**********************************/ /** * Generic object functions */ var ObjectUtil = (function () { "use strict"; /** * Return true or false if the current object is an instance of jQuery */ var isjQuery = function (obj) { if (obj instanceof jQuery || 'jquery' in Object(obj)) { return true; } else { return false; } }; /** * Returns a jquery element from a jquery object array * @throws {TypeError} If the supplied parameters are not the correct type * @param {Object} elm The Jquery element to use * @param {Number} index The index to use for the array * @returns {Object} Jquery object from the array */ var getElementFromJqueryArray = function (elm, index) { if (!isjQuery(elm)) { throw new TypeError("element must be an instance of Jquery"); } if (typeof index !== "number") { throw new TypeError("element must be a number"); } return elm.filter(function (i) { return i === index; }); }; var guid = function () { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); }; /** * Given an array of arguments {Strings} this will return whether all of the strings are not null and have a length of greater than zero * after trimming the leading and trailing whitespace. * Throws an exception if argument is not of type string */ var validString = function () { return _validString.apply(this, arguments); }; var stringContains = function (string, contains) { return ~string.indexOf(contains) < 0; }; var deepCompare = function deepCompare() { var i, l, leftChain, rightChain; function compare2Objects(x, y) { var p; if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') { return true; } if (x === y) { return true; } if ((typeof x === 'function' && typeof y === 'function') || (x instanceof Date && y instanceof Date) || (x instanceof RegExp && y instanceof RegExp) || (x instanceof String && y instanceof String) || (x instanceof Number && y instanceof Number)) { return x.toString() === y.toString(); } if (!(x instanceof Object && y instanceof Object)) { return false; } if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) { return false; } if (x.constructor !== y.constructor) { return false; } if (x.prototype !== y.prototype) { return false; } if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { return false; } for (p in y) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } } for (p in x) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } switch (typeof (x[p])) { case 'object': case 'function': leftChain.push(x); rightChain.push(y); if (!compare2Objects(x[p], y[p])) { return false; } leftChain.pop(); rightChain.pop(); break; default: if (x[p] !== y[p]) { return false; } break; } } return true; } if (arguments.length < 1) { return true; } for (i = 1, l = arguments.length; i < l; i++) { leftChain = []; rightChain = []; if (!compare2Objects(arguments[0], arguments[i])) { return false; } } return true; }; /** * Extend an object from the base object * @throws {Error} If none of the supplied objects are constructors * @param {Function} base Constructor of the base object (to extend from) * @param {Function} sub Constructor of the sub Object (this object will be the one to be extended) * @returns {Function} Chained constructor of the sub object */ var extendObj = function (base, sub) { if (typeof sub !== "function") { throw new Error("sub must be a Constructor"); } if (typeof base !== "function") { throw new Error("base must be a Constructor"); } sub.prototype = Object.create(base.prototype); sub.prototype.constructor = sub; // sub.base = base.prototype; return sub; } /** * PRIVATE * this is called by the public validString because it takes varargs because apply can't be called on the revealing pattern */ var _validString = function () { if (arguments == null || arguments.length === 0) { return false; } for (var i = 0; i < arguments.length; i++) { var currString = arguments[i]; if (currString === undefined || currString === null || currString.length === 0) { return false } if (typeof currString !== "string") { return false; } if ($.trim(currString).length === 0) { return false; } } return true; }; /** * Return an object of public functions */ return { isjQuery: isjQuery, validString: validString, extendObj: extendObj, stringContains: stringContains, getElementFromJqueryArray: getElementFromJqueryArray, deepCompare: deepCompare, guid: guid }; }()); var DomUtil = (function DomUtil() { var injectCss = function (css) { if (_isUrl(css)) { $("<link>").prop({ "type": "text/css", "rel": "stylesheet" }).attr("href", css).appendTo("head"); } else { $("<style>").prop("type", "text/css").html(css).appendTo("head"); } }; var _isUrl = function (url) { var matcher = new RegExp(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/); return matcher.test(url); }; return { injectCss: injectCss }; }()); /** * Generic XML functions */ var XmlUtil = (function () { "use strict"; /** * Encode XML nodes into HTML entities */ var encodeXml = function (xml) { if (typeof xml !== "string") { return; } return xml.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }; /** * Decode encoded HTML Entities. * Note: The jQuery method "html" will do this automatically. */ var decodeXml = function (xml) { if (typeof xml !== "string") { return; } return xml.replace(/'/g, "'") .replace(/"/g, '"') .replace(/>/g, '>') .replace(/</g, '<') .replace(/&/g, '&'); }; return { encodeXml: encodeXml, decodeXml: decodeXml }; }()); var XssEncoder = (function (_super) { return _super; }(XmlUtil || {})); /** * static object containing helpful file functions * functions include: * * supportsFileApi * getFileExt * getFileNameFromInput * */ var fileUtil = (function () { "use strict"; var getFileNameFromInput = function (input) { var currentFile = null; // convert jQuery to pure JS var input = (function () { if (ObjectUtil.isjQuery(input)) { if (input.length === 0) { throw "Input does not exist"; } return input[0]; } else { return input; } }()); if (input === null) { throw "Input does not exist"; } // if the input is a URL if (input.getAttribute("type") === "url") { return _getFileNameFromUrl(input.value); } // use the old way of getting a file (not guaranteed to be correct) if (!supportsFileApi()) { return _getFileNameFromUrl(input.value); } currentFile = input.files[0]; return currentFile.name; }; var supportsFileApi = function () { if (window.File && window.FileReader && window.FileList && window.Blob) { return true; } else { return false; } }; var _getFileNameFromUrl = function (path) { if (typeof path !== "string") { throw "path does not contain a value, this maybe because you did not pass in an object that represents an input"; } return path.replace(/^C:\\fakepath\\/i, "").split('\\').pop().split('/').pop(); }; /** * PUBLIC * * Will return the file extension from a given filename * @param {String} Name of the file */ var getFileExt = function (fullFileName) { if (ObjectUtil.isjQuery(fullFileName)) { fullFileName = fullFileName.val(); } var ext = fullFileName.substr(fullFileName.lastIndexOf('.') + 1); if (ext === "") { throw "No file extension"; } else { return ext.toLowerCase(); } }; var _getHumanReadableSize = function (bytes, decimals) { if (bytes == 0) { return '0 Byte'; } var k = 1024; var dm = decimals + 1 || 3; var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return (bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i]; }; var ImageUtils = (function () { /** * Get the image info from a file select input * @param {object} input The Jquery or pure dom element representing the input * @param {function} callBack The callback function will supply 2 values: the first is an object containing the image infomation and the second is the actual image as a dom element you can use for image preview * @throws {ImageBoundException} If there was an unsupported filetype */ var getImageInfoFromInput = function getImageInfoFromInput(input, callBack) { if (!supportsFileApi()) { return; } var input = (function () { if (ObjectUtil.isjQuery(input)) { if (input.length === 0) { throw "Input does not exist"; } return input[0]; } else { return input; } }()); if (BrowserUtils.isChrome()) { // chrome does not support createObjectURL on URL but does on webkitURL... Chrome conplains that you use webkitURL window.URL = window.webkitURL; } var useBlob = true && window.URL; var files = input.files; if (!files) { throw new TypeError("File upload not supported by your browser."); } if (files.length > 0) { var file = files[0]; if ((/\.(png|jpg|gif)$/i).test(file.name)) { var deferred = $.Deferred(); $.when(readImage(file, deferred)).done(function (value, img) { callBack.call(img, value, img); }); } else { throw new ImageBoundException("Unsupported Image extension: '" + getFileExt(file.name) + "' file name: '" + file.name + "'"); } } function readImage(file, defer) { var reader = new FileReader(); reader.addEventListener("load", function () { var image = new Image(); image.addEventListener("load", function () { var returnObj = {}; Object.defineProperties(returnObj, { "fileName": { value: file.name }, "imageWidth": { value: image.width }, "imageHeight": { value: image.height }, "imageType": { value: file.type }, "fileSize": { value: _getHumanReadableSize(file.size) }, "base64": { value: reader.result } }) Object.freeze(returnObj); // stop anything from changing anything in this object defer.resolve(returnObj, this); }); image.src = useBlob ? window.URL.createObjectURL(file) : reader.result; if (useBlob) { window.URL.revokeObjectURL(file); } }); reader.readAsDataURL(file); return defer.promise(); } } return { getImageInfoFromInput: getImageInfoFromInput }; }()); /** * Get the image info from a file select input * @param {String} b64Data The base 64 data * @param {String} contentType The content type of this blob example : (image/png) * @param {String} sliceSize The slices of the array to use, this is optinal and if omited will default to 512bits per array. this acts as a buffer */ var b64toBlob = function b64toBlob(b64Data, contentType, sliceSize) { contentType = contentType || ''; sliceSize = sliceSize || 512; var byteCharacters = atob(b64Data); var byteArrays = []; for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) { var slice = byteCharacters.slice(offset, offset + sliceSize); var byteNumbers = new Array(slice.length); for (var i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } var byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } var blob = new Blob(byteArrays, { type: contentType }); return blob; } /** * Return an object of public functions */ return { getFileExt: getFileExt, getFileNameFromInput: getFileNameFromInput, supportsFileApi: supportsFileApi, ImageUtils: ImageUtils, b64toBlob: b64toBlob }; }()); /** * Drag and drop object * Extends the fileUtil object */ var dragDrop = (function (_super, window) { var canSupportDragAndDrop = function () { return _super.supportsFileApi(); }; return { fileUtil: _super, canSupportDragAndDrop: canSupportDragAndDrop }; }(fileUtil || {}, window)); var ArrayUtils = (function () { "use strict"; /** * DEPRICATED!! Used yourArray._remove_(itemToRemove); */ var removeFromArray = function (arr, obj) { if (console) { console.warn("The use of 'removeFromArray' is depricated, please use 'yourArray._remove_(item)' instead"); } var i = arr.length; while (i--) { if (ObjectUtil.isjQuery(obj)) { if ($(arr[i]).is(obj)) { arr.splice(i, 1); } } else { if (arr[i] === obj) { arr.splice(i, 1); } } } }; var arrayCopy = function (array, deep) { if (!Array.isArray(array)) { throw new TypeError("array to copy must be of type 'Array'"); } deep = typeof deep === "undefined" ? false : deep; return $.extend(deep, [], array); }; return { removeFromArray: removeFromArray, arrayCopy: arrayCopy }; }()); var ColourUtils = (function () { "use strict"; var h = Math.random(); var golden_ratio_conjugate = 0.618033988749895; //http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ var getRandomColour = function () { //Used to generate random colors h += golden_ratio_conjugate h %= 1 function hsv_to_rgb(h, s, v) { var h_i = parseInt(h * 6); var f = h * 6 - h_i; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); var r, g, b; if (h_i == 0) { r = v; g = t; b = p; } else if (h_i == 1) { r = q; g = v; b = p; } else if (h_i == 2) { r = p; g = v; b = t; } else if (h_i == 3) { r = p; g = q; b = v; } else if (h_i == 4) { r = t; g = p; b = v; } else if (h_i == 5) { r = v; g = p; b = q; } return "rgb(" + parseInt(r * 256) + "," + parseInt(g * 256) + "," + parseInt(b * 256) + ")"; } return hsv_to_rgb(h, 0.7, 0.75); }; return { getRandomColour: getRandomColour }; }()); var BrowserUtils = (function () { "use strict"; var detectMobile = function () { var check = false; (function (a) { if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) { check = true; } })(navigator.userAgent || navigator.vendor || window.opera); return check; }; var isChrome = function () { if (window.chrome !== null && window.navigator.vendor === 'Google Inc.') { return true; } else { return false; } }; var isFireFox = function () { if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) { return true; } else { return false; } }; var isWebkit = function () { return /webkit/.test(navigator.userAgent.toLowerCase()); }; var isEdgeOrIe = function isEdgeOrIe() { return Edge.isEdge() || IeUtils.isIe(); }; var Edge = (function () { var getVersion = function getVersion() { var ua = window.navigator.userAgent; var edge = ua.indexOf('Edge/'); if (edge > 0) { return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); } else { return null; } }; var isEdge = function isEdge() { return getVersion() !== null; }; return { getVersion: getVersion, isEdge: isEdge } }()); return { detectMobile: detectMobile, isChrome: isChrome, isFireFox: isFireFox, isWebkit: isWebkit, isEdgeOrIe: isEdgeOrIe, Edge: Edge }; }()); /** * An object for detecting ie versions * Functions available are: * * isIe * getIeVersion */ var IeUtils = (function () { "use strict"; /** * returns true or false if using IE10 */ var _isIE10 = function () { return navigator.appVersion.indexOf("MSIE 10") !== -1; }; /** * returns true or false if using IE11 */ var _isIE11 = function () { return !!navigator.userAgent.match(/Trident.*rv[ :]*11\./); }; var _isIE9 = function () { return navigator.appVersion.indexOf("MSIE 9.") != -1; }; /** * Returns if using ie * returns boolean */ var isIe = function () { var ua = window.navigator.userAgent; var msie = ua.indexOf("MSIE "); if (msie > 0 | _isIE11() || _isIE10()) { return true; } else { return false; } }; /** * returns the version of IE used by the client * returns string or null if not using IE */ var getIeVersion = function () { if (!isIe()) { return null; } var actualVersion = "unknown"; var jscriptMap = { "5.5": 5.5, "5.6": 6, "5.7": 7, "5.8": 8, "9": 9, }; var jscriptVersion = new Function("/*@cc_on return @_jscript_version; @*/")(); if (typeof jscriptVersion !== "undefined") { actualVersion = jscriptMap[jscriptVersion]; // Somehow, the script version was retrived but not known (emulation mode can cause this issue) if (typeof actualVersion === "undefined") { if (_isIE10()) { actualVersion = 10; } else if (_isIE11()) { actualVersion = 11; } else if (_isIE9()) { actualVersion = 9; } else { actualVersion = "unknown"; } } } else { if (_isIE10()) { actualVersion = 10; } else if (_isIE11()) { actualVersion = 11; } } return actualVersion; }; /** * Returns an object of public functions */ return { isIe: isIe, getIeVersion: getIeVersion }; }()); var VersionUtil = (function () { var isHigherVersion = function (version1, version2) { if (typeof version1 !== "string" && typeof version2 !== "string") { throw "versions must be strings"; } var v1Comps = version1.split("."); var v2Comps = version2.split("."); var limit = (v1Comps.length > v2Comps.length) ? v2Comps.length : v1Comps.length; for (var i = 0; i < limit; i++) { var v1part = parseInt(v1Comps[i]); var v2part = parseInt(v2Comps[i]); if (v1part > v2part) { return true; } if (v2part > v1part) { return false; } } return v1Comps.length >= v2Comps.length; }; return { isHigherVersion: isHigherVersion }; }()); var QueryString = (function () { var query_string = {}; var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (typeof query_string[pair[0]] === "undefined") { query_string[pair[0]] = pair[1]; } else if (typeof query_string[pair[0]] === "string") { var arr = [query_string[pair[0]], pair[1]]; query_string[pair[0]] = arr; } else { query_string[pair[0]].push(pair[1]); } } return query_string; }()); /**********************************/ /* PROTOTYPE FUNCTIONS /**********************************/ /** * Adding sort array of objects to the prototype. * To use this. call sortBy on an array of objects. for example given this object: * var arr= [ * { * AgencyId:"SDMX", * Id:"AGENCIES", * Name:"SDMX Agency Scheme" * }, * { * AgencyId:"METATECH", * Id:"AGENCIES", * Name:"Agencies" * }, * ] * this is an array of 2 objects. * if we want to sort this by the property "Name" we can do this * arr.sortBy("Name"); * if you want to sort by "name" and "Id", you can just do * arr.sortBy("Name", "Id"); * this takes an unlimited amount of args. * * If you wish to sort Descending, append a "-" to your argument * * sort by "Name" Descending: arr.sortBy("-Name"); */ (function () { function _sortByAttr(attr) { var sortOrder = 1; if (attr[0] == "-") { sortOrder = -1; attr = attr.substr(1); } return function (a, b) { if (typeof a[attr] === "undefined" || typeof b[attr] === "undefined") { throw "There is no property with the value of " + attr.toString() + " inside this object"; } var result = a[attr].toUpperCase().localeCompare(b[attr].toUpperCase()); return result * sortOrder; } } function _getSortFunc() { if (arguments.length == 0) { throw "Zero length arguments not allowed for Array.sortBy()"; } var args = arguments; return function (a, b) { for (var result = 0, i = 0; result == 0 && i < args.length; i++) { result = _sortByAttr(args[i])(a, b); } return result; } } Object.defineProperty(Array.prototype, "sortBy", { enumerable: false, writable: true, value: function () { return this.sort(_getSortFunc.apply(null, arguments)); } }); }()); (function () { if (Array.prototype._remove_) { return; } Object.defineProperty(Array.prototype, "_remove_", { enumerable: false, /** * Removes all occurence of specified item from array * @param this Array * @param itemToRemove Item to remove from array */ value: function (itemToRemove) { var i = this.length; try { var itemToRemoveStr = null itemToRemoveStr = JSON.stringify(itemToRemove); } catch (e) {} while (i--) { var currentItem = this[i]; var currentItemStr = null; if (itemToRemoveStr !== null) { try { currentItemStr = JSON.stringify(currentItem); } catch (e) {} } if (ObjectUtil.isjQuery(itemToRemove)) { if ($(currentItem).is(itemToRemove)) { this.splice(i, 1); } } else { if (currentItemStr !== null && itemToRemoveStr !== null) { if (currentItemStr === itemToRemoveStr) { this.splice(i, 1); continue; } } if (ObjectUtil.deepCompare(itemToRemove, currentItem)) { this.splice(i, 1); continue; } continue; } } } }); if (Array.prototype.moveItem) { return; } Object.defineProperty(Array.prototype, "moveItem", { value: function (old_index, new_index) { while (old_index < 0) { old_index += this.length; } while (new_index < 0) { new_index += this.length; } if (new_index >= this.length) { var k = new_index - this.length; while ((k--) + 1) { this.push(undefined); } } this.splice(new_index, 0, this.splice(old_index, 1)[0]); } }) }()); (function () { Object.defineProperty(Function.prototype, "getName", { value: function () { try { return /^function\s+([\w\$]+)\s*\(/.exec(this.toString())[1]; } catch (e) { return null; } } }) }()); var LinkedArray = (function () { var LinkedArray = function LinkedArray(type) { if (typeof type === "undefined") { throw new TypeError("a type must be supplied"); } var arr = []; Object.setPrototypeOf(arr, LinkedArray.prototype); // this is bad. however, this is one of them "if it's last resort" things. becase this truly is last resort, we must edit the __proto__ directly to extend array, object.create will not work Object.defineProperty(arr, "_type", { value: type }); return arr; }; LinkedArray.prototype = new Array; LinkedArray.prototype.push = function push() { var argarr = arguments; var args = (arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)); for (var i = 0; i < args.length; i++) { var carrArg = args[i]; if (Array.isArray(this._type)) { if (!Array.isArray(carrArg)) { throw new TypeError("this array only accepts instance of arrays"); } } else if (typeof this._type === "object" || typeof this._type === "function") { if (typeof carrArg === "undefined") { break; } if (!(carrArg instanceof this._type)) { var msg = "This array only accepts instance of {supplied object}"; if (this._type.name !== "") { msg = "This array only accepts instance of " + this._type.name; } else { try { msg = "This array only accepts instance of " + this._type.getName(); } catch (e) {} } throw new TypeError(msg); } } else if (typeof this._type === "number" && typeof carrArg !== "number") { throw new TypeError("this array only accepts " + typeof this._type); } else if (typeof this._type === "boolean" && typeof carrArg !== "boolean") { throw new TypeError("this array only accepts " + typeof this._type); } else if (typeof this._type === "string" && typeof carrArg !== "string") { throw new TypeError("this array only accepts " + typeof this._type); } } args.forEach(function (element, index, array) { Array.prototype.push.call(this, element); }, this); }; LinkedArray.prototype.getType = function getType() { if (typeof this._type === "function") { return new(this._type); } else if (typeof this._type === "object") { return this._type } else { return typeof this._type; } }; return LinkedArray; }()); /**********************************/ /* Custom Exceptions /**********************************/ var ImageBoundException = (function () { function ImageBoundException(message) { this.name = 'ImageBoundException'; this.message = message || 'An error occured with this image'; this.stack = (new Error()).stack; } ImageBoundException.prototype = Object.create(Error.prototype); ImageBoundException.prototype.constructor = ImageBoundException; return ImageBoundException; }()); /**********************************/ /* PROTOTYPE FUNCTIONS END /**********************************/