Greasy Fork is available in English.

WM Host Object

This is the host object which is created under the WM version 4.x script

Ovu skriptu ne treba izravno instalirati. To je biblioteka za druge skripte koje se uključuju u meta direktivu // @require https://update.greatest.deepsurf.us/scripts/6908/28422/WM%20Host%20Object.js

  1. // ==UserScript==
  2. // @name WM Host Object
  3. // @namespace MerricksdadWMHostObject
  4. // @description This is the host object which is created under the WM version 4.x script
  5. // @license http://creativecommons.org/licenses/by-nc-nd/3.0/us/
  6. // @version 4.0.0.4
  7. // @copyright Charlie Ewing except where noted
  8. // ==/UserScript==
  9.  
  10. //this script requires some functions in the WM Common Library
  11. //this script needs access to a pre-defined JSON object
  12.  
  13.  
  14. (function(){
  15.  
  16. //*****short text versions for WM.config menu options*****
  17.  
  18. var checkBox=function(l,d,c,n){return ({type:"checkbox",label:l,"default":d||false,kids:c,newitem:n});}
  19. var hidden=function(l,d,c){return ({type:"hidden",label:l,"default":d,kids:c});}
  20. var optionBlock=function(l,c,hideSelectAll,n){hideSelectAll=hideSelectAll||false;return ({type:"optionblock",label:l,kids:c,hideSelectAll:hideSelectAll,newitem:n});}
  21. var separator=function(l,s,c,hideSelectAll){hideSelectAll=hideSelectAll||false; return ({type:"separator",label:l,section:s,kids:c}); }
  22. var section=function(l,c){return ({type:"section",label:l,kids:c});}
  23. var tabSection=function(l,c){return ({type:"tab",label:l,kids:c});}
  24. var inputBox=function(l,d,n){return ({type:"float",label:l,"default":(d||0),newitem:n});}
  25. var textArea=function(l,d,n){return ({type:"textarea",label:l,"default":(d||0),newitem:n});}
  26. var colorBox=function(l,d,n){return ({type:"colorbox",label:l,"default":(d||"black"),newitem:n});}
  27. var button=function(l,s){return ({type:"button",label:l,script:s});}
  28. var anchor=function(l,u,t){return ({type:"link",label:l,href:u,title:(t||'')});}
  29.  
  30. this.WallManager={
  31. paused : false,
  32. fetchPaused : false,
  33. requestsOpen : 0,
  34. reqTO : 30000, //request timeout default
  35. newSidekicks : [],
  36.  
  37. accDefaultText : "Got this!",
  38. failText : "Oh no! Sorry pardner!",
  39. overLimitText : "Limit reached!",
  40.  
  41. version:"4.0.0.4",
  42. currentUser:{
  43. id:"",
  44. profile:"",
  45. alias:""
  46. },
  47. resources:{
  48. iconsURL:GM_getResourceURL("IconSheet")
  49. },
  50. apps:{},
  51. posts:{},
  52. history:{},
  53. config:null,
  54. opts:{},
  55. quickOpts:{},
  56. displayGroups:{},
  57. likeQueue:[],
  58. switches:{
  59. manualAuthToken:true
  60. },
  61.  
  62. statusText : {
  63. "20":"Sidekick returned force accept",
  64. "3":"Marked as accepted by user",
  65. "2":"Responseless Collection",
  66. "1":"Accepted",
  67. "0":"Unknown",
  68. "-1":"Failed",
  69. "-2":"None Left",
  70. "-3":"Over Limit (App)",
  71. "-4":"Over Limit, Sent One Anyway",
  72. "-5":"Server Error",
  73. "-6":"Already Got",
  74. "-7":"Server Down For Repairs",
  75. "-8":"Problem Getting Passback Link",
  76. "-9":"Final Request Returned Null Page",
  77. "-10":"Final Request Failure",
  78. "-11":"Expired",
  79. "-12":"Not a Neighbor",
  80. "-13":"Requirements not met",
  81. "-14":"Timeout",
  82. "-15":"Unrecognized Response",
  83. "-16":"Passback Link is missing",
  84. "-17":"Window Missing",
  85. "-18":"Marked as failed by user",
  86. "-20":"Sidekick returned force fail",
  87. "-19":"Over Limit (Bonus Type)",
  88. "-21":"Cancelled mid-process by user",
  89. },
  90. sortGroups : function(params){
  91. params=params||{};
  92. params.direction=(WM.quickOpts.groupDirection=(params.direction||WM.quickOpts.groupDirection||"desc")); //default descending to keep time ordered posts in order newest to oldest
  93. WM.saveQuickOpts();
  94. //reorder the groups
  95. var groupsArray=[];
  96. for (var g in WM.displayGroups) {
  97. groupsArray.push({id:g,node:WM.displayGroups[g].parentNode,box:WM.displayGroups[g]});
  98. }
  99. if (["asc","ascending"].inArray(params.direction.toLowerCase())) groupsArray.sort(function(a,b){return a.id>b.id;});
  100. else if (["desc","descending"].inArray(params.direction.toLowerCase())) groupsArray.sort(function(a,b){return a.id<b.id;});
  101. WM.displayGroups={};
  102. for (var g=0; g<groupsArray.length; g++) {
  103. WM.displayGroups[groupsArray[g].id]=groupsArray[g].box;
  104. WM.console.feedNode.appendChild(groupsArray[g].node);
  105. }
  106. },
  107.  
  108. newGroup : function(params){
  109. params=params||{};
  110.  
  111. //prevent duplicates
  112. if (WM.displayGroups[params.by]||null) return WM.displayGroups[params.by];
  113. //create the nodes
  114. var box;
  115. var group=createElement("div",{className:"listItem"},[
  116. createElement("div",{className:"line", onclick:function(){
  117. //toggle rollout
  118. with (this.nextSibling) className=className.swapWordB((className.containsWord("collapsed")),"expanded","collapsed");
  119. with (this.firstChild.firstChild) className=className.swapWordB((className.containsWord("treeCollapse"+WM.opts.littleButtonSize)),"treeExpand"+WM.opts.littleButtonSize,"treeCollapse"+WM.opts.littleButtonSize);
  120. }},[
  121. createElement("div",{className:"littleButton",title:"Toggle Content"},[
  122. createElement("img",{className:"resourceIcon treeCollapse"+WM.opts.littleButtonSize}),
  123. ]),
  124. createElement("label",{textContent:params.label||params.by})
  125. ]),
  126. box=createElement("div",{className:"subsection rollout expanded"}),
  127. ]);
  128. //add it to our group list
  129. WM.displayGroups[params.by]=box;
  130. WM.sortGroups();
  131. return box;
  132. },
  133. pauseCollecting : function(doPause){
  134. var isPaused;
  135. if (exists(doPause)) isPaused = (WM.paused = doPause);
  136. else isPaused=(WM.paused = !WM.paused);
  137. var btn=WM.console.pauseCollectButton;
  138. btn.className = btn.className.swapWordB(isPaused,"oddGreen","oddOrange");
  139. btn.title = (isPaused)?"Start Automatic Collection":"Pause Automatic Collection";
  140. var img = btn.childNodes[0];
  141. img.className = img.className.swapWordB(isPaused,"playRight24","stop24");
  142. },
  143.  
  144. pauseFetching : function(doPause){
  145. var isPaused;
  146. if (exists(doPause)) isPaused = (WM.fetchPaused = doPause);
  147. else isPaused=(WM.fetchPaused = !WM.fetchPaused);
  148. var btn=WM.console.pauseFetchButton;
  149. btn.className = btn.className.swapWordB(isPaused,"oddGreen","oddOrange");
  150. btn.title = (isPaused)?"Start Automatic Fetching":"Pause Automatic Fetching";
  151. },
  152.  
  153. clearGroups : function(params){
  154. //destroy previous groups
  155. for (var g in WM.displayGroups){
  156. remove(WM.displayGroups[g].parentNode); //kill the node
  157. delete WM.displayGroups[g]; //remove from list
  158. }
  159. },
  160.  
  161. clearPosts : function(){
  162. //remove all post nodes from the collector panel
  163. for (var p in WM.posts){
  164. if (WM.posts[p].node) remove(WM.posts[p].node);
  165. }
  166. },
  167. constructGroups : function(params){
  168. params=params||{};
  169. //this specifically allows a null so we can remove grouping
  170. var by=exists(params.by)?params.by:WM.quickOpts.groupBy;
  171. //if nothing changed, just cancel
  172. if (by==WM.quickOpts.groupBy) return;
  173. //set the new group order
  174. WM.quickOpts.groupBy=by;
  175. WM.saveQuickOpts();
  176. WM.clearGroups();
  177. },
  178. sortPosts : function(params){
  179. params=params||{};
  180. params.direction=(WM.quickOpts.sortDirection=(params.direction||WM.quickOpts.sortDirection||"desc")); //default descending to keep time ordered posts in order newest to oldest
  181. params.by=(WM.quickOpts.sortBy=(exists(params.by)?params.by:(WM.quickOpts.sortBy||"created_time"))); //default by date
  182. WM.saveQuickOpts();
  183.  
  184. //convert to array
  185. var postsArray=methodsToArray(WM.posts);
  186.  
  187. //sort
  188. postsArray.sort(function(a,b){
  189. if (["ascending","asc"].inArray(params.direction.toLowerCase())) return a[params.by]>b[params.by];
  190. if (["descending","desc"].inArray(params.direction.toLowerCase())) return a[params.by]<b[params.by];
  191. });
  192.  
  193. //convert back to object
  194. WM.posts=arrayToMethods(postsArray);
  195. },
  196.  
  197. doWhichTestTree : function(post, testList, testData, custom) {try{
  198. //match post to an app
  199. var app=post.app;
  200. var synApp=app.synApp, w=null;
  201.  
  202. for (var i=0,test;((test=testList[i]) && (w===null));i++) {
  203.  
  204. //run only for tests that are not specifically disabled
  205. if (test.enabled===false) continue;
  206. //set find mode
  207. var findMode="auto";
  208. //finish constructing dynamic collection tests
  209. var ret = test.ret;
  210. if (custom) {
  211. if (!ret) ret = "dynamic"; //default to dynamic
  212. if (ret!="dynamic" && ret!="none" && ret!="exclude" && !ret.startsWith(synApp.appID)) ret=synApp.appID+ret; //add appID except to magic words
  213. findMode=test.findMode;
  214. }
  215.  
  216. //part to make dynamic collection tests work only if they are the correct appID
  217. //also do not process disabled tests
  218. if (!custom || (custom && (!test.appID || (app.appID==test.appID)))){
  219.  
  220. //if the test is not disabled (by test enabled both existing and being false)
  221. //OR if the test IS a dynamic test and the appID matches
  222. //OR if the test IS a dynamic test and no appID was supplied
  223. //then run the test
  224.  
  225. //detect test type
  226. var testType=(test.search||null);
  227. var types=WM.grabber.methods;
  228. if (!testType) for (var tt=0,len=types.length; tt<len; tt++) {if (test[types[tt]]||"") {testType=types[tt];break;}}
  229.  
  230. //select the type of data to use
  231. var src="";
  232. if (isArray(testType)){ //new search array format
  233. for (var t=0,tlen=testType.length;t<tlen;t++) src+=(testData[testType[t]]||"");
  234. }
  235. else src = (testData[testType]||""); //old test method like testType:text
  236.  
  237. if (src){
  238. //begin processing this test
  239. var subTests=test.subTests, kids=test.kids, allowNone=false, subNumRange=test.subNumRange,text=(test.find||test[testType]||"");
  240.  
  241. //process subtests array
  242. if (subTests && (findMode=="auto" || findMode=="subtests") && text) {
  243. for (var i2=0,subTest,found=false;((subTest=subTests[i2]) && (!found));i2++) {
  244. var testX = text.replace('{%1}',subTest).toLowerCase();
  245.  
  246. //do a standard test with the replaced search string
  247. found=src.find(testX);
  248.  
  249. //return a found value, replacing %1 with a lowercase no-space text equal to the subtest string
  250. w=(found)?ret.replace('{%1}',subTest.noSpaces().toLowerCase()):w;
  251.  
  252. testX=null;
  253. }
  254.  
  255. //process number array
  256. } else if (subNumRange && (findMode=="auto" || findMode=="subnumrange") && text){
  257. var start=parseInt(subNumRange.split(",")[0]), end=parseInt(subNumRange.split(",")[1]);
  258. for (var i2=start,found=false;((!found) && i2<=end);i2++) {
  259. var testX = text.replace('{%1}',i2).toLowerCase();
  260.  
  261. //do a standard test with the replaced search string
  262. found=src.find(testX);
  263.  
  264. //return a found value, replacing %1 with a lowercase no-space text equal to the subtest string
  265. w=(found)?ret.replace('{%1}',i2):w;
  266.  
  267. testX=null;
  268. }
  269.  
  270. //process text array, process similar to subtests
  271. } else if (text && (findMode=="auto" || findMode=="basic") && (isArray(text))) {
  272. for (var i2=0,subTest,found=false;((subTest=text[i2]) && (!found));i2++) {
  273. var testX = subTest.toLowerCase();
  274.  
  275. //do a standard test with the replaced search string
  276. found=src.find(testX);
  277.  
  278. //return the same value no matter which element from the array is found
  279. w=(found)?ret:w;
  280.  
  281. testX=null;
  282. }
  283.  
  284.  
  285. //process regex
  286. } else if (text && (test.regex||test.isRegex||null) ) {
  287. var mods = (test.mods||"gi");
  288. var testRegex = new RegExp(text,mods);
  289. var match=src.match(testRegex);
  290. if (match) match=match[0]; //always take the first match
  291. w=ret||match||w;
  292.  
  293.  
  294.  
  295. //process single text
  296. } else if (text) {
  297. try{
  298. w=(src.find(text.toLowerCase() ))?ret:w;
  299. } catch(e){
  300. log("WM.doWhichTestTree:"+e);
  301. log("--app:"+app.appID);
  302. log("--test:"+JSON.stringify(test));
  303. }
  304. }
  305.  
  306. }
  307.  
  308. //see if test has type 2 subtests (child node tests based on parent test)
  309. w = ((kids && w)?WM.doWhichTestTree(post, kids, testData, custom):w) || w; //if kids return null, default to key found above
  310.  
  311. //if this test tree returned "none", start over with next tree by replacing "none" with null
  312. //true "none" is handled in the which() function below
  313. if (w==="none") w=null;
  314.  
  315.  
  316. }//end custom checker
  317. }
  318.  
  319. return w;
  320. }catch(e){log("WM.doWhichTestTree: "+e);}},
  321.  
  322. which : function(post,params) {try{
  323. //prevent the rules manager from mistaking main as a post object
  324. if (!post) return;
  325. params=params||{};
  326. //match post to an app
  327. var w, app=post.app, synApp=app.synApp;
  328.  
  329. //create various data for the tests to use
  330. if (!params.reid) post.testData = {
  331. title: (post.name||"undefined").toLowerCase(),
  332. msg: (post.message||"undefined").toLowerCase(),
  333. caption: (post.caption||"undefined").toLowerCase(),
  334. desc: (post.description||"undefined").toLowerCase(),
  335. link: (post.linkText||"undefined").toLowerCase(),
  336. url: Url.decode(post.linkHref).toLowerCase(),
  337. img: (post.picture||"undefined").toLowerCase(),
  338. fromName: post.fromName.toLowerCase(),
  339. fromID: post.fromID.toLowerCase(),
  340. targetName: "undefined", //","+post.getTargets("name").join(",").toLowerCase(),
  341. //targetID: "undefined", //","+post.getTargets("id").join(",").toLowerCase(),
  342. canvas: "undefined", //app.namespace.toLowerCase(),
  343. likeName: "undefined", //","+post.getLikes("name").join(",").toLowerCase(),
  344. likeID: "undefined", //","+post.getLikes("id").join(",").toLowerCase(),
  345. comments: "undefined", //post.getComments("message").join(" \n").toLowerCase(),
  346. commentorName: "undefined", //","+post.getComments("name").join(",").toLowerCase(),
  347. commentorID: "undefined", //","+post.getComments("id").join(",").toLowerCase(),
  348. };
  349. var testData=post.testData;
  350.  
  351. //replacement for old options like body, either and html
  352. testData.body = testData.title+testData.caption+testData.desc;
  353. testData.either = testData.link+testData.body;
  354. testData.html = testData.fromID + testData.fromName + testData.targetID + testData.targetName + testData.message
  355. + testData.href + testData.either + testData.img + testData.canvas + testData.likeID + testData.likeName
  356. + testData.commentorID + testData.commentorName + testData.comments;
  357.  
  358. var dynamicTests = WM.grabber.tests;
  359.  
  360. //check user built dynamic tests first if enabled and told to run first
  361. if (WM.opts["dynamic"+app.appID] && WM.opts.dynamicFirst && dynamicTests) {
  362. w=WM.doWhichTestTree(post,dynamicTests, testData, true)||"none";
  363. }
  364.  
  365. //process this game's tests if dynamic didn't already get one
  366. if (w=="none" || !w || w=="") {
  367. w=((tests=synApp.tests)?WM.doWhichTestTree(post,tests, testData):"none")||"none";
  368. }
  369.  
  370. //check user built dynamic tests last if enabled and not told to run first
  371. if (w=="none" || !w || w=="") {
  372. if (WM.opts["dynamic"+app.appID] && !WM.opts.dynamicFirst && dynamicTests) {
  373. w=WM.doWhichTestTree(post,dynamicTests,testData, true)||"none";
  374. }
  375. }
  376.  
  377. //switch to undefined collection if enabled
  378. w=(w==="none" && app.opts["doUnknown"])?"doUnknown":w;
  379.  
  380. return w;
  381. }catch(e){log("WM.which: "+e);}},
  382.  
  383. resetAccepted : function(params) {
  384. params=params||{};
  385. var ask=WM.opts.historyConfirmClear;
  386. if (params.noConfirm || !ask || (ask && confirm("Delete all history for this profile?"))){
  387. doAction(function(){
  388. WM.history={};
  389. setOpt('history_'+WM.currentUser.profile,'{}');
  390. });
  391. }
  392. },
  393. getIsConfigOpen : function(){
  394. if (document.evaluate("//iframe[@id='Config']",document,null,9,null).singleNodeValue) return true;
  395. return false;
  396. },
  397.  
  398. onWindowResize : function(){
  399. WM.resizeConsole();
  400. },
  401. onHeartbeat : function(){
  402. if (WM.rulesManager.enabled) {
  403.  
  404. //affect rules at the base level
  405. WM.rulesManager.doEvent("onHeartbeat",{});
  406. //affect rules at the app level
  407. if (WM.opts.heartbeatAffectsApps) {
  408. for (var a in WM.apps) {
  409. (function(){
  410. WM.rulesManager.doEvent("onHeartbeat",WM.apps[a]);
  411. })();
  412. }
  413. }
  414.  
  415. //affect rules at the post level
  416. if (WM.opts.heartbeatAffectsPosts) {
  417. for (var p in WM.posts) if (!WM.posts[p].isGhost) {
  418. (function(){
  419. WM.rulesManager.doEvent("onHeartbeat",WM.posts[p]);
  420. })();
  421. }
  422. }
  423.  
  424. //affect rules at the rule level
  425. if (WM.opts.heartbeatAffectsRules) {
  426. for (var r=0; r<WM.rulesManager.rules.length; r++) {
  427. (function(){
  428. WM.rulesManager.doEvent("onHeartbeat",WM.rulesManager.rules[r]);
  429. })();
  430. }
  431. }
  432.  
  433. //affect rules at the feed and feed filter levels
  434. if (WM.opts.heartbeatAffectsFeeds || WM.opts.heartbeatAffectsFeedFilters) {
  435. var feeds=WM.feedManager.feeds;
  436. for (var f=0,len=feeds.length; f<len; f++) {
  437. //do the feed
  438. if (WM.opts.heartbeatAffectsFeeds) (function(){
  439. WM.rulesManager.doEvent("onHeartbeat",feeds[f]);
  440. })();
  441. //do the feed filters
  442. if (WM.opts.heartbeatAffectsFeedFilters) {
  443. for (var ff in feeds[f].filters){
  444. (function(){
  445. WM.rulesManager.doEvent("onHeartbeat",feeds[f].filters[ff]);
  446. })();
  447. }
  448. }
  449. }
  450. }
  451. }
  452. //check for new sidekick arrivals
  453. if (isArrayAndNotEmpty(WM.newSidekicks)) {
  454. while (WM.newSidekicks.length>0) {
  455. var app=WM.newSidekicks.shift();
  456. app.fetchPosts();
  457. }
  458. }
  459. //check for autolike queue contents
  460. var quePost = WM.checkAutoLikeQue();
  461. if (quePost) {
  462. //log([quePost.fn,quePost.post.id]);
  463. switch (quePost.fn) {
  464. case "like":quePost.post.like();break;
  465. case "comment":quePost.post.comment(quePost.say);break;
  466. }
  467. }
  468. },
  469.  
  470. //this is for when the WM.config and globalConfig settings change
  471. onSave : function() {
  472. //recopy the settings array from WM.config
  473. WM.updateSettingsValues();
  474.  
  475. //hide or show counters
  476. if (WM.opts.showcounters) WM.showCounters(); else WM.hideCounters();
  477.  
  478. //update intervals
  479. WM.setIntervals();
  480.  
  481. //set new user colors
  482. WM.setColors();
  483. //update config settings
  484. WM.changeConfigSettings();
  485.  
  486. //update those settings we use as global variables
  487. WM.changeDebugSettings();
  488. //set console heights
  489. //WM.resizeConsole();
  490. },
  491.  
  492. updateSettingsValues : function(){try{
  493. WM.opts = WM.config.values;
  494. //new: do this for each of the apps too
  495. for (var a in WM.apps) WM.apps[a].opts=WM.apps[a].config.values;
  496. }catch(e){"WM.updateSettingsValues: "+e}},
  497.  
  498. getAccText: function(appID,w,past,status){
  499. var app=WM.apps[appID].synApp;
  500. //detect and use a status code message
  501. if (!(status>-1 || status==-4 || status==-6)) return WM.statusText[status];
  502. //or return a generic message based on post type
  503. else return (w=="dynamic")?"Dynamic Grab"+((past)?"bed":""):(((w.find("send")?"Sen"+((past)?"t":"d")+" ":w.find("wishlist")?"":"G"+((past?"o":"e"))+"t ") + (app.userDefinedTypes[w]||app.accText[w])) || ((past)?WM.accDefaultText:"Get Unknown") || ((w.startsWith(app.appID+"doUnknown"))?"Unknown":"") );
  504. },
  505. refreshBrowser : function(){
  506. /*
  507. make sure no collection process is running
  508. make sure the options menu is not open
  509. */
  510. if (WM.requestsOpen>0 || $("Config")) {
  511. setTimeout(WM.refreshBrowser,5000);
  512. } else {
  513. window.location.reload();
  514. }
  515. },
  516.  
  517. stopCollectionOf : function(w){
  518. for (var p in WM.posts) if (!WM.posts[p].isGhost && WM.posts[p].which==w) WM.posts[p].stopCollect();
  519. },
  520.  
  521. startCollectionOf : function(w){
  522. for (var p in WM.posts) if (!WM.posts[p].isGhost && WM.posts[p].which==w) WM.posts[p].collect();
  523. },
  524.  
  525. pauseByType : function(app,w){
  526. if (!isArray(w)) w=[w];
  527. //mark as paused all those posts not yet done
  528. for (var p in WM.posts) if (!WM.posts[p].isGhost && w.inArray(WM.posts[p].which)) WM.posts[p].pause();
  529. //store the paused type but dont save it
  530. var a=(app.parent||app);
  531. for (var i=0; i<w.length; i++) {
  532. var t=w[i];
  533. //add it to the array without making a duplicate
  534. if (!a.typesPaused.inArray(t)) {
  535. a.typesPaused.push(t);
  536. //add a visible node
  537. a.typesPausedNode.appendChild(
  538. a.pausedTypesListNodes[t]=createElement("div",{className:"line"},[
  539. createElement("span",{textContent:(a.userDefinedTypes[t]||a.accText[t])+" ("+t+") "}),
  540. createElement("div",{className:"littleButton oddGreen", title:"Unpause Type"},[
  541. createElement("img",{className:"resourceIcon playRight"+WM.opts.littleButtonSize,onclick:function(){
  542. WM.unPauseByType(a,t);
  543. }})
  544. ])
  545. ])
  546. );
  547. }
  548. }
  549. },
  550.  
  551. unPauseByType : function(app,w){
  552. if (!isArray(w)) w=[w];
  553. //unpause all those posts not yet done
  554. for (var p in WM.posts) if (!WM.posts[p].isGhost && w.inArray(WM.posts[p].which)) WM.posts[p].unPause();
  555. //remove paused type from list but dont save it
  556. var a=(app.parent||app);
  557. for (var i=0; i<w.length; i++) {
  558. //remove the visible node
  559. remove (a.pausedTypesListNodes[w[i]]);
  560. //delete the visible node entry
  561. delete a.pausedTypesListNodes[w[i]];
  562. //remove it from the array
  563. a.typesPaused.removeByValue(w[i]);
  564. }
  565. },
  566.  
  567. setAsAccepted : function(comment,status, post) {try{
  568. var app=post.app;
  569. var synApp=app.synApp;
  570. post.state="accepted";
  571. post.status=status;
  572. post.accept();
  573.  
  574. WM.history[post.id]={status:status, date:timeStamp(), which:(post.which||"undefined").removePrefix(synApp.appID), appID:app.appID};
  575. setOptJSON('history_'+WM.currentUser.profile,WM.history);
  576.  
  577. //do friend tracking
  578. if (WM.opts.useFriendTracker && WM.opts.trackAccepted){
  579. WM.friendTracker.trackStatus(post,true);
  580. }
  581.  
  582. var postNode=post.node||$("post_"+post.id);
  583. if (postNode){
  584. var link=selectSingleNode(".//a[contains(@class,'linkText')]",{node:postNode});
  585.  
  586. var text=WM.getAccText(synApp.appID,post.which,true,status);
  587.  
  588. link.textContent = (comment || text || WM.statusText[status] || WM.accDefaultText);
  589. WM.updatePostStatus(post.id);
  590. }
  591.  
  592. app.acceptCount++;
  593.  
  594. //perform the onAccepted event
  595. WM.rulesManager.doEvent("onAccepted",post);
  596.  
  597. //try autolike
  598. try{
  599. if (WM.opts.useautolike && (WM.opts.autolikeall || WM.opts.autolikeaccepted || (WM.opts.autolikesent && (post.which||"undefined").startsWith("send")) )) {
  600. if (!WM.opts["nolike"+app.appID]){
  601. WM.queAutoLike(post);
  602. //post.like();
  603. }
  604. }
  605. } catch(e){log("setAsAccepted: autolike failed: "+e,{level:3});}
  606. //try autocomment
  607. try{
  608. if (WM.opts.useautocomment && (WM.opts.autolikeall || WM.opts.autolikeaccepted || (WM.opts.autolikesent && (post.which||"undefined").startsWith(synApp.appID+"send")) )) {
  609. if (!WM.opts["nolike"+app.appID]){
  610. //setTimeout(function(){post.comment();},100+(WM.opts.autolikedelay*1000));
  611. WM.queAutoComment(post,null);
  612. }
  613. }
  614. } catch(e){log("setAsAccepted: autocomment failed: "+e,{level:3});}
  615. }catch(e){log("WM.setAsAccepted: "+e);}},
  616.  
  617. disableOpt : function(w,app){try{
  618. var targetConfig=(app||null)?app.config:WM.config;
  619. ((app||null)?app.opts:WM.opts)[w]=false;
  620. targetConfig.set(w,false);
  621. targetConfig.save();
  622. debug.print([w,app,false]);
  623. }catch(e){log("WM.disableOpt: "+e);}},
  624.  
  625. enableOpt : function(w,app){try{
  626. var targetConfig=(app||null)?app.config:WM.config;
  627. ((app||null)?app.opts:WM.opts)[w]=true;
  628. targetConfig.set(w,true);
  629. targetConfig.save();
  630. debug.print([w,app,true]);
  631. }catch(e){log("WM.enableOpt: "+e);}},
  632.  
  633. setOpt : function(w,v,app){try{
  634. var targetConfig=(app||null)?app.config:WM.config;
  635. ((app||null)?app.opts:WM.opts)[w]=v;
  636. targetConfig.set(w,v);
  637. targetConfig.save();
  638. debug.print([w,app,v]);
  639. }catch(e){log("WM.setOpt: "+e);}},
  640.  
  641. resetCounters : function(){try{
  642. for (var a in WM.apps) WM.apps[a].resetCounter();
  643. }catch(e){log("WM.resetCounters: "+e);}},
  644.  
  645. setAsFailed : function(comment, status, post){try{
  646. var app=post.app;
  647. var synApp=app.synApp;
  648. var postNode=post.node||$("post_"+post.id);
  649.  
  650. //special effects for timeout and cancelProcess
  651. if ((!WM.opts.failontimeout && status==-14) || status==-21) {
  652. post.state="timeout";
  653. post.timeout();
  654. if (status==-14) WM.rulesManager.doEvent("onTimeout",post);
  655.  
  656. } else {
  657. post.state="failed";
  658. post.fail(); // don't pass true or it will loop here
  659.  
  660. WM.history[post.id]={status:status, date:timeStamp(), which:(post.which||"undefined").removePrefix(synApp.appID), appID:app.appID};
  661. setOptJSON('history_'+WM.currentUser.profile,WM.history);
  662. WM.rulesManager.doEvent("onFailed",post);
  663. }
  664. post.status=status;
  665.  
  666. //do friend tracking
  667. if (WM.opts.useFriendTracker && WM.opts.trackFailed){
  668. WM.friendTracker.trackStatus(post,false);
  669. }
  670. if (postNode) {
  671. var link=selectSingleNode(".//a[contains(@class,'linkText')]",{node:postNode});
  672. if (link) {
  673. //I can see no reason the link should be missing, but since its been proven to fail, here is a patch
  674. link.textContent = (comment || WM.statusText[status] || WM.failText);
  675. }
  676. WM.updatePostStatus(post.id);
  677. }
  678.  
  679. app.failCount++;
  680. //try autolike
  681. try{
  682. if (WM.opts.useautolike && WM.opts.autolikeall) {
  683. if (!WM.opts["nolike"+app.appID]){
  684. WM.queAutoLike(post);
  685. //post.like();
  686. //setTimeout(function(){post.like();},100+(WM.opts.autolikedelay*1000));
  687. }
  688. }
  689. } catch(e){log("setAsFailed: autolike failed: "+e,{level:3});}
  690. //try autocomment
  691. try{
  692. if (WM.opts.useautocomment && WM.opts.autolikeall) {
  693. if (!WM.opts["nolike"+app.appID]){
  694. //setTimeout(function(){post.comment();},100+(WM.opts.autolikedelay*1000));
  695. WM.queAutoComment(post,null);
  696. }
  697. }
  698. } catch(e){log("setAsFailed: autocomment failed: "+e,{level:3});}
  699. }catch(e){log("WM.setAsFailed: "+e);}},
  700.  
  701. setPriority : function(){
  702. var postNode=selectSingleNode(".//ancestor::*[starts-with(@id,'post_')]",{node:this});
  703. var id=postNode.id.replace("post_","");
  704. WM.posts[id]["priority"]=this.getAttribute("name");
  705. remove(postNode);
  706. WM.posts[id].draw();
  707. },
  708.  
  709. clearURL : function(tab){
  710. WM.collector.close(tab);
  711. WM.requestsOpen--;
  712. },
  713. //constantly update sidekick channel data
  714. skChannel : {},
  715. fetchSidekickData : function(){try{
  716. if (WM) {
  717. var node=selectSingleNode("./div",{node:$("wmDataDump")});
  718. while (node){
  719. log("WM.fetchSidekickData: found "+JSON.parse(node.getAttribute("data-ft")));
  720. WM.skChannel=mergeJSON(WM.skChannel,JSON.parse(node.getAttribute("data-ft")));
  721. remove(node);
  722. node=selectSingleNode("./div",{node:$("wmDataDump")});
  723. }
  724. setTimeout(WM.fetchSidekickData,1000);
  725. }
  726. }catch(e){log("WM.fetchSidekickData: "+e);}},
  727. //this is WM3's method of handling conversations with sidekicks
  728. onFrameLoad3 : function(tab){try{
  729. log("onFrameLoad3(): tab="+tab.id);
  730. var postID=tab.postID||tab.id;
  731. var post=tab.post||WM.posts[postID];
  732.  
  733. //detect if post process was cancelled by user
  734. if (post.processCancelled){
  735. //reset the cancel memory
  736. post.processCancelled = false;
  737. log("onFrameLoad3: process cancelled by user");
  738. //set the timeout flag even though its not timed out
  739. WM.setAsFailed(null,-21,post);
  740. WM.clearURL(tab);
  741. return;
  742. }
  743.  
  744. //detect if valid WM.collector window still exists
  745. var windowExists=(tab.hwnd && !tab.hwnd.closed);
  746. /*try{
  747. var testUrl=tab.hwnd.location.toString();
  748. } catch(e) {
  749. windowExists=false;
  750. }*/
  751. //make sure the post object still exists
  752. if (!(post||null)){
  753. log("onFrameLoad3: post is null");
  754. WM.clearURL(tab);
  755. return;
  756. }
  757.  
  758. //check if window object is missing
  759. if (!windowExists) {
  760. log("windowExists = false");
  761. if (!tab.hwnd) log("onFrameLoad3: tab.hwnd is null");
  762. if (tab.hwnd.closed) log("onFrameLoad3: tab.hwnd is closed");
  763. WM.setAsFailed(null,-17,post);
  764. WM.clearURL(tab);
  765. return;
  766. }
  767. //check timer on this open post
  768. var openTime=tab.openTime;
  769. var nowTime=timeStamp();
  770. if ((WM.opts.reqtimeout*1000)<(nowTime-openTime)){
  771. log("onFrameLoad3: post timed out");
  772. WM.setAsFailed(null,-14,post);
  773. WM.clearURL(tab);
  774. return;
  775. }
  776. //create the retry function
  777. var retry=function(){setTimeout(function(){WM.onFrameLoad3(tab); return;},1000); return;};
  778. //look for status data
  779. var tabID = tab.id;
  780. var skData = WM.skChannel[tabID]||null;
  781. if (skData) {
  782. //data exists for this post
  783. if (skData.status) {
  784. //status is available
  785. delete WM.skChannel[tabID];
  786. //get useful post data
  787. var app=post.app; var synApp=app.parent||app;
  788. var postNode=post.node||$("post_"+post.id);
  789. var link=selectSingleNode(".//a[contains(@class,'linkText')]",{node:postNode});
  790. var w=post.which||"undefined";
  791. //confirm status
  792. var gotItem=((skData.status>0) || (skData.status==-6) || (skData.status==-4) || (skData.status==-15 && WM.opts.accepton15));
  793. var failedItem=(skData.status<0);
  794. if (gotItem){
  795. //build debug block
  796. switch(skData.status){
  797. case -6: case -4: case 1:
  798. // this bonus is available or we still have the ability to send something for no return
  799. //dont break before next
  800. case -15: case 2:
  801. if (!synApp.flags.requiresTwo){
  802. WM.setAsAccepted(null, skData.status, post);
  803. }
  804. break;
  805.  
  806. default:
  807. //should not have come here for any reason, but if we did assume its a status code I didnt script for
  808. WM.setAsFailed(null, skData.status, post);
  809. log("onFrameLoad3: unexpected status code: "+skData.status,{level:2});
  810. break;
  811. }
  812. } else {
  813. WM.setAsFailed(null,skData.status,post);
  814. }
  815. // click "yes" to accept it, if we got this far we actually found an accept button
  816. if(synApp.flags.requiresTwo && gotItem) {
  817. if (skData.nopopLink) {
  818. var req; req=GM_xmlhttpRequest({
  819. method: "GET",
  820. url: skData.nopopLink,
  821. timeout: WM.opts.reqtimeout*1000,
  822. onload: function(response) {
  823. //search for error messages
  824. var test=response.responseText;
  825. if (test==""){
  826. //no text was found at requested href
  827. log("onFrameLoad3: final stage: null response",{level:2});
  828. WM.setAsFailed(null, -9,post);
  829. } else {
  830. //if no errors then we got it
  831. WM.setAsAccepted(null, skData.status,post);
  832. }
  833. WM.clearURL(tab);
  834. if(req)req=null;
  835. },
  836.  
  837. onerror: function(response) {
  838. log("onFrameLoad3: final stage: error returned",{level:2});
  839. //if final request fails, drop the request for now
  840. WM.setAsFailed(null, -10,post);
  841. WM.clearURL(tab);
  842. if(req)req=null;
  843. },
  844.  
  845. onabort: function(response) {
  846. log("onFrameLoad3: final stage: request aborted",{level:2});
  847. WM.setAsFailed(null, -10,post);
  848. WM.clearURL(tab);
  849. if(req)req=null;
  850. },
  851. ontimeout: function(response) {
  852. log("onFrameLoad3: final stage: request timeout",{level:2});
  853. WM.setAsFailed(null, -10,post);
  854. WM.clearURL(tab);
  855. if(req)req=null;
  856. },
  857. });
  858.  
  859. } else {
  860. log("onFrameLoad3: skData.nopopLink is null and a string was expected",{level:3});
  861. WM.setAsFailed(null, -16,post);
  862. WM.clearURL(tab);
  863. return;
  864. }
  865. } else WM.clearURL(tab); //<- default page clearer, do not remove
  866. } else retry();
  867. } else {
  868. retry();
  869. //send the tab its init message (again)
  870. tab.hwnd.postMessage({
  871. channel:"WallManager",
  872. msg:1,
  873. tabID:tab.id,
  874. },"*");
  875. //log("useGM_openInTab: "+WM.opts.useGM_openInTab);
  876. }
  877. }catch(e){log("WM.onFrameLoad3: "+e);}},
  878. //this is WM1-2's method of handling conversation with sidekicks
  879. //WM3 defaults to this if sidekick is not WM3 compatible
  880. onFrameLoad : function(tab,noDebug){try{
  881. //tab object contains {id,post,url}
  882. if (!noDebug) log("onFrameLoad()",{level:0});
  883.  
  884. var id=tab.id; var post=tab.post||WM.posts[id];
  885. if (!(post||null)) {
  886. //resource deleted while post was out
  887. WM.clearURL(tab);
  888. return;
  889. }
  890.  
  891. //detect if post process was cancelled by user
  892. if (post.processCancelled){
  893. //reset the cancel memory
  894. post.processCancelled = false;
  895. log("onFrameLoad3: process cancelled by user");
  896. //set the timeout flag even though its not timed out
  897. WM.setAsFailed(null,-21,post);
  898. WM.clearURL(tab);
  899. return;
  900. }
  901.  
  902. var app=post.app;
  903. var synApp=app.parent||app;
  904.  
  905. var httpsTrouble=synApp.flags.httpsTrouble;
  906. var responseLess=synApp.flags.skipResponse;
  907.  
  908. var postNode=post.node||$("post_"+post.id);
  909. var link=selectSingleNode(".//a[contains(@class,'linkText')]",{node:postNode});
  910. var w=post.which||"undefined";
  911.  
  912. tab.tries=(tab.tries||0)+1;
  913. if (tab.tries>WM.opts.reqtimeout) {
  914. log("onFrameLoad: request timeout",{level:3});
  915. WM.setAsFailed(null, -14, post);
  916. WM.clearURL(tab);
  917. return;
  918. }
  919.  
  920. var retry=function(){setTimeout(function(e){WM.onFrameLoad(tab, true);}, 1000);};
  921.  
  922. var failedItem=false, gotItem=false, nopopLink;
  923.  
  924. //check if window object is missing
  925. var windowExists=(tab.hwnd && !tab.hwnd.closed);
  926. if (!windowExists) {WM.setAsFailed(null,-17,post); WM.clearURL(tab); return;}
  927. //check if window document does not yet exist
  928. //if (!(tab.hwnd.document||null)) {retry(); return;}
  929.  
  930. //get sidekick return value
  931. var hashMsg="",hashStatus=0;
  932. try{
  933. //if error encountered, reload the page
  934. if (tab.hwnd.document.title==="Problem loading page"){
  935. log("processPosts: problem loading page",{level:1});
  936. tab.hwnd.location.reload();
  937. retry();
  938. return;
  939. }
  940.  
  941. var temphash = tab.hwnd.location.hash; //capture a hash if we can
  942. hashMsg = ((temphash)?temphash.removePrefix("#"):null) || tab.hwnd.location.href.split("#")[1];
  943. hashStatus=(responseLess)?2:(hashMsg||null)?parseInt(hashMsg.split('status=')[1].split("&")[0]):0;
  944. gotItem=((hashStatus>0) || (hashStatus==-6) || (hashStatus==-4) || (hashStatus==-15 && WM.opts.accepton15));
  945. failedItem=(hashStatus<0);
  946. if (!gotItem && !failedItem) {retry(); return;}
  947.  
  948. } catch(e){
  949. var errText=""+e;
  950. if (errText.contains("hashMsg is undefined")) {
  951. //this known issue occurs when a page is not yet fully loaded and the
  952. //WM script tries to read the page content
  953. retry();
  954. return;
  955. }
  956. else if (errText.contains("Permission denied to access property")) {
  957. //we've reached some known cross domain issue
  958. if (responseLess) {
  959. //if the sidekick creator has chosen to use responseless collection
  960. //simply assume the page has loaded and mark the item as collected
  961.  
  962. gotItem=true;failedItem=false;hashStatus=2;
  963. } else {
  964. console.log("WM.onFrameLoad(before retry): "+e);
  965. retry();
  966. return;
  967. }
  968. }
  969. else if (errText.contains("NS_ERROR_INVALID_POINTER")
  970. || errText.contains("tab.hwnd.document is null") ) {
  971.  
  972. WM.setAsFailed(null,-17,post);
  973. WM.clearURL(tab);
  974. return;
  975. }
  976. else {
  977. log("onFrameLoad: "+e,{level:3});
  978. retry();
  979. return;
  980. }
  981. }
  982.  
  983. //if gotItem then we have been offered the item so far
  984. if (gotItem){
  985. //build debug block
  986. switch(hashStatus){
  987. case -6: case -4: case 1:
  988. // this bonus is available or we still have the ability to send something for no return
  989. if (synApp.flags.requiresTwo){
  990. try{
  991. nopopLink=hashMsg.split("&link=[")[1].split("]")[0];
  992. }catch(e){
  993. //known rare issue where no link is passed back by pioneer trail
  994. }
  995. }
  996. //dont break before next
  997. case -15: case 2:
  998. if (!synApp.flags.requiresTwo){
  999. WM.setAsAccepted(null, hashStatus,post);
  1000. }
  1001. break;
  1002.  
  1003. default:
  1004. //should not have come here for any reason, but if we did assume its a status code I didnt script for
  1005. WM.setAsFailed(null, hashStatus,post);
  1006. log("onFrameLoad: unexpected status code: "+hashStatus,{level:2});
  1007. break;
  1008. }
  1009. } else {
  1010. WM.setAsFailed(null,hashStatus,post);
  1011. }
  1012.  
  1013.  
  1014. // click "yes" to accept it, if we got this far we actually found an accept button
  1015. if(synApp.flags.requiresTwo && gotItem) {
  1016. if (nopopLink) {
  1017. var req; req=GM_xmlhttpRequest({
  1018. method: "GET",
  1019. url: nopopLink,
  1020. timeout: WM.opts.reqtimeout*1000,
  1021. onload: function(response) {
  1022. //search for error messages
  1023. var test=response.responseText;
  1024. if (test==""){
  1025. //no text was found at requested href
  1026. log("onFrameLoad: final stage: null response",{level:2});
  1027. WM.setAsFailed(null, -9,post);
  1028. } else {
  1029. //if no errors then we got it
  1030. WM.setAsAccepted(null, hashStatus,post);
  1031. }
  1032. WM.clearURL(tab);
  1033. if(req)req=null;
  1034. },
  1035.  
  1036. onerror: function(response) {
  1037. log("onFrameLoad: final stage: error returned",{level:2});
  1038. //if final request fails, drop the request for now
  1039. WM.setAsFailed(null, -10,post);
  1040. WM.clearURL(tab);
  1041. if(req)req=null;
  1042. },
  1043.  
  1044. onabort: function(response) {
  1045. log("onFrameLoad: final stage: request aborted",{level:2});
  1046. WM.setAsFailed(null, -10,post);
  1047. WM.clearURL(tab);
  1048. if(req)req=null;
  1049. },
  1050. ontimeout: function(response) {
  1051. log("onFrameLoad: final stage: request timeout",{level:2});
  1052. WM.setAsFailed(null, -10,post);
  1053. WM.clearURL(tab);
  1054. if(req)req=null;
  1055. },
  1056. });
  1057.  
  1058. } else {
  1059. log("onFrameLoad: nopopLink is null and a string was expected",{level:3});
  1060. WM.setAsFailed(null, -16,post);
  1061. WM.clearURL(tab);
  1062. return;
  1063. }
  1064. } else WM.clearURL(tab);
  1065.  
  1066. }catch(e){log("WM.onFrameLoad: "+e);}},
  1067.  
  1068. toggle : function(opt,app){
  1069. var targetConfig=(app||null)?app.config:WM.config;
  1070. var targetOpts=(app||null)?app.opts:WM.opts;
  1071. if (targetOpts[opt]){
  1072. targetConfig.set(opt, false);
  1073. targetOpts[opt] = false;
  1074. } else {
  1075. targetConfig.set(opt, true);
  1076. targetOpts[opt] = true;
  1077. }
  1078. targetConfig.save();
  1079. },
  1080.  
  1081. getAppDropDownList : function(selectedIndex,allowBlank){
  1082. var retApps=[];
  1083. //add the fake initial option
  1084. retApps.push(createElement("option",{textContent:"select an app",value:""}));
  1085. retApps.push(createElement("option",{textContent:"* All",value:""}));
  1086. if (allowBlank) retApps.push(createElement("option",{textContent:"all apps",value:""}));
  1087.  
  1088. for(var i in WM.apps){
  1089. if (!WM.apps[i].parent) {
  1090. var elem = createElement("option",{textContent:WM.apps[i].name,value:i});
  1091. if ((selectedIndex||null) == i) elem.selected = true;
  1092. retApps.push(elem);
  1093. }
  1094. }
  1095. return retApps;
  1096. },
  1097.  
  1098. getBonusDropDownList : function(params){
  1099. params=params||{};
  1100. var selected = params.selected||"";
  1101. var appID = params.appID||null;
  1102. var dropID = params.dropID||false; //force the element value to drop its appID prefix
  1103.  
  1104. var optsret=[], bonuses={};
  1105. if (appID) bonuses = mergeJSON(WM.apps[appID].accText,WM.apps[appID].userDefinedTypes);
  1106. bonuses["dynamic"]="* Dynamic: Just Grab It";
  1107. bonuses["none"]="* None: Break Identification Circuit";
  1108. bonuses["wishlist"]="* Flag as Wishlist";
  1109. bonuses["exclude"]="* Exclude: Prevent Collection";
  1110. bonuses["send"]="* Send Unknown";
  1111. bonuses["doUnknown"]="* Get Unknown";
  1112.  
  1113. //create option values and names;
  1114. for (var i in bonuses) {
  1115. var elem
  1116. if (appID) elem = createElement("option",{textContent:((i.startsWith(appID+"send"))?"Send ":((bonuses[i].substring(0,1)=="*")?"":"Get "))+bonuses[i],value:((dropID)?i.removePrefix(appID):i)});
  1117. else elem = createElement("option",{textContent:bonuses[i],value:i});
  1118.  
  1119. if (appID) {if (selected==((dropID)?i.removePrefix(appID):i) ) elem.selected = true;}
  1120. else {if (selected==i) elem.selected=true;}
  1121.  
  1122. optsret.push(elem);
  1123. }
  1124.  
  1125. return optsret;
  1126. },
  1127.  
  1128. reIDAll : function(){
  1129. for (var p in WM.posts) {
  1130. if (!WM.posts[p].isGhost && WM.posts[p].identify({reid:true}))
  1131. WM.rulesManager.doEvent("onIdentify",WM.posts[p]);
  1132. }
  1133. WM.sortPosts(); //in this case sorting may cancel movetotop and movetobottom
  1134. WM.clearGroups();
  1135. WM.redrawPosts({postRedraw:true});
  1136. },
  1137.  
  1138. updatePostStatus : function(id){
  1139. var status = WM.posts[id].status;
  1140. var statusNode = selectSingleNode(".//*[contains(@class,'status')]",{node:$("post_"+id)});
  1141. if (statusNode) statusNode.textContent="Status: "+(status||"0") + " " + (WM.statusText[status||"0"]);
  1142. status=null; statusNode=null;
  1143. },
  1144.  
  1145. onLikePost : function(post){
  1146. post.isLiked=true;
  1147. return;
  1148. //pre beta 40 stuff
  1149. var postID=tab.id;
  1150. var post=tab.post||WM.posts[postID];
  1151.  
  1152. //detect if post process was cancelled by user
  1153. if (post.processCancelled){
  1154. //reset the cancel memory
  1155. post.processCancelled = false;
  1156. log("onLikePost: feedback cancelled by user");
  1157. WM.collector.close(tab);
  1158. return;
  1159. }
  1160.  
  1161. //detect if valid WM.collector window still exists
  1162. var windowExists=(tab.hwnd && !tab.hwnd.closed);
  1163.  
  1164. //check if window object is missing
  1165. if (!windowExists) {
  1166. log("onLikePost: tab.hwnd is null or closed");
  1167. WM.collector.close(tab);
  1168. return;
  1169. }
  1170. try{
  1171. var like=tab.hwnd.location.hash.removePrefix("#").getUrlParam("status")=="1";
  1172. if (like) {
  1173. if (tab.post) {
  1174. //tell the post it is liked
  1175. tab.post.isLiked = true;
  1176. //delete the post reference from the tab
  1177. delete tab.post;
  1178. }
  1179. WM.collector.close(tab);
  1180. return;
  1181. }
  1182. } catch (e){
  1183. //log(""+e);
  1184. }
  1185.  
  1186. tab.tries=(tab.tries||0)+1;
  1187. if (tab.tries<WM.opts.autoliketimeout) setTimeout(function(){WM.onLikePost(tab);}, 1000);
  1188. else {
  1189. log("onLikePost: unable to finish feedback",{level:3});
  1190. doAction(function(){WM.collector.close(tab);});
  1191. }
  1192. },
  1193.  
  1194. toggleSidekick : function(){
  1195. var appID = this.id.split("master_")[1];
  1196. var opt = !(WM.quickOpts["masterSwitch"][appID]||false); //toggle
  1197. WM.quickOpts["masterSwitch"][appID]=opt;
  1198. var className = this.parentNode.className;
  1199. this.parentNode.className = ((opt)?className.removeWord("disabled"):className.addWord("disabled"));
  1200. this.textContent=((opt)?"Disable":"Enable");
  1201. WM.saveQuickOpts();
  1202. },
  1203.  
  1204. saveQuickOpts : function(){
  1205. setOptJSON('quickopts_'+WM.currentUser.profile, WM.quickOpts);
  1206. },
  1207.  
  1208. setAppFilter : function(tab){
  1209. WM.quickOpts.filterApp=tab.appFilter;
  1210. WM.saveQuickOpts();
  1211. WM.clearGroups();
  1212. WM.redrawPosts({postRedraw:false,reorder:true});
  1213. WM.rulesManager.doEvent("onSetAppFilter",WM.apps[tab.appFilter]);
  1214. //debug.print(["Collection Tab Selected",WM.currentAppTab,WM.apps[tab.appFilter]]);
  1215. },
  1216. setDisplay : function(){
  1217. var x=this.getAttribute("name");
  1218. WM.quickOpts.displayMode=x;
  1219. WM.saveQuickOpts();
  1220. WM.redrawPosts({postRedraw:true,reorder:true});
  1221. WM.setDisplayCols();
  1222. },
  1223. setDisplayCols : function(params){
  1224. params=params||{};
  1225. params.cols=params.cols||WM.quickOpts.displayCols;
  1226. WM.quickOpts.displayCols=params.cols||1;
  1227. WM.saveQuickOpts();
  1228. with (WM.console.feedNode) {
  1229. className=className
  1230. .toggleWordB(params.cols==1,"singleCol")
  1231. .toggleWordB(params.cols==2,"twoCol")
  1232. .toggleWordB(params.cols==3,"threeCol")
  1233. .toggleWordB(params.cols==4,"fourCol");
  1234. }
  1235. },
  1236.  
  1237. redrawPosts : function(params){
  1238. params=params||{};
  1239. var feedNode=WM.console.feedNode;
  1240. //set the proper display mode
  1241. feedNode.className=feedNode.className
  1242. .toggleWordB((WM.quickOpts.displayMode=="1" || WM.quickOpts.displayMode=="3"),"short");
  1243. //avoid order issues by removing the posts from the panel
  1244. WM.clearPosts();
  1245.  
  1246. //redraw||reorder
  1247. for (var p in WM.posts) {
  1248. var post=WM.posts[p];
  1249. if (!post.isGhost) {
  1250. post.draw(params.postRedraw,params.reorder);
  1251. }
  1252. }
  1253. },
  1254.  
  1255. moveFloater : function(ev){
  1256. if (isChrome) return;
  1257. var img=this, offset=trueOffset(img), scrolled=trueScrollOffset(img),
  1258. post=selectSingleNode(".//ancestor::div[starts-with(@id,'post')]",{node:img}),
  1259. floater=$(post.id.replace("post","floater")), special={};
  1260.  
  1261. //log( (scrolled.left) +","+ (scrolled.top) );
  1262.  
  1263. special.x=(ev.clientX > (document.documentElement.clientWidth/2))?-(240+4+22):0; //width+overshot+BorderAndPadding
  1264. special.y=(ev.clientY > (document.documentElement.clientHeight/2))?-(120+4+12):0;
  1265.  
  1266. floater.style.left=(ev.clientX-(offset.left-scrolled.left))+(2+special.x)+"px";
  1267. floater.style.top=(ev.clientY-(offset.top-scrolled.top))+(2+special.y)+"px";
  1268. },
  1269. //create a drip system for autolike, instead of an offset
  1270. queAutoLike : function(post){
  1271. var nowTime = timeStamp();
  1272. var lastInQue = WM.likeQueue.last();
  1273. var targetTime = nowTime + (1000*WM.opts.autolikedelay);
  1274. if (lastInQue||null) {
  1275. if (lastInQue.timer>nowTime) {
  1276. targetTime = lastInQue.timer + (1000*WM.opts.autolikedelay);
  1277. }
  1278. }
  1279. WM.likeQueue.push({post:post, timer:targetTime, fn:"like"});
  1280. WM.console.likeQueueCounterNode.textContent = WM.likeQueue.length;
  1281. },
  1282. //create a drip system for autolike, instead of an offset
  1283. queAutoComment : function(post,say){
  1284. var nowTime = timeStamp();
  1285. var lastInQue = WM.likeQueue.last();
  1286. var targetTime = nowTime + (1000*WM.opts.autolikedelay);
  1287. if (lastInQue||null) {
  1288. if (lastInQue.timer>nowTime) {
  1289. targetTime = lastInQue.timer + (1000*WM.opts.autolikedelay);
  1290. }
  1291. }
  1292. WM.likeQueue.push({post:post, timer:targetTime, say:say, fn:"comment"});
  1293. WM.console.likeQueueCounterNode.textContent = WM.likeQueue.length;
  1294. //log(["autocomment added",say]);
  1295. },
  1296.  
  1297. //dump the autolike queue
  1298. emptyAutoLikeQue : function() {
  1299. WM.likeQueue=[];
  1300. WM.console.likeQueueCounterNode.textContent = 0;
  1301. },
  1302. //get the next ready autolike target
  1303. checkAutoLikeQue : function() {
  1304. if (WM.likeQueue.length<1) return null;
  1305. var nowTime = timeStamp();
  1306. if (WM.likeQueue[0].timer<=nowTime) {
  1307. WM.console.likeQueueCounterNode.textContent = (WM.likeQueue.length-1);
  1308. var t=nowTime;
  1309. for (var i in WM.likeQueue) {
  1310. i.timer = t;
  1311. t+=(1000*WM.opts.autolikedelay);
  1312. }
  1313. return WM.likeQueue.shift(); // no longer returns the post, but the block of what to do with what post
  1314. }
  1315. return null;
  1316. },
  1317.  
  1318. processPosts : function(){
  1319. //dont run if menu is open or if requests are still out or if the console is paused
  1320. if($("Config") || (WM.requestsOpen >= WM.opts.maxrequests) || WM.paused) return;
  1321.  
  1322. var postNode=selectSingleNode(".//div[starts-with(@id,'post_') and contains(@class,'collect') and not(contains(@class,'paused') or contains(@class,'working'))]",{node:WM.console.feedNode});
  1323. if (postNode) {
  1324. var post = WM.posts[postNode.id.replace('post_','')];
  1325. if (post) post.open();
  1326. }
  1327. },
  1328.  
  1329. olderPosts : function (params) {
  1330. WM.fetch({older:true});
  1331. },
  1332.  
  1333. newerPosts : function (params) {
  1334. WM.fetch({newer:true});
  1335. },
  1336. fetchRange : function (params) {
  1337. WM.fetch({bypassPause:true, older:true, targetEdge:params.oldedge, currentEdge:params.newedge});
  1338. },
  1339.  
  1340. cleanPosts : function () {try{
  1341. for (var p in WM.posts) if (!WM.posts[p].isGhost) {
  1342. var post = WM.posts[p];
  1343. with (post) if (!(
  1344. isPinned || isCollect || isWorking ||
  1345. (isTimeout && !WM.opts.cleanTimedOut)
  1346. )) post.remove();
  1347. }
  1348. }catch(e){log("WM.cleanPosts(): "+e);}},
  1349. setIntervals : function() {try{
  1350. //setup the timer to try post collection
  1351. if (procIntv) window.clearInterval(procIntv);
  1352. procIntv=window.setInterval(WM.processPosts, 2000);
  1353.  
  1354. //setup the timer to get new posts
  1355. /*
  1356. if (newIntv) window.clearInterval(newIntv);
  1357. if(calcTime(WM.opts.newinterval)>0) newIntv=window.setInterval(WM.newerPosts, calcTime(WM.opts.newinterval));
  1358. */
  1359.  
  1360. //setup the timer to get older posts
  1361. /*
  1362. if (oldIntv) window.clearInterval(oldIntv);
  1363. if(calcTime(WM.opts.oldinterval)>0) oldIntv=window.setInterval(WM.olderPosts, calcTime(WM.opts.oldinterval)+2000);
  1364. */
  1365. olderLimit=calcTime(WM.opts.maxinterval)||0;
  1366.  
  1367. //setup the timer to refresh page, fetching newer content
  1368. if (refreshIntv) window.clearInterval(refreshIntv);
  1369. if(calcTime(WM.opts.autoRefresh)>0) refreshIntv=window.setInterval(WM.refreshPage, calcTime(WM.opts.autoRefresh));
  1370.  
  1371. //setup the timer to clean up old posts from the feed
  1372. if (cleanIntv) window.clearInterval(cleanIntv);
  1373. if(calcTime(WM.opts.cleaninterval)>0) cleanIntv=window.setInterval(WM.cleanPosts, calcTime(WM.opts.cleaninterval)+250);
  1374.  
  1375. //setup global heartbeat
  1376. if (hbIntv) window.clearInterval(hbIntv);
  1377. hbIntv=window.setInterval(WM.onHeartbeat, WM.opts.heartRate);
  1378. }catch(e){log("WM.setIntervals: "+e);}},
  1379.  
  1380. hideCounters : function(){try{
  1381. hideNodes("//*[contains(@class,'accFailBlock')]");
  1382. }catch(e){log("WM.hideCounters: "+e);}},
  1383.  
  1384. showCounters : function(){try{
  1385. showNodes("//*[contains(@class,'accFailBlock')]");
  1386. }catch(e){log("WM.showCounters: "+e);}},
  1387.  
  1388. validatePost : function(fbPost){try{
  1389. //alert("validatepost");
  1390. //validate required post fields
  1391. /*if (!( exists(fbPost.application) && exists(fbPost.link) && fbPost.type=="link")) {
  1392. return;
  1393. }*/
  1394.  
  1395. //accept only posts we have sidekicks for
  1396. var app=WM.apps[fbPost.app_id];
  1397. //debug.print(app);
  1398. if (!exists(app)) return;
  1399. //debug.print("app detected");
  1400. //prevent redrawing same post in case one slips past the graph validator
  1401. var postID=fbPost.source_id + "_" + fbPost.post_id;
  1402. //debug.print([postID,fbPost.qid]);
  1403. if (WM.posts[postID]||null) {
  1404. //debug.print(WM.posts[postID].id);
  1405. return;
  1406. }
  1407. //debug.print("no duplicate post detected");
  1408. //fbPost.pageNode.className +=" notDuplicatePost";
  1409.  
  1410. //accept only posts for which a sidekick is enabled
  1411. if (!WM.quickOpts.masterSwitch[app.appID]) return;
  1412. //debug.print("sidekick for this app is ready and willing");
  1413.  
  1414. //create a Post object from the post data
  1415. var post=(WM.posts[postID]=new WM.Post(fbPost));
  1416. if (post) {
  1417. var hasID=post.identify();
  1418. WM.sortPosts(); //make sure new posts fit the current sort order and direction
  1419. if (hasID) {
  1420. WM.rulesManager.doEvent("onValidate",post);
  1421. WM.rulesManager.doEvent("onIdentify",post);
  1422. post.draw(true,true);
  1423. //debug.print("post has been told to draw");
  1424. //track the post
  1425. if (WM.opts.useFriendTracker && !post.isMyPost){
  1426. WM.friendTracker.track(post);
  1427. }
  1428. }
  1429. } else {
  1430. log("WM.validatePost: Unable to transform post data into a useful post object. (id:"+fbPost.source_id + "_" + fbPost.post_id+")");
  1431. }
  1432. }catch(e){log("WM.validatePost: "+e);}},
  1433.  
  1434. handleEdges : function(params){
  1435. /*
  1436. apps
  1437. friends
  1438. edge:{newer,older}
  1439. */
  1440. //console.log("handleEdges: "+JSON.stringify(params));
  1441. if (params.friends||null) {
  1442. //update user created feeds
  1443. for (var f=0,l=WM.feedManager.feeds.length;f<l;f++){
  1444. var feed = WM.feedManager.feeds[f];
  1445. //if this feed is listed in those passed back...
  1446. if (params.friends.contains(feed.id)){
  1447. //update each app filter in this feed
  1448. for (var c=0,l=params.apps.length;c<l;c++) {
  1449. var appID=params.apps[c];
  1450. filter = feed.filters["app_"+appID];
  1451. if (!(filter||null)) {
  1452. //this filter does not exist, create one
  1453. filter=feed.addFilter({id:"app_"+appID});
  1454. }
  1455. if (params.edge.older) filter.oldedge = params.edge.older;
  1456. if (params.edge.newer) filter.newedge = params.edge.newer;
  1457. filter.oldedgeNode.textContent = filter.oldedge;
  1458. filter.newedgeNode.textContent = filter.newedge;
  1459. if (timeStamp()-(filter.oldedge*1000)>olderLimit) filter.olderLimitReached=true;
  1460. }
  1461. }
  1462. }
  1463. } else {
  1464. //update base feed
  1465. feed = WM.feedManager.feeds[0];
  1466. for (var c=0,l=params.apps.length;c<l;c++) {
  1467. var appID=params.apps[c];
  1468. //update each app filter in this feed
  1469. filter = feed.filters["app_"+appID];
  1470. if (!(filter||null)) {
  1471. //this filter does not exist, create one
  1472. filter=feed.addFilter({id:"app_"+appID});
  1473. }
  1474. if (params.edge.older) filter.oldedge = params.edge.older;
  1475. if (params.edge.newer) filter.newedge = params.edge.newer;
  1476. filter.oldedgeNode.textContent = filter.oldedge;
  1477. filter.newedgeNode.textContent = filter.newedge;
  1478. if (timeStamp()-(filter.oldedge*1000)>olderLimit) filter.olderLimitReached=true;
  1479. }
  1480. }
  1481. },
  1482. fetch : function(params) {try{
  1483. /*
  1484. older:bool
  1485. newer:bool
  1486. apps:[]
  1487. feed:[]
  1488. targetEdge:unixtime
  1489. currentEdge:unixtime
  1490. bypassPause:bool
  1491. bypassFeedDisabled:bool
  1492. bypassAppDisabled:bool
  1493. */
  1494. params=params||{};
  1495. if (WM.fetchPaused && !params.bypassPause) return;
  1496. Graph.fetchPosts({bypassPause:true});
  1497.  
  1498. //convert a single passed app to a single entry list
  1499. /*
  1500. if (exists(params.apps) && ((params.apps.objType||null)=="app")) {
  1501. var ret={};
  1502. ret[params.apps.appID]=params.apps;
  1503. params.apps=ret;
  1504. }
  1505. var useApps = params.apps||WM.apps;
  1506.  
  1507. //convert a single passed feed to an array
  1508. if (exists(params.feeds) && ((params.feeds.objType||null)=="feed")) {
  1509. params.feeds=[params.feeds];
  1510. }
  1511. params.currentEdge = params.currentEdge||null; //nullify undefined edge
  1512. //for each feed individually
  1513. var feeds=params.feeds||WM.feedManager.feeds;
  1514. for (var f=0,len=feeds.length;f<len;f++) {
  1515. var feed=feeds[f];
  1516. var friend=(feed.url!="https://graph.facebook.com/me/home")?[feed.id]:null;
  1517. //ignore the old me feed because it is a duplicate of the wall feed
  1518. if (feed.url!="https://graph.facebook.com/me/feed") if (feed.enabled || params.bypassFeedDisabled) {
  1519. //for each app make a separate fetch call for the given feed
  1520. //override this: no more by-app fetching
  1521. if (false && !WM.opts.groupFetching && (useApps||null)) {
  1522. for (var a in useApps) {
  1523. var app=useApps[a];
  1524. //only fetch for enabled apps
  1525. //where we are fetching new
  1526. //or if we are fetching old we are not at our older limit
  1527. var feedFilter=feed.filters["app_"+a];
  1528. if ((app.enabled || params.bypassAppDisabled) && (feedFilter.enabled || params.bypassFilterDisabled) && !(
  1529. params.older && feedFilter.olderLimitReached
  1530. )
  1531. ){
  1532. var G=Graph.fetchPostsFQL_B({
  1533. callback:WM.validatePost,
  1534. direction:(params.newer?1:(params.older?-1:0)),
  1535. limit:WM.opts.fetchQty,
  1536. targetEdge:(params.targetEdge||null), //special for new rules manager actions
  1537. friends:friend,
  1538. apps:[app.appID],
  1539. currentEdge:params.currentEdge||(params.newer?feedFilter.newedge:(params.older?feedFilter.oldedge:null)),
  1540. edgeHandler:WM.handleEdges,
  1541. noAppFiltering:WM.opts.noAppFiltering
  1542. });
  1543. }
  1544. }
  1545. //join apps together before fetching a single time for the given feed
  1546. } else {
  1547. //get the keys of the apps collection
  1548. var keys=Object.keys(useApps);
  1549. //if any sidekicks are docked
  1550. if (keys.length) {
  1551. //get the values of the apps collection
  1552. var appsToProcess=keys.map(function (key) {
  1553. return useApps[key];
  1554. //filter out which apps are able to be fetched for
  1555. }).filter(function(o,i,p){
  1556. //get the feed filter text
  1557. var feedFilter=feed.filters["app_"+o.appID];
  1558. //get if the app is enabled
  1559. var isEnabled = (o.enabled || params.bypassAppDisabled);
  1560. var isFilterEnabled=true,isOlderLimitReached=false;
  1561. if (feedFilter||null) {
  1562. //get if the feed filter is enabled
  1563. isFilterEnabled = (feedFilter.enabled || params.bypassFilterDisabled);
  1564. //get if the feed filter has already reached its older edge limit
  1565. isOlderLimitReached = (params.older && feedFilter.olderLimitReached);
  1566. } else {
  1567. //feed filter does not exist for this app
  1568. //assume it was deleted by the user on purpose
  1569. //and don't fetch for this app on this feed
  1570. log("WM.fetch: could not find filter for " + o.appID + "in feed " + feed.id);
  1571. return false;
  1572. }
  1573. if (isEnabled && isFilterEnabled && !isOlderLimitReached) return true;
  1574. return false;
  1575. //simply the array
  1576. }).map(function(o,i,p){
  1577. //just get the id's of apps to do, not the entire app object
  1578. return o.appID;
  1579. });
  1580. //make sure we matched filters to process
  1581. if (appsToProcess.length){
  1582. //get the shared edges of the passed apps
  1583. var edges = feed.getMergedEdges({apps:appsToProcess});
  1584. //console.log("getMergedEdges returned: "+JSON.stringify(edges));
  1585. var G=Graph.fetchPostsFQL_B({
  1586. callback:WM.validatePost,
  1587. direction:(params.newer?1:(params.older?-1:0)),
  1588. limit:WM.opts.fetchQty,
  1589. targetEdge:(params.targetEdge||null), //special for new rules manager actions
  1590. friends:friend,
  1591. apps:appsToProcess,
  1592. currentEdge:params.currentEdge||(params.newer?edges.newedge:(params.older?edges.oldedge:null)),
  1593. edgeHandler:WM.handleEdges,
  1594. noAppFiltering:WM.opts.noAppFiltering
  1595. });
  1596. }
  1597. }
  1598. }
  1599. }
  1600. }
  1601. */
  1602. }catch(e){log("WM.fetch: "+e);}},
  1603. changeDebugSettings : function(){try{
  1604. if (debug && debug.initialized) {
  1605. debug.doDebug = WM.opts.debug;
  1606. debug.debugLevel = parseInt(WM.opts.debugLevel);
  1607. debug.debugMaxComments = WM.opts.debugMaxComments;
  1608. debug.useScrollIntoView = WM.opts.debugScrollIntoView;
  1609. debug.stackRepeats = WM.opts.debugStackRepeats;
  1610. } else {
  1611. if (debug) debug.init();
  1612. setTimeout(WM.changeDebugSettings,1000);
  1613. }
  1614. }catch(e){log("WM.changeDebugSettings: "+e);}},
  1615. changeConfigSettings : function(){try{
  1616. WM.config.sectionsAsTabs=WM.opts.configSectionsAsTabs;
  1617. WM.config.separatorsAsTabs=WM.opts.configSeparatorsAsTabs;
  1618. WM.config.useScrollIntoView=WM.opts.configScrollIntoView;
  1619. WM.config.confirms={
  1620. save:WM.opts.configConfirmSave,
  1621. cancel:WM.opts.configConfirmCancel,
  1622. "import":WM.opts.configConfirmImport,
  1623. restore:WM.opts.configConfirmRestore
  1624. };
  1625. }catch(e){log("WM.changeConfigSettings: "+e);}},
  1626.  
  1627. resizeConsole : function(){try{
  1628. //negotiate height with fb bluebar
  1629. var node=$("pagelet_bluebar");
  1630. var h=(node)?elementOuterHeight(node):0;
  1631. with($("wmContent")){
  1632. style.height=document.documentElement.offsetHeight-h+"px";
  1633. style.width=document.documentElement.offsetWidth+"px";
  1634. }
  1635. WM.console.tabContainer.redraw();
  1636. WM.console.collectTabControl.redraw();
  1637.  
  1638. }catch(e){log("WM.resizeConsole: "+e);}},
  1639.  
  1640. setColors : function(){try{
  1641. var colors=["excluded","working","timeout","paused","nodef","failed","accepted","scam","pinned"];
  1642. var css="";
  1643. for (var c=0, color; (color=colors[c]); c++) {
  1644. css+=("div."+color+"{background-color:"+WM.opts["colors"+color]+" !important;}\n");
  1645. }
  1646. //set the new transition delay timer
  1647. css+=(".wm.post.short:hover .floater {-moz-transition-property: padding,border,width,height;-moz-transition-delay:"+WM.opts["transitiondelay"]+"s; width:240px; padding:5px 10px;border:1px solid;}\n");
  1648. remove($("user_colors_css"));
  1649. addGlobalStyle(css,"user_colors_css");
  1650. }catch(e){log("WM.setColors: "+e);}},
  1651.  
  1652. initConsole : function(){try{
  1653. WM.console.loading=false;
  1654. if (WM.console.initialized) log("WM Console Initialized");
  1655.  
  1656. //show options menu button
  1657. with (WM.console.configButton) {
  1658. className = className.removeWord("jsfHidden");
  1659. }
  1660.  
  1661. //set console heights
  1662. WM.resizeConsole();
  1663.  
  1664. //load feed sources
  1665. WM.feedManager.init();
  1666. //import friend tracker data
  1667. //and delete posts out of bounds with our "track for how many days"
  1668. WM.friendTracker.init();
  1669. WM.friendTracker.clean();
  1670.  
  1671. //initialize user colors
  1672. WM.setColors();
  1673. //set up the priorities and limits object
  1674. //and new rules manager
  1675. WM.rulesManager.init();
  1676.  
  1677. //decipher the dynamic tests
  1678. WM.grabber.init();
  1679.  
  1680. //show counters
  1681. if (WM.opts.showcounters) WM.showCounters(); else WM.hideCounters();
  1682. //set intervals
  1683. WM.setIntervals();
  1684. //set autopause
  1685. if (WM.opts.autopausecollect) WM.pauseCollecting(true);
  1686. if (WM.opts.autopausefetch) WM.pauseFetching(true);
  1687. //open a channel for sidekick communication
  1688. WM.fetchSidekickData();
  1689.  
  1690. //add an entrypoint for sidekicks since we know FB gave us access
  1691. var createDock = function(){
  1692. document.body.appendChild(
  1693. createElement('div',{id:'wmDock',style:'display:none;',onclick:function(){
  1694. WM.dock.answerDockingDoor();
  1695. }})
  1696. );
  1697. document.body.appendChild(
  1698. createElement('div',{id:'wmDataDump',style:'display:none;'})
  1699. );
  1700. };
  1701. createDock();
  1702.  
  1703. }catch(e){log("WM.initConsole: "+e);}},
  1704.  
  1705. cleanHistory : function(params){try{
  1706. log("Cleaning History");
  1707. params=params||{};
  1708. var ask=WM.opts.historyConfirmClean;
  1709. if (params.noConfirm || !ask || (ask && confirm("Clean and pack history for this profile?"))){
  1710. //history = getOptJSON("history_"+WM.currentUser.profile)||{};
  1711. var ageDays=parseInt(WM.opts.itemage);
  1712. var timeNow=timeStamp();
  1713. for(var i in WM.history) {
  1714. if( ( (timeNow-WM.history[i].date) /day) > ageDays) {
  1715. delete WM.history[i];
  1716. }
  1717. }
  1718. setOptJSON("history_"+WM.currentUser.profile, WM.history);
  1719. }
  1720. }catch(e){log("WM.cleanHistory: "+e);}},
  1721.  
  1722. optionsSetup : function(){try{
  1723. //debug.print("WM.optionsSetup:");
  1724. //create the settings tree
  1725. var configContent = {};
  1726. configContent.storageName="settings_"+(WM.quickOpts.useGlobalSettings?"global":WM.currentUser.profile);
  1727. configContent.onSave=WM.onSave;
  1728. configContent.title="FB Wall Manager "+WM.version+(WM.quickOpts.useGlobalSettings?" (!! Global Settings !!)":"");
  1729. configContent.logo=createElement("span",{}[
  1730. createElement("img",{className:"logo",src:"",textContent:"v"+WM.version}),
  1731. createElement("text","v"+WM.version)
  1732. ]);
  1733. configContent.css=WM.console.dynamicIcons()+jsForms.globalStyle();
  1734. //debug.print("starting settings section");
  1735. configContent.settings={}; o=configContent.settings;
  1736. o.btn_useGlobal={
  1737. type:"button",
  1738. label:"Use Global Settings",
  1739. title:"Switch to using a global storage for settings. Those settings can then be used by other accounts (not browser profiles).",
  1740. script:function(){
  1741. if (WM.quickOpts.useGlobalSettings||false) {
  1742. //already using global settings
  1743. return;
  1744. }
  1745. if (confirm("Switch to using global (shared) settings?")){
  1746. WM.quickOpts.useGlobalSettings=true;
  1747. WM.saveQuickOpts();
  1748. WM.config.title = "FB Wall Manager "+WM.version+" (!! Global Settings !!))";
  1749. WM.config.storageName = "settings_global";
  1750. WM.config.values=WM.config.read();
  1751. WM.config.configure();
  1752. WM.config.reload();
  1753. }
  1754. },
  1755. };
  1756. o.btn_useOwnProfile={
  1757. type:"button",
  1758. label:"Use Profile Settings",
  1759. title:"Switch to using your own profile storage for settings.",
  1760. script:function(){
  1761. if (!(WM.quickOpts.useGlobalSettings||false)) {
  1762. //already using profile settings
  1763. return;
  1764. }
  1765. if (confirm("Switch to using your own profile settings?")){
  1766. WM.quickOpts.useGlobalSettings=false;
  1767. WM.saveQuickOpts();
  1768. WM.config.title = "FB Wall Manager "+WM.version;
  1769. WM.config.storageName = "settings_"+WM.currentUser.profile;
  1770. WM.config.values=WM.config.read();
  1771. WM.config.configure();
  1772. WM.config.reload();
  1773. }
  1774. },
  1775. };
  1776. //debug.print("host options section start");
  1777. o.wmtab_opts=tabSection("Host Options",{
  1778. section_basicopts:section("Basics",{
  1779. /*authTokenTools:optionBlock("Authorization",{
  1780. devAuthToken:checkBox("Automatically check my developer tool app for my Auth Token"),
  1781. },true),*/
  1782. intervals:optionBlock("Post Fetching",{
  1783. newinterval:{
  1784. label:"Read Visible Posts Interval",
  1785. type:"selecttime",
  1786. title:"Read new posts from page after a set time (those on the page not yet read).",
  1787. options:{
  1788. "off":"Off",
  1789. "tenth":"6 seconds",
  1790. "sixth":"10 seconds",
  1791. "half":"30 seconds",
  1792. "one":"1 minute",
  1793. "two":"2 minutes",
  1794. "three":"3 minutes",
  1795. "four":"4 minutes",
  1796. "five":"5 minutes",
  1797. "ten":"10 minutes",
  1798. },
  1799. "default":"t:30s"
  1800. },
  1801.  
  1802. autoRefresh:{
  1803. label:"Refresh Page Interval",
  1804. type:"selecttime",
  1805. title:"Refresh page to look for newer posts.",
  1806. options:{
  1807. "off":"Off",
  1808. "one":"1 minute",
  1809. "two":"2 minutes",
  1810. "three":"3 minutes",
  1811. "four":"4 minutes",
  1812. "five":"5 minutes",
  1813. "ten":"10 minutes",
  1814. },
  1815. "default":"off"
  1816. },
  1817.  
  1818. /*fetchQty:{
  1819. label:"Fetch how many? (subject to filtering)",
  1820. type:"select",
  1821. title:"Posts fetched per request. Higher numbers affect speed of fetching.",
  1822. options:{
  1823. "5":"5",
  1824. "10":"10",
  1825. "25":"25",
  1826. "50":"50",
  1827. "100":"100",
  1828. "250":"250",
  1829. "500":"500 (FB maximum)", //known maximum fetch as of 9/8/2013
  1830. },
  1831. "default":"25"
  1832. },*/
  1833.  
  1834. /*oldinterval:{
  1835. label:"Get Older Posts Interval",
  1836. type:"selecttime",
  1837. title:"Fetch previous posts from facebook after a set time.",
  1838. options:{
  1839. "off":"Off",
  1840. "tenth":"6 seconds",
  1841. "sixth":"10 seconds",
  1842. "half":"30 seconds",
  1843. "one":"1 minute",
  1844. "two":"2 minutes",
  1845. "three":"3 minutes",
  1846. "four":"4 minutes",
  1847. "five":"5 minutes",
  1848. "ten":"10 minutes",
  1849. },
  1850. "default":"off"
  1851. },*/
  1852.  
  1853. maxinterval:{
  1854. label:"How old is too old?",
  1855. type:"selecttime",
  1856. title:"Tell WM what you think is a good max post age to fetch. Also affects which posts are considered 'stale'.",
  1857. options:{
  1858. "off":"Off/Infinite",
  1859. "hour":"1",
  1860. "2hour":"2",
  1861. "3hour":"3",
  1862. "4hour":"4",
  1863. "8hour":"8",
  1864. "12hour":"12",
  1865. "18hour":"18",
  1866. "24hour":"24",
  1867. "32hour":"32",
  1868. "48hour":"48",
  1869. },
  1870. "default":"t:1d"
  1871. },
  1872.  
  1873. //groupFetching:checkBox("All installed sidekicks in one request (default: one request per sidekick)",false,{},true),
  1874. //noAppFiltering:checkBox("Have WM filter posts for you instead of having facebook do it (may prevent some empty data set issues)",false,{},true),
  1875. },true),
  1876.  
  1877. autoPauseBlock:optionBlock("Fetching/Collecting Autopause",{
  1878. autopausefetch:checkBox("Pause Fetching after First Fetch"),
  1879. autopausecollect:checkBox("Pause Collection on Startup"),
  1880. },true),
  1881.  
  1882. multiTaskBlock:optionBlock("Multi-task",{
  1883. maxrequests:inputBox("Max requests simultaneously",1),
  1884. recycletabs:inputBox("Recycle Windows/Tabs",1),
  1885. recycletabsall:checkBox("Recycle All",true),
  1886. },true),
  1887.  
  1888. queBlock:optionBlock("Task-Queue",{
  1889. queuetabs:checkBox("Force all posts and autolikes through one tab using a queue (overrides multi-task)",true),
  1890. },true),
  1891.  
  1892. timeoutBlock:optionBlock("Time-outs",{
  1893. reqtimeout:inputBox("Item Acceptance Page Timeout (seconds)",30),
  1894. failontimeout:checkBox("Mark Timeout as Failure (default: retry indefinitely)"),
  1895. },true),
  1896. }),
  1897.  
  1898. section_access:section("Accessibility",{
  1899. shortModeBlock:optionBlock("Short Mode",{
  1900. thumbsize:{
  1901. label:"Thumbnail Size",
  1902. type:"select",
  1903. title:"Size of bonus thumbnails in display mode: short and .",
  1904. options:{
  1905. "mosquito":"16px",
  1906. "tiny":"24px",
  1907. "small":"32px",
  1908. "medium":"48px",
  1909. "large":"64px",
  1910. "xlarge":"96px",
  1911. },
  1912. "default":"medium"
  1913. },
  1914. transitiondelay:inputBox("Hover Box Delay (s)",1),
  1915. },true),
  1916.  
  1917. accessTweaksBlock:optionBlock("Tweaks",{
  1918. debugrecog:checkBox("Show Identified Text (instead of original link text)",true),
  1919. showcounters:checkBox("Show Accept/Fail Counts",true),
  1920. showdynamictips:checkBox("Show Dynamic Console Tips",true),
  1921. appsConfirmDeleteUDT:checkBox("Confirm Delete User Defined Types",true),
  1922. },true),
  1923.  
  1924. toolBoxBlock:optionBlock("Customize Post Toolbox",{
  1925. showtoolbox:checkBox("Enable ToolBox", true),
  1926.  
  1927. showopen:checkBox("Open Post",true),
  1928. showmarkfailed:checkBox("Mark As Failed",true),
  1929. showmarkaccepted:checkBox("Mark As Accepted",true),
  1930. showlike:checkBox("Like Post",true),
  1931. showreid:checkBox("Re-ID Post",true),
  1932. showmovetop:checkBox("Move to Top",true),
  1933. showmovebottom:checkBox("Move to Bottom",true),
  1934. showpin:checkBox("Pin Post",true),
  1935. showclean:checkBox("Clean Post",true),
  1936. showpostsrc:checkBox("Show Post Source",true),
  1937.  
  1938. showcancelprocess:checkBox("Cancel Process or Like",true),
  1939. showrestartprocess:checkBox("Restart Process or Like",true),
  1940. showpausetype:checkBox("Pause Bonus Type",true),
  1941. showunpausetype:checkBox("Unpause Bonus Type",true),
  1942. showaddfeed:checkBox("Add To Feeds",true),
  1943.  
  1944. showmakerule:checkBox("Rule From Post",true),
  1945. showoriginaldata:checkBox("Show Original Data",true),
  1946. //showautocomment:checkBox("Auto Comment",true),
  1947. },true),
  1948. littleToolBoxBlock:optionBlock("Customize Mini Toolbox",{
  1949. littleButtonSize:{
  1950. label:"Mini Toolbutton Size (requires refresh to redraw)",
  1951. type:"select",
  1952. title:"Size of buttons on mini toolbars",
  1953. options:{
  1954. "16":"16px",
  1955. "24":"24px",
  1956. "32":"32px",
  1957. },
  1958. "default":"24",
  1959. },
  1960. },true),
  1961.  
  1962. userColorsBlock:optionBlock("Colors",{
  1963. colorsaccepted:colorBox("Accepted","limegreen"),
  1964. colorsfailed:colorBox("Failed","red"),
  1965. colorsworking:colorBox("Working","yellow"),
  1966. colorsexcluded:colorBox("Excluded","gray"),
  1967. colorspaused:colorBox("Paused","silver"),
  1968. colorsnodef:colorBox("No Definition","deepskyblue"),
  1969. colorsscam:colorBox("Potential Scam","purple"),
  1970. colorspinned:colorBox("Pinned","black"),
  1971. colorstimeout:colorBox("Timeout","orange"),
  1972. },true),
  1973.  
  1974. }),
  1975.  
  1976. section_feedback:section("Feedback",{
  1977. //publishwarning:{type:"message",title:"Autolike has changed",textContent:"As of WM beta 40 you must allow 'publish_actions' on the 'user data permissions' tab in your Graph API Explorer token builder.",newitem:true},
  1978. //gotoapiexplorer:anchor("Visit API Explorer","http://developers.facebook.com/tools/explorer?&version=v1.0"),
  1979. autoSetup:optionBlock("Setup",{
  1980. //useautocomment:checkBox("Use Auto-comment (experimental)"),
  1981. useautolike:checkBox("Use Auto-like"),
  1982. //autoliketimeout:inputBox("Timeout (seconds)",30),
  1983. autolikedelay:inputBox("Ban-Prevention Delay (seconds)",3),
  1984. },true),
  1985. autoLikeBlock:optionBlock("Perform Feedback For",{
  1986. autolikeall:checkBox("All Posts"),
  1987. autolikeaccepted:checkBox("Accepted Posts"),
  1988. autolikesent:checkBox("Sent Posts"),
  1989. },true),
  1990. /*autoCommentListBlock:optionBlock("Comments (experimental)",{
  1991. autocommentlist:textArea("Random Comments (One per line)","Thanks\nThank you\nthanks"),
  1992. },true),*/
  1993. blockautolikebygame:optionBlock("Block Feedback by Game",{},false),
  1994. }),
  1995.  
  1996. section_filters:section("Filters",{
  1997. displayfilters:optionBlock("Remove Feed Parts (Classic Mode Only)",{
  1998. hideimages:checkBox("Images (All)"),
  1999. hideimagesunwanted:checkBox("Images (Unwanted Posts)"),
  2000. hidebody:checkBox("Post Body Text"),
  2001. hidevia:checkBox("Via App"),
  2002. hidedate:checkBox("Date/Time"),
  2003. },true),
  2004.  
  2005. filters:optionBlock("Hide By Type",{
  2006. hidemyposts:checkBox("My Posts"),
  2007. hideunwanted:checkBox("Unwanted"),
  2008. hideaccepted:checkBox("Accepted"),
  2009. hidefailed:checkBox("Failed"),
  2010. hidescams:checkBox("Scams"),
  2011. hidestale:checkBox("Stale Posts"),
  2012. hideexcluded:checkBox("Excluded"),
  2013. hideliked:checkBox("Liked By Me"),
  2014. hideunsupported:checkBox("Unsupported Apps"),
  2015.  
  2016. donthidewishlists:checkBox("Don't Hide Known Wish Lists"),
  2017. }),
  2018.  
  2019. //allow hiding all posts by particular games
  2020. filterapps:optionBlock("Hide By App",{}),
  2021.  
  2022. //now added dynamically as appID+"dontsteal"
  2023. dontstealBlock:optionBlock("Don't take W2W posts not for me",{}),
  2024.  
  2025. skipopts:optionBlock("Skip By Type",{
  2026. skipliked:checkBox("Liked By Me"),
  2027. skipstale:checkBox("Day-Old Posts"),
  2028. }),
  2029.  
  2030. filterTweaksBlock:optionBlock("Tweaks",{
  2031. accepton15:checkBox("Mark 'Unrecognized Response' As Accepted"),
  2032. markliked:checkBox("Mark Liked As Accepted (must check 'Skip By Type: Liked By Me')"),
  2033. },true),
  2034.  
  2035. filterCleanupBlock:optionBlock("Cleanup",{
  2036. cleaninterval:{
  2037. label:"Cleanup Interval",
  2038. type:"selecttime",
  2039. title:"Remove unwanted posts from collection console after a set time.",
  2040. options:{
  2041. "off":"Off",
  2042. "one":"1 minute",
  2043. "two":"2 minutes",
  2044. "five":"5 minutes",
  2045. "ten":"10 minutes",
  2046. "fifteen":"15 minutes",
  2047. "thirty":"30 minutes",
  2048. "hour":"1 hour",
  2049. },
  2050. "default":"off"
  2051. },
  2052. cleanTimedOut:checkBox("Clean timed out posts",true),
  2053. },true),
  2054. }),
  2055.  
  2056. section_history:section("History",{
  2057. itemage:inputBox("How long to keep tried items in memory (days)",2),
  2058. oblock_historyConfirms:optionBlock("Confirm (Changes available on next config open)",{
  2059. historyConfirmClear:{type:"checkbox",label:"Clear History",title:"Confirm before clearing history.","default":true},
  2060. },true),
  2061. reset:button("Clear History",
  2062. WM.resetAccepted
  2063. ),
  2064. }),
  2065.  
  2066. section_feedopts:section("Feeds Manager",{
  2067. oblock_feedsConfirms:optionBlock("Confirm",{
  2068. feedsConfirmDeleteFeed:{type:"checkbox",label:"Delete Rule",title:"Require confirmation to delete a feed.","default":true},
  2069. },true),
  2070. }),
  2071.  
  2072. section_dynamicopts:section("Dynamic Grabber",{
  2073. dynamicopts:optionBlock("Dynamic Collection",{
  2074. dynamicFirst:checkBox("Run Dynamics BEFORE Sidekicks",true),
  2075. },true),
  2076. enableDynamic:optionBlock("Enable Dynamics by Game",{}),
  2077. oblock_dynamicConfirms:optionBlock("Confirm",{
  2078. dynamicConfirmDeleteTest:{type:"checkbox",label:"Delete Rule",title:"Require confirmation to delete a test.","default":true},
  2079. },true),
  2080. }),
  2081.  
  2082. section_friendtrackopts:section("Friend Tracker",{
  2083. useFriendTracker:checkBox("Enable Friend Tracking",true),
  2084. trackTime:inputBox("Track For How Many Days",2),
  2085. trackeropts:optionBlock("Track Data",{
  2086. trackCreated:checkBox("Post Creation Counts",true),
  2087. trackLastKnownPost:checkBox("Last Known Post Time",true),
  2088. trackAccepted:checkBox("Bonuses Accepted",true),
  2089. trackFailed:checkBox("Bonuses Failed",true),
  2090. },true),
  2091. oblock_trackerConfirms:optionBlock("Confirm",{
  2092. trackConfirmClearUser:{type:"checkbox",label:"Clear User Data",title:"Require confirmation to clear user data.","default":true},
  2093. },true),
  2094. }),
  2095. section_rulesopts:section("Rules Manager",{
  2096. oblock_rulesHeartbeat:optionBlock("Heartbeat",{
  2097. heartRate:inputBox("Global Heartbeat Delay (ms)",1000),
  2098. heartbeatAffectsApps:{type:"checkbox",label:"Affect Apps",title:"Heartbeat can be heard at app level on every rule at once. This can slow down your system."},
  2099. heartbeatAffectsPosts:{type:"checkbox",label:"Affect Posts",title:"Heartbeat can be heard at post level on every rule at once. This can slow down your system."},
  2100. heartbeatAffectsRules:{type:"checkbox",label:"Affect Rules",title:"Heartbeat can be heard at rule level on every rule at once. This can slow down your system."},
  2101. heartbeatAffectsFeeds:{type:"checkbox",label:"Affect Feeds",title:"Heartbeat can be heard at feed level on every rule at once. This can slow down your system."},
  2102. heartbeatAffectsFeedFilters:{type:"checkbox",label:"Affect Feed Filters",title:"Heartbeat can be heard at feed filter level on every rule at once. This can slow down your system."},
  2103. },true),
  2104. oblock_rulesConfirms:optionBlock("Confirm",{
  2105. rulesConfirmDeleteValidator:{type:"checkbox",label:"Delete Validator",title:"Require confirmation to delete a rule's validator.","default":true},
  2106. rulesConfirmDeleteAction:{type:"checkbox",label:"Delete Action",title:"Require confirmation to delete a rule's action.","default":true},
  2107. rulesConfirmDeleteRule:{type:"checkbox",label:"Delete Rule",title:"Require confirmation to delete a rule.","default":true},
  2108. rulesConfirmResetLimit:{type:"checkbox",label:"Reset Limit",title:"Require confirmation to reset individual limits.","default":true},
  2109. rulesConfirmResetAllLimits:{type:"checkbox",label:"Reset All Limits",title:"Require confirmation to reset all limits.","default":true},
  2110. rulesConfirmHatch:{type:"checkbox",label:"Hatch Eggs",title:"Require confirmation to hatch eggs.","default":true},
  2111. },true),
  2112. rulesJumpToNewRule:{type:"checkbox",label:"Jump To New Rules",title:"When new rules are created from tests or posts, select the rules manager tab and scroll the new rule into view.","default":true},
  2113. }),
  2114.  
  2115. section_dev:section("Debug",{
  2116. oblock_debugTweaks:optionBlock("Tweaks",{
  2117. pinundefined:checkBox("Pin Undefined Bonus Types"),
  2118. },true),
  2119. debugOpts:optionBlock("Debug",{
  2120. debug:checkBox("Enable Debug",true),
  2121. debugLevel:{
  2122. label:"Debug Sensitivity",
  2123. title:"Sets the level of errors and warnings to report. 0 is all, 5 shows only the worst.",
  2124. type:"select",
  2125. options:{
  2126. "0":"Function calls",
  2127. "1":"Function subsections & debug notes",
  2128. "2":"Captured expected errors",
  2129. "3":"Known open errors",
  2130. "4":"Unexpected errors",
  2131. "5":"Fatal errors",
  2132. },
  2133. "default":"0"
  2134. },
  2135. debugMaxComments:inputBox("Max debug lines (0 for no limit)",100),
  2136. debugScrollIntoView:checkBox("Use scrollIntoView"),
  2137. debugStackRepeats:checkBox("Stack Immediate Repeats"),
  2138.  
  2139. },true),
  2140. advDebugOpts:optionBlock("Advanced Debug",{
  2141. devDebugFunctionSubsections:checkBox("Debug Function Subsections",false),
  2142. devDebugGraphData:checkBox("Debug Graph Packets (not available for Chrome)",false),
  2143. },true),
  2144. GM_special:optionBlock("Script-runner Options",{
  2145. useGM_openInTab:checkBox("Use GM_openInTab instead of window.open",false),
  2146. },true),
  2147.  
  2148. }),
  2149.  
  2150. section_configopts:section("Config",{
  2151. oblock_configConfirms:optionBlock("Confirm (Changes available on next config open)",{
  2152. configConfirmSave:{type:"checkbox",label:"Save",title:"Confirm before saving settings.","default":true},
  2153. configConfirmCancel:{type:"checkbox",label:"Cancel",title:"Confirm before closing settings without saving.","default":true},
  2154. configConfirmImport:{type:"checkbox",label:"Import",title:"Confirm before importing settings.","default":true},
  2155. configConfirmRestore:{type:"checkbox",label:"Restore Defaults",title:"Confirm before restoring defaults.","default":true},
  2156. },true),
  2157. oblock_configStyling:optionBlock("Styling (Changes available on next config open)",{
  2158. configSectionsAsTabs:{type:"checkbox",label:"Display Sections as Tabs",title:"Converts top level roll-outs only. Display those rollouts as tabs on next open of config."},
  2159. configSeparatorsAsTabs:{type:"checkbox",label:"Display Separators as Tabs",title:"Converts second level roll-outs only. Display those rollouts as tabs on next open of config. Removes select all/none buttons on top of the separator."},
  2160. },true),
  2161. oblock_configTweaks:optionBlock("Tweaks (Changes available on next config open)",{
  2162. configScrollIntoView:{type:"checkbox",label:"Use scrollIntoView",title:"When tabs and sections are opened, use the scrollIntoView function to bring them more fully into view. This is jerky at best."},
  2163. },true),
  2164. }),
  2165. });
  2166.  
  2167. /*wmtab_games:tabSection("Sidekick Options",{
  2168. skmovedwarning:{type:"message",title:"Sidekick options have moved",textContent:"Sidekick options have been moved to separate config windows. Access them by using the 'Manage Sidekicks' tab, where you can find new 'Options' buttons for each sidekick."},
  2169. }),*/
  2170. //debug.print("info section start");
  2171. o.wmtab_info=tabSection("Info",{
  2172. MainMessageCenter:separator("Documentation - Messages - Help",null,{
  2173. //Mainupdate:anchor("Update Script","http://userscripts.org/scripts/source/86674.user.js"),
  2174. donateWM:{type:"link",label:"Donate for FBWM via Paypal",href:"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=merricksdad%40gmail%2ecom&lc=US&item_name=Charlie%20Ewing&item_number=FBWM&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"},
  2175. Mainwikipage:anchor("Wiki Support Page","http://fbwm.wikia.com/wiki/Known_Issues"),
  2176. Mainsetupinfo:anchor("Setup Info","http://fbwm.wikia.com/wiki/New_User_Setup"),
  2177. Maindiscuss:anchor("Known Bugs","http://fbwm.wikia.com/wiki/Known_Issues"),
  2178. Mainrevisionlog:anchor("Revision Log","http://fbwm.wikia.com/wiki/Revisions"),
  2179. },true)
  2180. });
  2181. //debug.print("done config content");
  2182.  
  2183. //debug.print(configContent);
  2184. WM.config = new Config(configContent);
  2185. //debug.print("host options menu created");
  2186. // add options shortcut to user script commands
  2187. GM_registerMenuCommand("Wall Manager "+WM.version+" Options", function(){WM.config.open();});
  2188. }catch(e){log("WM.optionsSetup: "+e);}},
  2189.  
  2190. init : function(){try{
  2191. //capture user id/alias/name and make it global
  2192. WM.currentUser.id = Graph.userID;
  2193. WM.currentUser.alias = Graph.userAlias;
  2194. WM.currentUser.profile = WM.currentUser.id||WM.currentUser.alias; //switch to id over alias preference, as alias may change
  2195.  
  2196. debug.print("UserID:"+WM.currentUser.id+"; UserAlias:"+WM.currentUser.alias+"; WM is Using:"+WM.currentUser.profile);
  2197.  
  2198. //get WM.quickOpts
  2199. WM.quickOpts = getOptJSON('quickopts_'+WM.currentUser.profile)||{};
  2200. WM.quickOpts["filterApp"]=(WM.quickOpts["filterApp"]||"All");
  2201. WM.quickOpts["displayMode"]=(WM.quickOpts["displayMode"]||"0");
  2202. WM.quickOpts["masterSwitch"]=(WM.quickOpts["masterSwitch"]||{});
  2203. WM.quickOpts["useGlobalSettings"]=(WM.quickOpts["useGlobalSettings"]||false);
  2204.  
  2205. //create the options menu
  2206. //debug.print("starting options setup");
  2207. WM.optionsSetup();
  2208.  
  2209. //duplicate the options saved in WM.config
  2210. //debug.print("starting update settings values");
  2211. WM.updateSettingsValues();
  2212.  
  2213. //set up the config with its internal special variables
  2214. WM.changeConfigSettings();
  2215.  
  2216. //setup debug beyond its defaults
  2217. WM.changeDebugSettings();
  2218. //clean history
  2219. WM.history = getOptJSON('history_'+WM.currentUser.profile)||{};
  2220. WM.cleanHistory();
  2221. //prep the console now that we have an id and/or alias
  2222. //and then carry on with our init
  2223. WM.console.init({callback:WM.initConsole});
  2224. }catch(e){log("WM.init: "+e);}},
  2225. receiveSidekickMessage: function(event) {
  2226. if (isObject(event.data)) {
  2227. var data=event.data; //just shorten the typing
  2228. if (data.channel=="WallManager"){
  2229. //log(JSON.stringify(data));
  2230. //$("WM_debugWindow").childNodes[1].lastChild.scrollIntoView();
  2231. switch (data.msg){
  2232. case 2: //getting a comOpen response from sidekick
  2233. //WM.collector.tabs[data.tabID].comOpen=true;
  2234. break;
  2235. case 4: //getting a status package from sidekick
  2236. switch (data.params.action){
  2237. case "onFrameLoad":
  2238. WM.onFrameLoad(data.params);
  2239. break;
  2240. case "onFrameLoad3":
  2241. WM.onFrameLoad3(data.params);
  2242. break;
  2243. }
  2244. break;
  2245. }
  2246. }
  2247. }
  2248. },
  2249.  
  2250. run : function() {try{
  2251. // pre-load console images
  2252. //for(var img in imgs) try{new Image().src = imgs[img];}catch(e){log("preload: "+e);}
  2253.  
  2254. /* Removed for version 4
  2255.  
  2256. //special about:config entry for disabling storage of fb auth token
  2257. //should help multi account users
  2258. //if (getOpt("disableSaveAuthToken"))
  2259. Graph.authToken=null;
  2260. //patch 38 auth token stuff
  2261. var flagManualAuthSuccessful=getOpt("flagManualAuthSuccessful")||false;
  2262. if (WallManager.switches.manualAuthToken && !flagManualAuthSuccessful) {
  2263. var m="WM can no longer access your FB Access Token without your manual assistance.\nTo successfully fetch posts, please complete the following:\n\n*In a new browser window, visit: http://developers.facebook.com/tools/explorer\n\n*If required, allow that app access to your facebook information\n*Find the 'Get Access Token' button and click it\n*In the panel that appears, click 'extended permissions'\n*Be sure that 'read_stream' is selected or otherwise not blank\n*If you want to use autolike/autocomment also select 'publish_actions' from the 'user data permissions' tab*Click the 'Get Access Token' button\n*Now find the box that says 'Access Token' and select its value\n*Copy that value and paste it into the box on this promp\n\nNote: this token does not last forever, you may need to repeat this process";
  2264. var manualToken = prompt(m,"paste token here");
  2265. //validate manualToken at least somewhat
  2266. //halt if manual token is not given
  2267. if (manualToken=="" || manualToken==null || manualToken=="paste token here") {
  2268. alert("manual token not accepted, please refresh and try again");
  2269. return;
  2270. }
  2271. //pass the manual token along
  2272. Graph.authToken=manualToken;
  2273. //consider saving time by looking for auth tokens automatically from here out
  2274. var m = "WM thinks your auth token setup is successful.\nIf you like, I can make it so WM just checks your dev tool for new auth tokens every time.\n\nPress Cancel to continue entering auth codes manually.\n\n*If you have multiple facebook accounts on this computer using WM, please make sure you set up the API explorer with every account.";
  2275. var saveProgress = confirm(m);
  2276. if (saveProgress) {
  2277. setOpt("flagManualAuthSuccessful",true);
  2278. }
  2279. }
  2280.  
  2281. var G=Graph.fetchUser({callback:WM.init});
  2282. if (G){if (G.requestAlreadyOut) {
  2283. } else if (G.initRequestSlow) {
  2284. } else if (G.olderLimitReached) {
  2285. } else if (G.getAuthTokenFailed) {
  2286. }}
  2287. */
  2288. WM.init();
  2289. }catch(e){log("WM.run: "+e);}}
  2290.  
  2291. };
  2292.  
  2293. this.WM=WallManager;
  2294. //allow certain options to be seen outside of the WallManager object
  2295. //graph extension is external but still calls on WM options if they exist
  2296. this.opts=WM.opts;
  2297. this.quickOpts=WM.quickOpts;
  2298.  
  2299. })();