A collection of useful functions and objects, some of which are specific to the Wall Manager family of scripts.
Versión del día
Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyfork.org/scripts/416/16185/WM%20Common%20Library.js
// ==UserScript==
// @name WM Common Library
// @namespace MerricksdadCommonLibrary
// @description A collection of useful functions and objects, some of which are specific to the Wall Manager family of scripts.
// @license http://creativecommons.org/licenses/by-nc-nd/3.0/us/
// @version 3.1.3
// @copyright Charlie Ewing except where noted
// ==/UserScript==
(function(){
var sandbox=this;
//***************************************************************************************************************************************
//***** Greasemonkey and Browser Type Validation
//***************************************************************************************************************************************
// is Greasemonkey running
sandbox.isGM = (typeof GM_getValue != 'undefined' && typeof GM_getValue('a', 'b') != 'undefined');
sandbox.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
//***************************************************************************************************************************************
//***** Global Enumerated Values
//***************************************************************************************************************************************
//enumerated string equal to script that does nothing
sandbox.jsVoid="javascript:void(0)";
//time enums
sandbox.second=1000;
sandbox.minute=second*60;
sandbox.hour=minute*60;
sandbox.day=hour*24;
//***************************************************************************************************************************************
//***** Data Type Verification
//***************************************************************************************************************************************
//return true if o is undefined
sandbox.isUndefined=function(o){try{return ((typeof o)=="undefined");}catch(e){log("wmLibrary.isUndefined: "+e);}};
//return true if o is a string
sandbox.isString=function(o){try{return ((typeof o)=="string");}catch(e){log("wmLibrary.isString: "+e);}};
//return true if o is not undefined
sandbox.exists=function(o){try{return (!isUndefined(o));}catch(e){log("wmLibrary.exists: "+e);}};
// Returns true if object o is an array
sandbox.isArray=function(o){try{return Object.prototype.toString.call(o)==="[object Array]";}catch(e){log("wmLibrary.isArray: "+e);}};
// Returns true if object o is an array and has a length > 0
sandbox.isArrayAndNotEmpty=function(o){try{return isArray(o) && o.length>0;}catch(e){log("wmLibrary.isArrayAndNotEmpty: "+e);}};
// Returns true if object o is an object but not an array
sandbox.isObject=function(o){try{return (((typeof o)=="object") && !isArray(o));}catch(e){log("wmLibrary.isObject: "+e);}};
//return true if o is undefined
//sandbox.isNaN=function(o){try{return (o.toString()==="NaN");}catch(e){log("wmLibrary.isNaN: "+e);}};
//return integer value of object
sandbox.val=function(o){try{return parseInt(o);}catch(e){log("wmLibrary.val: "+e);}};
sandbox.calcTime=function(timer) {try{
if ((typeof timer)=="integer") return timer;
if (timer.match(/^(\d)/)) return val(timer);
//debug.print(timer);
var t=2; //defaults to 2 minutes on error
//check for U:# time format (u = millisecond count)
if (timer.toLowerCase().startsWith("u:")) {
t=parseInt(timer.toLowerCase().split("u:")[1]||"");
return t;
}
//check for s:# (s = second count)
if (timer.toLowerCase().startsWith("s:")) {
t=parseInt(timer.toLowerCase().split("s:")[1]||"")||0;
return t*1000;
}
//check for t:#D:#H:#M:#S time format
if (timer.toLowerCase().startsWith("t:")){
var fnNumberFromHMSDate = function(i,l) {
var teststring = "(\\d)*?"+l;
var test = new RegExp(teststring,"i");
var testret = test.exec(i);
//debug.print([i,teststring,testret]);
return parseInt((testret||["0"])[0]);
};
t=timer.toLowerCase().split("t:")[1];
//it should now be in "1d:2h:5m:30s" format
var d = fnNumberFromHMSDate(t,"d");
var h = fnNumberFromHMSDate(t,"h");
var m = fnNumberFromHMSDate(t,"m");
var s = fnNumberFromHMSDate(t,"s");
//debug.print([d,h,m,s]);
return ((s*second)+(m*minute)+(h*hour)+(d*day));
}
//do originally programmed time words
switch(timer) {
case "off": return 0; break; //off
case "tenth": t = 0.1; break; // 6 seconds
case "sixth": t = 0.1666667; break; // 10 seconds
case "third": t = 0.3333333; break; // 20 seconds
case "half": t = 0.5; break; // 30 seconds
case "one": t = 1; break; // 1 minute
case "two": t = 2; break; // 2 minutes
case "three": t = 3; break; // 3 minutes
case "four": t = 4; break; // 4 minutes
case "five": t = 5; break; // 5 minutes
case "ten": t = 10; break; // 10 minutes
case "fifteen": t = 15; break; // 15 minutes
case "thirty": t = 30; break; // 30 minutes
case "hour": t = 60; break; // 1 hour
case "2hour": t = 60*2; break; // 2 hours
case "3hour": t = 60*3; break; // 3 hours
case "4hour": t = 60*4; break; // 4 hours
case "8hour": t = 60*8; break; // 8 hours
case "12hour": t = 60*12; break; // 12 hours
case "18hour": t = 60*18; break; // 18 hours
case "24hour": t = 60*24; break; // 1 day
case "36hour": t = 60*36; break; // 1.5 days
case "48hour": t = 60*48; break; // 2 days
case "30s2m": t = (Math.random() * 1.5) + 0.5; break; // random between 30s and 2m
case "2m5m": t = (Math.random() * 3) + 2; break; // random between 2m and 5m
case "5m10m": t = (Math.random() * 5) + 5; break; // random between 5m and 10m
}
return Math.round((t*60000)+(Math.random()*(t*100)));
}catch(e){log("wmLibrary.calcTime: "+e);}};
//comprehensive convert anything to a boolean value
sandbox.cBool = function(x){try{
//log(x||"undefined");
//capture undefined
if (!exists(x)) return false;
//capture nulls
if (x==null) return false;
//capture checkboxes
if (exists(x.checked)) x=x.checked;
//capture objects with value property
if (exists(x.value)) x=x.value;
//capture boolean values
if ((typeof x)=="boolean") return x;
//capture non-null objects
if (isObject(x)) return true;
//capture arrays
if (isArray(x)) return true;
//capture text
if (typeof x=="string") {
var trueVal=x;
if (exists(x.toLowerCase)) trueVal=x.toLowerCase();
switch(trueVal){
case "1": case "true": case "yes": case "checked": return true; break;
case "0": case "false": case "no": case "unchecked": return false; break;
}
}
//default
return Boolean(x);
}catch(e){log("wmLibrary.cBool: {x="+x+"}: "+e);}};
//***************************************************************************************************************************************
//***** Logging
//***************************************************************************************************************************************
// cross-browser log function, turns the log variable into a function
// originally from FVWM by Joe Simmons
// now also catches the WM debug window first
sandbox.log=function(){try{
var fx, debug=this.debug;
if (exists(debug)) fx=debug.print;
else if (isGM) fx=GM_log;
else if (window.opera) fx=opera.postError;
else fx=console.log;
if (fx) {var args=arguments, self=this; setTimeout(function(){fx.apply(self,args);},0); }
}catch(e){console.log("WmLibrary.log: "+e);}};
//***************************************************************************************************************************************
//***** Style Sheet Creation
//***************************************************************************************************************************************
//append css style to the header
//supply a name and this function will force that style sheet to have an id attribute equal to the name supplied
//supply a doc object and the stylesheet will be put in that document instead of this one
sandbox.addGlobalStyle=function(css,name,doc) {try{var head, style;head = (doc||document).getElementsByTagName('head')[0];if (!head) { return; };style = (doc||document).createElement('style');style.type = 'text/css';style.innerHTML = css;head.appendChild(style); if(name||null) style.setAttribute("id",name);}catch(e){log("wmLibrary.addGlobalStyle: "+e);}};
//***************************************************************************************************************************************
//***** Mouse Events
//***************************************************************************************************************************************
//click specified DOM element
sandbox.click=function(e) {try{if(!e && typeof e=='string') e=document.getElementById(e);if(!e) return;var evObj = e.ownerDocument.createEvent('MouseEvents');evObj.initMouseEvent("click",true,true,e.ownerDocument.defaultView,0,0,0,0,0,false,false,false,false,0,null);e.dispatchEvent(evObj);}catch(e){log("wmLibrary.click: "+e);}};
//pretend to put the mouse over specified DOM element
sandbox.mouseover=function(e) {try{if(!e && typeof e=='string') e=document.getElementById(e);if(!e) return;var evObj = e.ownerDocument.createEvent('MouseEvents');evObj.initMouseEvent("mouseover",true,true,e.ownerDocument.defaultView,0,0,0,0,0,false,false,false,false,0,null);e.dispatchEvent(evObj);}catch(e){log("wmLibrary.mouseover: "+e);}};
//***************************************************************************************************************************************
//***** DOM Creation/Manipulation
//***************************************************************************************************************************************
//return a DOM element by ID with optional alternate root document
sandbox.$=function(ID,root) {try{return (root||document).getElementById(ID);}catch(e){log("wmLibrary.$: "+e);}};
//return new DOM element a, with parameters b, and children c
sandbox.createElement=function(a,b,c) {try{
if(a=="text") {return document.createTextNode(b);};
var ret=document.createElement(a.toLowerCase());
if(b) for(var prop in b) {
if(prop.indexOf("on")==0) {
ret.addEventListener(prop.substring(2),b[prop],false);
} else if (
",style,accesskey,id,name,src,href,which,rel,action,method,value,data-ft".indexOf(","+prop.toLowerCase())!=-1
) {
ret.setAttribute(prop.toLowerCase(), b[prop]);
/*} else if (
!exists(ret[prop.toLowerCase()])
} {
ret.setAttribute(prop.toLowerCase(), b[prop]);*/
} else {
ret[prop]=b[prop];
}
}
if(c) c.forEach(
function(e) {
if (e) ret.appendChild(e);
}
);
return ret;
}catch(e){log("wmLibrary.createElement: "+e);}};
//return document.location.pathname
sandbox.getDocName=function() {try{return document.location.pathname;}catch(e){log("wmLibrary.getDocName: "+e);}};
//remove specified DOM element
sandbox.remove=function(e) {try{var node=(typeof e=='string')?$(e):e; if(node && node.parentNode) node.parentNode.removeChild(node); node=null;}catch(e){log("wmLibrary.remove: "+e);}};
//return selected nodes using xpath, with additional parameters
sandbox.selectNodes=function(xPath,params){try{params=(params||{});var doc = (params.doc||document), node = (params.node||doc); return doc.evaluate(xPath,node,null,(params['type']||6),null);}catch(e){log("wmLibrary.selectNodes: "+e);}};
//return single selected node using xpath, with additional parameters
sandbox.selectSingleNode=function(xPath,params){try{params=params||{}; params['type']=9;return selectNodes(xPath,params).singleNodeValue;}catch(e){log("wmLibrary.selectSingleNode: "+e);}};
//for the selected nodes using xpath and additional parameters, perform passed function
sandbox.forNodes=function(xPath,params,fx){try{if(!fx) return;var nodes = selectNodes(xPath,params);if (nodes.snapshotLength) {for (var i=0,node;(node=nodes.snapshotItem(i));i++) {fx(node);}}nodes=null;}catch(e){log("wmLibrary.forNodes: "+e);}};
//fetch the selected elements from an html select multi into an array
//this fetches the ELEMENT not its value
sandbox.getSelectedOptions=function(elem){try{
var ret=[];
for (var i=0; i<elem.options.length; i++) {
if (elem.options[i].selected) ret.push(elem.options[i]);
}
return ret;
}catch(e){log("wmLibrary.getSelectedOptions: "+e);}};
//fetch the selected values from an html select multi into an array
//this fetches the VALUE not the element
sandbox.getSelectedOptionValues=function(elem){try{
var ret=[];
for (var i=0; i<elem.options.length; i++) {
if (elem.options[i].selected) ret.push(elem.options[i].value);
}
return ret;
}catch(e){log("wmLibrary.getSelectedOptionValues: "+e);}};
//attach an array of elements to a node
sandbox.appendChildren = function(node,arr){try{for (var i=0,len=arr.length;i<len;i++){node.appendChild(arr[i]);};}catch(e){log("wmLibrary.appendChildren: "+e);}};
//create a set of options for a selection list based on an array
sandbox.optionsFromArray = function(arr){try{var ret=[];for (var i=0,len=arr.length;i<len;i++) {ret.push(createElement("option",{value:arr[i],textContent:arr[i]}));};return ret;}catch(e){log("wmLibrary.optionsFromArray: "+e);}};
//select an element from a dropdown box with a certain value
sandbox.selectDropDownElement = function(obj,value){try{var node = selectSingleNode(".//option[@value='"+value+"']",{node:obj});if (node) node.selected=true;}catch(e){log("wmLibrary.selectDropDownElement: "+e);}};
//return the value of a dropdown's selected inded
sandbox.valueOfSelect = function(obj){try{return obj.options[obj.selectedIndex].value;}catch(e){log("wmLibrary.valueOfSelect: "+e);}};
//hides all snapshots or iterations in an xpathResult object
sandbox.hideNodes=function(xPath,params) {try{forNodes(xPath,params,function(item){item.style.display="none";});}catch(e){log("wmLibrary.hideNodes: "+e);}};
//unhides all snapshots or iterations in an xpathResult object
sandbox.showNodes=function(xPath,params) {try{forNodes(xPath,params,function(item){item.style.display="";});}catch(e){log("wmLibrary.showNodes: "+e);}};
//move element up
sandbox.elementMoveUp=function(e){try{
//if this element has a parent
if (e.parentNode) {
//and its not the first child
if (e.parentNode.firstChild!=e){
//move it to just before its previous sibling
e.parentNode.insertBefore(e,e.previousSibling);
}
}
return e;
}catch(e){log("wmLibrary.elementMoveUp: "+e);}};
//move element down
sandbox.elementMoveDown=function(e){try{
//if this element has a parent
if (e.parentNode) {
//and its not the last child
if (e.parentNode.lastChild!=e){
//if the next sibling IS the last child
if (e.parentNode.lastChild==e.nextSibling){
//just move it to the bottom
e.parentNode.appendChild(e);
} else {
//insert it between the next sibling and the next next sibling
e.parentNode.insertBefore(e,e.nextSibling.nextSibling);
}
}
}
return e;
}catch(e){log("wmLibrary.elementMoveDown: "+e);}};
//move element up to top of container
sandbox.elementMoveTop=function(e){try{
//if this element has a parent
if (e.parentNode) {
//and its not the first child
if (e.parentNode.firstChild!=e){
//move it to the top of the container
e.parentNode.insertBefore(e,e.parentNode.firstChild);
}
}
return e;
}catch(e){log("wmLibrary.elementMoveTop: "+e);}};
//move element up to top of container
sandbox.elementMoveBottom=function(e){try{
//if this element has a parent
if (e.parentNode) {
//and its not the first child
if (e.parentNode.lastChild!=e){
//move it to the bottom of the container
e.parentNode.appendChild(e);
}
}
return e;
}catch(e){log("wmLibrary.elementMoveBottom: "+e);}};
//sort an element's children by an attribute
sandbox.elementSortChildren=function(e,by){try{
by=by||"name";
if (e && e.childNodes) {
//pack into an array
var ret=[];
for (var n=0;n<e.childNodes.length;n++) {
ret.push(e.childNodes[n]);
}
//sort the array
ret.sort(function(a,b){return a[by]>b[by]});
//fix order of display
for (var n=0;n<ret.length;n++) {
e.appendChild(ret[n]);
}
//clean up
ret=null;
}
}catch(e){log("wmLibrary.elementSortChildren: "+e);}};
//remove all of a node's child nodes
sandbox.removeAllChildren=function(e){
var node=e.childNodes[0];
while (node) {
remove(node);
node=e.childNodes[0];
}
};
//return the real url of a location
sandbox.realURL=function() {try{var u=window.location.href, host=window.location.host, protocol=window.location.protocol+"//", hash=window.location.hash;if(hash!="" && (/#\/.*\.php/).test(hash)) u=protocol+host+hash.split("#")[1];else if(hash!="" && hash.find("#")) u=u.split("#")[0];if (u.substr(-1) === "#") u=u.split("#")[0];return u;}catch(e){log("wmLibrary.realURL: "+e);}};
// compile and return the true x,y scroll offset onscreen of an element in Firefox
sandbox.trueScrollOffset = function(o){try{
var offset={left:o.scrollLeft,top:o.scrollTop}, parentOffset=null;
if (!(o==document.body) && !(0==document.documentElement) && o.parentNode) parentOffset=trueScrollOffset(o.parentNode);
if (parentOffset) {
offset.left+=parentOffset.left||0;
offset.top+=parentOffset.top||0;
}
return offset;
}catch(e){log("wmLibrary.trueScrollOffset: "+e);}},
// compile and return the true x,y offset onscreen of an element in Firefox
sandbox.trueOffset = function(o){try{
var offset={left:o.offsetLeft,top:o.offsetTop}, parentOffset=null;
if (o.offsetParent) parentOffset=trueOffset(o.offsetParent);
if (parentOffset) {
offset.left+=parentOffset.left||0;
offset.top+=parentOffset.top||0;
}
return offset;
}catch(e){log("wmLibrary.trueOffset: "+e);}},
//force a page to transition to new location s even if changing the document location does not work
sandbox.linkTo = function(s) {try{
var link=document.body.appendChild(createElement("a",{href:s,target:"_top"}));
click(link);
}catch(e){log("wmLibrary.linkTo: "+e);}};
//***************************************************************************************************************************************
//***** Date/Time
//***************************************************************************************************************************************
//return a unix timestamp
sandbox.timeStamp=function(){try{return (new Date()).getTime();}catch(e){log("wmLibrary.timeStamp: "+e);}};
//return a facebook timestamp without millisecond data
sandbox.timeStampNoMS=function(){try{var t=timeStamp().toString(); return t.substr(0,t.length-3);}catch(e){log("wmLibrary.timeStampNoMS: "+e);}};
//returns a guaranteed unique timestamp in base36 prefixed with an underscore
sandbox.unique=function(){try{var now=timeStamp();var newnow=now;while (newnow==now){newnow=timeStamp();} return "_"+(newnow.toString(36));}catch(e){log("wmLibrary.unique: "+e);}};
//***************************************************************************************************************************************
//***** String Prototype Additions
//***************************************************************************************************************************************
//return true if string starts with s
sandbox.String.prototype.startsWith = function(s) {try{if (this.length<s.length) return false; else return (this.substring(0,s.length)===s)}catch(e){log("wmLibrary.String.prototype.startsWith: "+e);}};
//return true if string ends with s
sandbox.String.prototype.endsWith = function(s) {try{if (this.length<s.length) return false; else return (this.substring(this.length-s.length,s.length)===s)}catch(e){log("wmLibrary.String.prototype.endsWith: "+e);}};
//return true if string contains s
sandbox.String.prototype.find = function(s) {try{
return (this.indexOf(s) != -1);
}catch(e){log("wmLibrary.String.prototype.find: "+e);}};
sandbox.String.prototype.contains = function(s) {return this.find(s);};
//inserts string s into this string at position startIndex
sandbox.String.prototype.insert = function(s,startIndex) {try{
return this.substr(0,startIndex)+s+this.substr(startIndex,this.length-startIndex);
}catch(e){log("wmLibrary.String.prototype.insert: "+e);}};
//pads the string with space or a specific character, on the left
//strings already longer than totalLength are not changed
sandbox.String.prototype.padLeft = function(totalLength,c) {try{
c=(c||" ").charAt(0);
if (totalLength>0){
return (totalLength<=this.length)?this:
c.repeat((totalLength-this.length))+this;
}
}catch(e){log("wmLibrary.String.prototype.padLeft: "+e);}};
//pads the string with space or a specific character, on the left
//strings already longer than totalLength are not changed
sandbox.String.prototype.padRight = function(totalLength,c) {try{
c=(c||" ").charAt(0);
if (totalLength>0){
return (totalLength<=this.length)?this:
this+c.repeat((totalLength-this.length));
}
}catch(e){log("wmLibrary.String.prototype.padright: "+e);}};
//return the string as an array of characters
sandbox.String.prototype.toCharArray = function() {try{
return this.split(/(.|\n|\r)/g);
}catch(e){log("wmLibrary.String.prototype.toCharArray: "+e);}};
//return the passed string minus spaces
sandbox.String.prototype.noSpaces = function(s) {try{return (this.replace(/\s+/g,''));}catch(e){log("wmLibrary.String.prototype.noSpaces: "+e);}};
//return the passed string with word first letters capitalized
sandbox.String.prototype.upperWords = function(s) {try{return (this+'').replace(/^(.)|\s(.)/g, function($1){return $1.toUpperCase();});}catch(e){log("wmLibrary.String.prototype.upperWords: "+e);}};
//return the passed string repeated n times
sandbox.String.prototype.repeat = function(n) {try{return new Array(n+1).join(this);}catch(e){log("wmLibrary.String.prototype.repeat: "+e);}};
//return the passed string minus line breaks
sandbox.String.prototype.noLineBreaks = function(s) {try{return (this.replace(/(\r\n|\n|\r)/gm," "));}catch(e){log("wmLibrary.String.prototype.noLineBreaks: "+e);}};
//return the passed string without beginning or ending quotes
sandbox.String.prototype.unQuote = function() {try{return this.replace(/^"|"$/g, '');}catch(e){log("wmLibrary.String.prototype.unQuote: "+e);}};
//return the passed string without beginning or ending quotes
sandbox.String.prototype.quote = function() {try{return "\""+this+"\"";}catch(e){log("wmLibrary.String.prototype.quote: "+e);}};
//return the passed string without beginning or ending brackets
sandbox.String.prototype.unBracket = function() {try{return this.replace(/^\[|\]$/g, '');}catch(e){log("wmLibrary.String.prototype.unBracket: "+e);}};
//return the passed string without beginning spaces
sandbox.String.prototype.trimStart = function(){try{
return this.replace(/^\s\s*/, '');
}catch(e){log("wmLibrary.String.prototype.trimStart: "+e);}};
//return the passed string without ending spaces
sandbox.String.prototype.trimEnd = function(){try{
return this.replace(/\s\s*$/, '');
}catch(e){log("wmLibrary.String.prototype.trimEnd: "+e);}};
//return the passed string without beginning or ending spaces
sandbox.String.prototype.trim = function(){try{
return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}catch(e){log("wmLibrary.String.prototype.trim: "+e);}};
//assuming passed string is a url parameter list, return named parameter's value or ""
//this works great for both search and hash parts
//do not pass a document.location without first splitting off search and hash parts
sandbox.String.prototype.getUrlParam = function(s) {try{
var r=this.removePrefix("#").removePrefix("?").split("&");
for (var p=0,param;(param=r[p]);p++){
if ( param.startsWith(s+"=") || param==s ) {
return (param.split("=")[1]||null);
}
}
return null;
}catch(e){log("wmLibrary.String.prototype.getUrlParam: "+e);}};
//return passed string with word added to end. words are separated by spaces
//alternately accepts an array of words to add
sandbox.String.prototype.addWord= function(word){try{
if (!isArray(word)) word=[word];
var words = this.split(" ");
var ret=this;
for (var w=0,len=word.length;w<len;w++){
if (!words.inArray(word[w])) ret=ret+" "+word;
}
return ret;
}catch(e){log("wmLibrary.String.prototype.addWord: "+e);}};
//return passed string minus specified word
//alternately accepts an array of words to remove
sandbox.String.prototype.removeWord= function(word){try{
if (!isArray(word)) word=[word];
var words=this.split(" ");
var ret;
for (var w=0,len=word.length;w<len;w++){
ret = words.removeByValue(word[w]);
}
return ret.join(" ");
}catch(e){log("wmLibrary.String.prototype.removeWord: "+e);}};
//return true if passed string contains word
sandbox.String.prototype.containsWord= function(word){try{return this.split(" ").inArray(word);}catch(e){log("wmLibrary.String.prototype.containsWord: "+e);}};
//return passed string with word replaced with word2
sandbox.String.prototype.replaceWord= function(word,word2){try{return this.split(" ").replace(word,word2).join(" ");}catch(e){log("wmLibrary.String.prototype.replaceWord: "+e);}};
//return passed string with word toggled
sandbox.String.prototype.toggleWord= function(word){try{if (this.containsWord(word)) return this.removeWord(word); return this.addWord(word);}catch(e){log("wmLibrary.String.prototype.toggleWord: "+e);}};
//return passed string with word toggled based on a boolean input
sandbox.String.prototype.toggleWordB = function(bool,word){try{
return this[(bool?"add":"remove")+"Word"](word);
}catch(e){log("wmLibrary.String.prototype.toggleWordB: "+e);}};
//return passed string with word swapped for another based on a boolean input
//if bool==true then we return string including word1 and excluding word2
//else we return string including word2 and excluding word1
sandbox.String.prototype.swapWordB = function(bool,word1,word2){try{
return this.replaceWord((bool?word2:word1),(bool?word1:word2));
}catch(e){log("wmLibrary.String.prototype.swapWordB: "+e);}};
//return passed string minus prefix of s if it exists
sandbox.String.prototype.removePrefix = function(s){try{if (this.startsWith(s)) {return this.substring(s.length);} else return this;}catch(e){log("wmLibrary.String.prototype.removePrefix: "+e);}};
//return passed string minus suffix of s if it exists
sandbox.String.prototype.removeSuffix = function(s){try{if (this.endsWith(s)) {return this.substring(0,this.length-s.length);} else return this;}catch(e){log("wmLibrary.String.prototype.removeSuffix: "+e);}};
// visual basic alternate for string.toLowerCase()
sandbox.String.prototype.lcase = function() {try{return this.toLowercase();}catch(e){log("wmLibrary.String.prototype.lcase: "+e);}};
// visual basic alternate for string.toUpperCase()
sandbox.String.prototype.ucase = function() {try{return this.toUppercase();}catch(e){log("wmLibrary.String.prototype.ucase: "+e);}};
// copy the calling string to the clipboard (IE or GM)
sandbox.String.prototype.toClipboard = function() {try{
if (window.clipboardData){
window.clipboardData.setData("Text", this);
} else if (unsafeWindow) {
try{
unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
} catch(e){
log("wmLibrary.String.prototype.toClipboard: Cannot enable privelege 'UniversalXPConnect'. Be sure that 'signed.applets.codebase_principal_support' is set to true in 'about:config'");
}
const clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
clipboardHelper.copyString(this);
} else {
log("wmLibrary.String.prototype.toClipboard: Cannot perform task");
}
} catch(e){log("wmLibrary.String.prototype.toClipboard: "+e);}};
//replaces all instances of {x} with passed argument x
//or arguments[0][x] when the first argument is an array
sandbox.String.prototype.format = function() {try{
var ret = this;
var args=arguments; //use argument mode
if (isArray(args[0])) args=args[0]; //switch to array mode
for (var i = 0; i < args.length; i++) {
var re = new RegExp('\\{'+i+'\\}', 'gi');
ret = ret.replace(re, args[i]);
}
return ret;
}catch(e){log("wmLibrary.String.prototype.format: "+e);}};
//similar to String.format, except that instances of {%x} are replaced
//instead of instances of {x}
sandbox.String.prototype.format2 = function() {try{
var ret = this;
var args=arguments; //use argument mode
if (isArray(args[0])) args=args[0]; //switch to array mode
for (var i=0; i < args.length; i++) {
var re = new RegExp('\\{%'+i+'\\}', 'gi');
ret = ret.replace(re, args[i]);
}
return ret;
}catch(e){log("wmLibrary.String.prototype.format2: "+e);}};
//returns true if the string is zero-length
sandbox.String.prototype.isEmpty = function() {try{
return this.length==0;
}catch(e){log("wmLibrary.String.prototype.isEmpty: "+e);}};
//format a JSON string with linebreaks and indents
//with optional indent number to set indent length in spaces
//default intent is a tab character
sandbox.String.prototype.formatJSON = function(indent) {try{
indent=(indent)?(" ").repeat(indent):"\t";
//first lets convert the supposed JSON string to an actual object
//so we can validate that it is of good format
var topObj=JSON.parse(this);
//if we got this far, it is valid
//make a function to spell our our branches
var writeBranch=function(obj,name,level){
var ret="";
//start our output string
ret+=(level)?indent.repeat(level):"";
ret+=(name)?JSON.stringify(name)+": ":"";
ret+=(isArray(obj))?
"["+((!obj.isEmpty())?
"\n":
""
):
(isObject(obj))?
"{"+((!methodsToArray(obj).isEmpty())?
"\n":
""
):
"";
//draw the inside object(s)
var c=0;
if (isArray(obj)) for (var i=0,len=obj.length;i<len;i++){
//write arrays out
if (i>0) ret+=",\n";
ret+=writeBranch(obj[i],null,level+1);
} else if (isObject(obj)) for (var i in obj){
if (c>0) ret+=",\n";
//write objects out
ret+=writeBranch(obj[i],i,level+1);
c++;
} else {
//branch is not an object or array
ret+=JSON.stringify(obj);
}
//end our output string
ret+=(isArray(obj))?
((!obj.isEmpty())?
"\n"+((level)?
indent.repeat(level):
""
):
""
)+"]":
(isObject(obj))?
((!methodsToArray(obj).isEmpty())?
"\n"+((level)?
indent.repeat(level):
""
):
""
)+"}":
"";
//back to previous branch
return ret;
}
//start writing the branches
return writeBranch(topObj,null,0);
}catch(e){log("wmLibrary.String.prototype.formatJSON: "+e);}};
//returns the longested quoted text within the calling string
//which also returns true when passed through matchFunc
sandbox.String.prototype.longestQuoteWithin = function(matchFunc) {try{
var p=0, c=0, s="", a=0, b=0, l=0;
//parse entire string input
while (p<this.length){
a=this.indexOf('"', p); //find start of next quotes
if (a!=-1) {
p=a+1; //remember cursor
b=this.indexOf('"',p); //find end of current quotes
if (b!=-1) {
p=b+1; //update cursor
l=b-a; //determine length
//check if longer than current length remembered
if (l>c) {
c=l;
ss=this.substr(a+1,l-1);
//check against matchFunc if one exists
if (matchFunc) {
if (matchFunc(ss)) s=ss;
} else {
//no matchFunc given, assume true
s=ss;
}
}
} else {
p=this.length;
}
} else {
p=this.length;
}
}
return s;
}catch(e){log("wmLibrary.String.prototype.longestQuoteWithin: "+e);}};
//***************************************************************************************************************************************
//***** Array Prototype Additions
//***************************************************************************************************************************************
//returns true if the array is zero-length
sandbox.Array.prototype.isEmpty = function() {try{
return this.length==0;
}catch(e){log("wmLibrary.Array.prototype.isEmpty: "+e);}};
//return passed array with element x and element y swapped
sandbox.Array.prototype.swap = function (x,y) {try{
var b = this[x];
this[x] = this[y];
this[y] = b;
return this;
}catch(e){log("wmLibrary.Array.prototype.swap: "+e);}};
//return true if a value exists in the array
//with optional startIndex
//and optional count which specifies the number of elements to examine
sandbox.Array.prototype.inArray = function(value,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.inArray: Error: startIndex out of bounds");
return false;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.inArray: Error: count is less than 1");
return false;
}
var c=0;
for(var i=this.length-1; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i--) {
c++;
if(this[i]==value) return true;
}
return false;
}catch(e){log("wmLibrary.Array.prototype.inArray: "+e);}};
//alias for inArray
sandbox.Array.prototype.contains = function(value,startIndex,count) {return this.inArray(value,startIndex,count);};
//return the location of a value in an array
//with optional startIndex
//and optional count which specifies the number of elements to examine
sandbox.Array.prototype.inArrayWhere = function(value,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.inArrayWhere: Error: startIndex out of bounds");
return -1;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.inArrayWhere: Error: count is less than 1");
return -1;
}
var c=0;
for(var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++) {
c++;
if(this[i]==value) return i;
}
return -1;
}catch(e){log("wmLibrary.Array.prototype.inArrayWhere: "+e);}};
//alias for inArrayWhere
sandbox.Array.prototype.indexOf = function(value,startIndex,count) {return this.inArrayWhere(value,startIndex,count);};
//return the location of the last occurence of value in an array
//with optional startIndex
//and optional count which specifies the number of elements to examine
sandbox.Array.prototype.lastIndexOf = function(value,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.lastIndexOf: Error: startIndex out of bounds");
return -1;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.lastIndexOf: Error: count is less than 1");
return -1;
}
var c=0;
for(var i=this.length; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i++) {
c++;
if(this[i]==value) return i;
}
return -1;
}catch(e){log("wmLibrary.Array.prototype.lastIndexOf: "+e);}};
//return true if the location of value is 0
sandbox.Array.prototype.startsWith = function(value){return this.inArrayWhere(value)===0;}
//return the last value in an array
sandbox.Array.prototype.last = function() {try{return this[this.length - 1];}catch(e){log("wmLibrary.Array.prototype.last: "+e);}};
//return true if the content of the last index is equal to value
sandbox.Array.prototype.endsWith = function(value){return this.last()===value;}
//return the array will spaces removed from every element
sandbox.Array.prototype.noSpaces = function() {try{for(var i=0,l=this.length; i<l; i++) {this[i]=this[i].noSpaces();}; return this;}catch(e){log("wmLibrary.Array.prototype.noSpaces: "+e);}};
//remove the first instance of a value in an array
//now accepts an array of values to remove
//removes the first instance of every item in array passed
//returns the calling array
sandbox.Array.prototype.removeByValue = function(values) {try{
if (!isArray(values)) values=[values];
for (var i=0,len=values.length; i<len;i++) {
var e=this.inArrayWhere(values[i]);
if(e>=0)this.splice(e,1);
}
return this;
}catch(e){log("wmLibrary.Array.prototype.removeByValue: "+e);}};
//replace all instances of a value in an array
//returns the calling array
sandbox.Array.prototype.replaceAll = function(val, val2) {try{
var i=this.inArrayWhere(val);
while(i>=0) {
this[i]=val2;
i=this.inArrayWhere(val,i+1);
}
return this;
}catch(e){log("wmLibrary.Array.prototype.replaceAll: "+e);}};
//remove all instances of a value in an array
//now accepts an array of values to remove
//returns the calling array
sandbox.Array.prototype.removeAllByValue = function(values) {try{
if (!isArray(values)) values=[values];
for (var i=0,len=values.length; i<len;i++) {
var e=this.inArrayWhere(values[i]);
while (e>=0){
if(e>=0)this.splice(e,1);
e=this.inArrayWhere(values[i],e+1);
}
}
return this;
}catch(e){log("wmLibrary.Array.prototype.removeAllByValue: "+e);}};
//replace the first instance of a value in an array
//returns the calling array
sandbox.Array.prototype.replace = function(val, val2) {try{var i=this.inArrayWhere(val);if(i>=0)this[i]=val2;return this;}catch(e){log("wmLibrary.Array.prototype.replace: "+e);}};
//remove element i of an array
//returns the calling array
sandbox.Array.prototype.remove = function(i) {try{this.splice(i,1); return this;}catch(e){log("wmLibrary.Array.prototype.remove: "+e);}};
//remove elements beyond specified new size
//or add elements to fill the new size equal to defaultValue
sandbox.Array.prototype.resize = function(newSize,defaultValue) {try{
if (this.length>newSize) {
this.splice(newSize,this.length-newSize);
} else {
for (var i=this.length;i<newSize;i++){
this[i]=defaultValue;
}
}
return this;
}catch(e){log("wmLibrary.Array.prototype.resize: "+e);}};
//return a random element of an array
sandbox.Array.prototype.pickRandom = function () {try{var i=Math.floor(Math.random()*this.length); return this[i];}catch(e){log("wmLibrary.Array.prototype.pickRandom: "+e);}};
//sorts an array so that words which contain another word in the array are placed before that other word
//such as "pea" must come AFTER "peanut", and "great american race" must come BEFORE "american"
//the sort is case-insensitive
sandbox.Array.prototype.fixOrder = function(){
var compareFunc = function(a,b){
var s1=a.toLowerCase(), s2=b.toLowerCase();
if (s1.contains(s2)) return -1; //when a contains b, a must come first
else if (s2.contains(s1)) return 1 //when b contains a, b must come first
else return 0; //no order change is required
};
this.sort(compareFunc);
return this;
};
//alias for the previous function
sandbox.Array.prototype.optimize = sandbox.Array.prototype.fixOrder;
//returns a shallow copy of the calling array
sandbox.Array.prototype.clone = function(){try{
return this.slice(0);
}catch(e){log("wmLibrary.Array.prototype.clone: "+e);}};
//reverses the elements of an array
//with optional startIndex
//and optional count which limits the reverse section
//if startIndex+count is greater than the length of the array
//then only the available section is reversed
//returns the calling array
sandbox.Array.prototype.reverse = function(startIndex,count){try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.reverse: Error: startIndex out of bounds");
return -1;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.reverse: Error: count is less than 1");
return -1;
}
var endIndex=(exists(count))?startIndex+count:this.length-1;
if (endIndex>this.length-1) endIndex=this.length-1;
while (startIndex>endIndex){
this.swap(startIndex,endIndex);
startIndex++;
endIndex--;
}
return this;
}catch(e){log("wmLibrary.Array.prototype.reverse: "+e);}};
//sets a range of elements in the array to the defaultValue
//returns the calling array
sandbox.Array.prototype.clear = function(startIndex,count,defaultValue){try{
if (count>0 && this.length>startIndex) {
for (var i=startIndex,len=this.length; (i<len && i<(startIndex+count)); i++){
this[i]=defaultValue;
}
}
return this;
}catch(e){log("wmLibrary.Array.prototype.clear: "+e);}};
//copies elements from this array to a destination destArray
//starting in this array at sourceIndex
//and pasting into the destArray at destIndex
//where length is the number of elements to copy
//pasting beyond the higher bounds of the destArray simply increases the array size
//returns the calling array
sandbox.Array.prototype.copy = function(sourceIndex,destArray,destIndex,length){try{
if (!isArray(destArray)) {
log("wmLibrary.Array.prototype.copy: Error: destArray is not an array");
return this;
}
if (sourceIndex >= this.length) {
//log("wmLibrary.Array.prototype.copy: Error: sourceIndex out of bounds");
return this;
}
for (var i=0; i<length; i++){
destArray[destIndex+i]=this[sourceIndex+i];
}
return this;
}catch(e){log("wmLibrary.Array.prototype.copy: "+e);}};
//copies all elements from this array to a destination destArray
//pasting into the destArray at destIndex
//pasting beyond the higher bounds of the destArray simply increases the array size
//returns the calling array
sandbox.Array.prototype.copyTo = function(destArray,destIndex){try{
if (!isArray(destArray)) {
log("wmLibrary.Array.prototype.copyTo: Error: destArray is not an array");
return this;
}
for (var i=0, len=this.length; i<len; i++){
destArray[destIndex+i]=this[i];
}
return this;
}catch(e){log("wmLibrary.Array.prototype.copyTo: "+e);}};
//returns an array containing elements from the current array where the element has parameter p equal to value v
sandbox.Array.prototype.selectByParam = function(p,v) {try{var ret=[]; for(i=0;i<this.length;i++) if(this[i][p]==v) ret.push(this[i]); return ret;}catch(e){log("wmLibrary.Array.prototype.selectByParam: "+e);}};
//returns the element matched by matchFunc, or null
//with optional start index
//and optional count to limit the number of searched elements
sandbox.Array.prototype.find = function(matchFunc,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.find: Error: startIndex out of bounds");
return null;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.find: Error: count is less than 1");
return null;
}
var c=0;
for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
c++;
if (matchFunc(this[i])) {
return this[i];
break;
}
}
return null;
}catch(e){log("wmLibrary.Array.prototype.find: "+e);}};
//returns the index of element matched by matchFunc, or -1
//with optional startIndex
//and optional count which specifies the number of elements to check
sandbox.Array.prototype.findIndex = function(matchFunc,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.findIndex: Error: startIndex out of bounds");
return -1;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.findIndex: Error: count is less than 1");
return -1;
}
var c=0;
for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
c++;
if (matchFunc(this[i])) {
return i;
break;
}
}
return -1;
}catch(e){log("wmLibrary.Array.prototype.findIndex: "+e);}};
//returns all elements matched by matchFunc, or null
//with optional start index
//and optional count to limit the number of elements searched
sandbox.Array.prototype.findAll = function(matchFunc,startIndex,count) {try{
startIndex=startIndex||0;
var ret=[];
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.findAll: Error: startIndex out of bounds");
return null;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.findAll: Error: count is less than 1");
return null;
}
var c=0;
for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
c++;
if (matchFunc(this[i])) {
ret.push(this[i]);
}
}
return (isArrayAndNotEmpty(ret))?ret:null;
}catch(e){log("wmLibrary.Array.prototype.findAll: "+e);}};
//returns true if all elements in the array match the matchFunc
//with optional start index
//and optional count to limit the number of elements searched
sandbox.Array.prototype.trueForAll = function(matchFunc,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.trueForAll: Error: startIndex out of bounds");
return false;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.trueForAll: Error: count is less than 1");
return false;
}
var c=0;
for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
c++;
if (!matchFunc(this[i])) {
return false;
}
}
return true;
}catch(e){log("wmLibrary.Array.prototype.trueForAll: "+e);}};
//returns true if array contains an element matched by the matchFunc
//with optional startIndex
//and optional count which specifies the number of elements to check
sandbox.Array.prototype.exists = function(matchFunc,startIndex,count) {try{
return this.findIndex(matchFunc,startIndex,count)!=-1;
}catch(e){log("wmLibrary.Array.prototype.exists: "+e);}};
//returns the last element matched by matchFunc, or null
//with optional start index
//and optional count to limit the number of searched elements
sandbox.Array.prototype.findLast = function(matchFunc,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.findLast: Error: startIndex out of bounds");
return null;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.findLast: Error: count is less than 1");
return null;
}
var c=0;
for (var i=this.length; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i--){
c++;
if (matchFunc(this[i])) {
return this[i];
break;
}
}
return null;
}catch(e){log("wmLibrary.Array.prototype.findLast: "+e);}};
//returns the last element matched by matchFunc, or -1
//with optional start index
//and optional count which specifies the number of elements to check
sandbox.Array.prototype.findLastIndex = function(matchFunc,startIndex,count) {try{
startIndex=startIndex||0;
if (startIndex>=this.length) {
//log("wmLibrary.Array.prototype.findLastIndex: Error: startIndex out of bounds");
return -1;
}
if (exists(count) && count<1) {
//log("wmLibrary.Array.prototype.findLastIndex: Error: count is less than 1");
return -1;
}
var c=0;
for (var i=this.length; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i--){
c++;
if (matchFunc(this[i])) {
return i;
break;
}
}
return -1;
}catch(e){log("wmLibrary.Array.prototype.findLastIndex: "+e);}};
//***************************************************************************************************************************************
//***** JSON/OBJECT Construction and Matching
//***************************************************************************************************************************************
//returns the merge of any number of JSON objects passed as unnamed arguments
sandbox.mergeJSON_long = function(){try{
var ret = {};
//for each JSON object passed
for (var a=0,len=arguments.length;a<len;a++) {
//for each element in that object
for (var v in arguments[a]) {
if (!exists(ret[v])) {
//simply copy the element to the return value
ret[v] = arguments[a][v];
} else {
if ((typeof arguments[a][v])=="object") {
//merge the two elements, preserving tree structure
ret[v] = mergeJSON(ret[v], arguments[a][v]);
} else {
//overwrite simple variable
ret[v] = arguments[a][v];
}
}
}
}
//the problem here is that its way too recursive and jams firefox often
return ret;
}catch(e){log("wmLibrary.mergeJSON: "+e);}};
sandbox.mergeJSON = function(){try{
var ret = {};
//for each JSON object passed
for (var a=0,len=arguments.length;a<len;a++) {
var o=arguments[a];
//for each element in that object
for (var v in o) {
//replace the initial element with that of the next
ret[v] = o[v];
}
//the problem here is that only the top level branches are preserved
}
return ret;
}catch(e){log("wmLibrary.mergeJSON: "+e);}};
//returns all members of an array that have a specified parameter with a specified value
//sandbox.matchByParam=function(arr,param,value){try{var ret=[];for (var i=0,e;(e=arr[i]);i++){if (e[param]==value) ret.push(e);};return ret;}catch(e){log("wmLibrary.matchByParam: "+e);}};
//returns all members of an array that have a specified parameter with a specified value
//now accepts input of array or object
//can now specify output of array or object
sandbox.matchByParam=function(o,param,value,outputType){try{
if(!exists(outputType)) outputType="array";
var inputType=(isArray(o))?"array":((typeof o) == "object")?"object":"unknown";
var ret=(outputType=="object")?{}:[]; //default to array on error
switch(inputType){
case "array": for (var i=0,e;(e=o[i]);i++){
switch(outputType){
case "array": if (e[param]==value) ret.push(e); break;
case "object": if (e[param]==value) ret[i]=e; break;
}
};break;
case "object": for (var i in o){
var e=o[i];
switch(outputType){
case "array": if (e[param]==value) ret.push(e); break;
case "object": if (e[param]==value) ret[i]=e; break;
}
};break;
}
return ret;
}catch(e){log("wmLibrary.matchByParam: "+e);}};
//sorts the methods of an object by method 'id' or method 'value'
//beware this may mangle some objects
sandbox.sortCollection=function(o,by){
var a=[];
for (var i in o){
a.push({id:i,value:o[i]});
}
a.sort(function(a,b){return a[by]>b[by];});
var ret={};
for (var i=0;i<a.length;i++){
ret[a[i].id]=a[i].value;
}
return ret;
};
// Collect all the values from parameter p in object o, traversing kids nodes
sandbox.getBranchValues=function(o,p){try{
var ret={};
for(var i in o) {
//get value p for object o's element i
if (p=="id"){ //special case for fetching a list of ID's
if (exists(o[i][p])) ret[i]=o[i][p];
else ret[i]=i;
} else if (p=="."){ //special case for fetching a list of all objects without a tree structure
ret[i]=o[i];
}
else if (exists(o[i][p])) ret[i]=o[i][p];
//if object o has kids, then get all the values p inside that kid k
if (o[i].kids) ret=mergeJSON(ret,getBranchValues(o[i].kids,p));
}
return ret;
}catch(e){log("wmLibrary.getBranchValues: "+e);}};
//convert an object's methods to an array, storing the method's key on the object as an id
sandbox.methodsToArray = function(o) {try{var ret=[]; for (var i in o) {o[i].id=o[i].id||i; ret.push(o[i])}; return ret;}catch(e){log("wmLibrary.methodsToArray: "+e);}};
//convert an array of objects to methods of an object using either the object's ai or name as its key
sandbox.arrayToMethods = function(a) {try{var ret={}; for (var i=0;i<a.length;i++) ret[ a[i].id||a[i].name ]=a[i]; return ret;}catch(e){log("wmLibrary.arrayToMethods: "+e);}};
//convert an object's methods to an array of those method names
sandbox.methodNames = function(o) {try{var ret=[]; for (i in o) ret.push(i); return ret;}catch(e){log("wmLibrary.methodNames: "+e);}};
//copy parts from one object to another
//used for extending one object with parts from another
//by John Resig
sandbox.extend = function(a,b) {try{
for ( var i in b ) {
//collect setter/getter functions
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
//copy setter/getter functions
if ( g || s ) {
if ( g ) a.__defineGetter__(i, g);
if ( s ) a.__defineSetter__(i, s);
} else a[i] = b[i]; //copy vars
}
return a;
}catch(e){log("wmLibrary.extend: "+e);}};
//***************************************************************************************************************************************
//***** WM Specific Functions
//***************************************************************************************************************************************
//returns an object suitable for accText data based on an array, and allowing an idPrefix and textSuffix
sandbox.createAccTextFromArray=function(arr,keyPrefix,textSuffix){
var ret={};
if (arr) {
for (var i=0,len=arr.length;i<len;i++){
o=arr[i];
ret[(keyPrefix||'')+o.noSpaces().toLowerCase()]=o.upperWords()+(textSuffix||'');
}
}
return ret;
};
//writes a message to the hash section of the document location, or redirects to a location that can accept a new hash section
sandbox.sendMessage=function(s,hwnd,flag){try{
hwnd = (hwnd||window.top);
if (exists(hwnd)) try {hwnd.location.hash = s;} catch(e){
if (flag==1) hwnd.location.href = "http://apps.facebook.com/?#"+s;
else hwnd.location.href = "http://www.facebook.com/reqs.php?#"+s;
}
}catch(e){log("wmLibrary.sendMessage: "+e);}};
//flags for menu building function
sandbox.MENU_ID_ENFORCE_NAME=1; //causes menuFromData to return lowercase nospace names as the id instead of the calculated id
//inserts one or more menu option blocks based upon a data object
//marking all new items in the newitem list above as green so users can easily find your changes
sandbox.menuFromData=function(data,menuNode,newItemList,idPrefix,flags){try{
flags=(flags||0); newItemList=(newItemList||[]);
if (data) for (var m=0,len=data.length; m<len; m++) {
var text = data[m]["name"].upperWords(), event = (data[m]["event"]||"Unsorted").upperWords();
var outid = (flags==MENU_ID_ENFORCE_NAME)?data[m].name.noSpaces().toLowerCase():(data[m]["id"]||data[m]["name"]).noSpaces().toLowerCase();
var thisMenu; if( !(thisMenu=(menuNode["optblock"+event]||null) ) ) {thisMenu=(menuNode["optblock"+event]={type:"optionblock",label:event,kids:{} });}
thisMenu.kids[idPrefix+outid]={type:"checkbox",label:text,newitem:newItemList.inArray(idPrefix+outid)};
}
}catch(e){log("wmLibrary.menuFromData: "+e);}};
//returns a list of search strings from a data object containing id's names and events, already optimized for searching
sandbox.searchFromData=function(data,idPrefix){try{
idPrefix=(idPrefix||"");
var ret = [];
for (var m=0,mat;(mat=data[m]);m++){
ret.push(idPrefix+(mat.id||mat.name));
}
ret.optimize();
return ret;
}catch(e){log("wmLibrary.searchFromData: "+e);}};
//returns a list of materials from a data object containing id's names and events, already optimized for searching
sandbox.matListFromData=function(data){try{
var ret = [];
for (var m=0,mat;(mat=data[m]);m++){
ret.push(mat.name);
} ret.optimize();
return ret;
}catch(e){log("wmLibrary.matListFromData: "+e);}};
//returns a valid accText object from a data object containing id's names and events
sandbox.accTextFromData=function(data,idPrefix,textSuffix,flags){try{idPrefix=(idPrefix||""); textSuffix=(textSuffix||"");var ret={}; for (var m=0,mat;(mat=data[m]);m++){ret[idPrefix+((flags==MENU_ID_ENFORCE_NAME)?mat.name:(mat.id||mat.name)).noSpaces().toLowerCase()]=(mat.name+textSuffix).upperWords();} return ret;}catch(e){log("wmLibrary.accTextFromData: "+e);}};
//***************************************************************************************************************************************
//***** Sidekick Object
//***************************************************************************************************************************************
//sidekick specific functions
sandbox.Sidekick={
//init
tabID:null,
status:0,
nopopLink:"",
//attempts to dock the sidekick script to the wm host script
//params takes an object that contains the following parameters:
//appID(string), version(string), skType(integer),
//name(string), thumbSource(string or array),
//flags(object), icon(string), desc(string),
//addFilters(object),
//alterLink(object), accText(object),
//tests(array) and menu(object)
dock: function(params){try{
//find the dock node on this page
var door=$('wmDock');
if (!door) {
//does not exist, wait and try again later
window.setTimeout(function(){Sidekick.dock(params);}, 1000);
return;
}
//detect if a sidekick for this app is already docked
var doorMark=$('wmDoor_app'+params.appID);
if (doorMark && (params.skType==doorMark.getAttribute("value")) ) {
//a sidekick of this level is already here, cancel docking
return;
}
//setup defaults for a few of the expected parameters
params.thumbsSource=(params.thumbsSource||"app_full_proxy.php?app"+params.appID);
params.desc=(params.desc||params.name+" Sidekick (ver "+params.version+")");
//create a block of data to attach to the dock
var attString=JSON.stringify(params);
door.appendChild(
doorMark=createElement('div',{id:'wmDoor_app'+params.appID,'data-ft':attString,value:(params.skType||0)})
);
//doorMark.setAttribute("skType",(params.skType||0));
//confirm(doorMark.getAttribute("skType"));
//ring the buzzer so the host knows the package is ready
window.setTimeout(function(){click(door);},1000);
}catch(e){log("wmLibrary.Sidekick.dock: "+e);}},
//receive and process messages
//msg code 1 is a packet from the wm host containing data about the post we are processing
//that packet must contain at least the tab/window ID with which the WM host can access that tab again
//msg code 3 is a packet from this or a deeper iframe window about the return value for this post
//because Chrome returns NULL at event.source on msg 1, we now have to rethink
receiveMessage: function(event) {try{
if (isObject(event.data)) {
var data=event.data; //just shorten the typing
if (data.channel=="WallManager"){
log(JSON.stringify(data));
switch (data.msg) {
case 1: //get init data from wm host
//if (!Sidekick.tabID)
Sidekick.tabID=data.tabID;
log("Sidekick hears host...");
//
break;
case 3: //get message from child
if (Sidekick.tabID) {
log("Sidekick hears iframe...");
//send our status packet back to wm
Sidekick.status=data.status;
Sidekick.nopopLink=data.nopopLink||null;
//update the stored data about this post
var skChannel = getOptJSON("skChannel")||{};
skChannel[Sidekick.tabID]={
tabID:Sidekick.tabID,
status:Sidekick.status,
nopopLink:Sidekick.nopopLink,
};
log(JSON.stringify(skChannel));
setOptJSON("skChannel",skChannel);
} else {
//have not yet recieved tabID package from wm, wait a sec
setTimeout(function(){Sidekick.receiveMessage(event);},1000);
}
break;
}
}
}
}catch(e){log("wmLibrary.Sidekick.receiveMessage: "+e);}},
//disable the listener started below
unlisten: function(params){try{
window.removeEventListener("message", Sidekick.receiveMessage, false);
}catch(e){log("wmLibrary.Sidekick.unlisten: "+e);}},
//turn on the listener which can receive messages from wm host (if this window = window.top) or from iframes
listen: function(params){try{
window.addEventListener("message", Sidekick.receiveMessage, false);
}catch(e){log("wmLibrary.Sidekick.listen: "+e);}},
//listen for changes to the skChannel variable and report those changes to WM whenever docked
openChannel: function(){try{
var dump=$("wmDataDump");
if (dump) {
var skData=getOpt("skChannel");
setOpt("skChannel","");
if (skData) dump.appendChild(createElement('div',{'data-ft':skData}));
}
setTimeout(Sidekick.openChannel,1000);
}catch(e){log("wmLibrary.Sidekick.openChannel: "+e);}},
//send a status code from the deepest iframe to the topmost frame so that it can be passed back with data the top window already has
sendStatus: function(status,link){try{
if (exists(window.top)) {
window.top.postMessage({
channel:"WallManager",
msg:3,
status:status,
nopopLink:(link?link:''),
},"*");
} else {
//window.top is hidden to us from this location
contentEval('window.top.postMessage({"channel":"WallManager","msg":3,"status":'+status+',"link":"'+(link?link:'')+'"},"*");');
}
}catch(e){log("wmLibrary.Sidekick.sendStatus: "+e);}},
};
//***************************************************************************************************************************************
//***** Visual Effects
//***************************************************************************************************************************************
//slides element e toward the specified destination offset
//specify [t, l, r, b] top, left, right, and bottom as the final offset
//specify s as the number of MS the move should loop on
//specify p as the number of pixels to move per interval
sandbox.slide=function(e,t,l,r,b,s,p) {try{
s=s||50;p=p||10;
var top= e.style.top; top=parseInt(top); top=(isNaN(top))?0:top;
var bottom = e.style.bottom; bottom=parseInt(bottom); bottom=(isNaN(bottom))?0:bottom;
var left= e.style.left; left=parseInt(left); left=(isNaN(left))?0:left;
var right = e.style.right; right=parseInt(right); right=(isNaN(right))?0:right;
p1=(p>Math.abs(t))?Math.abs(t):p;
if(t>0) {e.style.top = (top+p1)+"px";t-=p1;}
else if (t<0) {e.style.top = (top-p1)+"px";t+=p1;}
p1=(p>Math.abs(l))?Math.abs(l):p;
if(l>0) {e.style.left = (left+p1)+"px";l-=p1;}
else if (l<0) {e.style.left = (left-p1)+"px";l+=p1;}
p1=(p>Math.abs(r))?Math.abs(r):p;
if(r>0) {e.style.right = (right+p1)+"px";r-=p1;}
else if (r<0) {e.style.right = (right-p1)+"px";r+=p1;}
p1=(p>Math.abs(b))?Math.abs(b):p;
if(b>0) {e.style.bottom = (bottom+p1)+"px";b-=p1;}
else if (b<0) {e.style.bottom = (bottom-p1)+"px";b+=p1;}
if (t!=0||l!=0||r!=0||b!=0) window.setTimeout(function(){slide(e,t,l,r,b,s,p);},s);
}catch(e){log("wmLibrary.slide: "+e);}};
//***************************************************************************************************************************************
//***** URL Encode/Decode
//***************************************************************************************************************************************
//url encode/decode functions nicely wrapped from webtoolkit
sandbox.Url = {
// public method for url encoding
encode : function (string) {try{return escape(this._utf8_encode(string));}catch(e){log("wmLibrary.Url.encode: "+e);}},
// public method for url decoding
decode : function (string) {try{return this._utf8_decode(unescape(string));}catch(e){log("wmLibrary.Url.decode: "+e);}},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};
//***************************************************************************************************************************************
//***** GM Local Storage Commands
//***************************************************************************************************************************************
// set an option
sandbox.setOpt=function(opt,value){try{GM_setValue(opt,value);}catch(e){log("wmLibrary.setOpt: "+e);}}
// Get a stored option
sandbox.getOpt=function(opt){try{return GM_getValue(opt);}catch(e){log("wmLibrary.getOpt: "+e);}}
// set an option
sandbox.setOptJSON=function(opt,value){try{GM_setValue(opt,JSON.stringify(value));}catch(e){log("wmLibrary.setOptJSON: "+e);}}
// Get a stored option
sandbox.getOptJSON=function(opt){try{var v=GM_getValue(opt, '{}');return JSON.parse(v);}catch(e){log("wmLibrary.getOptJSON: "+e+" opt is:"+opt+", data is:"+v);}}
//***************************************************************************************************************************************
//***** 2D Math
//***************************************************************************************************************************************
// add two points or vectors
sandbox.addPoints = function(p0, p1){try{
var p2=mergeJSON(p0); //copy p0
for (var v in p1) p2[v]=(p2[v]||0)+(p1[v]||0);
return p2;
}catch(e){log("wmLibrary.addPoints: "+e);}},
//***************************************************************************************************************************************
//***** Delays and Repeaters
//***************************************************************************************************************************************
// shortform for window.setTimeout(x,0)
sandbox.doAction = function(f) {try{setTimeout(f,0);}catch(e){log("doAction: "+e);}};
//repeat a function fn a number of times n with a delay of 1 second between calls
sandbox.signal = function(fn,n){try{
if (n>0) {
doAction(fn);
setTimeout(function(){signal(fn,n-1);},1000);
}
}catch(e){log("wmLibrary.signal: "+e);}};
//***************************************************************************************************************************************
//***** Enum Creation
//***************************************************************************************************************************************
// create an unprotected enumeration list
sandbox.Enum = function() {try{for (var i in arguments) {this[arguments[i]] = i;}}catch(e){log("Enum.init: "+e);}};
//create an unprotected enumeration list of binary flags
sandbox.EnumFlags = function() {try{for (var i in arguments) {this[arguments[i]] = Math.pow(2,i);}}catch(e){log("EnumFlags.init: "+e);}};
//***************************************************************************************************************************************
//***** Pop-ups
//***************************************************************************************************************************************
//create a centered iframe to display multiline text in a textarea
//with optional isJSON flag which will format JSON strings with indents and linebreaks
sandbox.promptText = function(s,isJSON){try{
if (isJSON) s=s.formatJSON(4);
var newFrame;
document.body.appendChild((newFrame=createElement('iframe',{style:'position:fixed; top:0; left:0; display:none !important; z-index:999; width:75%; height:75%; max-height:95%; max-width:95%; border:1px solid #000000; overflow:auto; background-color:white;'})));
newFrame.src = 'about:blank'; // In WebKit src cant be set until it is added to the page
newFrame.addEventListener('load', function(){
var frameBody = this.contentDocument.getElementsByTagName('body')[0];
var close=function(){try{
remove(newFrame);
delete newFrame;
}catch(e){log("wmLibrary.promptText.close: "+e);}};
// Add save and close buttons
frameBody.appendChild(
createElement("textArea",{textContent:s,style:"height:90%;width:100%;"})
);
frameBody.appendChild(
createElement("div", {id:"buttons_holder"}, [
createElement('button',{id:"closeBtn", textContent:"Close",title:"Close window",onclick:close}),
])
);
var center=function(){try{
var style=newFrame.style;
var node=newFrame;
style.display = '';
style.top = Math.floor((window.innerHeight/2)-(node.offsetHeight/2)) + 'px';
style.left = Math.floor((window.innerWidth/2)-(node.offsetWidth/2)) + 'px';
}catch(e){log("wmLibrary.promptText.center: "+e);}};
center();
window.addEventListener('resize', center, false); // Center it on resize
// Close frame on window close
window.addEventListener('beforeunload', function(){newFrame.remove(this);}, false);
}, false);
}catch(e){log("wmLibrary.promptText: "+e);}};
//***************************************************************************************************************************************
//***** Text To Script
//***************************************************************************************************************************************
//force code to be run outside the GM sandbox
sandbox.contentEval = function(source) {try{
// Check for function input.
if ('function' == typeof source) {
// Execute this function with no arguments, by adding parentheses.
// One set around the function, required for valid syntax, and a
// second empty set calls the surrounded function.
source = '(' + source + ')();'
}
// Create a script node holding this source code.
var script = document.createElement('script');
script.setAttribute("type", "application/javascript");
script.textContent = source;
// Insert the script node into the page, so it will run, and immediately
// remove it to clean up.
document.body.appendChild(script);
document.body.removeChild(script);
}catch(e){log("wmLibrary.contentEval: "+e);}};
//***************************************************************************************************************************************
//***** RegExp Construction
//***************************************************************************************************************************************
//convert an array to a pipe delimited RegExp group
sandbox.arrayToRegExp = function(a) {try{
var ret="";
if (isArrayAndNotEmpty(a)) {
ret="(";
for (var i=0,len=a.length; i<len;i++){
ret=ret+a[i];
if (i<(len-1)) ret=ret+"|";
}
ret=ret+")";
}
return ret;
}catch(e){log("wmLibrary.arrayToRegExp: "+e);}};
//takes an integer range and converts it to a regular expression
//which can search for that number range in a string
sandbox.integerRangeToRegExp = function(params) {try{
params=params||{};
var min=params.min.toString(), max=params.max.toString();
var ret="";
//on the odd case that both min and max values were equal
if (max==min) return max;
//count shared digits we can omit from complex regexp
var numSharedDigits=0;
if (min.length==max.length) {
for (var n=max.length;n>0;n--){
if (max.substring(0,n) == min.substring(0,n)) {
numSharedDigits=n;
break;
}
}
}
var shared=max.substring(0,numSharedDigits);
//crop the min and max values
min=min.removePrefix(shared);
max=max.removePrefix(shared);
//move the shared stuff to the front of the test
ret+=shared+"(";
//count the digits
var minDigits=min.length;
var maxDigits=max.length;
//set some flags
var isSingleDigit=(minDigits==1 && maxDigits==1);
var isVariableDigits=(minDigits != maxDigits);
//using 1 to 4444 as a range
//calculate maximum range tests
//ie: 444x 44xx 4xxx
if (maxDigits>1){
ret+=max.substr(0,maxDigits-1)+"[0-"+max.substr(maxDigits-1,1)+"]";
for (var n=(maxDigits-2); n>0; n--) {
if (max.substr(n,1)!="0") {
ret+="|"+max.substr(0,n)+"[0-"+(val(max.substr(n,1))-1)+"]"+("\\d").repeat((maxDigits-1)-n);
}
}
}
//calculate intermediate range tests
//ie: 1xxx, 1xx, 1x
for (var n=maxDigits;n>1;n--){
//check if min and max both use this digit
if (minDigits==n && maxDigits==n) {
//as neither bound would be put out of range
//and the bounds are not equal
if ((min.substr(0,1)!="9") && (max.substr(0,1)!="1") && (val(max.substr(0,1))>(val(min.substr(0,1))+1))) {
ret+="|["+(val(min.substr(0,1))+1)+"-"+(val(max.substr(0,1))-1)+"]"+("\\d").repeat(n-1);
}
//detect if min uses this digit
} else if (minDigits==n) {
//as long as it does not start with 9
if (min.substr(0,1)!="9") {
ret+="|["+(val(min.substr(0,1))+1)+"-9]"+("\\d").repeat(n-1);
}
break;
//detect if max uses this digit
} else if (maxDigits==n) {
//as long as it does not start with 1
if (max.substr(0,1)!="1") {
ret+="|[1-"+(val(max.substr(0,1))-1)+"]"+("\\d").repeat(n-1);
}
} else {
//they do not use this digit
//is it BETWEEN their digit counts
if (n > minDigits) {
ret+="|[1-9]"+("\\d").repeat(n-1);
}
}
}
//calculate minimum range tests
//ie: [1-9]
if (minDigits>1){
ret+="|"+min.substr(0,minDigits-1)+"["+min.substr(minDigits-1,1)+"-9]";
for (var n=(minDigits-2); n>0; n--) {
if (min.substr(n,1)!="9") {
ret+="|"+min.substr(0,n)+"["+(val(min.substr(n,1))+1)+"-9]"+("[0-9]").repeat((minDigits-1)-n);
}
}
} else {
//single digit min
if (maxDigits>minDigits) {
ret+="|["+min+"-9]";
} else {
//both min and max are single digits
ret+="|["+min+"-"+max+"]";
}
}
//fix same start and end range issues
for (var i=0;i<=9;i++){
ret=ret.replace(new RegExp("\\["+i+"-"+i+"\\]","gi"),i);
}
ret=ret.replace(new RegExp("\\[0-9\\]","gi"),"\\d");
return ret+")";
}catch(e){log("wmLibrary.integerRangeToRegExp: "+e);}};
//***************************************************************************************************************************************
//***** Typing Simulation
//***************************************************************************************************************************************
sandbox.simulateKeyEvent = function(character,byCode) {
var evt = document.createEvent("KeyboardEvent");
(evt.initKeyEvent || evt.initKeyboardEvent)("keypress", true, true, window,
0, 0, 0, 0,
0, ((byCode||null) || character.charCodeAt(0)) )
var canceled = !body.dispatchEvent(evt);
if(canceled) {
// A handler called preventDefault
alert("canceled");
} else {
// None of the handlers called preventDefault
alert("not canceled");
}
};
sandbox.typeText = function(s) {
for (var i=0,len=s.length; i<len; i++){
simulateKeyEvent(s.substr(i,1));
log(s.substr(i,1));
}
};
sandbox.typeEnter = function() {
simulateKeyEvent(null,13);
};
/*formatting notes
format a number to x decimal places
number.toFixed(x);
convert to hexidecimal
number.toString(16);
//try something like this to get your own header details
define your own parseHeaders function
var fileMETA = parseHeaders(<><![CDATA[
// ==UserScript==
// @name My Script
// @namespace http://www.example.com/gmscripts
// @description Scripting is fun
// @copyright 2009+, John Doe (http://www.example.com/~jdoe)
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @version 0.0.1
// @include http://www.example.com/*
// @include http://www.example.org/*
// @exclude http://www.example.org/foo
// @require foo.js
// @resource resourceName1 resource1.png
// @resource resourceName2 http://www.example.com/resource2.png
// @uso:script scriptid
// ==/UserScript==
]]></>.toString());
//include jquery stuff
// ==UserScript==
// @name jQuery Example
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
// ==/UserScript==
*/
//a custom collection wrapper
//this pretty much mimics collections in visual basic
//with a lot of collection methods added from other systems
var jsCollection=function(objOrArray){
var self=this;
this.items={};
//return an item from this collection by index or key
this.__defineGetter__("item",function(indexOrKey){try{
return this.items[indexOrKey]||null;
}catch(e){log("jsCollection.item: "+e);}});
//return the count of items in this collection
this.__defineGetter__("count",function(){try{
var ret=0;
for (var e in this.items) ret++;
return ret;
}catch(e){log("jsCollection.count: "+e);}});
//return true if the count of items in this collection is 0
this.__defineGetter__("isEmpty",function(){try{
return this.count==0;
}catch(e){log("jsCollection.isEmpty: "+e);}});
//remove all items from this collection
this.clear=function(){try{
while(this.items[0]) delete this.items[0];
}catch(e){log("jsCollection.clear: "+e);}};
//return the index of the first occurence of obj
this.indexOf=function(obj){try{
var c=0;
for (var i in this.items){
if (this.items[i]===obj) {
return c;
break;
}
c++;
}
return -1;
}catch(e){log("jsCollection.indexOf: "+e);}};
//return the key of the first occurence of obj
this.keyOf=function(obj){try{
for (var i in this.items){
if (this.items[i]===obj) {
return i;
break;
}
}
return -1;
}catch(e){log("jsCollection.keyOf: "+e);}};
//returns true if obj occurs in this collection
this.contains=function(obj){try{
return this.indexOf(obj)!=-1;
}catch(e){log("jsCollection.contains: "+e);}};
//returns true if an item in this collection has key = key
this.containsKey=function(key){try{
return exists(this.items[key]);
}catch(e){log("jsCollection.containsKey: "+e);}};
//remove an item from the collection by index or key
this.remove=function(indexOrKey){try{
delete this.items[indexOrKey];
}catch(e){log("jsCollection.remove: "+e);}};
//add an item to the collection
//with optional key which defaults to unique()
//with optional before which is an object to match
//with optional after which is an object to match
this.add=function(item,key,before,after){try{
key=key||unique();
if (before && this.indexOf(before)!=-1) {
var ret={};
for (var i in this.items){
if (this.items[i]===before) {
ret[key]=item;
}
ret[i]=this.items[i];
}
this.items=ret;
} else if (after && this.indexOf(after)!=-1) {
var ret={};
for (var i in this.items){
ret[i]=this.items[i];
if (this.items[i]===after) {
ret[key]=item;
}
}
this.items=ret;
} else {
this.items[key]=item;
}
}catch(e){log("jsCollection.add: "+e);}};
//shortform to add an item
//after an item
//with optional key
this.insertAfter=function(item,after,key){try{
this.add(item,key,null,after);
}catch(e){log("jsCollection.insertAfter: "+e);}};
//shortform to add an item
//before an item
//with optional key
this.insertBefore=function(item,before,key){try{
this.add(item,key,before,null);
}catch(e){log("jsCollection.insertBefore: "+e);}};
//shortform to add an item
//with optional key
this.append=function(item,key){try{
this.add(item,key);
}catch(e){log("jsCollection.append: "+e);}};
//shortform to add an item
//to the beginning of the collection
//with optional key
this.prepend=function(item,key){try{
this.add(item,key,(this.items[0]||null));
}catch(e){log("jsCollection.prepend: "+e);}};
//add an array of items
//with optional before and after
this.addRange=function(itemArray,before,after){try{
if (before && this.indexOf(before)!=-1) {
var ret={};
for (var i in this.items){
if (this.items[i]===before) {
for (var a=0,len=itemArrayLength;a<len;a++){
ret[unique()]=itemArray[a];
}
}
ret[i]=this.items[i];
}
this.items=ret;
} else if (after && this.indexOf(after)!=-1) {
var ret={};
for (var i in this.items){
ret[i]=this.items[i];
if (this.items[i]===after) {
for (var a=0,len=itemArrayLength;a<len;a++){
ret[unique()]=itemArray[a];
}
}
}
this.items=ret;
} else {
for (var a=0,len=itemArrayLength;a<len;a++){
this.items[unique()]=itemArray[a];
}
}
}catch(e){log("jsCollection.addRange: "+e);}};
//shortform to add an array of items
this.appendRange=function(itemArray){try{
this.addRange(itemArray);
}catch(e){log("jsCollection.appendRange: "+e);}};
//shortform to add an array of items
//to the beginning of the collection
this.prependRange=function(itemArray){try{
this.addRange(itemArray,(this.items[0]||null));
}catch(e){log("jsCollection.prependRange: "+e);}};
//add a copy of item
//with optional before or after
this.addCopy=function(item,before,after){try{
this.add(item,null,before,after);
}catch(e){log("jsCollection.addCopy: "+e);}};
//add multiple copies of item
//with optional before and after
this.addCopies=function(item,count,before,after){try{
var ret=[];
for (var i=0;i<count;i++) ret.push(item);
this.addRange(item,before,after);
}catch(e){log("jsCollection.addCopies: "+e);}};
//return the collection converted to an array
this.toArray=function(){try{
return methodsToArray(this.items);
}catch(e){log("jsCollection.toArray: "+e);}};
//return the index of item with key=key
this.indexOfKey=function(key){try{
return this.indexOf(this.items[key]||null);
}catch(e){log("jsCollection.indexOfKey: "+e);}};
//return the key of the item at index=index
this.keyOfIndex=function(index){try{
var c=0;
for (var i in this.items){
if (c==index) return i;
c++;
}
}catch(e){log("jsCollection.keyOfIndex: "+e);}};
//use passed data on creation to create initial items
if (objOrArray){
if (isArrayAndNotEmpty(objOrArray)){
for (var i=0,len=objOrArray.length;i<len;i++){
this.add(objOrArray[i],i);
}
} else if (isObject(objOrArray)) {
for (var i in objOrArray){
this.items[i]=objOrArray[i];
}
}
}
//return self for external use
return this;
};
sandbox.matchFunc_OnlyAlphaNumeric = function(s){
if (s.match(/[^a-zA-Z\d\s:]/g)) return false;
return true;
};
})();