WM Host Object

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

אין להתקין סקריפט זה ישירות. זוהי ספריה עבור סקריפטים אחרים // @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. })();