WM Common Library

A collection of useful functions and objects, some of which are specific to the Wall Manager family of scripts.

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/416/27761/WM%20Common%20Library.js

  1. // ==UserScript==
  2. // @name WM Common Library
  3. // @namespace MerricksdadCommonLibrary
  4. // @description A collection of useful functions and objects, some of which are specific to the Wall Manager family of scripts.
  5. // @license http://creativecommons.org/licenses/by-nc-nd/3.0/us/
  6. // @version 4.0.0.2
  7. // @copyright Charlie Ewing except where noted
  8. // ==/UserScript==
  9.  
  10. (function(){
  11. var sandbox=this;
  12.  
  13. //***************************************************************************************************************************************
  14. //***** Greasemonkey and Browser Type Validation
  15. //***************************************************************************************************************************************
  16.  
  17. // is Greasemonkey running
  18. sandbox.isGM = (typeof GM_getValue != 'undefined' && typeof GM_getValue('a', 'b') != 'undefined');
  19. sandbox.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
  20.  
  21. //***************************************************************************************************************************************
  22. //***** Global Enumerated Values
  23. //***************************************************************************************************************************************
  24.  
  25. //enumerated string equal to script that does nothing
  26. sandbox.jsVoid="javascript:void(0)";
  27.  
  28. //time enums
  29. sandbox.second=1000;
  30. sandbox.minute=second*60;
  31. sandbox.hour=minute*60;
  32. sandbox.day=hour*24;
  33.  
  34. //***************************************************************************************************************************************
  35. //***** Data Type Verification
  36. //***************************************************************************************************************************************
  37.  
  38. //return true if o is undefined
  39. sandbox.isUndefined=function(o){try{return ((typeof o)=="undefined");}catch(e){log("wmLibrary.isUndefined: "+e);}};
  40.  
  41. //return true if o is a string
  42. sandbox.isString=function(o){try{return ((typeof o)=="string");}catch(e){log("wmLibrary.isString: "+e);}};
  43.  
  44. //return true if o is not undefined
  45. sandbox.exists=function(o){try{return (!isUndefined(o));}catch(e){log("wmLibrary.exists: "+e);}};
  46.  
  47. // Returns true if object o is an array
  48. sandbox.isArray=function(o){try{return Object.prototype.toString.call(o)==="[object Array]";}catch(e){log("wmLibrary.isArray: "+e);}};
  49.  
  50. sandbox.isNumber = function(o){return ((typeof o) == "number");};
  51. //sandbox.isArray = function(o) {return Object.prototype.toString.call(o) === "[object Array]";};
  52.  
  53. // Returns true if object o is an array and has a length > 0
  54. sandbox.isArrayAndNotEmpty=function(o){try{return isArray(o) && o.length>0;}catch(e){log("wmLibrary.isArrayAndNotEmpty: "+e);}};
  55.  
  56. // Returns true if object o is an object but not an array
  57. sandbox.isObject=function(o){try{return (((typeof o)=="object") && !isArray(o));}catch(e){log("wmLibrary.isObject: "+e);}};
  58.  
  59. //return true if o is undefined
  60. //sandbox.isNaN=function(o){try{return (o.toString()==="NaN");}catch(e){log("wmLibrary.isNaN: "+e);}};
  61.  
  62. //return integer value of object
  63. sandbox.val=function(o){try{return parseInt(o);}catch(e){log("wmLibrary.val: "+e);}};
  64.  
  65. sandbox.calcTime=function(timer) {try{
  66.  
  67. if ((typeof timer)=="integer") return timer;
  68. if (timer.match(/^(\d)/)) return val(timer);
  69.  
  70. //debug.print(timer);
  71. var t=2; //defaults to 2 minutes on error
  72. //check for U:# time format (u = millisecond count)
  73. if (timer.toLowerCase().startsWith("u:")) {
  74. t=parseInt(timer.toLowerCase().split("u:")[1]||"");
  75. return t;
  76. }
  77. //check for s:# (s = second count)
  78. if (timer.toLowerCase().startsWith("s:")) {
  79. t=parseInt(timer.toLowerCase().split("s:")[1]||"")||0;
  80. return t*1000;
  81. }
  82. //check for t:#D:#H:#M:#S time format
  83. if (timer.toLowerCase().startsWith("t:")){
  84. var fnNumberFromHMSDate = function(i,l) {
  85. var teststring = "(\\d)*?"+l;
  86. var test = new RegExp(teststring,"i");
  87. var testret = test.exec(i);
  88. //debug.print([i,teststring,testret]);
  89. return parseInt((testret||["0"])[0]);
  90. };
  91. t=timer.toLowerCase().split("t:")[1];
  92. //it should now be in "1d:2h:5m:30s" format
  93. var d = fnNumberFromHMSDate(t,"d");
  94. var h = fnNumberFromHMSDate(t,"h");
  95. var m = fnNumberFromHMSDate(t,"m");
  96. var s = fnNumberFromHMSDate(t,"s");
  97. //debug.print([d,h,m,s]);
  98. return ((s*second)+(m*minute)+(h*hour)+(d*day));
  99. }
  100. //do originally programmed time words
  101. switch(timer) {
  102. case "off": return 0; break; //off
  103. case "tenth": t = 0.1; break; // 6 seconds
  104. case "sixth": t = 0.1666667; break; // 10 seconds
  105. case "third": t = 0.3333333; break; // 20 seconds
  106. case "half": t = 0.5; break; // 30 seconds
  107. case "one": t = 1; break; // 1 minute
  108. case "two": t = 2; break; // 2 minutes
  109. case "three": t = 3; break; // 3 minutes
  110. case "four": t = 4; break; // 4 minutes
  111. case "five": t = 5; break; // 5 minutes
  112. case "ten": t = 10; break; // 10 minutes
  113. case "fifteen": t = 15; break; // 15 minutes
  114. case "thirty": t = 30; break; // 30 minutes
  115. case "hour": t = 60; break; // 1 hour
  116. case "2hour": t = 60*2; break; // 2 hours
  117. case "3hour": t = 60*3; break; // 3 hours
  118. case "4hour": t = 60*4; break; // 4 hours
  119. case "8hour": t = 60*8; break; // 8 hours
  120. case "12hour": t = 60*12; break; // 12 hours
  121. case "18hour": t = 60*18; break; // 18 hours
  122. case "24hour": t = 60*24; break; // 1 day
  123. case "36hour": t = 60*36; break; // 1.5 days
  124. case "48hour": t = 60*48; break; // 2 days
  125. case "30s2m": t = (Math.random() * 1.5) + 0.5; break; // random between 30s and 2m
  126. case "2m5m": t = (Math.random() * 3) + 2; break; // random between 2m and 5m
  127. case "5m10m": t = (Math.random() * 5) + 5; break; // random between 5m and 10m
  128. }
  129. return Math.round((t*60000)+(Math.random()*(t*100)));
  130. }catch(e){log("wmLibrary.calcTime: "+e);}};
  131.  
  132. //comprehensive convert anything to a boolean value
  133. sandbox.cBool = function(x){try{
  134. //log(x||"undefined");
  135. //capture undefined
  136. if (!exists(x)) return false;
  137. //capture nulls
  138. if (x==null) return false;
  139. //capture checkboxes
  140. if (exists(x.checked)) x=x.checked;
  141. //capture objects with value property
  142. if (exists(x.value)) x=x.value;
  143. //capture boolean values
  144. if ((typeof x)=="boolean") return x;
  145. //capture non-null objects
  146. if (isObject(x)) return true;
  147. //capture arrays
  148. if (isArray(x)) return true;
  149. //capture text
  150. if (typeof x=="string") {
  151. var trueVal=x;
  152. if (exists(x.toLowerCase)) trueVal=x.toLowerCase();
  153. switch(trueVal){
  154. case "1": case "true": case "yes": case "checked": return true; break;
  155. case "0": case "false": case "no": case "unchecked": return false; break;
  156. }
  157. }
  158. //default
  159. return Boolean(x);
  160. }catch(e){log("wmLibrary.cBool: {x="+x+"}: "+e);}};
  161.  
  162. //***************************************************************************************************************************************
  163. //***** Logging
  164. //***************************************************************************************************************************************
  165.  
  166. // cross-browser log function, turns the log variable into a function
  167. // originally from FVWM by Joe Simmons
  168. // now also catches the WM debug window first
  169. sandbox.log=function(){try{
  170. var fx, debug=this.debug;
  171. if (exists(debug)) fx=debug.print;
  172. else if (isGM) fx=GM_log;
  173. else if (window.opera) fx=opera.postError;
  174. else fx=console.log;
  175. if (fx) {var args=arguments, self=this; setTimeout(function(){fx.apply(self,args);},0); }
  176. }catch(e){console.log("WmLibrary.log: "+e);}};
  177.  
  178. //***************************************************************************************************************************************
  179. //***** Style Sheet Creation
  180. //***************************************************************************************************************************************
  181.  
  182. //append css style to the header
  183. //supply a name and this function will force that style sheet to have an id attribute equal to the name supplied
  184. //supply a doc object and the stylesheet will be put in that document instead of this one
  185. 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);}};
  186.  
  187. //***************************************************************************************************************************************
  188. //***** Mouse Events
  189. //***************************************************************************************************************************************
  190.  
  191. //click specified DOM element
  192. 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);}};
  193.  
  194. //pretend to put the mouse over specified DOM element
  195. 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);}};
  196.  
  197. //***************************************************************************************************************************************
  198. //***** DOM Creation/Manipulation
  199. //***************************************************************************************************************************************
  200.  
  201. //return a DOM element by ID with optional alternate root document
  202. sandbox.$=function(ID,root) {try{return (root||document).getElementById(ID);}catch(e){log("wmLibrary.$: "+e);}};
  203.  
  204. //return new DOM element a, with parameters b, and children c
  205. sandbox.createElement=function(a,b,c) {try{
  206. if(a=="text") {return document.createTextNode(b);};
  207. var ret=document.createElement(a.toLowerCase());
  208. if(b) for(var prop in b) {
  209. if(prop.indexOf("on")==0) {
  210. ret.addEventListener(prop.substring(2),b[prop],false);
  211. } else if (
  212. ",style,accesskey,id,name,src,href,which,rel,action,method,value,data-ft".indexOf(","+prop.toLowerCase())!=-1
  213. ) {
  214. ret.setAttribute(prop.toLowerCase(), b[prop]);
  215. /*} else if (
  216. !exists(ret[prop.toLowerCase()])
  217. } {
  218. ret.setAttribute(prop.toLowerCase(), b[prop]);*/
  219. } else {
  220. ret[prop]=b[prop];
  221. }
  222. }
  223. if(c) c.forEach(
  224. function(e) {
  225. if (e) ret.appendChild(e);
  226. }
  227. );
  228. return ret;
  229. }catch(e){log("wmLibrary.createElement: "+e);}};
  230.  
  231. //return document.location.pathname
  232. sandbox.getDocName=function() {try{return document.location.pathname;}catch(e){log("wmLibrary.getDocName: "+e);}};
  233.  
  234. //remove specified DOM element
  235. 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);}};
  236.  
  237. //return selected nodes using xpath, with additional parameters
  238. 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);}};
  239.  
  240. //return single selected node using xpath, with additional parameters
  241. sandbox.selectSingleNode=function(xPath,params){try{params=params||{}; params['type']=9;return selectNodes(xPath,params).singleNodeValue;}catch(e){log("wmLibrary.selectSingleNode: "+e);}};
  242.  
  243. //for the selected nodes using xpath and additional parameters, perform passed function
  244. 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);}};
  245.  
  246. //fetch the selected elements from an html select multi into an array
  247. //this fetches the ELEMENT not its value
  248. sandbox.getSelectedOptions=function(elem){try{
  249. var ret=[];
  250. for (var i=0; i<elem.options.length; i++) {
  251. if (elem.options[i].selected) ret.push(elem.options[i]);
  252. }
  253. return ret;
  254. }catch(e){log("wmLibrary.getSelectedOptions: "+e);}};
  255.  
  256. //fetch the selected values from an html select multi into an array
  257. //this fetches the VALUE not the element
  258. sandbox.getSelectedOptionValues=function(elem){try{
  259. var ret=[];
  260. for (var i=0; i<elem.options.length; i++) {
  261. if (elem.options[i].selected) ret.push(elem.options[i].value);
  262. }
  263. return ret;
  264. }catch(e){log("wmLibrary.getSelectedOptionValues: "+e);}};
  265.  
  266. //attach an array of elements to a node
  267. 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);}};
  268.  
  269. //create a set of options for a selection list based on an array
  270. 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);}};
  271.  
  272. //select an element from a dropdown box with a certain value
  273. 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);}};
  274.  
  275. //return the value of a dropdown's selected inded
  276. sandbox.valueOfSelect = function(obj){try{return obj.options[obj.selectedIndex].value;}catch(e){log("wmLibrary.valueOfSelect: "+e);}};
  277.  
  278. //hides all snapshots or iterations in an xpathResult object
  279. sandbox.hideNodes=function(xPath,params) {try{forNodes(xPath,params,function(item){item.style.display="none";});}catch(e){log("wmLibrary.hideNodes: "+e);}};
  280.  
  281. //unhides all snapshots or iterations in an xpathResult object
  282. sandbox.showNodes=function(xPath,params) {try{forNodes(xPath,params,function(item){item.style.display="";});}catch(e){log("wmLibrary.showNodes: "+e);}};
  283.  
  284. //move element up
  285. sandbox.elementMoveUp=function(e){try{
  286. //if this element has a parent
  287. if (e.parentNode) {
  288. //and its not the first child
  289. if (e.parentNode.firstChild!=e){
  290. //move it to just before its previous sibling
  291. e.parentNode.insertBefore(e,e.previousSibling);
  292. }
  293. }
  294. return e;
  295. }catch(e){log("wmLibrary.elementMoveUp: "+e);}};
  296.  
  297. //move element down
  298. sandbox.elementMoveDown=function(e){try{
  299. //if this element has a parent
  300. if (e.parentNode) {
  301. //and its not the last child
  302. if (e.parentNode.lastChild!=e){
  303. //if the next sibling IS the last child
  304. if (e.parentNode.lastChild==e.nextSibling){
  305. //just move it to the bottom
  306. e.parentNode.appendChild(e);
  307. } else {
  308. //insert it between the next sibling and the next next sibling
  309. e.parentNode.insertBefore(e,e.nextSibling.nextSibling);
  310. }
  311. }
  312. }
  313. return e;
  314. }catch(e){log("wmLibrary.elementMoveDown: "+e);}};
  315.  
  316. //move element up to top of container
  317. sandbox.elementMoveTop=function(e){try{
  318. //if this element has a parent
  319. if (e.parentNode) {
  320. //and its not the first child
  321. if (e.parentNode.firstChild!=e){
  322. //move it to the top of the container
  323. e.parentNode.insertBefore(e,e.parentNode.firstChild);
  324. }
  325. }
  326. return e;
  327. }catch(e){log("wmLibrary.elementMoveTop: "+e);}};
  328.  
  329. //move element up to top of container
  330. sandbox.elementMoveBottom=function(e){try{
  331. //if this element has a parent
  332. if (e.parentNode) {
  333. //and its not the first child
  334. if (e.parentNode.lastChild!=e){
  335. //move it to the bottom of the container
  336. e.parentNode.appendChild(e);
  337. }
  338. }
  339. return e;
  340. }catch(e){log("wmLibrary.elementMoveBottom: "+e);}};
  341.  
  342. //sort an element's children by an attribute
  343. sandbox.elementSortChildren=function(e,by){try{
  344. by=by||"name";
  345. if (e && e.childNodes) {
  346. //pack into an array
  347. var ret=[];
  348. for (var n=0;n<e.childNodes.length;n++) {
  349. ret.push(e.childNodes[n]);
  350. }
  351. //sort the array
  352. ret.sort(function(a,b){return a[by]>b[by]});
  353. //fix order of display
  354. for (var n=0;n<ret.length;n++) {
  355. e.appendChild(ret[n]);
  356. }
  357. //clean up
  358. ret=null;
  359. }
  360. }catch(e){log("wmLibrary.elementSortChildren: "+e);}};
  361.  
  362. //remove all of a node's child nodes
  363. sandbox.removeAllChildren=function(e){
  364. var node=e.childNodes[0];
  365. while (node) {
  366. remove(node);
  367. node=e.childNodes[0];
  368. }
  369. };
  370.  
  371. //return the real url of a location
  372. 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);}};
  373.  
  374. // compile and return the true x,y scroll offset onscreen of an element in Firefox
  375. sandbox.trueScrollOffset = function(o){try{
  376. var offset={left:o.scrollLeft,top:o.scrollTop}, parentOffset=null;
  377. if (!(o==document.body) && !(0==document.documentElement) && o.parentNode) parentOffset=trueScrollOffset(o.parentNode);
  378. if (parentOffset) {
  379. offset.left+=parentOffset.left||0;
  380. offset.top+=parentOffset.top||0;
  381. }
  382. return offset;
  383. }catch(e){log("wmLibrary.trueScrollOffset: "+e);}},
  384.  
  385. // compile and return the true x,y offset onscreen of an element in Firefox
  386. sandbox.trueOffset = function(o){try{
  387. var offset={left:o.offsetLeft,top:o.offsetTop}, parentOffset=null;
  388. if (o.offsetParent) parentOffset=trueOffset(o.offsetParent);
  389. if (parentOffset) {
  390. offset.left+=parentOffset.left||0;
  391. offset.top+=parentOffset.top||0;
  392. }
  393. return offset;
  394. }catch(e){log("wmLibrary.trueOffset: "+e);}},
  395.  
  396. //force a page to transition to new location s even if changing the document location does not work
  397. sandbox.linkTo = function(s) {try{
  398. var link=document.body.appendChild(createElement("a",{href:s,target:"_top"}));
  399. click(link);
  400. }catch(e){log("wmLibrary.linkTo: "+e);}};
  401.  
  402. //***************************************************************************************************************************************
  403. //***** Date/Time
  404. //***************************************************************************************************************************************
  405.  
  406. //return a unix timestamp
  407. sandbox.timeStamp=function(){try{return (new Date()).getTime();}catch(e){log("wmLibrary.timeStamp: "+e);}};
  408.  
  409. //return a facebook timestamp without millisecond data
  410. sandbox.timeStampNoMS=function(){try{var t=timeStamp().toString(); return t.substr(0,t.length-3);}catch(e){log("wmLibrary.timeStampNoMS: "+e);}};
  411.  
  412. //returns a guaranteed unique timestamp in base36 prefixed with an underscore
  413. 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);}};
  414.  
  415. //***************************************************************************************************************************************
  416. //***** String Prototype Additions
  417. //***************************************************************************************************************************************
  418.  
  419. //return true if string starts with s
  420. 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);}};
  421.  
  422. //return true if string ends with s
  423. 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);}};
  424.  
  425. //return true if string contains s
  426. sandbox.String.prototype.find = function(s) {try{
  427. return (this.indexOf(s) != -1);
  428. }catch(e){log("wmLibrary.String.prototype.find: "+e);}};
  429. sandbox.String.prototype.contains = function(s) {return this.find(s);};
  430.  
  431. //inserts string s into this string at position startIndex
  432. sandbox.String.prototype.insert = function(s,startIndex) {try{
  433. return this.substr(0,startIndex)+s+this.substr(startIndex,this.length-startIndex);
  434. }catch(e){log("wmLibrary.String.prototype.insert: "+e);}};
  435.  
  436. //pads the string with space or a specific character, on the left
  437. //strings already longer than totalLength are not changed
  438. sandbox.String.prototype.padLeft = function(totalLength,c) {try{
  439. c=(c||" ").charAt(0);
  440. if (totalLength>0){
  441. return (totalLength<=this.length)?this:
  442. c.repeat((totalLength-this.length))+this;
  443. }
  444. }catch(e){log("wmLibrary.String.prototype.padLeft: "+e);}};
  445.  
  446. //pads the string with space or a specific character, on the left
  447. //strings already longer than totalLength are not changed
  448. sandbox.String.prototype.padRight = function(totalLength,c) {try{
  449. c=(c||" ").charAt(0);
  450. if (totalLength>0){
  451. return (totalLength<=this.length)?this:
  452. this+c.repeat((totalLength-this.length));
  453. }
  454. }catch(e){log("wmLibrary.String.prototype.padright: "+e);}};
  455.  
  456. //return the string as an array of characters
  457. sandbox.String.prototype.toCharArray = function() {try{
  458. return this.split(/(.|\n|\r)/g);
  459. }catch(e){log("wmLibrary.String.prototype.toCharArray: "+e);}};
  460.  
  461. //return the passed string minus spaces
  462. sandbox.String.prototype.noSpaces = function(s) {try{return (this.replace(/\s+/g,''));}catch(e){log("wmLibrary.String.prototype.noSpaces: "+e);}};
  463.  
  464. //return the passed string with word first letters capitalized
  465. 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);}};
  466.  
  467. //return the passed string repeated n times
  468. sandbox.String.prototype.repeat = function(n) {try{return new Array(n+1).join(this);}catch(e){log("wmLibrary.String.prototype.repeat: "+e);}};
  469.  
  470. //return the passed string minus line breaks
  471. sandbox.String.prototype.noLineBreaks = function(s) {try{return (this.replace(/(\r\n|\n|\r)/gm," "));}catch(e){log("wmLibrary.String.prototype.noLineBreaks: "+e);}};
  472.  
  473. //return the passed string without beginning or ending quotes
  474. sandbox.String.prototype.unQuote = function() {try{return this.replace(/^"|"$/g, '');}catch(e){log("wmLibrary.String.prototype.unQuote: "+e);}};
  475.  
  476. //return the passed string without beginning or ending quotes
  477. sandbox.String.prototype.quote = function() {try{return "\""+this+"\"";}catch(e){log("wmLibrary.String.prototype.quote: "+e);}};
  478.  
  479. //return the passed string without beginning or ending brackets
  480. sandbox.String.prototype.unBracket = function() {try{return this.replace(/^\[|\]$/g, '');}catch(e){log("wmLibrary.String.prototype.unBracket: "+e);}};
  481.  
  482. //return the passed string without beginning spaces
  483. sandbox.String.prototype.trimStart = function(){try{
  484. return this.replace(/^\s\s*/, '');
  485. }catch(e){log("wmLibrary.String.prototype.trimStart: "+e);}};
  486.  
  487. //return the passed string without ending spaces
  488. sandbox.String.prototype.trimEnd = function(){try{
  489. return this.replace(/\s\s*$/, '');
  490. }catch(e){log("wmLibrary.String.prototype.trimEnd: "+e);}};
  491.  
  492. //return the passed string without beginning or ending spaces
  493. sandbox.String.prototype.trim = function(){try{
  494. return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  495. }catch(e){log("wmLibrary.String.prototype.trim: "+e);}};
  496.  
  497. //assuming passed string is a url parameter list, return named parameter's value or ""
  498. //this works great for both search and hash parts
  499. //do not pass a document.location without first splitting off search and hash parts
  500. sandbox.String.prototype.getUrlParam = function(s) {try{
  501. var r=this.removePrefix("#").removePrefix("?").split("&");
  502. for (var p=0,param;(param=r[p]);p++){
  503. if ( param.startsWith(s+"=") || param==s ) {
  504. return (param.split("=")[1]||null);
  505. }
  506. }
  507. return null;
  508. }catch(e){log("wmLibrary.String.prototype.getUrlParam: "+e);}};
  509.  
  510. //return passed string with word added to end. words are separated by spaces
  511. //alternately accepts an array of words to add
  512. sandbox.String.prototype.addWord= function(word){try{
  513. if (!isArray(word)) word=[word];
  514. var words = this.split(" ");
  515. var ret=this;
  516. for (var w=0,len=word.length;w<len;w++){
  517. if (!words.inArray(word[w])) ret=ret+" "+word;
  518. }
  519. return ret;
  520. }catch(e){log("wmLibrary.String.prototype.addWord: "+e);}};
  521.  
  522. //return passed string minus specified word
  523. //alternately accepts an array of words to remove
  524. sandbox.String.prototype.removeWord= function(word){try{
  525. if (!isArray(word)) word=[word];
  526. var words=this.split(" ");
  527. var ret;
  528. for (var w=0,len=word.length;w<len;w++){
  529. ret = words.removeByValue(word[w]);
  530. }
  531. return ret.join(" ");
  532. }catch(e){log("wmLibrary.String.prototype.removeWord: "+e);}};
  533.  
  534. //return true if passed string contains word
  535. sandbox.String.prototype.containsWord= function(word){try{return this.split(" ").inArray(word);}catch(e){log("wmLibrary.String.prototype.containsWord: "+e);}};
  536.  
  537. //return passed string with word replaced with word2
  538. sandbox.String.prototype.replaceWord= function(word,word2){try{return this.split(" ").replace(word,word2).join(" ");}catch(e){log("wmLibrary.String.prototype.replaceWord: "+e);}};
  539.  
  540. //return passed string with word toggled
  541. 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);}};
  542.  
  543. //return passed string with word toggled based on a boolean input
  544. sandbox.String.prototype.toggleWordB = function(bool,word){try{
  545. return this[(bool?"add":"remove")+"Word"](word);
  546. }catch(e){log("wmLibrary.String.prototype.toggleWordB: "+e);}};
  547.  
  548. //return passed string with word swapped for another based on a boolean input
  549. //if bool==true then we return string including word1 and excluding word2
  550. //else we return string including word2 and excluding word1
  551. sandbox.String.prototype.swapWordB = function(bool,word1,word2){try{
  552. return this.replaceWord((bool?word2:word1),(bool?word1:word2));
  553. }catch(e){log("wmLibrary.String.prototype.swapWordB: "+e);}};
  554.  
  555. //return passed string minus prefix of s if it exists
  556. 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);}};
  557.  
  558. //return passed string minus suffix of s if it exists
  559. 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);}};
  560.  
  561. // visual basic alternate for string.toLowerCase()
  562. sandbox.String.prototype.lcase = function() {try{return this.toLowercase();}catch(e){log("wmLibrary.String.prototype.lcase: "+e);}};
  563.  
  564. // visual basic alternate for string.toUpperCase()
  565. sandbox.String.prototype.ucase = function() {try{return this.toUppercase();}catch(e){log("wmLibrary.String.prototype.ucase: "+e);}};
  566. // copy the calling string to the clipboard (IE or GM)
  567. sandbox.String.prototype.toClipboard = function() {try{
  568. if (window.clipboardData){
  569. window.clipboardData.setData("Text", this);
  570. } else if (unsafeWindow) {
  571. try{
  572. unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
  573. } catch(e){
  574. log("wmLibrary.String.prototype.toClipboard: Cannot enable privelege 'UniversalXPConnect'. Be sure that 'signed.applets.codebase_principal_support' is set to true in 'about:config'");
  575. }
  576. const clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
  577. clipboardHelper.copyString(this);
  578. } else {
  579. log("wmLibrary.String.prototype.toClipboard: Cannot perform task");
  580. }
  581. } catch(e){log("wmLibrary.String.prototype.toClipboard: "+e);}};
  582.  
  583. //replaces all instances of {x} with passed argument x
  584. //or arguments[0][x] when the first argument is an array
  585. sandbox.String.prototype.format = function() {try{
  586. var ret = this;
  587. var args=arguments; //use argument mode
  588. if (isArray(args[0])) args=args[0]; //switch to array mode
  589. for (var i = 0; i < args.length; i++) {
  590. var re = new RegExp('\\{'+i+'\\}', 'gi');
  591. ret = ret.replace(re, args[i]);
  592. }
  593. return ret;
  594. }catch(e){log("wmLibrary.String.prototype.format: "+e);}};
  595.  
  596. //similar to String.format, except that instances of {%x} are replaced
  597. //instead of instances of {x}
  598. sandbox.String.prototype.format2 = function() {try{
  599. var ret = this;
  600. var args=arguments; //use argument mode
  601. if (isArray(args[0])) args=args[0]; //switch to array mode
  602. for (var i=0; i < args.length; i++) {
  603. var re = new RegExp('\\{%'+i+'\\}', 'gi');
  604. ret = ret.replace(re, args[i]);
  605. }
  606. return ret;
  607. }catch(e){log("wmLibrary.String.prototype.format2: "+e);}};
  608.  
  609. //returns true if the string is zero-length
  610. sandbox.String.prototype.isEmpty = function() {try{
  611. return this.length==0;
  612. }catch(e){log("wmLibrary.String.prototype.isEmpty: "+e);}};
  613.  
  614. //returns an object derived from the JSON string calling this function
  615. sandbox.String.prototype.parseJSON = function() {try{
  616. return JSON.parse(this);
  617. }catch(e){log("wmLibrary.String.prototype.parseJSON: "+e);}};
  618.  
  619. //format a JSON string with linebreaks and indents
  620. //with optional indent number to set indent length in spaces
  621. //default intent is a tab character
  622. sandbox.String.prototype.formatJSON = function(indent) {try{
  623. indent=(indent)?(" ").repeat(indent):"\t";
  624. //first lets convert the supposed JSON string to an actual object
  625. //so we can validate that it is of good format
  626. var topObj=JSON.parse(this);
  627. //if we got this far, it is valid
  628. //make a function to spell our our branches
  629. var writeBranch=function(obj,name,level){
  630. var ret="";
  631. //start our output string
  632. ret+=(level)?indent.repeat(level):"";
  633. ret+=(name)?JSON.stringify(name)+": ":"";
  634. ret+=(isArray(obj))?
  635. "["+((!obj.isEmpty())?
  636. "\n":
  637. ""
  638. ):
  639. (isObject(obj))?
  640. "{"+((!methodsToArray(obj).isEmpty())?
  641. "\n":
  642. ""
  643. ):
  644. "";
  645. //draw the inside object(s)
  646. var c=0;
  647. if (isArray(obj)) for (var i=0,len=obj.length;i<len;i++){
  648. //write arrays out
  649. if (i>0) ret+=",\n";
  650. ret+=writeBranch(obj[i],null,level+1);
  651. } else if (isObject(obj)) for (var i in obj){
  652. if (c>0) ret+=",\n";
  653. //write objects out
  654. ret+=writeBranch(obj[i],i,level+1);
  655. c++;
  656. } else {
  657. //branch is not an object or array
  658. ret+=JSON.stringify(obj);
  659. }
  660. //end our output string
  661. ret+=(isArray(obj))?
  662. ((!obj.isEmpty())?
  663. "\n"+((level)?
  664. indent.repeat(level):
  665. ""
  666. ):
  667. ""
  668. )+"]":
  669. (isObject(obj))?
  670. ((!methodsToArray(obj).isEmpty())?
  671. "\n"+((level)?
  672. indent.repeat(level):
  673. ""
  674. ):
  675. ""
  676. )+"}":
  677. "";
  678. //back to previous branch
  679. return ret;
  680. }
  681. //start writing the branches
  682. return writeBranch(topObj,null,0);
  683. }catch(e){log("wmLibrary.String.prototype.formatJSON: "+e);}};
  684.  
  685. //returns the longested quoted text within the calling string
  686. //which also returns true when passed through matchFunc
  687. sandbox.String.prototype.longestQuoteWithin = function(matchFunc) {try{
  688. var p=0, c=0, s="", a=0, b=0, l=0;
  689. //parse entire string input
  690. while (p<this.length){
  691. a=this.indexOf('"', p); //find start of next quotes
  692. if (a!=-1) {
  693. p=a+1; //remember cursor
  694. b=this.indexOf('"',p); //find end of current quotes
  695. if (b!=-1) {
  696. p=b+1; //update cursor
  697. l=b-a; //determine length
  698. //check if longer than current length remembered
  699. if (l>c) {
  700. c=l;
  701. ss=this.substr(a+1,l-1);
  702. //check against matchFunc if one exists
  703. if (matchFunc) {
  704. if (matchFunc(ss)) s=ss;
  705. } else {
  706. //no matchFunc given, assume true
  707. s=ss;
  708. }
  709. }
  710. } else {
  711. p=this.length;
  712. }
  713. } else {
  714. p=this.length;
  715. }
  716. }
  717. return s;
  718. }catch(e){log("wmLibrary.String.prototype.longestQuoteWithin: "+e);}};
  719.  
  720. //***************************************************************************************************************************************
  721. //***** Array Prototype Additions
  722. //***************************************************************************************************************************************
  723.  
  724. //returns true if the array is zero-length
  725. sandbox.Array.prototype.isEmpty = function() {try{
  726. return this.length==0;
  727. }catch(e){log("wmLibrary.Array.prototype.isEmpty: "+e);}};
  728.  
  729. //return passed array with element x and element y swapped
  730. sandbox.Array.prototype.swap = function (x,y) {try{
  731. var b = this[x];
  732. this[x] = this[y];
  733. this[y] = b;
  734. return this;
  735. }catch(e){log("wmLibrary.Array.prototype.swap: "+e);}};
  736.  
  737. //return true if a value exists in the array
  738. //with optional startIndex
  739. //and optional count which specifies the number of elements to examine
  740. sandbox.Array.prototype.inArray = function(value,startIndex,count) {try{
  741. startIndex=startIndex||0;
  742. if (startIndex>=this.length) {
  743. //log("wmLibrary.Array.prototype.inArray: Error: startIndex out of bounds");
  744. return false;
  745. }
  746. if (exists(count) && count<1) {
  747. //log("wmLibrary.Array.prototype.inArray: Error: count is less than 1");
  748. return false;
  749. }
  750. var c=0;
  751. for(var i=this.length-1; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i--) {
  752. c++;
  753. if(this[i]==value) return true;
  754. }
  755. return false;
  756. }catch(e){log("wmLibrary.Array.prototype.inArray: "+e);}};
  757.  
  758. //alias for inArray
  759. sandbox.Array.prototype.contains = function(value,startIndex,count) {return this.inArray(value,startIndex,count);};
  760.  
  761. //return the location of a value in an array
  762. //with optional startIndex
  763. //and optional count which specifies the number of elements to examine
  764. sandbox.Array.prototype.inArrayWhere = function(value,startIndex,count) {try{
  765. startIndex=startIndex||0;
  766. if (startIndex>=this.length) {
  767. //log("wmLibrary.Array.prototype.inArrayWhere: Error: startIndex out of bounds");
  768. return -1;
  769. }
  770. if (exists(count) && count<1) {
  771. //log("wmLibrary.Array.prototype.inArrayWhere: Error: count is less than 1");
  772. return -1;
  773. }
  774. var c=0;
  775. for(var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++) {
  776. c++;
  777. if(this[i]==value) return i;
  778. }
  779. return -1;
  780. }catch(e){log("wmLibrary.Array.prototype.inArrayWhere: "+e);}};
  781. //alias for inArrayWhere
  782. sandbox.Array.prototype.indexOf = function(value,startIndex,count) {return this.inArrayWhere(value,startIndex,count);};
  783.  
  784. //return the location of the last occurence of value in an array
  785. //with optional startIndex
  786. //and optional count which specifies the number of elements to examine
  787. sandbox.Array.prototype.lastIndexOf = function(value,startIndex,count) {try{
  788. startIndex=startIndex||0;
  789. if (startIndex>=this.length) {
  790. //log("wmLibrary.Array.prototype.lastIndexOf: Error: startIndex out of bounds");
  791. return -1;
  792. }
  793. if (exists(count) && count<1) {
  794. //log("wmLibrary.Array.prototype.lastIndexOf: Error: count is less than 1");
  795. return -1;
  796. }
  797. var c=0;
  798. for(var i=this.length; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i++) {
  799. c++;
  800. if(this[i]==value) return i;
  801. }
  802. return -1;
  803. }catch(e){log("wmLibrary.Array.prototype.lastIndexOf: "+e);}};
  804.  
  805. //return true if the location of value is 0
  806. sandbox.Array.prototype.startsWith = function(value){return this.inArrayWhere(value)===0;}
  807.  
  808. //return the last value in an array
  809. sandbox.Array.prototype.last = function() {try{return this[this.length - 1];}catch(e){log("wmLibrary.Array.prototype.last: "+e);}};
  810.  
  811. //return true if the content of the last index is equal to value
  812. sandbox.Array.prototype.endsWith = function(value){return this.last()===value;}
  813.  
  814. //return the array will spaces removed from every element
  815. 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);}};
  816.  
  817. //remove the first instance of a value in an array
  818. //now accepts an array of values to remove
  819. //removes the first instance of every item in array passed
  820. //returns the calling array
  821. sandbox.Array.prototype.removeByValue = function(values) {try{
  822. if (!isArray(values)) values=[values];
  823. for (var i=0,len=values.length; i<len;i++) {
  824. var e=this.inArrayWhere(values[i]);
  825. if(e>=0)this.splice(e,1);
  826. }
  827. return this;
  828. }catch(e){log("wmLibrary.Array.prototype.removeByValue: "+e);}};
  829.  
  830. //replace all instances of a value in an array
  831. //returns the calling array
  832. sandbox.Array.prototype.replaceAll = function(val, val2) {try{
  833. var i=this.inArrayWhere(val);
  834. while(i>=0) {
  835. this[i]=val2;
  836. i=this.inArrayWhere(val,i+1);
  837. }
  838. return this;
  839. }catch(e){log("wmLibrary.Array.prototype.replaceAll: "+e);}};
  840.  
  841. //remove all instances of a value in an array
  842. //now accepts an array of values to remove
  843. //returns the calling array
  844. sandbox.Array.prototype.removeAllByValue = function(values) {try{
  845. if (!isArray(values)) values=[values];
  846. for (var i=0,len=values.length; i<len;i++) {
  847. var e=this.inArrayWhere(values[i]);
  848. while (e>=0){
  849. if(e>=0)this.splice(e,1);
  850. e=this.inArrayWhere(values[i],e+1);
  851. }
  852. }
  853. return this;
  854. }catch(e){log("wmLibrary.Array.prototype.removeAllByValue: "+e);}};
  855.  
  856. //replace the first instance of a value in an array
  857. //returns the calling array
  858. 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);}};
  859.  
  860.  
  861. //remove element i of an array
  862. //returns the calling array
  863. sandbox.Array.prototype.remove = function(i) {try{this.splice(i,1); return this;}catch(e){log("wmLibrary.Array.prototype.remove: "+e);}};
  864.  
  865. //remove elements beyond specified new size
  866. //or add elements to fill the new size equal to defaultValue
  867. sandbox.Array.prototype.resize = function(newSize,defaultValue) {try{
  868. if (this.length>newSize) {
  869. this.splice(newSize,this.length-newSize);
  870. } else {
  871. for (var i=this.length;i<newSize;i++){
  872. this[i]=defaultValue;
  873. }
  874. }
  875. return this;
  876. }catch(e){log("wmLibrary.Array.prototype.resize: "+e);}};
  877.  
  878. //return a random element of an array
  879. 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);}};
  880.  
  881. //sorts an array so that words which contain another word in the array are placed before that other word
  882. //such as "pea" must come AFTER "peanut", and "great american race" must come BEFORE "american"
  883. //the sort is case-insensitive
  884. sandbox.Array.prototype.fixOrder = function(){
  885. var compareFunc = function(a,b){
  886. var s1=a.toLowerCase(), s2=b.toLowerCase();
  887. if (s1.contains(s2)) return -1; //when a contains b, a must come first
  888. else if (s2.contains(s1)) return 1 //when b contains a, b must come first
  889. else return 0; //no order change is required
  890. };
  891. this.sort(compareFunc);
  892. return this;
  893. };
  894.  
  895. //alias for the previous function
  896. sandbox.Array.prototype.optimize = sandbox.Array.prototype.fixOrder;
  897.  
  898. //returns a shallow copy of the calling array
  899. sandbox.Array.prototype.clone = function(){try{
  900. return this.slice(0);
  901. }catch(e){log("wmLibrary.Array.prototype.clone: "+e);}};
  902.  
  903. //reverses the elements of an array
  904. //with optional startIndex
  905. //and optional count which limits the reverse section
  906. //if startIndex+count is greater than the length of the array
  907. //then only the available section is reversed
  908. //returns the calling array
  909. sandbox.Array.prototype.reverse = function(startIndex,count){try{
  910. startIndex=startIndex||0;
  911. if (startIndex>=this.length) {
  912. //log("wmLibrary.Array.prototype.reverse: Error: startIndex out of bounds");
  913. return -1;
  914. }
  915. if (exists(count) && count<1) {
  916. //log("wmLibrary.Array.prototype.reverse: Error: count is less than 1");
  917. return -1;
  918. }
  919. var endIndex=(exists(count))?startIndex+count:this.length-1;
  920. if (endIndex>this.length-1) endIndex=this.length-1;
  921. while (startIndex>endIndex){
  922. this.swap(startIndex,endIndex);
  923. startIndex++;
  924. endIndex--;
  925. }
  926. return this;
  927. }catch(e){log("wmLibrary.Array.prototype.reverse: "+e);}};
  928.  
  929. //sets a range of elements in the array to the defaultValue
  930. //returns the calling array
  931. sandbox.Array.prototype.clear = function(startIndex,count,defaultValue){try{
  932. if (count>0 && this.length>startIndex) {
  933. for (var i=startIndex,len=this.length; (i<len && i<(startIndex+count)); i++){
  934. this[i]=defaultValue;
  935. }
  936. }
  937. return this;
  938. }catch(e){log("wmLibrary.Array.prototype.clear: "+e);}};
  939.  
  940. //copies elements from this array to a destination destArray
  941. //starting in this array at sourceIndex
  942. //and pasting into the destArray at destIndex
  943. //where length is the number of elements to copy
  944. //pasting beyond the higher bounds of the destArray simply increases the array size
  945. //returns the calling array
  946. sandbox.Array.prototype.copy = function(sourceIndex,destArray,destIndex,length){try{
  947. if (!isArray(destArray)) {
  948. log("wmLibrary.Array.prototype.copy: Error: destArray is not an array");
  949. return this;
  950. }
  951. if (sourceIndex >= this.length) {
  952. //log("wmLibrary.Array.prototype.copy: Error: sourceIndex out of bounds");
  953. return this;
  954. }
  955. for (var i=0; i<length; i++){
  956. destArray[destIndex+i]=this[sourceIndex+i];
  957. }
  958. return this;
  959. }catch(e){log("wmLibrary.Array.prototype.copy: "+e);}};
  960.  
  961. //copies all elements from this array to a destination destArray
  962. //pasting into the destArray at destIndex
  963. //pasting beyond the higher bounds of the destArray simply increases the array size
  964. //returns the calling array
  965. sandbox.Array.prototype.copyTo = function(destArray,destIndex){try{
  966. if (!isArray(destArray)) {
  967. log("wmLibrary.Array.prototype.copyTo: Error: destArray is not an array");
  968. return this;
  969. }
  970. for (var i=0, len=this.length; i<len; i++){
  971. destArray[destIndex+i]=this[i];
  972. }
  973. return this;
  974. }catch(e){log("wmLibrary.Array.prototype.copyTo: "+e);}};
  975.  
  976. //returns an array containing elements from the current array where the element has parameter p equal to value v
  977. 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);}};
  978.  
  979. //returns the element matched by matchFunc, or null
  980. //with optional start index
  981. //and optional count to limit the number of searched elements
  982. sandbox.Array.prototype.find = function(matchFunc,startIndex,count) {try{
  983. startIndex=startIndex||0;
  984. if (startIndex>=this.length) {
  985. //log("wmLibrary.Array.prototype.find: Error: startIndex out of bounds");
  986. return null;
  987. }
  988. if (exists(count) && count<1) {
  989. //log("wmLibrary.Array.prototype.find: Error: count is less than 1");
  990. return null;
  991. }
  992. var c=0;
  993. for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
  994. c++;
  995. if (matchFunc(this[i])) {
  996. return this[i];
  997. break;
  998. }
  999. }
  1000. return null;
  1001. }catch(e){log("wmLibrary.Array.prototype.find: "+e);}};
  1002.  
  1003. //returns the index of element matched by matchFunc, or -1
  1004. //with optional startIndex
  1005. //and optional count which specifies the number of elements to check
  1006. sandbox.Array.prototype.findIndex = function(matchFunc,startIndex,count) {try{
  1007. startIndex=startIndex||0;
  1008. if (startIndex>=this.length) {
  1009. //log("wmLibrary.Array.prototype.findIndex: Error: startIndex out of bounds");
  1010. return -1;
  1011. }
  1012. if (exists(count) && count<1) {
  1013. //log("wmLibrary.Array.prototype.findIndex: Error: count is less than 1");
  1014. return -1;
  1015. }
  1016. var c=0;
  1017. for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
  1018. c++;
  1019. if (matchFunc(this[i])) {
  1020. return i;
  1021. break;
  1022. }
  1023. }
  1024. return -1;
  1025. }catch(e){log("wmLibrary.Array.prototype.findIndex: "+e);}};
  1026.  
  1027. //returns all elements matched by matchFunc, or null
  1028. //with optional start index
  1029. //and optional count to limit the number of elements searched
  1030. sandbox.Array.prototype.findAll = function(matchFunc,startIndex,count) {try{
  1031. startIndex=startIndex||0;
  1032. var ret=[];
  1033. if (startIndex>=this.length) {
  1034. //log("wmLibrary.Array.prototype.findAll: Error: startIndex out of bounds");
  1035. return null;
  1036. }
  1037. if (exists(count) && count<1) {
  1038. //log("wmLibrary.Array.prototype.findAll: Error: count is less than 1");
  1039. return null;
  1040. }
  1041. var c=0;
  1042. for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
  1043. c++;
  1044. if (matchFunc(this[i])) {
  1045. ret.push(this[i]);
  1046. }
  1047. }
  1048. return (isArrayAndNotEmpty(ret))?ret:null;
  1049. }catch(e){log("wmLibrary.Array.prototype.findAll: "+e);}};
  1050.  
  1051. //returns true if all elements in the array match the matchFunc
  1052. //with optional start index
  1053. //and optional count to limit the number of elements searched
  1054. sandbox.Array.prototype.trueForAll = function(matchFunc,startIndex,count) {try{
  1055. startIndex=startIndex||0;
  1056. if (startIndex>=this.length) {
  1057. //log("wmLibrary.Array.prototype.trueForAll: Error: startIndex out of bounds");
  1058. return false;
  1059. }
  1060. if (exists(count) && count<1) {
  1061. //log("wmLibrary.Array.prototype.trueForAll: Error: count is less than 1");
  1062. return false;
  1063. }
  1064. var c=0;
  1065. for (var i=startIndex,len=this.length; (i<len && (!exists(count) || (exists(count) && c<count))); i++){
  1066. c++;
  1067. if (!matchFunc(this[i])) {
  1068. return false;
  1069. }
  1070. }
  1071. return true;
  1072. }catch(e){log("wmLibrary.Array.prototype.trueForAll: "+e);}};
  1073.  
  1074. //returns true if array contains an element matched by the matchFunc
  1075. //with optional startIndex
  1076. //and optional count which specifies the number of elements to check
  1077. sandbox.Array.prototype.exists = function(matchFunc,startIndex,count) {try{
  1078. return this.findIndex(matchFunc,startIndex,count)!=-1;
  1079. }catch(e){log("wmLibrary.Array.prototype.exists: "+e);}};
  1080.  
  1081. //returns the last element matched by matchFunc, or null
  1082. //with optional start index
  1083. //and optional count to limit the number of searched elements
  1084. sandbox.Array.prototype.findLast = function(matchFunc,startIndex,count) {try{
  1085. startIndex=startIndex||0;
  1086. if (startIndex>=this.length) {
  1087. //log("wmLibrary.Array.prototype.findLast: Error: startIndex out of bounds");
  1088. return null;
  1089. }
  1090. if (exists(count) && count<1) {
  1091. //log("wmLibrary.Array.prototype.findLast: Error: count is less than 1");
  1092. return null;
  1093. }
  1094. var c=0;
  1095. for (var i=this.length; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i--){
  1096. c++;
  1097. if (matchFunc(this[i])) {
  1098. return this[i];
  1099. break;
  1100. }
  1101. }
  1102. return null;
  1103. }catch(e){log("wmLibrary.Array.prototype.findLast: "+e);}};
  1104.  
  1105. //returns the last element matched by matchFunc, or -1
  1106. //with optional start index
  1107. //and optional count which specifies the number of elements to check
  1108. sandbox.Array.prototype.findLastIndex = function(matchFunc,startIndex,count) {try{
  1109. startIndex=startIndex||0;
  1110. if (startIndex>=this.length) {
  1111. //log("wmLibrary.Array.prototype.findLastIndex: Error: startIndex out of bounds");
  1112. return -1;
  1113. }
  1114. if (exists(count) && count<1) {
  1115. //log("wmLibrary.Array.prototype.findLastIndex: Error: count is less than 1");
  1116. return -1;
  1117. }
  1118. var c=0;
  1119. for (var i=this.length; (i>=startIndex && (!exists(count) || (exists(count) && c<count))); i--){
  1120. c++;
  1121. if (matchFunc(this[i])) {
  1122. return i;
  1123. break;
  1124. }
  1125. }
  1126. return -1;
  1127. }catch(e){log("wmLibrary.Array.prototype.findLastIndex: "+e);}};
  1128.  
  1129. //***************************************************************************************************************************************
  1130. //***** JSON/OBJECT Construction and Matching
  1131. //***************************************************************************************************************************************
  1132.  
  1133. //returns the merge of any number of JSON objects passed as unnamed arguments
  1134. sandbox.mergeJSON_long = function(){try{
  1135. var ret = {};
  1136. //for each JSON object passed
  1137. for (var a=0,len=arguments.length;a<len;a++) {
  1138. //for each element in that object
  1139. for (var v in arguments[a]) {
  1140. if (!exists(ret[v])) {
  1141. //simply copy the element to the return value
  1142. ret[v] = arguments[a][v];
  1143. } else {
  1144. if ((typeof arguments[a][v])=="object") {
  1145. //merge the two elements, preserving tree structure
  1146. ret[v] = mergeJSON(ret[v], arguments[a][v]);
  1147. } else {
  1148. //overwrite simple variable
  1149. ret[v] = arguments[a][v];
  1150. }
  1151. }
  1152. }
  1153. }
  1154. //the problem here is that its way too recursive and jams firefox often
  1155. return ret;
  1156. }catch(e){log("wmLibrary.mergeJSON: "+e);}};
  1157.  
  1158. sandbox.mergeJSON = function(){try{
  1159. var ret = {};
  1160. //for each JSON object passed
  1161. for (var a=0,len=arguments.length;a<len;a++) {
  1162. var o=arguments[a];
  1163. //for each element in that object
  1164. for (var v in o) {
  1165. //replace the initial element with that of the next
  1166. ret[v] = o[v];
  1167. }
  1168. //the problem here is that only the top level branches are preserved
  1169. }
  1170. return ret;
  1171. }catch(e){log("wmLibrary.mergeJSON: "+e);}};
  1172.  
  1173. //returns all members of an array that have a specified parameter with a specified value
  1174. //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);}};
  1175. //returns all members of an array that have a specified parameter with a specified value
  1176. //now accepts input of array or object
  1177. //can now specify output of array or object
  1178. sandbox.matchByParam=function(o,param,value,outputType){try{
  1179. if(!exists(outputType)) outputType="array";
  1180. var inputType=(isArray(o))?"array":((typeof o) == "object")?"object":"unknown";
  1181. var ret=(outputType=="object")?{}:[]; //default to array on error
  1182.  
  1183. switch(inputType){
  1184. case "array": for (var i=0,e;(e=o[i]);i++){
  1185. switch(outputType){
  1186. case "array": if (e[param]==value) ret.push(e); break;
  1187. case "object": if (e[param]==value) ret[i]=e; break;
  1188. }
  1189. };break;
  1190.  
  1191. case "object": for (var i in o){
  1192. var e=o[i];
  1193. switch(outputType){
  1194. case "array": if (e[param]==value) ret.push(e); break;
  1195. case "object": if (e[param]==value) ret[i]=e; break;
  1196. }
  1197. };break;
  1198. }
  1199. return ret;
  1200. }catch(e){log("wmLibrary.matchByParam: "+e);}};
  1201.  
  1202. //sorts the methods of an object by method 'id' or method 'value'
  1203. //beware this may mangle some objects
  1204. sandbox.sortCollection=function(o,by){
  1205. var a=[];
  1206. for (var i in o){
  1207. a.push({id:i,value:o[i]});
  1208. }
  1209. a.sort(function(a,b){return a[by]>b[by];});
  1210. var ret={};
  1211. for (var i=0;i<a.length;i++){
  1212. ret[a[i].id]=a[i].value;
  1213. }
  1214. return ret;
  1215. };
  1216.  
  1217. // Collect all the values from parameter p in object o, traversing kids nodes
  1218. sandbox.getBranchValues=function(o,p){try{
  1219. var ret={};
  1220. for(var i in o) {
  1221. //get value p for object o's element i
  1222. if (p=="id"){ //special case for fetching a list of ID's
  1223. if (exists(o[i][p])) ret[i]=o[i][p];
  1224. else ret[i]=i;
  1225. } else if (p=="."){ //special case for fetching a list of all objects without a tree structure
  1226. ret[i]=o[i];
  1227. }
  1228.  
  1229. else if (exists(o[i][p])) ret[i]=o[i][p];
  1230. //if object o has kids, then get all the values p inside that kid k
  1231. if (o[i].kids) ret=mergeJSON(ret,getBranchValues(o[i].kids,p));
  1232. }
  1233. return ret;
  1234. }catch(e){log("wmLibrary.getBranchValues: "+e);}};
  1235.  
  1236. //convert an object's methods to an array, storing the method's key on the object as an id
  1237. 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);}};
  1238.  
  1239. //convert an array of objects to methods of an object using either the object's ai or name as its key
  1240. 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);}};
  1241.  
  1242. //convert an object's methods to an array of those method names
  1243. sandbox.methodNames = function(o) {try{var ret=[]; for (i in o) ret.push(i); return ret;}catch(e){log("wmLibrary.methodNames: "+e);}};
  1244.  
  1245. //copy parts from one object to another
  1246. //used for extending one object with parts from another
  1247. //by John Resig
  1248. sandbox.extend = function(a,b) {try{
  1249. for ( var i in b ) {
  1250. //collect setter/getter functions
  1251. var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
  1252. //copy setter/getter functions
  1253. if ( g || s ) {
  1254. if ( g ) a.__defineGetter__(i, g);
  1255. if ( s ) a.__defineSetter__(i, s);
  1256. } else a[i] = b[i]; //copy vars
  1257. }
  1258. return a;
  1259. }catch(e){log("wmLibrary.extend: "+e);}};
  1260.  
  1261. //***************************************************************************************************************************************
  1262. //***** WM Specific Functions
  1263. //***************************************************************************************************************************************
  1264.  
  1265. //returns an object suitable for accText data based on an array, and allowing an idPrefix and textSuffix
  1266. sandbox.createAccTextFromArray=function(arr,keyPrefix,textSuffix){
  1267. var ret={};
  1268. if (arr) {
  1269. for (var i=0,len=arr.length;i<len;i++){
  1270. o=arr[i];
  1271. ret[(keyPrefix||'')+o.noSpaces().toLowerCase()]=o.upperWords()+(textSuffix||'');
  1272. }
  1273. }
  1274. return ret;
  1275. };
  1276.  
  1277. //writes a message to the hash section of the document location, or redirects to a location that can accept a new hash section
  1278. sandbox.sendMessage=function(s,hwnd,flag){try{
  1279. hwnd = (hwnd||window.top);
  1280. if (exists(hwnd)) try {hwnd.location.hash = s;} catch(e){
  1281. if (flag==1) hwnd.location.href = "http://apps.facebook.com/?#"+s;
  1282. else hwnd.location.href = "http://www.facebook.com/reqs.php?#"+s;
  1283. }
  1284. }catch(e){log("wmLibrary.sendMessage: "+e);}};
  1285.  
  1286. //flags for menu building function
  1287. sandbox.MENU_ID_ENFORCE_NAME=1; //causes menuFromData to return lowercase nospace names as the id instead of the calculated id
  1288.  
  1289. //inserts one or more menu option blocks based upon a data object
  1290. //marking all new items in the newitem list above as green so users can easily find your changes
  1291. sandbox.menuFromData=function(data,menuNode,newItemList,idPrefix,flags){try{
  1292. flags=(flags||0); newItemList=(newItemList||[]);
  1293. if (data) for (var m=0,len=data.length; m<len; m++) {
  1294. var text = data[m]["name"].upperWords(), event = (data[m]["event"]||"Unsorted").upperWords();
  1295. var outid = (flags==MENU_ID_ENFORCE_NAME)?data[m].name.noSpaces().toLowerCase():(data[m]["id"]||data[m]["name"]).noSpaces().toLowerCase();
  1296. var thisMenu; if( !(thisMenu=(menuNode["optblock"+event]||null) ) ) {thisMenu=(menuNode["optblock"+event]={type:"optionblock",label:event,kids:{} });}
  1297. thisMenu.kids[idPrefix+outid]={type:"checkbox",label:text,newitem:newItemList.inArray(idPrefix+outid)};
  1298. }
  1299. }catch(e){log("wmLibrary.menuFromData: "+e);}};
  1300.  
  1301. //returns a list of search strings from a data object containing id's names and events, already optimized for searching
  1302. sandbox.searchFromData=function(data,idPrefix){try{
  1303. idPrefix=(idPrefix||"");
  1304. var ret = [];
  1305. for (var m=0,mat;(mat=data[m]);m++){
  1306. ret.push(idPrefix+(mat.id||mat.name));
  1307. }
  1308. ret.optimize();
  1309. return ret;
  1310. }catch(e){log("wmLibrary.searchFromData: "+e);}};
  1311.  
  1312. //returns a list of materials from a data object containing id's names and events, already optimized for searching
  1313. sandbox.matListFromData=function(data){try{
  1314. var ret = [];
  1315. for (var m=0,mat;(mat=data[m]);m++){
  1316. ret.push(mat.name);
  1317. } ret.optimize();
  1318. return ret;
  1319. }catch(e){log("wmLibrary.matListFromData: "+e);}};
  1320.  
  1321. //returns a valid accText object from a data object containing id's names and events
  1322. 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);}};
  1323.  
  1324. //***************************************************************************************************************************************
  1325. //***** Sidekick Object
  1326. //***************************************************************************************************************************************
  1327.  
  1328. //sidekick specific functions
  1329. sandbox.Sidekick={
  1330. //init
  1331. tabID:null,
  1332. status:0,
  1333. nopopLink:"",
  1334.  
  1335. //attempts to dock the sidekick script to the wm host script
  1336. //params takes an object that contains the following parameters:
  1337. //appID(string), version(string), skType(integer),
  1338. //name(string), thumbSource(string or array),
  1339. //flags(object), icon(string), desc(string),
  1340. //addFilters(object),
  1341. //alterLink(object), accText(object),
  1342. //tests(array) and menu(object)
  1343. dock: function(params){try{
  1344. //find the dock node on this page
  1345. var door=$('wmDock');
  1346. if (!door) {
  1347. //does not exist, wait and try again later
  1348. window.setTimeout(function(){Sidekick.dock(params);}, 1000);
  1349. return;
  1350. }
  1351. //detect if a sidekick for this app is already docked
  1352. var doorMark=$('wmDoor_app'+params.appID);
  1353. if (doorMark && (params.skType==doorMark.getAttribute("value")) ) {
  1354. //a sidekick of this level is already here, cancel docking
  1355. return;
  1356. }
  1357. //setup defaults for a few of the expected parameters
  1358. params.thumbsSource=(params.thumbsSource||"app_full_proxy.php?app"+params.appID);
  1359. params.desc=(params.desc||params.name+" Sidekick (ver "+params.version+")");
  1360.  
  1361. //create a block of data to attach to the dock
  1362. var attString=JSON.stringify(params);
  1363. door.appendChild(
  1364. doorMark=createElement('div',{id:'wmDoor_app'+params.appID,'data-ft':attString,value:(params.skType||0)})
  1365. );
  1366. //doorMark.setAttribute("skType",(params.skType||0));
  1367. //confirm(doorMark.getAttribute("skType"));
  1368. //ring the buzzer so the host knows the package is ready
  1369. window.setTimeout(function(){click(door);},1000);
  1370. }catch(e){log("wmLibrary.Sidekick.dock: "+e);}},
  1371. //receive and process messages
  1372. //msg code 1 is a packet from the wm host containing data about the post we are processing
  1373. //that packet must contain at least the tab/window ID with which the WM host can access that tab again
  1374. //msg code 3 is a packet from this or a deeper iframe window about the return value for this post
  1375. //because Chrome returns NULL at event.source on msg 1, we now have to rethink
  1376. receiveMessage: function(event) {try{
  1377. if (isObject(event.data)) {
  1378. var data=event.data; //just shorten the typing
  1379. if (data.channel=="WallManager"){
  1380. log(JSON.stringify(data));
  1381. switch (data.msg) {
  1382. case 1: //get init data from wm host
  1383. //if (!Sidekick.tabID)
  1384. Sidekick.tabID=data.tabID;
  1385. log("Sidekick hears host...");
  1386. //
  1387. break;
  1388. case 3: //get message from child
  1389. if (Sidekick.tabID) {
  1390. log("Sidekick hears iframe...");
  1391. //send our status packet back to wm
  1392. Sidekick.status=data.status;
  1393. Sidekick.nopopLink=data.nopopLink||null;
  1394. //update the stored data about this post
  1395. var skChannel = getOptJSON("skChannel")||{};
  1396. skChannel[Sidekick.tabID]={
  1397. tabID:Sidekick.tabID,
  1398. status:Sidekick.status,
  1399. nopopLink:Sidekick.nopopLink,
  1400. };
  1401. log(JSON.stringify(skChannel));
  1402. setOptJSON("skChannel",skChannel);
  1403. } else {
  1404. //have not yet recieved tabID package from wm, wait a sec
  1405. setTimeout(function(){Sidekick.receiveMessage(event);},1000);
  1406. }
  1407. break;
  1408. }
  1409. }
  1410. }
  1411. }catch(e){log("wmLibrary.Sidekick.receiveMessage: "+e);}},
  1412.  
  1413. //disable the listener started below
  1414. unlisten: function(params){try{
  1415. window.removeEventListener("message", Sidekick.receiveMessage, false);
  1416. }catch(e){log("wmLibrary.Sidekick.unlisten: "+e);}},
  1417. //turn on the listener which can receive messages from wm host (if this window = window.top) or from iframes
  1418. listen: function(params){try{
  1419. window.addEventListener("message", Sidekick.receiveMessage, false);
  1420. }catch(e){log("wmLibrary.Sidekick.listen: "+e);}},
  1421.  
  1422. //listen for changes to the skChannel variable and report those changes to WM whenever docked
  1423. openChannel: function(){try{
  1424. var dump=$("wmDataDump");
  1425. if (dump) {
  1426. var skData=getOpt("skChannel");
  1427. setOpt("skChannel","");
  1428. if (skData) dump.appendChild(createElement('div',{'data-ft':skData}));
  1429. }
  1430. setTimeout(Sidekick.openChannel,1000);
  1431. }catch(e){log("wmLibrary.Sidekick.openChannel: "+e);}},
  1432.  
  1433. //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
  1434. sendStatus: function(status,link){try{
  1435. if (exists(window.top)) {
  1436. window.top.postMessage({
  1437. channel:"WallManager",
  1438. msg:3,
  1439. status:status,
  1440. nopopLink:(link?link:''),
  1441. },"*");
  1442. } else {
  1443. //window.top is hidden to us from this location
  1444. contentEval('window.top.postMessage({"channel":"WallManager","msg":3,"status":'+status+',"link":"'+(link?link:'')+'"},"*");');
  1445. }
  1446. }catch(e){log("wmLibrary.Sidekick.sendStatus: "+e);}},
  1447. };
  1448.  
  1449. //***************************************************************************************************************************************
  1450. //***** Visual Effects
  1451. //***************************************************************************************************************************************
  1452.  
  1453. //slides element e toward the specified destination offset
  1454. //specify [t, l, r, b] top, left, right, and bottom as the final offset
  1455. //specify s as the number of MS the move should loop on
  1456. //specify p as the number of pixels to move per interval
  1457. sandbox.slide=function(e,t,l,r,b,s,p) {try{
  1458. s=s||50;p=p||10;
  1459.  
  1460. var top= e.style.top; top=parseInt(top); top=(isNaN(top))?0:top;
  1461. var bottom = e.style.bottom; bottom=parseInt(bottom); bottom=(isNaN(bottom))?0:bottom;
  1462. var left= e.style.left; left=parseInt(left); left=(isNaN(left))?0:left;
  1463. var right = e.style.right; right=parseInt(right); right=(isNaN(right))?0:right;
  1464.  
  1465. p1=(p>Math.abs(t))?Math.abs(t):p;
  1466. if(t>0) {e.style.top = (top+p1)+"px";t-=p1;}
  1467. else if (t<0) {e.style.top = (top-p1)+"px";t+=p1;}
  1468.  
  1469. p1=(p>Math.abs(l))?Math.abs(l):p;
  1470. if(l>0) {e.style.left = (left+p1)+"px";l-=p1;}
  1471. else if (l<0) {e.style.left = (left-p1)+"px";l+=p1;}
  1472.  
  1473. p1=(p>Math.abs(r))?Math.abs(r):p;
  1474. if(r>0) {e.style.right = (right+p1)+"px";r-=p1;}
  1475. else if (r<0) {e.style.right = (right-p1)+"px";r+=p1;}
  1476.  
  1477. p1=(p>Math.abs(b))?Math.abs(b):p;
  1478. if(b>0) {e.style.bottom = (bottom+p1)+"px";b-=p1;}
  1479. else if (b<0) {e.style.bottom = (bottom-p1)+"px";b+=p1;}
  1480.  
  1481. if (t!=0||l!=0||r!=0||b!=0) window.setTimeout(function(){slide(e,t,l,r,b,s,p);},s);
  1482. }catch(e){log("wmLibrary.slide: "+e);}};
  1483.  
  1484. //***************************************************************************************************************************************
  1485. //***** URL Encode/Decode
  1486. //***************************************************************************************************************************************
  1487.  
  1488. //url encode/decode functions nicely wrapped from webtoolkit
  1489. sandbox.Url = {
  1490. // public method for url encoding
  1491. encode : function (string) {try{return escape(this._utf8_encode(string));}catch(e){log("wmLibrary.Url.encode: "+e);}},
  1492. // public method for url decoding
  1493. decode : function (string) {try{return this._utf8_decode(unescape(string));}catch(e){log("wmLibrary.Url.decode: "+e);}},
  1494. // private method for UTF-8 encoding
  1495. _utf8_encode : function (string) {
  1496. string = string.replace(/\r\n/g,"\n");
  1497. var utftext = "";
  1498. for (var n = 0; n < string.length; n++) {
  1499. var c = string.charCodeAt(n);
  1500.  
  1501. if (c < 128) {
  1502. utftext += String.fromCharCode(c);
  1503. }
  1504. else if((c > 127) && (c < 2048)) {
  1505. utftext += String.fromCharCode((c >> 6) | 192);
  1506. utftext += String.fromCharCode((c & 63) | 128);
  1507. }
  1508. else {
  1509. utftext += String.fromCharCode((c >> 12) | 224);
  1510. utftext += String.fromCharCode(((c >> 6) & 63) | 128);
  1511. utftext += String.fromCharCode((c & 63) | 128);
  1512. }
  1513. }
  1514. return utftext;
  1515. },
  1516. // private method for UTF-8 decoding
  1517. _utf8_decode : function (utftext) {
  1518. var string = "";
  1519. var i = 0;
  1520. var c = c1 = c2 = 0;
  1521. while ( i < utftext.length ) {
  1522. c = utftext.charCodeAt(i);
  1523. if (c < 128) {
  1524. string += String.fromCharCode(c);
  1525. i++;
  1526. }
  1527. else if((c > 191) && (c < 224)) {
  1528. c2 = utftext.charCodeAt(i+1);
  1529. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  1530. i += 2;
  1531. }
  1532. else {
  1533. c2 = utftext.charCodeAt(i+1);
  1534. c3 = utftext.charCodeAt(i+2);
  1535. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  1536. i += 3;
  1537. }
  1538. }
  1539. return string;
  1540. }
  1541. };
  1542.  
  1543. //***************************************************************************************************************************************
  1544. //***** GM Local Storage Commands
  1545. //***************************************************************************************************************************************
  1546.  
  1547. // set an option
  1548. sandbox.setOpt=function(opt,value){try{GM_setValue(opt,value);}catch(e){log("wmLibrary.setOpt: "+e);}}
  1549.  
  1550. // Get a stored option
  1551. sandbox.getOpt=function(opt){try{return GM_getValue(opt);}catch(e){log("wmLibrary.getOpt: "+e);}}
  1552.  
  1553. // set an option
  1554. sandbox.setOptJSON=function(opt,value){try{GM_setValue(opt,JSON.stringify(value));}catch(e){log("wmLibrary.setOptJSON: "+e);}}
  1555.  
  1556. // Get a stored option
  1557. 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);}}
  1558.  
  1559.  
  1560. //***************************************************************************************************************************************
  1561. //***** 2D Math
  1562. //***************************************************************************************************************************************
  1563.  
  1564. // add two points or vectors
  1565. sandbox.addPoints = function(p0, p1){try{
  1566. var p2=mergeJSON(p0); //copy p0
  1567. for (var v in p1) p2[v]=(p2[v]||0)+(p1[v]||0);
  1568. return p2;
  1569. }catch(e){log("wmLibrary.addPoints: "+e);}},
  1570.  
  1571. //***************************************************************************************************************************************
  1572. //***** Delays and Repeaters
  1573. //***************************************************************************************************************************************
  1574.  
  1575. // shortform for window.setTimeout(x,0)
  1576. sandbox.doAction = function(f) {try{setTimeout(f,0);}catch(e){log("doAction: "+e);}};
  1577.  
  1578. //repeat a function fn a number of times n with a delay of 1 second between calls
  1579. sandbox.signal = function(fn,n){try{
  1580. if (n>0) {
  1581. doAction(fn);
  1582. setTimeout(function(){signal(fn,n-1);},1000);
  1583. }
  1584. }catch(e){log("wmLibrary.signal: "+e);}};
  1585.  
  1586. //***************************************************************************************************************************************
  1587. //***** Enum Creation
  1588. //***************************************************************************************************************************************
  1589.  
  1590. // create an unprotected enumeration list
  1591. sandbox.Enum = function() {try{for (var i in arguments) {this[arguments[i]] = i;}}catch(e){log("Enum.init: "+e);}};
  1592.  
  1593. //create an unprotected enumeration list of binary flags
  1594. sandbox.EnumFlags = function() {try{for (var i in arguments) {this[arguments[i]] = Math.pow(2,i);}}catch(e){log("EnumFlags.init: "+e);}};
  1595.  
  1596. //***************************************************************************************************************************************
  1597. //***** Pop-ups
  1598. //***************************************************************************************************************************************
  1599.  
  1600. //create a centered iframe to display multiline text in a textarea
  1601. //with optional isJSON flag which will format JSON strings with indents and linebreaks
  1602. sandbox.promptText = function(s,isJSON){try{
  1603. if (isJSON) s=s.formatJSON(4);
  1604. var newFrame;
  1605. 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;'})));
  1606. newFrame.src = 'about:blank'; // In WebKit src cant be set until it is added to the page
  1607. newFrame.addEventListener('load', function(){
  1608. var frameBody = this.contentDocument.getElementsByTagName('body')[0];
  1609. var close=function(){try{
  1610. remove(newFrame);
  1611. delete newFrame;
  1612. }catch(e){log("wmLibrary.promptText.close: "+e);}};
  1613. // Add save and close buttons
  1614. frameBody.appendChild(
  1615. createElement("textArea",{textContent:s,style:"height:90%;width:100%;"})
  1616. );
  1617. frameBody.appendChild(
  1618. createElement("div", {id:"buttons_holder"}, [
  1619. createElement('button',{id:"closeBtn", textContent:"Close",title:"Close window",onclick:close}),
  1620. ])
  1621. );
  1622. var center=function(){try{
  1623. var style=newFrame.style;
  1624. var node=newFrame;
  1625. style.display = '';
  1626. style.top = Math.floor((window.innerHeight/2)-(node.offsetHeight/2)) + 'px';
  1627. style.left = Math.floor((window.innerWidth/2)-(node.offsetWidth/2)) + 'px';
  1628. }catch(e){log("wmLibrary.promptText.center: "+e);}};
  1629. center();
  1630. window.addEventListener('resize', center, false); // Center it on resize
  1631.  
  1632. // Close frame on window close
  1633. window.addEventListener('beforeunload', function(){newFrame.remove(this);}, false);
  1634. }, false);
  1635. }catch(e){log("wmLibrary.promptText: "+e);}};
  1636.  
  1637. //***************************************************************************************************************************************
  1638. //***** Text To Script
  1639. //***************************************************************************************************************************************
  1640.  
  1641. //force code to be run outside the GM sandbox
  1642. sandbox.contentEval = function(source) {try{
  1643. // Check for function input.
  1644. if ('function' == typeof source) {
  1645. // Execute this function with no arguments, by adding parentheses.
  1646. // One set around the function, required for valid syntax, and a
  1647. // second empty set calls the surrounded function.
  1648. source = '(' + source + ')();'
  1649. }
  1650.  
  1651. // Create a script node holding this source code.
  1652. var script = document.createElement('script');
  1653. script.setAttribute("type", "application/javascript");
  1654. script.textContent = source;
  1655.  
  1656. // Insert the script node into the page, so it will run, and immediately
  1657. // remove it to clean up.
  1658. document.body.appendChild(script);
  1659. document.body.removeChild(script);
  1660. }catch(e){log("wmLibrary.contentEval: "+e);}};
  1661.  
  1662. //***************************************************************************************************************************************
  1663. //***** RegExp Construction
  1664. //***************************************************************************************************************************************
  1665.  
  1666. //convert an array to a pipe delimited RegExp group
  1667. sandbox.arrayToRegExp = function(a) {try{
  1668. var ret="";
  1669. if (isArrayAndNotEmpty(a)) {
  1670. ret="(";
  1671. for (var i=0,len=a.length; i<len;i++){
  1672. ret=ret+a[i];
  1673. if (i<(len-1)) ret=ret+"|";
  1674. }
  1675. ret=ret+")";
  1676. }
  1677. return ret;
  1678. }catch(e){log("wmLibrary.arrayToRegExp: "+e);}};
  1679.  
  1680. //takes an integer range and converts it to a regular expression
  1681. //which can search for that number range in a string
  1682. sandbox.integerRangeToRegExp = function(params) {try{
  1683. params=params||{};
  1684. var min=params.min.toString(), max=params.max.toString();
  1685. var ret="";
  1686.  
  1687. //on the odd case that both min and max values were equal
  1688. if (max==min) return max;
  1689. //count shared digits we can omit from complex regexp
  1690. var numSharedDigits=0;
  1691. if (min.length==max.length) {
  1692. for (var n=max.length;n>0;n--){
  1693. if (max.substring(0,n) == min.substring(0,n)) {
  1694. numSharedDigits=n;
  1695. break;
  1696. }
  1697. }
  1698. }
  1699. var shared=max.substring(0,numSharedDigits);
  1700. //crop the min and max values
  1701. min=min.removePrefix(shared);
  1702. max=max.removePrefix(shared);
  1703.  
  1704. //move the shared stuff to the front of the test
  1705. ret+=shared+"(";
  1706.  
  1707. //count the digits
  1708. var minDigits=min.length;
  1709. var maxDigits=max.length;
  1710.  
  1711. //set some flags
  1712. var isSingleDigit=(minDigits==1 && maxDigits==1);
  1713. var isVariableDigits=(minDigits != maxDigits);
  1714. //using 1 to 4444 as a range
  1715. //calculate maximum range tests
  1716. //ie: 444x 44xx 4xxx
  1717. if (maxDigits>1){
  1718. ret+=max.substr(0,maxDigits-1)+"[0-"+max.substr(maxDigits-1,1)+"]";
  1719. for (var n=(maxDigits-2); n>0; n--) {
  1720. if (max.substr(n,1)!="0") {
  1721. ret+="|"+max.substr(0,n)+"[0-"+(val(max.substr(n,1))-1)+"]"+("\\d").repeat((maxDigits-1)-n);
  1722. }
  1723. }
  1724. }
  1725.  
  1726. //calculate intermediate range tests
  1727. //ie: 1xxx, 1xx, 1x
  1728. for (var n=maxDigits;n>1;n--){
  1729. //check if min and max both use this digit
  1730. if (minDigits==n && maxDigits==n) {
  1731. //as neither bound would be put out of range
  1732. //and the bounds are not equal
  1733. if ((min.substr(0,1)!="9") && (max.substr(0,1)!="1") && (val(max.substr(0,1))>(val(min.substr(0,1))+1))) {
  1734. ret+="|["+(val(min.substr(0,1))+1)+"-"+(val(max.substr(0,1))-1)+"]"+("\\d").repeat(n-1);
  1735. }
  1736. //detect if min uses this digit
  1737. } else if (minDigits==n) {
  1738. //as long as it does not start with 9
  1739. if (min.substr(0,1)!="9") {
  1740. ret+="|["+(val(min.substr(0,1))+1)+"-9]"+("\\d").repeat(n-1);
  1741. }
  1742. break;
  1743. //detect if max uses this digit
  1744. } else if (maxDigits==n) {
  1745. //as long as it does not start with 1
  1746. if (max.substr(0,1)!="1") {
  1747. ret+="|[1-"+(val(max.substr(0,1))-1)+"]"+("\\d").repeat(n-1);
  1748. }
  1749. } else {
  1750. //they do not use this digit
  1751. //is it BETWEEN their digit counts
  1752. if (n > minDigits) {
  1753. ret+="|[1-9]"+("\\d").repeat(n-1);
  1754. }
  1755. }
  1756. }
  1757. //calculate minimum range tests
  1758. //ie: [1-9]
  1759. if (minDigits>1){
  1760. ret+="|"+min.substr(0,minDigits-1)+"["+min.substr(minDigits-1,1)+"-9]";
  1761. for (var n=(minDigits-2); n>0; n--) {
  1762. if (min.substr(n,1)!="9") {
  1763. ret+="|"+min.substr(0,n)+"["+(val(min.substr(n,1))+1)+"-9]"+("[0-9]").repeat((minDigits-1)-n);
  1764. }
  1765. }
  1766. } else {
  1767. //single digit min
  1768. if (maxDigits>minDigits) {
  1769. ret+="|["+min+"-9]";
  1770. } else {
  1771. //both min and max are single digits
  1772. ret+="|["+min+"-"+max+"]";
  1773. }
  1774. }
  1775. //fix same start and end range issues
  1776. for (var i=0;i<=9;i++){
  1777. ret=ret.replace(new RegExp("\\["+i+"-"+i+"\\]","gi"),i);
  1778. }
  1779. ret=ret.replace(new RegExp("\\[0-9\\]","gi"),"\\d");
  1780. return ret+")";
  1781. }catch(e){log("wmLibrary.integerRangeToRegExp: "+e);}};
  1782.  
  1783. //***************************************************************************************************************************************
  1784. //***** Typing Simulation
  1785. //***************************************************************************************************************************************
  1786.  
  1787. sandbox.simulateKeyEvent = function(character,byCode) {
  1788. var evt = document.createEvent("KeyboardEvent");
  1789. (evt.initKeyEvent || evt.initKeyboardEvent)("keypress", true, true, window,
  1790. 0, 0, 0, 0,
  1791. 0, ((byCode||null) || character.charCodeAt(0)) )
  1792. var canceled = !body.dispatchEvent(evt);
  1793. if(canceled) {
  1794. // A handler called preventDefault
  1795. alert("canceled");
  1796. } else {
  1797. // None of the handlers called preventDefault
  1798. alert("not canceled");
  1799. }
  1800. };
  1801.  
  1802. sandbox.typeText = function(s) {
  1803. for (var i=0,len=s.length; i<len; i++){
  1804. simulateKeyEvent(s.substr(i,1));
  1805. log(s.substr(i,1));
  1806. }
  1807. };
  1808.  
  1809. sandbox.typeEnter = function() {
  1810. simulateKeyEvent(null,13);
  1811. };
  1812.  
  1813. /*formatting notes
  1814. format a number to x decimal places
  1815. number.toFixed(x);
  1816.  
  1817. convert to hexidecimal
  1818. number.toString(16);
  1819.  
  1820. //try something like this to get your own header details
  1821. define your own parseHeaders function
  1822. var fileMETA = parseHeaders(<><![CDATA[
  1823. // ==UserScript==
  1824. // @name My Script
  1825. // @namespace http://www.example.com/gmscripts
  1826. // @description Scripting is fun
  1827. // @copyright 2009+, John Doe (http://www.example.com/~jdoe)
  1828. // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
  1829. // @version 0.0.1
  1830. // @include http://www.example.com/*
  1831. // @include http://www.example.org/*
  1832. // @exclude http://www.example.org/foo
  1833. // @require foo.js
  1834. // @resource resourceName1 resource1.png
  1835. // @resource resourceName2 http://www.example.com/resource2.png
  1836. // @uso:script scriptid
  1837. // ==/UserScript==
  1838. ]]></>.toString());
  1839.  
  1840. //include jquery stuff
  1841. // ==UserScript==
  1842. // @name jQuery Example
  1843. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
  1844. // ==/UserScript==
  1845. */
  1846.  
  1847. //a custom collection wrapper
  1848. //this pretty much mimics collections in visual basic
  1849. //with a lot of collection methods added from other systems
  1850. var jsCollection=function(objOrArray){
  1851. var self=this;
  1852. this.items={};
  1853. //return an item from this collection by index or key
  1854. this.__defineGetter__("item",function(indexOrKey){try{
  1855. return this.items[indexOrKey]||null;
  1856. }catch(e){log("jsCollection.item: "+e);}});
  1857.  
  1858. //return the count of items in this collection
  1859. this.__defineGetter__("count",function(){try{
  1860. var ret=0;
  1861. for (var e in this.items) ret++;
  1862. return ret;
  1863. }catch(e){log("jsCollection.count: "+e);}});
  1864. //return true if the count of items in this collection is 0
  1865. this.__defineGetter__("isEmpty",function(){try{
  1866. return this.count==0;
  1867. }catch(e){log("jsCollection.isEmpty: "+e);}});
  1868.  
  1869. //remove all items from this collection
  1870. this.clear=function(){try{
  1871. while(this.items[0]) delete this.items[0];
  1872. }catch(e){log("jsCollection.clear: "+e);}};
  1873. //return the index of the first occurence of obj
  1874. this.indexOf=function(obj){try{
  1875. var c=0;
  1876. for (var i in this.items){
  1877. if (this.items[i]===obj) {
  1878. return c;
  1879. break;
  1880. }
  1881. c++;
  1882. }
  1883. return -1;
  1884. }catch(e){log("jsCollection.indexOf: "+e);}};
  1885.  
  1886. //return the key of the first occurence of obj
  1887. this.keyOf=function(obj){try{
  1888. for (var i in this.items){
  1889. if (this.items[i]===obj) {
  1890. return i;
  1891. break;
  1892. }
  1893. }
  1894. return -1;
  1895. }catch(e){log("jsCollection.keyOf: "+e);}};
  1896.  
  1897. //returns true if obj occurs in this collection
  1898. this.contains=function(obj){try{
  1899. return this.indexOf(obj)!=-1;
  1900. }catch(e){log("jsCollection.contains: "+e);}};
  1901. //returns true if an item in this collection has key = key
  1902. this.containsKey=function(key){try{
  1903. return exists(this.items[key]);
  1904. }catch(e){log("jsCollection.containsKey: "+e);}};
  1905.  
  1906. //remove an item from the collection by index or key
  1907. this.remove=function(indexOrKey){try{
  1908. delete this.items[indexOrKey];
  1909. }catch(e){log("jsCollection.remove: "+e);}};
  1910. //add an item to the collection
  1911. //with optional key which defaults to unique()
  1912. //with optional before which is an object to match
  1913. //with optional after which is an object to match
  1914. this.add=function(item,key,before,after){try{
  1915. key=key||unique();
  1916. if (before && this.indexOf(before)!=-1) {
  1917. var ret={};
  1918. for (var i in this.items){
  1919. if (this.items[i]===before) {
  1920. ret[key]=item;
  1921. }
  1922. ret[i]=this.items[i];
  1923. }
  1924. this.items=ret;
  1925. } else if (after && this.indexOf(after)!=-1) {
  1926. var ret={};
  1927. for (var i in this.items){
  1928. ret[i]=this.items[i];
  1929. if (this.items[i]===after) {
  1930. ret[key]=item;
  1931. }
  1932. }
  1933. this.items=ret;
  1934. } else {
  1935. this.items[key]=item;
  1936. }
  1937. }catch(e){log("jsCollection.add: "+e);}};
  1938. //shortform to add an item
  1939. //after an item
  1940. //with optional key
  1941. this.insertAfter=function(item,after,key){try{
  1942. this.add(item,key,null,after);
  1943. }catch(e){log("jsCollection.insertAfter: "+e);}};
  1944.  
  1945. //shortform to add an item
  1946. //before an item
  1947. //with optional key
  1948. this.insertBefore=function(item,before,key){try{
  1949. this.add(item,key,before,null);
  1950. }catch(e){log("jsCollection.insertBefore: "+e);}};
  1951. //shortform to add an item
  1952. //with optional key
  1953. this.append=function(item,key){try{
  1954. this.add(item,key);
  1955. }catch(e){log("jsCollection.append: "+e);}};
  1956. //shortform to add an item
  1957. //to the beginning of the collection
  1958. //with optional key
  1959. this.prepend=function(item,key){try{
  1960. this.add(item,key,(this.items[0]||null));
  1961. }catch(e){log("jsCollection.prepend: "+e);}};
  1962.  
  1963. //add an array of items
  1964. //with optional before and after
  1965. this.addRange=function(itemArray,before,after){try{
  1966. if (before && this.indexOf(before)!=-1) {
  1967. var ret={};
  1968. for (var i in this.items){
  1969. if (this.items[i]===before) {
  1970. for (var a=0,len=itemArrayLength;a<len;a++){
  1971. ret[unique()]=itemArray[a];
  1972. }
  1973. }
  1974. ret[i]=this.items[i];
  1975. }
  1976. this.items=ret;
  1977. } else if (after && this.indexOf(after)!=-1) {
  1978. var ret={};
  1979. for (var i in this.items){
  1980. ret[i]=this.items[i];
  1981. if (this.items[i]===after) {
  1982. for (var a=0,len=itemArrayLength;a<len;a++){
  1983. ret[unique()]=itemArray[a];
  1984. }
  1985. }
  1986. }
  1987. this.items=ret;
  1988. } else {
  1989. for (var a=0,len=itemArrayLength;a<len;a++){
  1990. this.items[unique()]=itemArray[a];
  1991. }
  1992. }
  1993. }catch(e){log("jsCollection.addRange: "+e);}};
  1994.  
  1995. //shortform to add an array of items
  1996. this.appendRange=function(itemArray){try{
  1997. this.addRange(itemArray);
  1998. }catch(e){log("jsCollection.appendRange: "+e);}};
  1999. //shortform to add an array of items
  2000. //to the beginning of the collection
  2001. this.prependRange=function(itemArray){try{
  2002. this.addRange(itemArray,(this.items[0]||null));
  2003. }catch(e){log("jsCollection.prependRange: "+e);}};
  2004.  
  2005. //add a copy of item
  2006. //with optional before or after
  2007. this.addCopy=function(item,before,after){try{
  2008. this.add(item,null,before,after);
  2009. }catch(e){log("jsCollection.addCopy: "+e);}};
  2010.  
  2011. //add multiple copies of item
  2012. //with optional before and after
  2013. this.addCopies=function(item,count,before,after){try{
  2014. var ret=[];
  2015. for (var i=0;i<count;i++) ret.push(item);
  2016. this.addRange(item,before,after);
  2017. }catch(e){log("jsCollection.addCopies: "+e);}};
  2018.  
  2019. //return the collection converted to an array
  2020. this.toArray=function(){try{
  2021. return methodsToArray(this.items);
  2022. }catch(e){log("jsCollection.toArray: "+e);}};
  2023.  
  2024. //return the index of item with key=key
  2025. this.indexOfKey=function(key){try{
  2026. return this.indexOf(this.items[key]||null);
  2027. }catch(e){log("jsCollection.indexOfKey: "+e);}};
  2028. //return the key of the item at index=index
  2029. this.keyOfIndex=function(index){try{
  2030. var c=0;
  2031. for (var i in this.items){
  2032. if (c==index) return i;
  2033. c++;
  2034. }
  2035. }catch(e){log("jsCollection.keyOfIndex: "+e);}};
  2036.  
  2037. //use passed data on creation to create initial items
  2038. if (objOrArray){
  2039. if (isArrayAndNotEmpty(objOrArray)){
  2040. for (var i=0,len=objOrArray.length;i<len;i++){
  2041. this.add(objOrArray[i],i);
  2042. }
  2043. } else if (isObject(objOrArray)) {
  2044. for (var i in objOrArray){
  2045. this.items[i]=objOrArray[i];
  2046. }
  2047. }
  2048. }
  2049. //return self for external use
  2050. return this;
  2051. };
  2052.  
  2053. sandbox.matchFunc_OnlyAlphaNumeric = function(s){
  2054. if (s.match(/[^a-zA-Z\d\s:]/g)) return false;
  2055. return true;
  2056. };
  2057.  
  2058. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址