WM Common Library

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

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/407/1284/WM%20Common%20Library.js

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

QingJ © 2025

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