WM Rules Manager Objects

This is the rules manager system which is created under the WM version 4.x script

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

  1. // ==UserScript==
  2. // @name WM Rules Manager Objects
  3. // @namespace MerricksdadWMRulesManagerObjects
  4. // @description This is the rules manager system 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. //***************************************************************************************************************************************
  17. //***** Rules Manager Object
  18. //***************************************************************************************************************************************
  19. WM.rulesManager = {
  20. rules:[],
  21. enabled:function(){return !WM.quickOpts.heartbeatDisabled;},
  22.  
  23. init:function(params){try{
  24. params=(params||{});
  25. // build a kidsNode getter
  26. WM.rulesManager.__defineGetter__("kidsNode",function(){try{
  27. return $("wmPriorityBuilder");
  28. }catch(e){log("WM.rulesManager.kidsNode: "+e);}});
  29.  
  30. //import rules
  31. WM.rulesManager.rules=[];
  32. var rulesIn=getOptJSON("priority3_"+WM.currentUser.profile)||{};
  33. var globalsIn=getOptJSON("priority3_global")||{};
  34. //detect early beta rule lists
  35. if (isObject(rulesIn)) for (var i in rulesIn){
  36. var rule=rulesIn[i];
  37. WM.rulesManager.rules.push( new WM.rulesManager.Rule(rule) );
  38. //don't bother with globals here
  39. //or use current version rule arrays
  40. } else if (isArrayAndNotEmpty(rulesIn)) for (var i=0,rule;(rule=rulesIn[i]);i++) {
  41. if (rule.isGlobal) {
  42. var glob=globalsIn[rule.uniqueID]||null;
  43. if (glob){
  44. var merge=mergeJSON(glob,rule);
  45. WM.rulesManager.rules.push( new WM.rulesManager.Rule(merge) );
  46. glob.alreadyUsed=true;
  47. } else {
  48. log("WM.rulesManager.init: Global rule missing, cannot merge");
  49. }
  50. } else {
  51. WM.rulesManager.rules.push( new WM.rulesManager.Rule(rule) );
  52. }
  53. }
  54. //import all globals not already accounted for
  55. for (var t in globalsIn) {
  56. var glob=globalsIn[t];
  57. //avoid already imported globals
  58. if (!glob.alreadyUsed){
  59. glob.uniqueID=t;
  60. glob.isGlobal=true;
  61. WM.rulesManager.rule.push( new WM.rulesManager.Rule(glob) );
  62. }
  63. }
  64. }catch(e){log("WM.rulesManager.init: "+e);}},
  65. //check to see if any rules match the post object
  66. doEvent:function(event,obj){
  67. //do nothing if disabled
  68. if (!WM.rulesManager.enabled) return;
  69. //log("WM.rulesManager.doEvent: event="+event+", post="+post.id);
  70. for (var r=0,rule;(rule=WM.rulesManager.rules[r]);r++){
  71. if (rule.enabled) (function(){rule.doEvent(event,obj);})();
  72. }
  73. },
  74. //convert a test (such as dynamic grab entry) to a rule
  75. ruleFromTest:function(test){
  76. //[{"id":"_h6qil21n","label":"new test","search":["body"],"find":["nothing"],"ret":"dynamic","kids":[{"id":"_h6qiw4zf","find":[]}],"appID":"102452128776","disabled":true}]
  77. //[{"enabled":true,"limit":0,"limitCount":0,"expanded":true,"validators":[{"search":["body"],"operand":"lessThan","find":"chipmunk"}],"actions":[{"event":"onIdentify","action":"setColor","params":"orange"}],"kids":[{"enabled":true,"limit":0,"limitCount":0,"expanded":true,"validators":[],"actions":[],"kids":[],"eggs":[]},{"enabled":true,"limit":0,"limitCount":0,"expanded":true,"validators":[],"actions":[],"kids":[],"eggs":[]}],"eggs":[{"enabled":true,"limit":0,"limitCount":0,"expanded":true,"validators":[],"actions":[],"kids":[],"eggs":[]},{"enabled":true,"limit":0,"limitCount":0,"expanded":true,"validators":[],"actions":[],"kids":[],"eggs":[]}]}]
  78. var ret={
  79. title:(test.label||test.title)||"Converted Dynamic Test",
  80. enabled:!(test.disabled||false),
  81. limit:0,
  82. limitCount:0,
  83. expanded:true,
  84. validators:function(){
  85. var ret=[];
  86. //add the initial validator
  87. ret.push({
  88. search:["appID"],
  89. operand:"equals",
  90. find:test.appID
  91. });
  92. //detect search/find method
  93. var method="basic";
  94. if (isArrayAndNotEmpty(test.subTests) && test.find.contains("{%1}")) method="subTests";
  95. if (exists(test.subNumRange) && test.find.contains("{%1}")) method="subNumRange";
  96. if (test.regex==true) method="regexp";
  97. if (method=="regexp") {
  98. //leave the expression just as it is
  99. ret.push({
  100. search:test.search||[],
  101. operand:"matchRegExp",
  102. find:test.find,
  103. });
  104. } else if (method=="basic") {
  105. //convert the test.find array into a regular espression
  106. ret.push({
  107. search:test.search||[],
  108. operand:"matchRegExp",
  109. find:arrayToRegExp(test.find),
  110. });
  111. } else if (method=="subTests") {
  112. //insert the subTests into the find insertion point as a regular expression
  113. //but make the rest of the find parameter not return if found
  114. var find=test.find;
  115. if (find.contains("{%1}")){
  116. find=find.split("{%1}");
  117. find=(find[0].length?("(?:"+find[0]+")"):"")+arrayToRegExp(test.subTests)+(find[1].length?("(?:"+find[1]+")"):"");
  118. }
  119. ret.push({
  120. search:test.search||[],
  121. operand:"matchRegExp",
  122. find:find
  123. });
  124. } else if (method=="subNumRange") {
  125. //insert the subNumRange into the find insertion point as a regular expression
  126. //but make the rest of the find parameter not return if found
  127. var numRange=("string"==typeof test.subNumRange)?test.subNumRange.split(","):[test.subNumRange.low,test.subNumRange.high];
  128. var find=test.find;
  129. if (find.contains("{%1}")){
  130. find=find.split("{%1}");
  131. find=(find[0].length?("(?:"+find[0]+")"):"")+integerRangeToRegExp({min:numRange[0],max:numRange[1]})+(find[1].length?("(?:"+find[1]+")"):"");
  132. }
  133. ret.push({
  134. search:test.search||[],
  135. operand:"matchRegExp",
  136. find:find
  137. });
  138. }
  139. return ret;
  140. }(),
  141. actions:[
  142. {
  143. event:"onIdentify",
  144. action:"setWhich",
  145. params:test.ret||"dynamic",
  146. }
  147. ],
  148. kids:[],
  149. eggs:[],
  150. };
  151. //convert children
  152. if (isArrayAndNotEmpty(test.kids)) {
  153. for (var k=0,kid;(kid=test.kids[k]);k++) {
  154. ret.kids.push(WM.rulesManager.ruleFromTest(kid));
  155. }
  156. }
  157. return ret;
  158. },
  159. //create a rule based on a specific post
  160. ruleFromPost:function(post){
  161. //create some data to get us started
  162. var rule={
  163. basedOn:post,
  164. title:"Based On: "+post.id,
  165. enabled:false, //start out not using this rule
  166. validators:[
  167. {search:["appID"],find:post.appID,operand:"equals"},
  168. {search:["title"],find:post.name,operand:"matchRegExp"},
  169. {search:["caption"],find:post.caption,operand:"matchRegExp"},
  170. {search:["desc"],find:post.description,operand:"matchRegExp"},
  171. {search:["link"],find:post.linkText,operand:"matchRegExp"},
  172. ],
  173. actions:[
  174. {event:"onIdentify",action:"setWhich",params:"dynamic"}
  175. ]
  176. };
  177. WM.rulesManager.rules.push(rule=new WM.rulesManager.Rule(rule));
  178.  
  179. if (WM.opts.rulesJumpToNewRule){
  180. //jump to rule view
  181. WM.console.tabContainer.selectTab(3);
  182. //scroll to new rule
  183. rule.node.scrollIntoView();
  184. }
  185. },
  186. //copy all dynamics to new rules
  187. //does not destroy dynamics as they are converted
  188. convertDynamics:function(){
  189. var tests=WM.grabber.tests;
  190. if (isArrayAndNotEmpty(tests)) {
  191. for (var t=0,test;(test=tests[t]);t++){
  192. WM.rulesManager.rules.push( new WM.rulesManager.Rule( WM.rulesManager.ruleFromTest(test) ) );
  193. }
  194. }
  195. },
  196.  
  197. //rest rule limits for all rules and their children
  198. resetAllLimits:function(params){
  199. params=params||{};
  200. var ask=WM.opts.rulesConfirmResetLimit;
  201. if (params.noConfirm || !ask || (ask && confirm("Reset Limit Counter?"))) {
  202. if (isArrayAndNotEmpty(WM.rulesManager.rules)) for (var r=0,rule;(rule=WM.rulesManager.rules[r]);r++) {
  203. rule.resetLimit({preventSave:true,resetChildren:true,noConfirm:true});
  204. }
  205. WM.rulesManager.saveRules();
  206. }
  207. },
  208. saveRules : function(){try{
  209. //pack rule objects
  210. var retRules=[];
  211. var retGlobal={};
  212. if (isArrayAndNotEmpty(WM.rulesManager.rules)) {
  213. for (var r=0,rule; (rule=WM.rulesManager.rules[r]);r++){
  214. if (!rule.isGlobal) {
  215. retRules.push(rule.saveableData);
  216. } else {
  217. //make a placeholder locally
  218. retRules.push({isGlobal:true, uniqueID:rule.uniqueID, enabled:rule.enabled, expanded:rule.expanded});
  219. //and save it globally
  220. var glob=rule.saveableData;
  221. glob.uniqueID=rule.uniqueID;
  222. retGlobal[rule.uniqueID]=glob;
  223. }
  224. }
  225. }
  226. //save rules
  227. setOptJSON("priority3_"+WM.currentUser.profile,retRules);
  228. setOptJSON("priority3_global",retGlobal);
  229. }catch(e){log("WM.rulesManager.saveRules: "+e);}},
  230. showData : function(){try{
  231. promptText(getOpt("priority3_"+WM.currentUser.profile),true);
  232. }catch(e){log("WM.rulesManager.showData: "+e);}},
  233.  
  234. newRule : function(p){try{
  235. var rule=new WM.rulesManager.Rule(p);
  236. WM.rulesManager.rules.push(rule);
  237. WM.rulesManager.saveRules();
  238. }catch(e){log("WM.rulesManager.newRule: "+e);}},
  239.  
  240. importRule: function(){try{
  241. var params=prompt("Input rule data",null);
  242. if (params) {
  243. var convertedInput=JSON.parse(params);
  244. if (isArray(convertedInput)){
  245. for (var i=0;i<convertedInput.length;i++){
  246. WM.rulesManager.newRule(convertedInput[i]);
  247. }
  248. } else {
  249. WM.rulesManager.newRule(convertedInput);
  250. }
  251. }
  252. }catch(e){log("WM.rulesManager.importRule: "+e);}},
  253.  
  254. toggleHeartbeat: function(){try{
  255. WM.quickOpts.heartbeatDisabled=!WM.quickOpts.heartbeatDisabled;
  256. with (WM.rulesManager.toggleHBNode) {
  257. className=className.swapWordB(WM.quickOpts.heartbeatDisabled,"oddOrange","oddGreen");
  258. }
  259. WM.saveQuickOpts();
  260. log(WM.quickOpts.heartbeatDisabled);
  261. }catch(e){log("WM.rulesManager.toggleHeartbeat: "+e);}},
  262. };
  263. //***************************************************************************************************************************************
  264. //***** Rules Manager Enums & Functions
  265. //***************************************************************************************************************************************
  266. WM.rulesManager.ruleActions = {
  267. "addToFeeds":{name:"Add Poster To Feeds",toolTip:"Add the post's creator to your feeds manager. Can also be used with onFriend* events."},
  268. "appendLink":{name:"Append To Link",toolTip:"Add specific code to the end of the collection link.",hasParam:true,paramType:"textBox","default":""},
  269. "birth":{name:"Birth Eggs",toolTip:"Clone the egg children to this rule's level, without destroying this rule."},
  270. "cancelInterval":{name:"Cancel Interval",toolTip:"Destroy the repeating timer on this rule."},
  271. "cancelTimer":{name:"Cancel Timer",toolTip:"Destroy the timer on this rule."} ,
  272. "cleanPost":{name:"Clean Post",toolTip:"Remove the calling post from the collector."},
  273. "commentPost":{name:"Comment Post",toolTip:"Create a comment on the calling post.",hasParam:true,paramLabel:"comment",paramType:"string","default":"Thanks!"},
  274. "createInterval":{name:"Create Interval",toolTip:"Create a repeating timer on this rule, where 1000 equals 1 second.",hasParam:true,paramType:"timePicker","default":1000} ,
  275. "createTimer":{name:"Create Timer",toolTip:"Create a timer on this rule, where 1000 equals 1 second.",hasParam:true,paramType:"timePicker","default":1000},
  276. "decrementCounter":{name:"Decrement Limit Counter",toolTip:"Decrement the rule limit counter.",hasParam:true,paramType:"number","default":1},
  277. "decrementParentCounter":{name:"Decrement Parent Limit Counter",toolTip:"Decrement the parent rule limit counter.",hasParam:true,paramType:"number","default":1},
  278. "destroyRule":{name:"Destroy Rule",toolTip:"Permanently removes this rule and all of its children."},
  279. "disableApp":{name:"Disable App",toolTip:"Disable the specified app. Leave blank to disable the app associated with the activating post.",hasParam:true,paramType:"textBox","default":""},
  280. "disableAppOption":{name:"Disable App Option",toolTip:"Disable an option in the related sidekick by internal name.",hasParam:true,paramType:"textBox","default":""},
  281. "disableAutocomment":{name:"Disable Autocomment",toolTip:"Disable the autocomment feature."},
  282. "disableAutolike":{name:"Disable Autolike",toolTip:"Disable the autolike feature."},
  283. "disableChildRules":{name:"Disable Child Rules",toolTip:"Disable the immediate children of this rule. Does not disable this rule."},
  284. "disableHostOption":{name:"Disable Host Option",toolTip:"Disable an option in the wm host by internal name.",hasParam:true},
  285. "disableRule":{name:"Disable Rule",toolTip:"Disable the current rule."},
  286. "emergencyOpen":{name:"Emergency Open",toolTip:"Move the calling post directly to a new processing window, no matter what your opened window limit is."},
  287. "emptyAutolikeQueue":{name:"emptyAutolikeQueue",toolTip:"Destroys the list of posts you intended to autolike or autocomment."},
  288. "enableApp":{name:"Enable App",toolTip:"Enable the specified app. Leave blank to enable the app associated with the activating post.",hasParam:true,paramType:"textBox","default":""},
  289. "enableAppOption":{name:"Enable App Option",toolTip:"Enable an option in the related sidekick by internal name.",hasParam:true,paramType:"textBox","default":""},
  290. "enableAutocomment":{name:"Enable Autocomment",toolTip:"Enable the autocomment feature."},
  291. "enableAutolike":{name:"Enable Autolike",toolTip:"Enable the autolike feature."},
  292. "enableChildRules":{name:"Enable Child Rules",toolTip:"Enable the immediate children of this rule."},
  293. "enableHostOption":{name:"Enable Host Option",toolTip:"Enable an option in the wm host by internal name.",hasParam:true},
  294. "enableRule":{name:"Enable Rule",toolTip:"Enable the current rule."},
  295. "fetchVisiblePosts":{name:"Fetch Visible Posts",toolTip:"Fetch some more posts from those loaded to the page."},
  296. //"fetchNewer":{name:"Fetch Newer Posts",toolTip:"Fetch some more posts for this app, feed or feed filter."},
  297. //"fetchOlder":{name:"Fetch Older Posts",toolTip:"Fetch some more posts for this app, feed or feed filter."},
  298. //"fetchHours":{name:"Fetch Hours of Posts",toolTip:"Fetch some more posts for this app, feed or feed filter.",hasParam:true,paramType:"number","default":24},
  299. "forceOpen":{name:"Force Open",toolTip:"Move the calling post directly to the collector queue."},
  300. "forceOpenFirst":{name:"Force Open First",toolTip:"Move the calling post directly to the collector queue AND cut in line to be next processed."},
  301. "hatch":{name:"Hatch Eggs",toolTip:"Hatch the egg-children of the current rule, and destroy this rule."},
  302. "incrementCounter":{name:"Increment Limit Counter",toolTip:"Increment the rule limit counter.",hasParam:true,paramType:"number","default":1},
  303. "incrementParentCounter":{name:"Increment Parent Limit Counter",toolTip:"Increment the parent rule limit counter.",hasParam:true,paramType:"number","default":1},
  304. "likePost":{name:"Like Post",toolTip:"Like the calling post."},
  305. "openPostSource":{name:"Open Post Source",toolTip:"Opens the post source in a separate window/tab."},
  306. "processLast":{name:"Move To Bottom",toolTip:"Move the post to the bottom of the collector window."},
  307. "processFirst":{name:"Move To Top",toolTip:"Move the post to the top of the collector window."},
  308. "pauseAllApps":{name:"Pause All Apps",toolTip:"Pause all apps currently associated with docked sidekicks."},
  309. "pauseApp":{name:"Pause App",toolTip:"Pauses processing anything by this app.",hasParam:true,paramType:"textBox","default":""},
  310. "pauseWM.collector":{name:"Pause WM.collector",toolTip:"Pauses collection of all posts."},
  311. "pauseFetch":{name:"Pause Fetching",toolTip:"Pauses fetching of all posts."},
  312. "pauseType":{name:"Pause Type",toolTip:"Pause collection of all bonuses of this type."},
  313. "pinPost":{name:"Pin Post",toolTip:"Pins the calling post."}, //pin the post
  314. "queueCommentPost":{name:"Queue Comment Post",toolTip:"Comment on the calling post by first using the autolike queue system to delay the autocomment.",hasParam:true,paramLabel:"comment",paramType:"string","default":"Thanks!"},
  315. "queueLikePost":{name:"Queue Like Post",toolTip:"Like the calling post by first using the autolike queue system to delay the autolike."},
  316. "refreshBrowser":{name:"Refresh Browser",toolTip:"Reloads the browser window."},
  317. "reIDAll":{name:"ReID All",toolTip:"Re-ID all posts in the collector."},
  318. "removePriority":{name:"Remove Priority",toolTip:"Sets the priority of the calling post to normal."},
  319. "removePriorityApp":{name:"Remove Priority (App)",toolTip:"Sets the priority of all posts of the calling or specified app to normal.",hasParam:true,paramType:"textBox","default":""},
  320. "removePriorityType":{name:"Remove Priority (Type)",toolTip:"Sets the priority of all posts of the calling app with specified or associated type to normal.",hasParam:true,paramType:"textBox","default":"dynamic"},
  321. "resetAllLimits":{name:"Reset All Limit Counters",toolTip:"Reset all limits in the rules manager."},
  322. "resetLimit":{name:"Reset Limit Counter",toolTip:"Reset the limit counter of the current rule."},
  323. "resetBranchLimits":{name:"Reset Branch Limit Counters",toolTip:"Reset the limit counter of ALL rules that are lower in this branch (children, grandchildren, etc.). Does not reset the limit on this rule."},
  324. "resetChildrenLimits":{name:"Reset Children Limit Counters",toolTip:"Reset the limit counter of immediate child rules of this rule. Does not reset the limit on this rule."},
  325. "resetParentLimit":{name:"Reset Parent Limit Counter",toolTip:"Reset the limit counter of the parent rule."},
  326. "setAppOption":{name:"Set App Option",toolTip:"Set an option in the related sidekick by internal name.",hasParam:true,paramCount:2,paramData:[{paramType:"textBox","default":"",paramLabel:"Name"},{paramType:"textBox","default":"",paramLabel:"Value"}]},
  327. "setAppTab":{name:"Set App Tab",toolTip:"Set the current collection tab by app ID.",hasParam:true,paramType:"textBox","default":"all"},
  328. "setAsAccepted":{name:"Set As Accepted",toolTip:"Set the calling post as accepted.",hasParam:true,paramType:"checkBox",paramLabel:"saveToHistory","default":false},
  329. "setAsExcluded":{name:"Set As Excluded",toolTip:"Set the calling post as excluded."},
  330. "setAsFailed":{name:"Set As Failed",toolTip:"Set the calling post as failed.",hasParam:true,paramType:"checkBox",paramLabel:"saveToHistory","default":false},
  331. "setColor":{name:"Set Post Color",toolTip:"Set the background color of the calling post.",hasParam:true,paramType:"colorPicker","default":"blue"},
  332. "setHostOption":{name:"Set Host Option",toolTip:"Set the value a host option by internal name.",hasParam:true,paramCount:2,paramData:[{paramType:"textBox","default":"",paramLabel:"Name"},{paramType:"textBox","default":"",paramLabel:"Value"}]},
  333. "setPriority":{name:"Set Priority",toolTip:"Set the priority of the calling post.",hasParam:true,paramType:"number","default":50},
  334. "setPriorityApp":{name:"Set Priority (App)",toolTip:"Set the priority of the calling app or specified app.",hasParam:true,paramCount:2,paramData:[{paramType:"textBox",paramLabel:"App","default":""},{paramType:"number",paramLabel:"Priority","default":50}]},
  335. "setPriorityType":{name:"Set Priority (Type)",toolTip:"Set the priority of the calling post type or specified type for the same app.",hasParam:true,paramCount:2,paramData:[{paramType:"textBox",paramLabel:"Type Code","default":""},{paramType:"number",paramLabel:"Priority","default":50}]},
  336. "setToCollect":{name:"Set To Collect",toolTip:"Set the calling post to be collected in normal order. Use Force Open to do more immediate collection, or Emergency Open to override your opened window limit."},
  337. "setToCollectPriority1":{name:"Set To Collect Top Priority",toolTip:"Set the calling post to be collected and also set its priority to 1. Use Force Open to do more immediate collection, or Emergency Open to override your opened window limit."},
  338. "setWhich":{name:"Set Type",toolTip:"Set the bonus type id of the calling post.",hasParam:true,paramType:"textBox","default":"dynamic"},
  339. "uncheckType":{name:"Uncheck Post Type",toolTip:"Unchecks option to collect this bonus in the options menu."},
  340. "unpauseAllApps":{name:"Unpause All Apps",toolTip:"Unpause all apps currently associated with docked sidekicks."},
  341. "unpauseAllTypesAllApps":{name:"Unpause All Types",toolTip:"Unpause all bonus types by all apps."},
  342. "unpauseAllTypesByApp":{name:"Unpause All Types By App",toolTip:"Unpause all bonus types associated with the given app, or the app associated with the activating post.",hasParam:true,paramType:"textBox","default":""},
  343. "unpauseApp":{name:"Unpause App",toolTip:"Starts processing anything by this app.",hasParam:true,paramType:"textBox","default":""},
  344. "unpauseWM.collector":{name:"Unpause WM.collector",toolTip:"Starts collection of posts."},
  345. "unpauseFetch":{name:"Unpause Fetching",toolTip:"Starts fetching of posts."},
  346. "unpauseType":{name:"Unpause Type",toolTip:"Unpause collection of all bonuses of this type."},
  347. };
  348. WM.rulesManager.ruleActionsCodes = {
  349. "addToFeeds":1,"appendLink":2,"birth":3,"cancelInterval":4,"cancelTimer":5,"cleanPost":6,"commentPost":7,"createInterval":8,"createTimer":9,
  350. "decrementCounter":10,"decrementParentCounter":11,"destroyRule":12,"disableApp":13,"disableAppOption":14,"disableAutolike":15,"disableChildRules":16,
  351. "disableHostOption":17,"disableRule":18,"emergencyOpen":19,"emptyAutolikeQueue":20,"enableApp":21,"enableAppOption":22,"enableAutolike":23,
  352. "enableChildRules":24,"enableHostOption":25,"enableRule":26,"fetchNewer":27,"fetchOlder":28,"forceOpen":29,"forceOpenFirst":30,"hatch":31,
  353. "incrementCounter":32,"incrementParentCounter":33,"likePost":34,"openPostSource":35,"processLast":36,"processFirst":37,"pauseAllApps":38,
  354. "pauseApp":39,"pauseWM.collector":40,"pauseFetch":41,"pauseType":42,"pinPost":43,"queueCommentPost":44,"queueLikePost":45,"refreshBrowser":46,
  355. "reIDAll":47,"removePriority":48,"removePriorityApp":49,"removePriorityType":50,"resetAllLimits":51,"resetLimit":52,"resetBranchLimits":53,
  356. "resetChildrenLimits":54,"resetParentLimit":55,"setAppOption":56,"setAppTab":57,"setAsAccepted":58,"setAsExcluded":59,"setAsFailed":60,"setColor":61,
  357. "setHostOption":62,"setPriority":63,"setPriorityApp":64,"setPriorityType":65,"setToCollect":66,"setToCollectPriority1":67,"setWhich":68,
  358. "uncheckType":69,"unpauseAllApps":70,"unpauseAllTypesAllApps":71,"unpauseAllTypesByApp":72,"unpauseApp":73,"unpauseWM.collector":74,"unpauseFetch":75,
  359. "unpauseType":76,"fetchHours":77,"enableAutocomment":78,"disableAutocomment":79,"fetchVisiblePosts":80
  360. };
  361. WM.rulesManager.ruleActionByCode = function(code){
  362. for (c in WM.rulesManager.ruleActionsCodes) {
  363. if (WM.rulesManager.ruleActionsCodes[c]==code) return c;
  364. }
  365. return null;
  366. };
  367. WM.rulesManager.ruleEvents = {
  368. //post events
  369. "onIdentify":"Called after a post is (re)identified. Posts are first identified as soon as they are fetched.",
  370. "onBeforeCollect":"Called before collection opens a sidekick window.",
  371. "onAfterCollect":"Called after collection is tried. Activates regardless of return status.",
  372. "onFailed":"Called when a post is marked failed. This could be actual or simulated by the user.",
  373. "onAccepted":"Called when a post is marked accepted. This could be actual or simulated by the user.",
  374. "onTimeout":"Called when a post is marked as timed out. This could be actual or simulated by the user.",
  375. "onValidate":"Called when a post is first fetched, but after its first identification. Not called on posts which fail identification.",
  376. //rule events
  377. "onLimit":"Called when this rule limit counter equals the rule's limit.",
  378. "onHatch":"Called when this rule's egg children are hatched.",
  379. "onTimer":"Called when the timer on this rule activates.",
  380. "onInterval":"Called when the repeating timer on this rule activates.",
  381. "onBirth":"Called when this rule's egg children are birthed.",
  382. "onRuleCreated":"Called when the rule is created (or loaded on startup).",
  383. "onRuleButtonClicked":"Called when the rule button is clicked. Available only for control rules.",
  384. //app events
  385. "onSidekickDock":"Called when the sidekick for this app docks.",
  386. "onSidekickReady":"Called when the sidekick for this app creates an app object, and after it appends the collection tab for that app.",
  387. /*
  388. paused/unpaused
  389. enabled/disabled
  390. failCountChanged
  391. acceptCountChanged
  392. */
  393. //console events
  394. "onHeartbeat":"Called when the global heartbeat interval ticks.",
  395. "onSetAppFilter":"Called when the collection panel app tab changes, including at startup if 'Show All' is selected as default",
  396. //feed events
  397. "onFeedFilterOlderLimitReached":"Called when a specific feed filter reaches its user-defined older limit.",
  398. };
  399. WM.rulesManager.ruleEventsCodes ={
  400. "onIdentify":1,"onBeforeCollect":2,"onAfterCollect":3,"onFailed":4,"onAccepted":5,"onTimeout":6,"onValidate":7,"onLimit":8,"onHatch":9,"onTimer":10,
  401. "onInterval":11,"onBirth":12,"onRuleCreated":13,"onSidekickDock":14,"onSidekickReady":15,"onHeartbeat":16,"onSetAppFilter":17,
  402. "onFeedFilterOlderLimitReached":18,"onRuleButtonClicked":19
  403. };
  404. WM.rulesManager.ruleEventByCode = function(code){
  405. for (c in WM.rulesManager.ruleEventsCodes) {
  406. if (WM.rulesManager.ruleEventsCodes[c]==code) return c;
  407. }
  408. return null;
  409. };
  410. WM.rulesManager.postParts = {
  411. "age":"The time between the current time and the post creation time (in ms).",
  412. "acceptCount":"An app's accept counter value. Friend objects also have an acceptCount.",
  413. "activatorType":"Returns the object type of the rule-activating object: app, post, rule, feed, feedfilter or unknown.",
  414. "alreadyProcessed":"Reports if a post has already created a history entry.",
  415. "appID":"The appID of the game for which a post belongs. You can read the appID from the following affected objects: app, post, and feedFilter.",
  416. "appName":"The appName of the game for which this post belongs, as reported by the FB database.",
  417. "body":"The body of a post is a compilation of the title, caption, and desc.",
  418. "canvas":"The canvas of a post is its namespace granted by FB, ie. FarmVille's namespace is 'onthefarm'.",
  419. "caption":"The caption of a post is one line just below its title (or 'name'). Not all posts have this field.",
  420. "commentorID":"The commentorID is a list of IDs of all commentors.",
  421. "commentorName":"The commentorName is a list of names of all commentors.",
  422. "comments":"The comments are list of all comments made to the post, excluding the initial msg.",
  423. "currentTime":"The current time (in ms) on your system, not localized. This global value can be referenced from any activating object type.",
  424. "currentAppTab":"The currently selected collection tab's appID, or the word 'all' if the 'Show All' tab is selected.",
  425. "date":"The date of a post is its creation time on FB, and is the 'created_time' parameter in fb data packets.",
  426. "desc":"The desc of a post is two lines below the title. This is the 'description' parameter in fb data packets. Not all posts have this field.",
  427. "either":"The either of a post is the compilation of the link and body.",
  428. "enabled":"The enabled state of an activating object.",
  429. "expanded":"The expanded state of an activating object.",
  430. "failCount":"An app's fail counter value. Friend objects also have a failCount.",
  431. "friendAcceptedCount":"Gets the accepted count from a FriendTracker friend object matching this post creator.",
  432. "friendFailedCount":"Gets the failed count from a FriendTracker friend object matching this post creator.",
  433. "fromID":"The fromID is the ID of the poster.",
  434. "fromName":"The fromName is the name of the poster.",
  435. "fromNameLastFirst":"The name of the poster, displayed as Lastname, Firstname",
  436. "html":"The html of a post is the compilation of ALL visible FB attributes.",
  437. "id":"Normally a post ID, which is usually the post creator's ID and a timestamp separated by an underscore. Alternately, you can ask for the id of an activating friend, feed or feed filter object.",
  438. "idText":"The identified link text of a post.",
  439. "img":"The img of a post is the url of the icon that displays with the post. This is the 'picture' parameter in fb data packets.",
  440. "isAccepted":"Reports if the post is set as having already been successfully collected.",
  441. "isAppPaused":"Reports if the associated app is paused.",
  442. "isCollect":"Reports if the post is set to be collected.",
  443. "isExcluded":"Reports if the post has been set as excluded.",
  444. "isFailed":"Reports if the post is set as having already failed.",
  445. "isForMe":"Reports if the W2W post targets the current user.",
  446. "isLiked":"Reports if the post has been identified as already being liked by the current user.",
  447. "isMyPost":"Reports if the post belongs to the current user.",
  448. "isPaused":"Reports if the calling object (post or app) is paused. Not specific!",
  449. "isPinned":"Reports if the post is marked as being pinned.",
  450. "isRemovable":"Reports if a feed is removeable. Your own profile wall and your home feed are not removeable, only disableable.",
  451. "isTimeout":"Reports if the post has been marked as a timed out collection attempt.",
  452. "isTypePaused":"Reports if the associated bonus type is paused.",
  453. "isScam":"Reports if a post is suspected of being a scam, usually when the canvas and appName do not match.",
  454. "isStale":"Reports if a post is older than the user-set older limit.",
  455. "isUndefined":"Reports if the post does not match any id given by the sidekick.",
  456. "isWishlist":"Reports if the post is deemed a whichlist request.",
  457. "isWorking":"Reports if the post is currently in the working state (being processed).",
  458. "isW2W":"Reports if the post is a Wall-To-Wall post, meaning that it was posted to a specific user's wall.",
  459. "lastKnownPostDate":"A friend object's last known post date (as unix time, no millisecond data).",
  460. "likeID":"The likeID is a list of IDs of users who liked the post.",
  461. "likeName":"The likeName is a list of names of users who liked this post.",
  462. "limit":"This rule's limit number.",
  463. "limitCount":"This rule's limit counter.",
  464. "link":"The 'link' of a post is the link text, not the url. This is the 'action.name' in fb data packets.",
  465. "linkHref":"The original url as it appeared from facebook. This SHOULD be exactly the same as 'url'.",
  466. "linkText":"The original link text as it appeared from facebook. You may want to NOT use 'link' and instead use this one.",
  467. "msg":"The msg of a post is the part the poster added as a comment during the post's creation.",
  468. "name":"With posts, this is the same as 'title', because its the FB name of a post object. With friend objects, this is the friend's text name.",
  469. "parentLimit":"The parent rule's limit number, or NULL if no parent exists.",
  470. "parentLimitCount":"The parent rule's limit counter, or NULL if no parent exists.",
  471. "postCount":"A friend object's count of posts it is tracking.",
  472. "postedDay":"A partial date-time value containing only the year/month/day portions, which corresponds to the post creation time.",
  473. "postedHour":"A partial date-time value containing only the year/month/day/hour portions, which corresponds to the post creation time.",
  474. "priority":"The priority of a post which could have been set by a rule, or by default of 50.",
  475. "status":"The status of a post is the return code given by a sidekick, or 0 if it has not been processed.",
  476. "targetID":"The targetID is a list of targets' IDs that the poster intended the post to display to.",
  477. "targetName":"The targetName is a list of targets the poster intended the post to display to.",
  478. "title":"The title of a post contains the bold text, usually including the poster's name, at the top of the post. This is the 'name' parameter in facebook data packets.",
  479. "totalCount":"An app's failcount and acceptcount combined. Friend objects also have a totalCount.",
  480. "typesPaused":"An app's list of paused bonus types. Only accessible from an activating post. Please stick to the contains/notContains operators because this is an array, not text.",
  481. "url":"The url of a post is the address to which the post redirects the user when clicked. This is the 'link' or 'action.link' parameter in fb data packets. This is the original url supplied by the app, not a modified url, such as WM's removal of https or a sidekick-modified url. Alternately, you can ask for the URL of a feed object.",
  482. "which":"The 'which' of a post is its identified codename that defines its bonus type and ties it to option menu entries. The codename starts with an appID and ends with something the sidekick developer uses to key the bonus type.",
  483. "whichText":"Text associated with this bonus type.",
  484. };
  485. WM.rulesManager.postPartsCodes = {
  486. "age":1,"acceptCount":2,"activatorType":3,"alreadyProcessed":4,"appID":5,"appName":6,"body":7,"canvas":8,"caption":9,"commentorID":10,
  487. "commentorName":11,"comments":12,"currentTime":13,"currentAppTab":14,"date":15,"desc":16,"either":17,"enabled":18,"expanded":19,"failCount":20,
  488. "fromID":21,"fromName":22,"fromNameLastFirst":23,"html":24,"id":25,"idText":26,"img":27,"isAccepted":28,"isAppPaused":29,"isCollect":30,
  489. "isExcluded":31,"isFailed":32,"isForMe":33,"isLiked":34,"isMyPost":35,"isPaused":36,"isPinned":37,"isRemovable":38,"isTimeout":39,"isTypePaused":40,
  490. "isScam":41,"isStale":42,"isUndefined":43,"isWishlist":44,"isWorking":45,"isW2W":46,"lastKnownPostDate":47,"likeID":48,"likeName":49,"limit":50,
  491. "limitCount":51,"link":52,"linkHref":53,"linkText":54,"msg":55,"name":56,"parentLimit":57,"parentLimitCount":58,"postCount":59,"postedDay":60,
  492. "postedHour":61,"priority":62,"status":63,"targetID":64,"targetName":65,"title":66,"totalCount":67,"typesPaused":68,"url":69,"which":70,
  493. "whichText":71,"friendAcceptedCount":72,"friendFailedCount":73
  494. };
  495. WM.rulesManager.postPartByCode = function(code){
  496. for (c in WM.rulesManager.postPartsCodes) {
  497. if (WM.rulesManager.postPartsCodes[c]==code) return c;
  498. }
  499. return null;
  500. };
  501. WM.rulesManager.ruleOperands = {
  502. "equals":"Property and query must match.",
  503. "notEquals":"Property and query must not match.",
  504. "startsWith":"Property must start with query value.",
  505. "notStartsWith":"Property cannot start with query value.",
  506. "endsWith":"Property must end with query value.",
  507. "notEndsWith":"Property cannot end with query value.",
  508. "contains":"Property contains anywhere the query value.",
  509. "notContains":"Property does not contain the query value.",
  510. "matchRegExp":"Property must match the registered expression.",
  511. "notMatchRegExp":"Property must not match the registered expression.",
  512. "greaterThan":"Property must be greater than query value.",
  513. "lessThan":"Property must be less than query value.",
  514. "greaterThanOrEquals":"Property must be greater than or equal to query value.",
  515. "lessThanOrEquals":"Property must be less than or equal to query value.",
  516.  
  517. "equalsExactly":"Property and query must match exactly via binary comparison.",
  518. "notEqualsExactly":"Property and query must not match exactly via binary comparison.",
  519. };
  520.  
  521. WM.rulesManager.ruleOperandsCodes = {
  522. "equals":1,
  523. "notEquals":2,
  524. "startsWith":3,
  525. "notStartsWith":4,
  526. "endsWith":5,
  527. "notEndsWith":6,
  528. "contains":7,
  529. "notContains":8,
  530. "matchRegExp":9,
  531. "notMatchRegExp":10,
  532. "greaterThan":11,
  533. "lessThan":12,
  534. "greaterThanOrEquals":13,
  535. "lessThanOrEquals":14,
  536. "equalsExactly":15,
  537. "notEqualsExactly":16,
  538. };
  539. WM.rulesManager.ruleOperandByCode = function(code){
  540. for (c in WM.rulesManager.ruleOperandsCodes) {
  541. if (WM.rulesManager.ruleOperandsCodes[c]==code) return c;
  542. }
  543. return null;
  544. };
  545. //***************************************************************************************************************************************
  546. //***** RuleValidator Class
  547. //***************************************************************************************************************************************
  548. WM.rulesManager.RuleValidator = function(params){try{
  549. var isNew=(!exists(params));
  550. var self=this;
  551. //return saveable data from this branch
  552. this.__defineGetter__("saveableData",function(){try{
  553. var s=self.search, modSearch=[]; //use a second array to avoid accidental overwrite of first byRef
  554. for (var c=0;c<s.length;c++){
  555. modSearch.push(WM.rulesManager.postPartsCodes[s[c]]);
  556. }
  557. var ret = {search:modSearch, operand:WM.rulesManager.ruleOperandsCodes[self.operand], find:self.find}
  558. return ret;
  559. }catch(e){log("WM.rulesManager.RuleValidator.saveableData: "+e);}});
  560.  
  561. //remove this from parent
  562. this.remove=function(){try{
  563. var ask=WM.opts.rulesConfirmDeleteValidator;
  564. if (!ask || (ask && confirm("Delete rule validator?"))){
  565. remove(this.node);
  566. this.parent.validators.removeByValue(this);
  567. doAction(WM.rulesManager.saveRules);
  568. }
  569. }catch(e){log("WM.rulesManager.RuleValidator.remove: "+e);}};
  570. this.moveUp=function(){try{
  571. //where is this
  572. var parentContainer = this.parent.validators;
  573. //only affects items not already the first in the list
  574. //and not the only child in the list
  575. if ((parentContainer.length>1) && (parentContainer[0]!=this)) {
  576. //which index is this?
  577. var myIndex=parentContainer.inArrayWhere(this);
  578. if (myIndex != -1) {
  579. //I have a proper index here
  580. //who is my sibling
  581. var sibling = parentContainer[myIndex-1];
  582. //swap me with my sibling
  583. parentContainer[myIndex-1]=this;
  584. parentContainer[myIndex]=sibling;
  585. //place my node before my sibling node
  586. sibling.node.parentNode.insertBefore(this.node,sibling.node);
  587. //save it
  588. WM.rulesManager.saveRules();
  589. }
  590. }
  591. }catch(e){log("WM.rulesManager.RuleValidator.moveUp: "+e);}};
  592.  
  593. //move down in the list
  594. this.moveDown=function(){try{
  595. //where is this
  596. var parentContainer = this.parent.validators;
  597. //only affects items not already the first in the list
  598. //and not the only child in the list
  599. if ((parentContainer.length>1) && (parentContainer.last()!=this)) {
  600. //which index is this?
  601. var myIndex=parentContainer.inArrayWhere(this);
  602. if (myIndex != -1) {
  603. //I have a proper index here
  604. //who is my sibling
  605. var sibling = parentContainer[myIndex+1];
  606. //swap me with my sibling
  607. parentContainer[myIndex+1]=this;
  608. parentContainer[myIndex]=sibling;
  609. //place my node before my sibling node
  610. sibling.node.parentNode.insertBefore(sibling.node,this.node);
  611. //save it
  612. WM.rulesManager.saveRules();
  613. }
  614. }
  615. }catch(e){log("WM.rulesManager.RuleValidator.moveDown: "+e);}};
  616.  
  617. //copy this validator on the parent
  618. this.clone=function(){try{
  619. this.parent.addValidator({search:this.search, operand:this.operand, find:this.find});
  620. WM.rulesManager.saveRules();
  621. }catch(e){log("WM.rulesManager.RuleValidator.clone: "+e);}};
  622.  
  623. //init
  624. //this.id=params.id||unique();
  625. this.parent=params.parent||null;
  626. if (!this.parent) {
  627. log("WM.rulesManager.RuleValidator: no parent specified: abort init");
  628. return null;
  629. }
  630. //this.validationNode=parent.validationNode;
  631. this.search=params.search||["appID"];
  632. if (!isArray(this.search)) this.search=[].push(this.search);
  633. //convert number codes to text commands
  634. for (var e in this.search) {
  635. //t=this.search[e];
  636. if (isNumber(this.search[e])) this.search[e]=WM.rulesManager.postPartByCode(this.search[e]);
  637. //log([this.search[e],t])
  638. }
  639. this.operand=params.operand||"matchRegExp";
  640. if (isNumber(this.operand)) this.operand=WM.rulesManager.ruleOperandByCode(this.operand);
  641. this.find=params.find||"";
  642. //draw it
  643. this.parent.validationNode.appendChild(this.node=createElement("div",{className:"validator"},[
  644. //search portion for this validator
  645. createElement("div",{className:"line"},[
  646. this.searchNode=(this.objSearch=new jsForms.comboBox({
  647. className:"jsfComboBox selectPostPart",
  648. onChange:function(){
  649. self.search=this.value;
  650. WM.rulesManager.saveRules();
  651. },
  652. items:(function(){
  653. var ret=[];
  654. for (var i in WM.rulesManager.postParts){
  655. ret.push(new jsForms.checkBox({
  656. text:i,
  657. value:i,
  658. toolTipText:WM.rulesManager.postParts[i],
  659. checked:(self.search.inArray(i)),
  660. size:{width:"200%"},
  661. }));
  662. }
  663. return ret;
  664. })(),
  665. borderStyle:"none",
  666. //borderRadius:{topLeft:"1px", bottomRight:"1px",topRight:"1px",bottomLeft:"1px"},
  667. //explicitClose:true,
  668. highlightSelected:true,
  669. dropDownSize:{height:"200px"},
  670. backColor:"#EEEEEE",
  671. })).node,
  672. //operator portion for this validator
  673. this.operandNode=createElement("select",{className:"selectOperand",onchange:function(){self.operand=this.value;WM.rulesManager.saveRules();}},(function(){
  674. var ret=[],elem;
  675. for (var i in WM.rulesManager.ruleOperands){
  676. ret.push(elem=createElement("option",{textContent:i,value:i,title:WM.rulesManager.ruleOperands[i]}));
  677. if (i==self.operand) elem.selected=true;
  678. }
  679. return ret;
  680. })()),
  681. //find portion for this validator
  682. /*
  683. right here we need to bring up an element based on
  684. the post part chosen
  685. for most cases, we just need an input box to accept string values
  686. for special case "which" we need a dropdown of bonus types
  687. for boolean flags we need a default value of true and maybe
  688. some kind of limitation to true and false in the box
  689. */
  690. this.findNode=createElement("input",{className:"findBox",value:this.find,onchange:function(){self.find=this.value;WM.rulesManager.saveRules();}}),
  691. //toolbox
  692. createElement("div",{className:"littleButton oddOrange",onclick:function(){self.remove();},title:"Delete Validator"},[
  693. createElement("img",{className:"resourceIcon trash"+WM.opts.littleButtonSize}),
  694. ]),
  695. createElement("div",{className:"littleButton oddBlue",onclick:function(){self.clone();},title:"Clone Validator"},[
  696. createElement("img",{className:"resourceIcon clone"+WM.opts.littleButtonSize}),
  697. ]),
  698. createElement("div",{className:"littleButton oddGreen",onclick:function(){self.moveUp();},title:"Move Up"},[
  699. createElement("img",{className:"resourceIcon arrowUp"+WM.opts.littleButtonSize}),
  700. ]),
  701. createElement("div",{className:"littleButton oddOrange",onclick:function(){self.moveDown();},title:"Move Down"},[
  702. createElement("img",{className:"resourceIcon arrowDown"+WM.opts.littleButtonSize}),
  703. ]),
  704. (self.parent.basedOn)?createElement("div",{className:"indent littleButton oddBlue",onclick:function(){
  705. //if a validator search array exists
  706. if (isArrayAndNotEmpty(self.search)){
  707. //fill the 'find' box with the post data linked to the search terms
  708. var f="";
  709. var post=self.parent.basedOn;
  710. for (var s=0;s<self.search.length;s++){
  711. if (s>0) f+=" ";
  712. f+=(post.testData[self.search[s]]||post[self.search[s]]||"");
  713. }
  714. self.findNode.value=f;
  715. self.find=f;
  716. WM.rulesManager.saveRules();
  717. }
  718. },title:"Capture Text From Linked Post"},[
  719. createElement("img",{className:"resourceIcon importData"+WM.opts.littleButtonSize}),
  720. ]):null,
  721. ]),
  722. ]));
  723. //if (isNew) WM.rulesManager.saveRules();
  724. return self;
  725. }catch(e){log("WM.rulesManager.RuleValidator.init(): "+e);}};
  726.  
  727. //***************************************************************************************************************************************
  728. //***** RuleAction Class
  729. //***************************************************************************************************************************************
  730. WM.rulesManager.RuleAction = function(params){try{
  731. var isNew=(!exists(params));
  732. var self=this;
  733. //return saveable data from this branch
  734. this.__defineGetter__("saveableData",function(){try{
  735. var a= {event:WM.rulesManager.ruleEventsCodes[this.event], action:WM.rulesManager.ruleActionsCodes[this.action]};
  736. if (this.hasParam) a.params=this.params;
  737. if (this.paramCount==2) a.params2=this.params2;
  738. return a;
  739. }catch(e){log("WM.rulesManager.RuleAction.saveableData: "+e);}});
  740.  
  741. //remove this from parent
  742. this.remove=function(){try{
  743. var ask=WM.opts.rulesConfirmDeleteAction;
  744. if (!ask || (ask && confirm("Delete rule action?"))){
  745. remove(this.node);
  746. this.parent.actions.removeByValue(this);
  747. doAction(WM.rulesManager.saveRules);
  748. }
  749. }catch(e){log("WM.rulesManager.RuleAction.remove: "+e);}};
  750. //move up in the list
  751. this.moveUp=function(){try{
  752. //where is this
  753. var parentContainer = this.parent.actions;
  754. //only affects items not already the first in the list
  755. //and not the only child in the list
  756. if ((parentContainer.length>1) && (parentContainer[0]!=this)) {
  757. //which index is this?
  758. var myIndex=parentContainer.inArrayWhere(this);
  759. if (myIndex != -1) {
  760. //I have a proper index here
  761. //who is my sibling
  762. var sibling = parentContainer[myIndex-1];
  763. //swap me with my sibling
  764. parentContainer[myIndex-1]=this;
  765. parentContainer[myIndex]=sibling;
  766. //place my node before my sibling node
  767. sibling.node.parentNode.insertBefore(this.node,sibling.node);
  768. //save it
  769. WM.rulesManager.saveRules();
  770. }
  771. }
  772. }catch(e){log("WM.rulesManager.RuleAction.moveUp: "+e);}};
  773.  
  774. //move down in the list
  775. this.moveDown=function(){try{
  776. //where is this
  777. var parentContainer = this.parent.actions;
  778. //only affects items not already the first in the list
  779. //and not the only child in the list
  780. if ((parentContainer.length>1) && (parentContainer.last()!=this)) {
  781. //which index is this?
  782. var myIndex=parentContainer.inArrayWhere(this);
  783. if (myIndex != -1) {
  784. //I have a proper index here
  785. //who is my sibling
  786. var sibling = parentContainer[myIndex+1];
  787. //swap me with my sibling
  788. parentContainer[myIndex+1]=this;
  789. parentContainer[myIndex]=sibling;
  790. //place my node before my sibling node
  791. sibling.node.parentNode.insertBefore(sibling.node,this.node);
  792. //save it
  793. WM.rulesManager.saveRules();
  794. }
  795. }
  796. }catch(e){log("WM.rulesManager.RuleAction.moveDown: "+e);}};
  797.  
  798. //copy this validator on the parent
  799. this.clone=function(){try{
  800. this.parent.addAction(this.saveableData());
  801. WM.rulesManager.saveRules();
  802. }catch(e){log("WM.rulesManager.RuleAction.clone: "+e);}};
  803.  
  804. //init
  805. //this.id=params.id||unique();
  806. this.parent=params.parent||null;
  807. if (!this.parent) {
  808. log("WM.rulesManager.RuleAction: no parent specified: abort init");
  809. return null;
  810. }
  811. //this.actionsNode=parent.actionsNode;
  812. this.action=params.action||"incrementCounter";
  813. //log(this.action);
  814. if (isNumber(this.action)) this.action=WM.rulesManager.ruleActionByCode(this.action);
  815. this.event=params.event||"onAccepted";
  816. if (isNumber(this.event)) this.event=WM.rulesManager.ruleEventByCode(this.event);
  817. //setup default values and param types
  818. //log(this.action);
  819. var def=WM.rulesManager.ruleActions[this.action];
  820. this.hasParam = def.hasParam;
  821. this.params = params.params||def["default"]||((def.paramData||null)?def.paramData[0]["default"]:"");
  822. this.params2 = params.params2||((def.paramData||null)?def.paramData[1]["default"]:"");
  823. this.paramCount = def.paramCount;
  824. //draw it
  825. this.parent.actionsNode.appendChild(this.node=createElement("div",{className:"action"},[
  826. //event for this action
  827. createElement("div",{className:"line"},[
  828. this.eventNode=createElement("select",{className:"selectEvent",onchange:function(){self.event=this.value; if (self.event=="onRuleButtonClicked") {self.parent.ruleButtonHousingNode.style.display="";} else {self.parent.ruleButtonHousingNode.style.display="none";}; WM.rulesManager.saveRules();}},(function(){
  829. var actioneventsret=[],elem;
  830. for (var i in WM.rulesManager.ruleEvents){
  831. actioneventsret.push(elem=createElement("option",{textContent:i,value:i,title:WM.rulesManager.ruleEvents[i]}));
  832. if (i==self.event) elem.selected=true;
  833. }
  834. return actioneventsret;
  835. })()),
  836. //function to call on the event
  837. this.actionNode=createElement("select",{className:"selectFunction",onchange:function(){
  838. self.action=this.value;
  839. WM.rulesManager.saveRules();
  840. //set the param type
  841. var action = WM.rulesManager.ruleActions[this.value];
  842. self.paramNode.style.display=((action.hasParam)?"":"none");
  843. self.param2Node.style.display=((action.hasParam && (action.paramCount==2))?"":"none");
  844.  
  845. }},(function(){
  846. var actionfuncsret=[],elem;
  847. for (var i in WM.rulesManager.ruleActions){
  848. entry=WM.rulesManager.ruleActions[i];
  849. actionfuncsret.push(elem=createElement("option",{textContent:entry.name,value:i,title:entry.toolTip}));
  850. if (i==self.action) elem.selected=true;
  851. }
  852. return actionfuncsret;
  853. })()),
  854. //this is for special cases only and should be hidden otherwise
  855. this.paramNode=createElement("input",{className:"paramBox",value:this.params,onchange:function(){self.params=this.value;WM.rulesManager.saveRules();}}),
  856. this.param2Node=createElement("input",{className:"paramBox",value:this.params2,onchange:function(){self.params2=this.value;WM.rulesManager.saveRules();}}),
  857. //toolbox
  858. createElement("div",{className:"littleButton oddOrange",onclick:function(){self.remove();},title:"Delete Action"},[
  859. createElement("img",{className:"resourceIcon trash"+WM.opts.littleButtonSize}),
  860. ]),
  861. createElement("div",{className:"littleButton oddBlue",onclick:function(){self.clone();},title:"Clone Action"},[
  862. createElement("img",{className:"resourceIcon clone"+WM.opts.littleButtonSize}),
  863. ]),
  864. createElement("div",{className:"littleButton oddGreen",onclick:function(){self.moveUp();},title:"Move Up"},[
  865. createElement("img",{className:"resourceIcon arrowUp"+WM.opts.littleButtonSize}),
  866. ]),
  867. createElement("div",{className:"littleButton oddOrange",onclick:function(){self.moveDown();},title:"Move Down"},[
  868. createElement("img",{className:"resourceIcon arrowDown"+WM.opts.littleButtonSize}),
  869. ]),
  870.  
  871. ]),
  872. ]));
  873. //hide param node when not used
  874. self.paramNode.style.display=((self.hasParam)?"":"none");
  875. self.param2Node.style.display=((self.hasParam && (self.paramCount==2))?"":"none");
  876.  
  877. //if (isNew) WM.rulesManager.saveRules();
  878. return self;
  879. }catch(e){log("WM.rulesManager.RuleAction.init(): "+e);}};
  880.  
  881. //***************************************************************************************************************************************
  882. //***** Rule Class
  883. //***************************************************************************************************************************************
  884. WM.rulesManager.Rule = function(params){try{
  885. this.objType="rule";
  886. var self=this;
  887. params=params||{};
  888.  
  889. //set defaults
  890. this.parent=null;
  891. this.enabled=true;
  892. this.kids=[]; //child nodes
  893. this.eggs=[]; //hatchable child nodes
  894. this.actions=[]; //events:actions list
  895. this.validators=[]; //search:find list
  896. this.limitCount=0;
  897. this.limit=0;
  898. this.actionsNode=null;
  899. this.validationNode=null;
  900. this.node=null;
  901. this.isChild=false;
  902. this.isEgg=false;
  903. this.expanded=true;
  904. this.timers={};
  905. this.intervals={};
  906. this._isGlobal=false;
  907. //return savable data from this branch
  908. this.__defineGetter__("saveableData",function(){try{
  909. var ret={};
  910. //ret.id=this.id;
  911. ret.title=this.title;
  912. ret.enabled=this.enabled;
  913. ret.limit=this.limit;
  914. ret.limitCount=this.limitCount;
  915. //ret.level=this.level;
  916. ret.expanded=this.expanded;
  917. ret.validators=[];
  918. if (isArrayAndNotEmpty(this.validators)) for (var i=0,validator;(validator=this.validators[i]);i++) {
  919. ret.validators.push(validator.saveableData);
  920. }
  921. ret.actions=[];
  922. if (isArrayAndNotEmpty(this.actions)) for (var i=0,action;(action=this.actions[i]);i++) {
  923. ret.actions.push(action.saveableData);
  924. }
  925. ret.kids=[];
  926. if (isArrayAndNotEmpty(this.kids)) for (var i=0,kid;(kid=this.kids[i]);i++) {
  927. ret.kids.push(kid.saveableData);
  928. }
  929. ret.eggs=[];
  930. if (isArrayAndNotEmpty(this.eggs)) for (var i=0,egg;(egg=this.eggs[i]);i++) {
  931. ret.eggs.push(egg.saveableData);
  932. }
  933. return ret;
  934. }catch(e){log("WM.rulesManager.Rule.saveableData: "+e);}});
  935.  
  936. //set/get wether this rule is saved as global or profile
  937. this.__defineGetter__("isGlobal",function(){try{
  938. return self._isGlobal;
  939. }catch(e){log("WM.rulesManager.Rule.isGlobal: "+e);}});
  940. this.__defineSetter__("isGlobal",function(v){try{
  941. //only top level rule can be global
  942. if (self.parent) {
  943. confirm("Only top level rule can be set to global.");
  944. return;
  945. }
  946. if (!v) {
  947. if (!confirm("Disabling profile sharing on this rule will prevent other users on this machine from loading it. Are you sure you wish to make this rule locally available only?")) return;
  948. }
  949. self._isGlobal=v;
  950. //make sure we have a uniqueID
  951. //but don't destroy one that already exists
  952. if (v && !exists(self.uniqueID)) self.uniqueID = unique();
  953. //change the color/icon of the isGlobal button
  954. if (self.toggleGlobalButton) {
  955. var s=WM.opts.littleButtonSize;
  956. with (self.toggleGlobalButton) className=className.swapWordB(v,"removeGlobal"+s,"addGlobal"+s);
  957. with (self.toggleGlobalButton.parentNode) {
  958. className=className.swapWordB(v,"oddOrange","oddGreen");
  959. title=(v)?"Disable Profile Sharing":"Share With Other Profiles";
  960. }
  961. }
  962. }catch(e){log("WM.rulesManager.Rule.isGlobal: "+e);}});
  963. this.__defineGetter__("parentLimit",function(){try{
  964. if (self.parent||null) return self.parent.limit;
  965. return null;
  966. }catch(e){log("WM.rulesManager.Rule.parentLimit: "+e);}});
  967.  
  968. this.__defineGetter__("isBranchDisabled",function(){try{
  969. var p=self.parent,ret=false;
  970. while(p) {
  971. if (!p.enabled) return true;
  972. p=p.parent;
  973. }
  974. return false;
  975. }catch(e){log("WM.rulesManager.Rule.isBranchDisabled: "+e);}});
  976.  
  977. this.__defineGetter__("parentLimitCount",function(){try{
  978. if (self.parent||null) return self.parent.limitCount;
  979. return null;
  980. }catch(e){log("WM.rulesManager.Rule.parentLimitCount: "+e);}});
  981.  
  982. //copy passed params to this object
  983. for (var p in params) {
  984. //omit specific params
  985. if (!(["actions","validators","kids","eggs"].inArray(p)) ) {
  986. //copy only params that make it past the checker
  987. this[p]=params[p];
  988. }
  989. }
  990. this.usesRuleButton=function(){
  991. for (var action in this.actions) {
  992. if (action.event=="onRuleButtonClicked") {return true;}
  993. }
  994. return false;
  995. };
  996. this.moveUp=function(){try{
  997. //where is this
  998. var parentContainer =
  999. (this.isChild)?this.parent.kids:
  1000. (this.isEgg)?this.parent.eggs:
  1001. WM.rulesManager.rules;
  1002. //only affects items not already the first in the list
  1003. //and not the only child in the list
  1004. if ((parentContainer.length>1) && (parentContainer[0]!=this)) {
  1005. //which index is this?
  1006. var myIndex=parentContainer.inArrayWhere(this);
  1007. if (myIndex != -1) {
  1008. //I have a proper index here
  1009. //who is my sibling
  1010. var sibling = parentContainer[myIndex-1];
  1011. //swap me with my sibling
  1012. parentContainer[myIndex-1]=this;
  1013. parentContainer[myIndex]=sibling;
  1014. //place my node before my sibling node
  1015. sibling.node.parentNode.insertBefore(this.node,sibling.node);
  1016. //save it
  1017. WM.rulesManager.saveRules();
  1018. }
  1019. }
  1020. }catch(e){log("WM.rulesManager.Rule.moveUp: "+e);}};
  1021. this.moveDown=function(){try{
  1022. //where is this
  1023. var parentContainer =
  1024. (this.isChild)?this.parent.kids:
  1025. (this.isEgg)?this.parent.eggs:
  1026. WM.rulesManager.rules;
  1027. //only affects items not already the last in the list
  1028. //and not the only child in the list
  1029. if ((parentContainer.length>1) && (parentContainer.last()!=this)) {
  1030. //which index is this?
  1031. var myIndex=parentContainer.inArrayWhere(this);
  1032. if (myIndex != -1) {
  1033. //I have a proper index here
  1034. //who is my sibling
  1035. var sibling = parentContainer[myIndex+1];
  1036. //swap me with my sibling
  1037. parentContainer[myIndex+1]=this;
  1038. parentContainer[myIndex]=sibling;
  1039. //place my node before my sibling node
  1040. sibling.node.parentNode.insertBefore(sibling.node,this.node);
  1041. //save it
  1042. WM.rulesManager.saveRules();
  1043. }
  1044. }
  1045. }catch(e){log("WM.rulesManager.Rule.moveDown: "+e);}};
  1046.  
  1047. this.moveUpLevel=function(){try{
  1048. if (this.parent) {
  1049. //this is not a top level node, so we can move it
  1050. var targetContainer=((this.parent.parent)?this.parent.parent.kids:WM.rulesManager.rules);
  1051. //remove from parent
  1052. this.parent[(this.isChild)?"kids":(this.isEgg)?"eggs":null].removeByValue(this);
  1053. //set new parent
  1054. this.parent=(this.parent.parent||null); //never point to the top level
  1055. //set flags
  1056. this.isChild=(this.parent!=null);
  1057. this.isEgg=false;
  1058. //move the object
  1059. targetContainer.push(this);
  1060. //move the node
  1061. if (this.parent) this.parent.kidsNode.appendChild(this.node);
  1062. else WM.console.priorityBuild.appendChild(this.node);
  1063. //save it
  1064. WM.rulesManager.saveRules();
  1065. }
  1066. }catch(e){log("WM.rulesManager.Rule.moveUpLevel: "+e);}};
  1067. this.moveDownLevel=function(){try{
  1068. //where is this
  1069. var parentContainer =
  1070. (this.isChild)?this.parent.kids:
  1071. (this.isEgg)?this.parent.eggs:
  1072. WM.rulesManager.rules;
  1073. //create a new rule at my level
  1074. var newRule = new WM.rulesManager.Rule({
  1075. parent:this.parent||null,
  1076. isChild:this.isChild,
  1077. isEgg:this.isEgg,
  1078. });
  1079. parentContainer.push(newRule);
  1080. //remove me from my current parent
  1081. parentContainer.removeByValue(this);
  1082. //attach me to my new parent
  1083. this.parent=newRule;
  1084. this.isChild=true;
  1085. this.isEgg=false;
  1086. newRule.kids.push(this);
  1087. //move my node
  1088. newRule.kidsNode.appendChild(this.node);
  1089. //save it
  1090. WM.rulesManager.saveRules();
  1091. }catch(e){log("WM.rulesManager.Rule.moveDownLevel: "+e);}};
  1092.  
  1093. this.enable=function(){try{
  1094. this.enabled=true;
  1095. this.node.className=this.node.className.removeWord("disabled");
  1096. WM.rulesManager.saveRules();
  1097. }catch(e){log("WM.rulesManager.Rule.enable: "+e);}};
  1098.  
  1099. this.disable=function(){try{
  1100. this.enabled=false;
  1101. this.node.className=this.node.className.addWord("disabled");
  1102. WM.rulesManager.saveRules();
  1103. }catch(e){log("WM.rulesManager.Rule.disable: "+e);}};
  1104.  
  1105. this.disableChildren=function(){try{
  1106. if (isArrayAndNotEmpty(this.kids)) for (var k=0,kid;(kid=this.kids[k]);k++){
  1107. kid.disable();
  1108. }
  1109. }catch(e){log("WM.rulesManager.Rule.disableChildren: "+e);}};
  1110.  
  1111. this.enableChildren=function(){try{
  1112. if (isArrayAndNotEmpty(this.kids)) for (var k=0,kid;(kid=this.kids[k]);k++){
  1113. kid.enable();
  1114. }
  1115. }catch(e){log("WM.rulesManager.Rule.enableChildren: "+e);}};
  1116. this.toggle=function(){try{
  1117. //if(this.enabled)this.disable(); else this.enable();
  1118. //this.enabled=!this.enabled;
  1119. this.enabled=this.toggleNode.checked;
  1120. this.node.className=this.node.className.swapWordB(this.enabled,"enabled","disabled");
  1121. WM.rulesManager.saveRules();
  1122. //this.toggleNode.checked=();
  1123.  
  1124. }catch(e){log("WM.rulesManager.Rule.toggle: "+e);}};
  1125.  
  1126. this.clone=function(){try{
  1127. var cloneRule=this.saveableData;
  1128. //cloneRule.id=unique();
  1129. if (this.isChild) this.parent.addChild(cloneRule);
  1130. else if (this.isEgg) this.parent.addEgg(cloneRule);
  1131. else WM.rulesManager.newRule(cloneRule);
  1132. }catch(e){log("WM.rulesManager.RuleAction.clone: "+e);}};
  1133.  
  1134. this.resetLimit=function(params){try{
  1135. params=params||{};
  1136. var ask=WM.opts.rulesConfirmResetLimit;
  1137. if (params.noConfirm || !ask || (ask && confirm("Reset Limit Counter?"))) {
  1138. this.limitCount=0;
  1139. this.limitCounterNode.value=this.limitCount;
  1140. if (!(params.resetChildren||false)) {
  1141. if (isArrayAndNotEmpty(this.kids)) for (var k=0,kid;(kid=this.kids[k]);k++){
  1142. kid.resetLimit(params);
  1143. }
  1144. }
  1145. if (!(params.preventSave||false)) WM.rulesManager.saveRules();
  1146. }
  1147. }catch(e){log("WM.rulesManager.Rule.resetLimit: "+e);}};
  1148. this.resetBranchLimits=function(params){try{
  1149. params=params||{};
  1150. //resets the limits of entire branch rules, but not self limit
  1151. if (isArrayAndNotEmpty(this.kids)) for (var k=0,kid;(kid=this.kids[k]);k++){
  1152. kid.resetLimit({resetChildren:true,noConfirm:params.noConfirm||false});
  1153. }
  1154. }catch(e){log("WM.rulesManager.Rule.resetBranchLimits: "+e);}};
  1155.  
  1156. this.resetChildrenLimits=function(params){try{
  1157. params=params||{};
  1158. //resets the limits of all immediate children, but not self limit
  1159. if (isArrayAndNotEmpty(this.kids)) for (var k=0,kid;(kid=this.kids[k]);k++){
  1160. kid.resetLimit({noConfirm:params.noConfirm||false});
  1161. }
  1162. }catch(e){log("WM.rulesManager.Rule.resetChildrenLimits: "+e);}};
  1163.  
  1164. this.incrementLimitCounter=function(o,n){try{
  1165. this.limitCount=parseInt(parseInt(this.limitCount)+(exists(n)?parseInt(n):1));
  1166. this.limitCounterNode.value=this.limitCount;
  1167. WM.rulesManager.saveRules();
  1168. //for reaching of limit
  1169. if (this.limit && (this.limitCount>=this.limit)) this.onEvent("onLimit",o);
  1170. }catch(e){log("WM.rulesManager.Rule.incrementLimitCounter: "+e);}};
  1171.  
  1172. this.decrementLimitCounter=function(o,n){try{
  1173. this.limitCount=parseInt(parseInt(this.limitCount)-(exists(n)?parseInt(n):1));
  1174. //dont allow to drop below 0
  1175. if (this.limitCount<0) this.limitCount=0;
  1176. this.limitCounterNode.value=this.limitCount;
  1177. WM.rulesManager.saveRules();
  1178. }catch(e){log("WM.rulesManager.Rule.decrementLimitCounter: "+e);}};
  1179.  
  1180. this.remove=function(noConfirm){try{
  1181. var ask=WM.opts.rulesConfirmDeleteRule;
  1182. if (noConfirm || (this.isGlobal && confirm("This rule is shared with other profiles. Deleting it here will prevent it from loading for other users. Are you sure you wish to delete this rule and its children.")) || !ask || (!this.isGlobal && ask && confirm("Delete rule and all of its child nodes?"))){
  1183. //destroy intervals and timers
  1184. this.cleanup();
  1185. //remove my data
  1186. var parentContainer=((this.isChild)?this.parent.kids:(this.isEgg)?this.parent.eggs:WM.rulesManager.rules);
  1187. parentContainer.removeByValue(this);
  1188. //remove my node
  1189. remove(this.node);
  1190. doAction(WM.rulesManager.saveRules);
  1191. }
  1192. }catch(e){log("WM.rulesManager.Rule.remove: "+e);}};
  1193.  
  1194. this.cancelAllTimers=function(){try{
  1195. //find the correct timer by target
  1196. for (var t in this.timers){
  1197. if (this.timers[t]!=null) {
  1198. window.clearTimeout(this.timers[t]);
  1199. delete this.timers[t];
  1200. }
  1201. }
  1202. }catch(e){log("WM.rulesManager.Rule.cancelAllTimers: "+e);}};
  1203.  
  1204. this.cancelTimer=function(target){try{
  1205. //find the correct timer by target
  1206. var timer=null;
  1207. for (var t in this.timers){
  1208. if (this.timers[t].target==target) {
  1209. timer=this.timers[t];
  1210. break;
  1211. }
  1212. }
  1213. if (timer) {
  1214. window.clearTimeout(timer.timer);
  1215. delete this.timers[timer.id];
  1216. }
  1217. }catch(e){log("WM.rulesManager.Rule.cancelTimer: "+e);}};
  1218. this.createTimer=function(t,o){try{
  1219. this.cancelTimer(o);
  1220. var self=this;
  1221. var stamp=unique();
  1222. var timer=window.setTimeout(function(){
  1223. self.onEvent("onTimer",o);
  1224. },t);
  1225. this.timers[stamp]={timer:timer, target:o, id:stamp};
  1226. }catch(e){log("WM.rulesManager.Rule.createTimer: "+e);}};
  1227. this.cancelAllIntervals=function(){try{
  1228. //find the correct timer by target
  1229. for (var t in this.intervals){
  1230. if (this.intervals[t]!=null) {
  1231. window.clearInterval(this.intervals[t]);
  1232. delete this.intervals[t];
  1233. }
  1234. }
  1235. }catch(e){log("WM.rulesManager.Rule.cancelAllIntervals: "+e);}};
  1236. this.cancelInterval=function(target){try{
  1237. //find the correct timer by target
  1238. var interval=null;
  1239. for (var t in this.intervals){
  1240. if (this.intervals[t].target==target) {
  1241. interval=this.intervals[t];
  1242. break;
  1243. }
  1244. }
  1245. if (interval) {
  1246. window.clearInterval(interval.timer);
  1247. delete this.intervals[interval.id];
  1248. }
  1249. }catch(e){log("WM.rulesManager.Rule.cancelInterval: "+e);}};
  1250. this.createInterval=function(t,o){try{
  1251. this.cancelInterval(o);
  1252. var self=this;
  1253. var stamp=unique();
  1254. var interval=window.setInterval(function(){
  1255. self.onEvent("onInterval",o);
  1256. },t);
  1257. this.intervals[stamp]={timer:interval, target:o, id:stamp};
  1258. }catch(e){log("WM.rulesManager.Rule.createInterval: "+e);}};
  1259. this.doEvent=function(event,obj,logit){try{
  1260. //check to see if post matches this rule, if it does, perform actions
  1261. //if (this.validators){
  1262. //logit=logit||(obj.objType=="post");
  1263. var obj=(obj||{});
  1264. //var self=this;
  1265. var matchPost=true, found=[];
  1266. for (var vl=0,validator;(validator=this.validators[vl]);vl++) { try{
  1267. //within the search array, each result is handled as an OR
  1268. var result=false;
  1269. for (var s=0,search; (search=validator.search[s]); s++) {
  1270. var v =
  1271. //special request for object type of the object that activated this rule
  1272. (search=="activatorType")?(
  1273. (exists(obj))?(obj.objType||"unknown"):"unknown"
  1274. ):
  1275. //special specific app being paused test
  1276. (search=="isAppPaused")?(
  1277. (exists(obj) && exists(obj.app))?obj.app.paused:false
  1278. ):
  1279. //special specific bonus type being paused
  1280. (search=="isTypePaused")?(
  1281. (exists(obj) && exists(obj.which) && exists(obj.app))?obj.app.typesPaused.inArray(obj.which):false
  1282. ):
  1283. //read from post object test data
  1284. (exists(obj) && exists(obj.testData) && exists(obj.testData[search]))?obj.testData[search]:
  1285. //read from activating object standard parameters
  1286. (exists(obj) && exists(obj[search]))?obj[search]:
  1287. //read from this rule object
  1288. exists(self[search])?self[search]:
  1289. //read from parameters in the console/main object
  1290. exists(WM[search])?WM[search]:
  1291. //there is no known reference for this query
  1292. "undefined";
  1293.  
  1294. //fail validators that do not work with this obj
  1295. if (v=="undefined") {result=false; break;}
  1296. //convert functions to values
  1297. if (typeof v=="function") v=v();
  1298. var query = validator.find;
  1299. //make the query the same type as the value
  1300. if (!(typeof query == typeof v)) {
  1301. switch (typeof v) {
  1302. case "boolean":
  1303. //convert texts of false/true to actual booleans
  1304. query = cBool(query);
  1305. break;
  1306. case "number":
  1307. //convert text numbers to real numbers
  1308. query=(query=Number(query))?query:0;
  1309. //if (query==null) query=0;
  1310. break;
  1311. }
  1312. }
  1313. //if (logit) log([search, v, query]);
  1314.  
  1315. //compare
  1316. switch(validator.operand){
  1317. case "equals": result=result||(v==query); break;
  1318. case "notEquals": result=result||(v!=query); break;
  1319. case "startsWith": result=result||(v.startsWith(query)); break;
  1320. case "notStartsWith": result=result||(!v.startsWith(query)); break;
  1321. case "endsWith": result=result||(v.endsWith(query)); break;
  1322. case "notEndsWith": result=result||(!v.endsWith(query)); break;
  1323. case "contains": result=result||(v.contains(query)); break;
  1324. case "notContains": result=result||(!v.contains(query)); break;
  1325. case "greaterThan": result=result||(v>query); break;
  1326. case "lessThan": result=result||(v<query); break;
  1327. case "greaterThanOrEquals": result=result||(v>=query); break;
  1328. case "lessThanOrEquals": result=result||(v<=query); break;
  1329. case "matchRegExp":
  1330. var f; //storage space for match array
  1331. var regex = new RegExp(query,"gi");
  1332. f=regex.exec(v);
  1333. result=result||isArrayAndNotEmpty(f);
  1334. //result=result||((f=v.match(regex))!=null);
  1335. if (f) found=found.concat(f);
  1336. break;
  1337. case "notMatchRegExp":
  1338. var regex = new RegExp(query,"gi");
  1339. result=result||(v.match(regex)==null);
  1340. break;
  1341. case "equalsExactly": result=result||(v===query); break;
  1342. case "notEqualsExactly": result=result||!(v===query); break;
  1343. }
  1344. //any result of true inside this loop is an automatic success
  1345. if (result) break;
  1346. }
  1347. //evaluate our current result with the previous results
  1348. //outside the search array, each value is handled as an AND
  1349. //any one non-match is a complete failure
  1350. matchPost=(matchPost && result);
  1351. if (!matchPost) break;
  1352. }catch(e){
  1353. log("WM.rulesManager.Rule.doEvent: "+e+"{event:" +event+ ", search:"+search+", value:"+v+", query:"+query+", result:"+result+"}");
  1354. continue;
  1355. }}
  1356. //if after all testing we still matched the object
  1357. //then perform this rule's events and check children
  1358. if (matchPost) {
  1359. //log("post matches all validators");
  1360. //first do every child rule
  1361. for (var k=0,kid;(kid=this.kids[k]);k++){
  1362. kid.doEvent(event,obj,true);
  1363. }
  1364. //now finish up with this rule's actions
  1365. this.onEvent(event,obj,found||null);
  1366. }
  1367. //}
  1368. //log("WM.rulesManager.Rule.doEvent: {obj="+obj.id+", event="+event+", matchPost="+matchPost+"}");
  1369. }catch(e){log("WM.rulesManager.Rule.doEvent: "+e);}};
  1370.  
  1371. this.onEvent=function(event,obj,found){try{
  1372. var actionFilter=["*"];
  1373. /*
  1374. handle special events
  1375. */
  1376. if (event=="onRuleCreated") {
  1377. /*
  1378. we do want onRuleCreated events to fire even if the rule is disabled,
  1379. or intervals won't be set and ready for later, if the user does enable the rule
  1380. this session. But we want to filter which actions are available.
  1381. */
  1382. if (!this.enabled || this.isBranchDisabled) actionFilter=["createInterval","createTimer"];
  1383. } else if ((event=="onInterval")||(event=="onTimer")) {
  1384. //special case for intervals and timers
  1385. if (!this.enabled || this.isBranchDisabled) return;
  1386. } else {
  1387. //always break if this rule is disabled
  1388. if (!this.enabled || this.isBranchDisabled) return;
  1389. }
  1390. /*
  1391. end handle special events
  1392. */
  1393. obj=obj||null;
  1394. //var self=this;
  1395. var post=(self!=obj)?obj:null;
  1396. var app=post?(exists(obj.app)?obj.app:obj):null;
  1397. //some insertable post parts
  1398. var inserts=["appID","which","fromID"];
  1399. //perform an action based on an event call
  1400. //post object may be null if called from this
  1401. for (var a1=0,action;(action=this.actions[a1]);a1++){
  1402. //filter actions: allow only those in the filter list, or all actions if "*" is in the list
  1403. if (actionFilter.inArray("*") || actionFilter.inArray(action.action) ) if (action.event==event){
  1404. var param=action.params;
  1405. var param2=action.params2;
  1406. var hasParam=action.hasParam;
  1407. //format some post parts into the param
  1408. if (hasParam && param) {
  1409. for (var i=0;i<inserts.length;i++){
  1410. if (post && (post.replace||null)) {
  1411. param.replace(new RegExp("{%"+inserts[i]+"}","gi"), post.testData[inserts[i]] || post[inserts[i]]);
  1412. }
  1413. }
  1414. }
  1415. switch(action.action){
  1416. case "destroyRule":(function(){
  1417. doAction(function(){
  1418. self.remove(true);
  1419. });
  1420. })(); break;
  1421. case "pauseType":(function(){
  1422. var w=post.which, a=app;
  1423. doAction(function(){
  1424. WM.pauseByType(a,w);
  1425. });
  1426. })(); break;
  1427. case "unpauseType":(function(){
  1428. var w=post.which, a=app;
  1429. doAction(function(){
  1430. WM.unPauseByType(a,w);
  1431. });
  1432. })(); break;
  1433. case "uncheckType":(function(){
  1434. var w=post.which, a=app;
  1435. doAction(function(){
  1436. WM.disableOpt(w,a);
  1437. //WM.stopCollectionOf(post.which);
  1438. });
  1439. })(); break;
  1440.  
  1441. case "checkType":(function(){
  1442. var w=post.which, a=app;
  1443. doAction(function(){
  1444. WM.enableOpt(w,a);
  1445. //WM.startCollectionOf(post.which);
  1446. });
  1447. })(); break;
  1448. case "disableAppOption":(function(){
  1449. var c=param, f=found, a=app;
  1450. if (f) c=c.format2(f);
  1451. doAction(function(){
  1452. WM.disableOpt(c,a);
  1453. });
  1454. })(); break;
  1455. case "enableAppOption":(function(){
  1456. var c=param, f=found, a=app;
  1457. if (f) c=c.format2(f);
  1458. doAction(function(){
  1459. WM.enableOpt(c,a);
  1460. });
  1461. })(); break;
  1462. case "disableHostOption":(function(){
  1463. //debug.print("option disabled");
  1464. var c=param, f=found;
  1465. if (f) c=c.format2(f);
  1466. doAction(function(){
  1467. WM.disableOpt(c);
  1468. });
  1469. })(); break;
  1470. case "enableHostOption":(function(){
  1471. //debug.print("option enabled");
  1472. var c=param, f=found;
  1473. if (f) c=c.format2(f);
  1474. doAction(function(){
  1475. WM.enableOpt(c);
  1476. });
  1477. })(); break;
  1478. case "disableAutolike":(function(){
  1479. doAction(function(){
  1480. //debug.print("autolike disabled");
  1481. WM.disableOpt("useautolike");
  1482. });
  1483. })(); break;
  1484. case "enableAutolike":(function(){
  1485. doAction(function(){
  1486. //debug.print("autolike enabled");
  1487. WM.enableOpt("useautolike");
  1488. });
  1489. })(); break;
  1490. case "disableAutocomment":(function(){
  1491. doAction(function(){
  1492. WM.disableOpt("useautocomment");
  1493. });
  1494. })(); break;
  1495. case "enableAutocomment":(function(){
  1496. doAction(function(){
  1497. WM.enableOpt("useautocomment");
  1498. });
  1499. })(); break;
  1500. case "pauseApp":(function(){
  1501. var a = WM.apps[param]||app;
  1502. doAction(function(){
  1503. a.pause();
  1504. });
  1505. })(); break;
  1506. case "unpauseApp":(function(){
  1507. var a = WM.apps[param]||app;
  1508. doAction(function(){
  1509. a.unPause();
  1510. });
  1511. })(); break;
  1512. case "appendLink":(function(){
  1513. var p=post, v=param||"";
  1514. if (p) doAction(function(){
  1515. p.link=p.linkHref+v;
  1516. });
  1517. })(); break;
  1518. case "unpauseAllTypesByApp":(function(){
  1519. var a = WM.apps[param]||app;
  1520. doAction(function(){
  1521. a.unpauseAllTypes();
  1522. });
  1523. })(); break;
  1524. case "unpauseAllTypesAllApps":(function(){
  1525. doAction(function(){
  1526. for (var a in WM.apps){
  1527. a.unpauseAllTypes();
  1528. }
  1529. });
  1530. })(); break;
  1531. case "unpauseAllApps":(function(){
  1532. doAction(function(){
  1533. for (var a in WM.apps){
  1534. a.unpause();
  1535. }
  1536. });
  1537. })(); break;
  1538. case "pauseAllApps":(function(){
  1539. doAction(function(){
  1540. for (var a in WM.apps){
  1541. a.pause();
  1542. }
  1543. });
  1544. })(); break;
  1545. case "refreshBrowser":(function(){
  1546. doAction(function(){
  1547. WM.refreshBrowser();
  1548. });
  1549. })(); break;
  1550. case "pauseWM.collector":(function(){
  1551. doAction(function(){
  1552. WM.pauseCollecting(true);
  1553. });
  1554. })(); break;
  1555. case "unpauseWM.collector":(function(){
  1556. doAction(function(){
  1557. WM.pauseCollecting(false);
  1558. });
  1559. })(); break;
  1560. case "pauseFetch":(function(){
  1561. doAction(function(){
  1562. WM.pauseFetching(true);
  1563. });
  1564. })(); break;
  1565. case "unpauseFetch":(function(){
  1566. doAction(function(){
  1567. WM.pauseFetching(false);
  1568. });
  1569. })(); break;
  1570. case "likePost":(function(){
  1571. doAction(function(){
  1572. post.like();
  1573. });
  1574. })(); break;
  1575. case "queueLikePost":(function(){
  1576. doAction(function(){
  1577. WM.queAutoLike(post);
  1578. });
  1579. })(); break;
  1580. case "commentPost":(function(){
  1581. var p=param,f=found;
  1582. if (f) p=p.format2(f);
  1583. doAction(function(){
  1584. post.comment(p);
  1585. });
  1586. })(); break;
  1587. case "queueCommentPost":(function(){
  1588. var p=param,f=found;
  1589. if (f) p=p.format2(f);
  1590. //log(["queueCommentPost fired",p]);
  1591. doAction(function(){
  1592. WM.queAutoComment(post,p);
  1593. });
  1594. })(); break;
  1595. case "cleanPost":(function(){
  1596. doAction(function(){
  1597. post.remove();
  1598. });
  1599. })(); break;
  1600. case "incrementCounter":(function(){
  1601. var o=obj,p=param,f=found;
  1602. //if (f) p=p.format2(f);
  1603. doAction(function(){
  1604. self.incrementLimitCounter(o,p);
  1605. });
  1606. })(); break;
  1607. case "decrementCounter":(function(){
  1608. var o=obj,p=param,f=found;
  1609. //if (f) p=p.format2(f);
  1610. doAction(function(){
  1611. self.decrementLimitCounter(o,p);
  1612. });
  1613. })(); break;
  1614. case "incrementParentCounter":(function(){
  1615. var o=obj,p=param, f=found;
  1616. //if (f) p=p.format2(f);
  1617. if (this.parent) {
  1618. doAction(function(){
  1619. //passes the activating object, not this rule
  1620. self.parent.incrementLimitCounter(o,p);
  1621. });
  1622. }
  1623. })(); break;
  1624. case "decrementParentCounter":(function(){
  1625. var o=obj,p=param, f=found;
  1626. //if (f) p=p.format2(f);
  1627. if (this.parent){
  1628. doAction(function(){
  1629. //passes the activating object, not this rule
  1630. self.parent.decrementLimitCounter(o,p);
  1631. });
  1632. }
  1633. })(); break;
  1634. case "setColor":(function(){
  1635. var c=param;
  1636. var f=found;
  1637. if (f) c=c.format2(f);
  1638. doAction(function(){
  1639. post.setColor(c);
  1640. });
  1641. })(); break;
  1642. case "pinPost":(function(){
  1643. doAction(function(){
  1644. post.pin();
  1645. });
  1646. })(); break;
  1647. case "setAsAccepted":(function(){
  1648. var saveit=param;
  1649. doAction(function(){
  1650. post.accept(saveit);
  1651. });
  1652. })(); break;
  1653. case "setAsFailed":(function(){
  1654. var saveit=param;
  1655. doAction(function(){
  1656. post.fail(saveit);
  1657. });
  1658. })(); break;
  1659. case "setAsExcluded":(function(){
  1660. doAction(function(){
  1661. post.exclude();
  1662. });
  1663. })(); break;
  1664. case "processFirst":(function(){
  1665. doAction(function(){
  1666. post.moveToTop();
  1667. });
  1668. })(); break;
  1669. case "processLast":(function(){
  1670. doAction(function(){
  1671. post.moveToBottom();
  1672. });
  1673. })(); break;
  1674. case "setPriority":(function(){
  1675. var p=param, f=found;
  1676. if (f) p=p.format2(f);
  1677. doAction(function(){
  1678. post.setPriority(p);
  1679. });
  1680. })(); break;
  1681. case "setPriorityApp":(function(){
  1682. var p=param2, a=WM.apps[param]||app, f=found;
  1683. if (f) p=p.format2(f);
  1684. doAction(function(){
  1685. app.setPriority(p);
  1686. });
  1687. })(); break;
  1688. case "removePriorityApp":(function(){
  1689. var p=param2, a=WM.apps[param]||app, f=found;
  1690. if (f) p=p.format2(f);
  1691. doAction(function(){
  1692. app.setPriority(50);
  1693. });
  1694. })(); break;
  1695. case "setPriorityType":(function(){
  1696. var p=param2, a=app, f=found, w=param||post.which;
  1697. if (f) p=p.format2(f);
  1698. doAction(function(){
  1699. app.setPriorityByType(w,p);
  1700. });
  1701. })(); break;
  1702. case "removePriorityType":(function(){
  1703. var a=app, f=found, w=param||post.which;
  1704. if (f) p=p.format2(f);
  1705. doAction(function(){
  1706. app.setPriorityByType(w,50);
  1707. });
  1708. })(); break;
  1709. case "removePriority":(function(){
  1710. doAction(function(){
  1711. post.setPriority(50);
  1712. });
  1713. })(); break;
  1714. case "resetLimit":(function(){
  1715. doAction(function(){
  1716. self.resetLimit({noConfirm:true});
  1717. });
  1718. })(); break;
  1719. case "resetParentLimit":(function(){
  1720. if (this.parent) {
  1721. doAction(function(){
  1722. self.parent.resetLimit({noConfirm:true});
  1723. });
  1724. }
  1725. })(); break;
  1726. case "resetChildrenLimits":(function(){
  1727. doAction(function(){
  1728. self.resetChildrenLimits({noConfirm:true});
  1729. });
  1730. })(); break;
  1731. case "resetBranchLimits":(function(){
  1732. doAction(function(){
  1733. self.resetBranchLimits({noConfirm:true});
  1734. });
  1735. })(); break;
  1736. case "hatch":(function(){
  1737. var o=obj;
  1738. doAction(function(){
  1739. self.hatch(o);
  1740. });
  1741. })(); break;
  1742. case "birth":(function(){
  1743. var o=obj;
  1744. doAction(function(){
  1745. this.birth(o);
  1746. });
  1747. })(); break;
  1748. case "fetchVisiblePosts":(function(){
  1749. doAction(function(){
  1750. WM.fetch({bypassPause:true});
  1751. });
  1752. })(); break;
  1753. case "fetchNewer":(function(){
  1754. doAction(function(){
  1755. app.fetchPosts({newer:true,bypassPause:true});
  1756. });
  1757. })(); break;
  1758. case "fetchOlder":(function(){
  1759. doAction(function(){
  1760. app.fetchPosts({older:true,bypassPause:true});
  1761. });
  1762. })(); break;
  1763. case "fetchHours":(function(){
  1764. var p=param, f=found, a=app;
  1765. if (f) p=p.format2(f);
  1766. doAction(function(){
  1767. //var t0=timestamp()/1000; //let the fetch script calc it from the feed
  1768. var t1=Math.round((timeStamp()-(p*hour))/1000);
  1769. //t=t.substr(0,t.length-3);
  1770. log("fetchHours: "+p+" please wait...");
  1771. WM.fetch({bypassPause:true, older:true, targetEdge:t1, currentEdge:Math.round(timeStamp()/1000), apps:app});
  1772. });
  1773. })(); break;
  1774. case "disableRule":(function(){
  1775. doAction(function(){
  1776. self.disable();
  1777. });
  1778. })(); break;
  1779. case "enableRule":(function(){
  1780. doAction(function(){
  1781. self.enable();
  1782. });
  1783. })(); break;
  1784. case "disableChildRules":(function(){
  1785. doAction(function(){
  1786. self.disableChildren();
  1787. });
  1788. })(); break;
  1789. case "enableChildRules":(function(){
  1790. doAction(function(){
  1791. self.enableChildren();
  1792. });
  1793. })(); break;
  1794. case "disableApp":(function(){
  1795. //check for specified app
  1796. var a = WM.apps[param]||app;
  1797. doAction(function(){
  1798. a.disable();
  1799. });
  1800. })(); break;
  1801. case "enableApp":(function(){
  1802. var a = WM.apps[param]||app;
  1803. doAction(function(){
  1804. a.enable();
  1805. });
  1806. })(); break;
  1807. case "forceOpen":(function(){
  1808. doAction(function(){
  1809. post.forceOpen();
  1810. });
  1811. })(); break;
  1812. case "forceOpenFirst":(function(){
  1813. doAction(function(){
  1814. post.forceOpen({first:true});
  1815. });
  1816. })(); break;
  1817. case "emergencyOpen":(function(){
  1818. doAction(function(){
  1819. post.forceOpen({emergency:true});
  1820. });
  1821. })(); break;
  1822. case "setToCollect":(function(){
  1823. doAction(function(){
  1824. post.collect();
  1825. });
  1826. })(); break;
  1827. case "setToCollectPriority1":(function(){
  1828. doAction(function(){
  1829. post.collect();
  1830. post.setPriority(1);
  1831. });
  1832. })(); break;
  1833. case "createTimer":(function(){
  1834. var o=obj, p=param, f=found;
  1835. if (f) p=p.format2(f);
  1836. //allow new time format entry
  1837. //if the calculated time differs from the passed time, then use that calculated time, as long as it doesn't translate to 0
  1838. var t=calcTime(p);
  1839. if (t!=0 && t!=p) p=t;
  1840. //debug.print(["b",param,t,p]);
  1841. doAction(function(){
  1842. self.createTimer(p,o);
  1843. });
  1844. })(); break;
  1845. case "cancelTimer":(function(){
  1846. var o=obj;
  1847. doAction(function(){
  1848. if (o.objType=="rule") self.cancelAllTimers();
  1849. else self.cancelTimer(o);
  1850. });
  1851. })(); break;
  1852. case "createInterval":(function(){
  1853. var o=obj, p=param, f=found;
  1854. if (f) p=p.format2(f);
  1855. //allow new time format entry
  1856. //if the calculated time differs from the passed time, then use that calculated time, as long as it doesn't translate to 0
  1857. var t=calcTime(p);
  1858. if (t!=0 && t!=p) p=t;
  1859. //debug.print(["b",param,t,p]);
  1860. doAction(function(){
  1861. self.createInterval(p,o);
  1862. });
  1863. })(); break;
  1864. case "cancelInterval":(function(){
  1865. var o=obj;
  1866. doAction(function(){
  1867. if (o.objType=="rule") self.cancelAllIntervals();
  1868. else self.cancelInterval(o);
  1869. });
  1870. })(); break;
  1871. case "setWhich":(function(){
  1872. var w=param;
  1873. var f=found;
  1874. if (f) w=w.format2(f);
  1875. doAction(function(){
  1876. post.setWhich(w);
  1877. });
  1878. })(); break;
  1879. case "reIDAll": (function(){
  1880. doAction(function(){
  1881. WM.reIDAll();
  1882. });
  1883. })(); break;
  1884. case "resetAllLimits":(function(){
  1885. doAction(function(){
  1886. WM.rulesManager.resetAllLimits();
  1887. });
  1888. })(); break;
  1889. case "openPostSource":(function(){
  1890. doAction(function(){
  1891. post.openSource();
  1892. });
  1893. })(); break;
  1894. case "emptyAutolikeQueue":(function(){
  1895. doAction(function(){
  1896. WM.emptyAutoLikeQueue();
  1897. });
  1898. })(); break;
  1899. case "setHostOption":(function(){
  1900. var c=param, c2=param2, f=found;
  1901. if (f) c=c.format2(f); //format only param1
  1902. doAction(function(){
  1903. WM.setOpt(c,c2);
  1904. });
  1905. })(); break;
  1906. case "setAppOption":(function(){
  1907. var c=param, c2=param2, f=found, a=app;
  1908. if (f) c=c.format2(f); //format only param1
  1909. doAction(function(){
  1910. WM.setOpt(c,c2,a);
  1911. });
  1912. })(); break;
  1913. case "setAppTab":(function(){
  1914. if (param=="all") {
  1915. doAction(function(){
  1916. //switch to Show All
  1917. WM.console.collectTabControl.selectTab(0);
  1918. });
  1919. } else {
  1920. //check for specified app
  1921. var a = WM.apps[param]||app;
  1922. if (a||null) doAction(function(){
  1923. //switch to associated tab
  1924. click(a.collectionTabNode);
  1925. });
  1926. }})(); break;
  1927. }
  1928. }
  1929. }
  1930. }catch(e){log("WM.rulesManager.Rule.onEvent: "+e);}};
  1931. this.addAction=function(p){try{
  1932. var isNew=!exists(p);
  1933. p=p||{};
  1934. p.parent=this;
  1935. var ret=new WM.rulesManager.RuleAction(p);
  1936. this.actions.push(ret);
  1937. if (isNew) WM.rulesManager.saveRules();
  1938. }catch(e){log("WM.rulesManager.Rule.addAction: "+e);}};
  1939.  
  1940. this.addValidator=function(p){try{
  1941. var isNew=!exists(p);
  1942. p=p||{};
  1943. p.parent=this;
  1944. var ret=new WM.rulesManager.RuleValidator(p);
  1945. this.validators.push(ret);
  1946. if (isNew) WM.rulesManager.saveRules();
  1947. }catch(e){log("WM.rulesManager.Rule.addValidator: "+e);}};
  1948. this.addChild=function(p){try{
  1949. var isNew=!exists(p);
  1950. p=p||{};
  1951. p.parent=this;
  1952. p.isChild=true;
  1953. var rule=new WM.rulesManager.Rule(p);
  1954. this.kids.push(rule);
  1955. if (isNew) WM.rulesManager.saveRules();
  1956. }catch(e){log("WM.rulesManager.Rule.addChild: "+e);}};
  1957.  
  1958. this.addEgg=function(p){try{
  1959. var isNew=!exists(p);
  1960. p=p||{};
  1961. p.parent=this;
  1962. p.isEgg=true;
  1963. var rule=new WM.rulesManager.Rule(p);
  1964. this.eggs.push(rule);
  1965. if (isNew) WM.rulesManager.saveRules();
  1966. }catch(e){log("WM.rulesManager.Rule.addEgg: "+e);}};
  1967. //move eggs to parent node and destroy this node
  1968. this.hatch=function(obj){try{
  1969. var ask=WM.opts.rulesConfirmHatch
  1970. if (!ask || (ask && confirm("Hatch egg child and remove current rule and all its children?")) ) {
  1971. this.onEvent("onHatch",obj||this);
  1972. for (var e=0,egg; (egg=this.eggs[e]); e++){
  1973. egg.moveUpLevel();
  1974. }
  1975. this.remove(true); //with noConfirm
  1976. }
  1977. }catch(e){log("WM.rulesManager.Rule.hatch: "+e);}};
  1978.  
  1979. //clone eggs to parent node
  1980. this.birth=function(obj){try{
  1981. this.onEvent("onBirth",obj||this);
  1982. for (var e=0,egg; (egg=this.eggs[e]); e++){
  1983. var cloneRule=egg.saveableData;
  1984. if (this.isChild) this.parent.addChild(cloneRule);
  1985. else WM.rulesManager.newRule(cloneRule);
  1986. }
  1987. }catch(e){log("WM.rulesManager.Rule.birth: "+e);}};
  1988.  
  1989. //self rule button clicked
  1990. this.ruleButtonClicked=function(obj){try{
  1991. this.onEvent("onRuleButtonClicked",obj||this);
  1992. }catch(e){log("WM.rulesManager.Rule.ruleButtonClicked: "+e);}};
  1993.  
  1994. this.toggleContent=function(){try{
  1995. this.expanded=!this.expanded;
  1996. var btnSize=WM.opts.littleButtonSize;
  1997. with (this.contentNode)
  1998. className=className.swapWordB(this.expanded,"expanded","collapsed");
  1999. with (this.toggleImgNode)
  2000. className=className.swapWordB(this.expanded,"treeCollapse"+btnSize,"treeExpand"+btnSize);
  2001. WM.rulesManager.saveRules();
  2002. }catch(e){log("WM.rulesManager.Rule.toggleContent: "+e);}};
  2003.  
  2004. this.populateBonusList=function(){try{
  2005. var node=this.bonusDropDown;
  2006. var bonuses=[];
  2007. //get the list of accept texts for this app
  2008. if (this.appID!="") {
  2009. if (this.appID=="* All") {
  2010. //populate list with bonuses from ALL docked sidekicks
  2011. } else bonuses = mergeJSON(WM.apps[this.appID].accText,WM.apps[this.appID].userDefinedTypes);
  2012. }
  2013. bonuses["dynamic"]="* Dynamic grab";
  2014. bonuses["none"]="* None";
  2015. bonuses["wishlist"]="* Flaged as Wishlist";
  2016. bonuses["exclude"]="* Excluded types";
  2017. bonuses["send"]="* Send Unknown";
  2018. bonuses["doUnknown"]="* Get Unknown";
  2019. bonuses["*"]="* All"; //perform rule on ALL bonus types for this app
  2020.  
  2021. //sort by display text
  2022. bonuses=sortCollection(bonuses,"value");
  2023.  
  2024. //add each element to the dropdown
  2025. var elem;
  2026. node.innerHTML=""; //wipe previous list
  2027. for (var i in bonuses) {
  2028. var showI=i.removePrefix(this.appID);
  2029. node.appendChild(elem=createElement("option",{textContent:((bonuses[i].startsWith("*"))?"":((showI.startsWith("send"))?"Send ":"Get "))+bonuses[i], value:showI}));
  2030. if (this.bonus== showI) elem.selected = true;
  2031. }
  2032. }catch(e){log("WM.rulesManager.Rule.populateBonusList: "+e);}};
  2033.  
  2034. //draw to priority/rule manager or to the parent node's kids or eggs section
  2035. try{(((this.parent)?this.parent[(this.isChild)?"kidsNode":"eggsNode"]:null)||$("wmPriorityBuilder")).appendChild(
  2036. this.node=createElement("div",{className:"listItem "+((this.enabled)?"enabled":"disabled")},[
  2037. createElement("div",{className:"line"},[
  2038. createElement("div",{className:"littleButton",title:"Toggle Content",onclick:function(){self.toggleContent();}},[
  2039. this.toggleImgNode=createElement("img",{className:"resourceIcon "+(this.expanded?"treeCollapse"+WM.opts.littleButtonSize:"treeExpand"+WM.opts.littleButtonSize)}),
  2040. ]),
  2041. this.toggleNode=createElement("input",{type:"checkbox",checked:this.enabled,onchange:function(){
  2042. self.enabled=this.checked;
  2043. with (self.node) className=className.toggleWordB(!this.checked,"disabled");
  2044. WM.rulesManager.saveRules();
  2045. }}),
  2046. createElement("label",{textContent:"Title:"}),
  2047. this.titleNode=createElement("input",{className:"w400",value:(this.title||""), onchange:function(){self.title=this.value; WM.rulesManager.saveRules();}}),
  2048. //toolbox
  2049. createElement("div",{className:"littleButton oddOrange", title:"Remove Rule"},[
  2050. createElement("img",{className:"resourceIcon trash"+WM.opts.littleButtonSize,onclick:function(){self.remove();}})]),
  2051. createElement("div",{className:"littleButton oddBlue",title:"Hatch Egg Children"},[
  2052. createElement("img",{className:"resourceIcon hatch"+WM.opts.littleButtonSize,onclick:function(){self.hatch();}})]),
  2053. createElement("div",{className:"littleButton oddBlue", title:"Reset Limit Counter"},[
  2054. createElement("img",{className:"resourceIcon reset"+WM.opts.littleButtonSize,onclick:function(){self.resetLimit();}})]),
  2055. createElement("div",{className:"littleButton oddBlue", title:"Clone Rule"},[
  2056. createElement("img",{className:"resourceIcon clone"+WM.opts.littleButtonSize,onclick:function(){self.clone();}})]),
  2057. createElement("div",{className:"littleButton oddBlue", title:"Birth Egg Children"},[
  2058. createElement("img",{className:"resourceIcon birth"+WM.opts.littleButtonSize,onclick:function(){self.birth();}})]),
  2059. createElement("div",{className:"littleButton oddGreen", title:"Move Up"},[
  2060. createElement("img",{className:"resourceIcon arrowUp"+WM.opts.littleButtonSize,onclick:function(){self.moveUp();}})]),
  2061. createElement("div",{className:"littleButton oddOrange", title:"Move Down"},[
  2062. createElement("img",{className:"resourceIcon arrowDown"+WM.opts.littleButtonSize,onclick:function(){self.moveDown();}})]),
  2063. createElement("div",{className:"littleButton oddGreen", title:"Move Up Level"},[
  2064. createElement("img",{className:"resourceIcon moveUpLevelLeft"+WM.opts.littleButtonSize,onclick:function(){self.moveUpLevel();}})]),
  2065. createElement("div",{className:"littleButton oddOrange", title:"Move Down Level"},[
  2066. createElement("img",{className:"resourceIcon moveInLevel"+WM.opts.littleButtonSize,onclick:function(){self.moveDownLevel();}})]),
  2067. createElement("div",{className:"littleButton oddBlue", title:"Show Source"},[
  2068. createElement("img",{className:"resourceIcon object"+WM.opts.littleButtonSize,onclick:function(){promptText(JSON.stringify(self.saveableData),true);}})]),
  2069.  
  2070. createElement("div",{className:"indent littleButton "+((this.isGlobal)?"oddOrange":"oddGreen"), title:((this.isGlobal)?"Disable Profile Sharing":"Share With Other Profiles")},[
  2071. this.toggleGlobalButton=createElement("img",{className:"resourceIcon "+((this.isGlobal)?"removeGlobal":"addGlobal")+WM.opts.littleButtonSize,onclick:function(){self.isGlobal=!self.isGlobal; WM.rulesManager.saveRules();}})]),
  2072. ]),
  2073. this.contentNode=createElement("div",{className:"subsection "+(this.expanded?"expanded":"collapsed")},[
  2074. (this.basedOn)?createElement("div",{className:"line"},[
  2075. createElement("label",{textContent:"This rule is linked to a post: ",title:"This rule is linked to a post. Validators can draw information from that post so you can easily capture similar posts just by editing the captured texts to suit your needs. Post linking is not carried from session to session."}),
  2076. this.basedOnNode=createElement("span",{textContent:this.basedOn.id}),
  2077. ]):null,
  2078. createElement("div",{className:"line"},[
  2079. createElement("label",{textContent:"Limit:"}),
  2080. this.limitNode=createElement("input",{value:(this.limit||0), onchange:function(){self.limit=this.value;WM.rulesManager.saveRules();}}),
  2081. ]),
  2082. createElement("div",{className:"line"},[
  2083. createElement("label",{textContent:"Counter:"}),
  2084. this.limitCounterNode=createElement("input",{value:(this.limitCount||0), onchange:function(){self.limitCount=this.value;WM.rulesManager.saveRules();}}),
  2085. ]),
  2086. this.ruleButtonHousingNode=createElement("div",{className:"line", style:(this.usesRuleButton())?"":"display:none;"},[
  2087. createElement("label",{textContent:"Rule Button:"}),
  2088. this.ruleButtonNode=createElement("button",{type:"button", textContent:"onRuleButtonClicked()", onclick:function(){self.ruleButtonClicked();}}),
  2089. ]),
  2090. //validation subbox
  2091. createElement("div",{className:"line"},[
  2092. createElement("label",{textContent:"For Activating Objects:",title:"These validators attempt to match a post or other activating object, such as feed, feed filter, app, or this rule. All activators that match here then have the following actions performed at certain events."}),
  2093. createElement("div",{className:"littleButton oddGreen",onclick:function(){self.addValidator();},title:"Add Validator"},[
  2094. createElement("img",{className:"resourceIcon plus"+WM.opts.littleButtonSize}),
  2095. ]),
  2096. this.validationNode=createElement("div",{className:"subsection"}),
  2097. ]),
  2098. //actions subbox
  2099. createElement("div",{className:"line"},[
  2100. createElement("label",{textContent:"Do Actions:",title:"Actions to perform on matching posts."}),
  2101. createElement("div",{className:"littleButton oddGreen",onclick:function(){self.addAction();},title:"Add Action"},[
  2102. createElement("img",{className:"resourceIcon plus"+WM.opts.littleButtonSize}),
  2103. ]),
  2104. this.actionsNode=createElement("div",{className:"subsection"}),
  2105. ]),
  2106. //kids subbox
  2107. createElement("div",{className:"line"},[
  2108. createElement("label",{textContent:"Child Rules:",title:"Child rules are nested rules which are applied to matching posts at the same time the parent rule is applied. Child rules can have different validators, but will only activate if the parent validators have already matched a post."}),
  2109. createElement("div",{className:"littleButton oddGreen",onclick:function(){self.addChild();},title:"Add Child"},[
  2110. createElement("img",{className:"resourceIcon plus"+WM.opts.littleButtonSize}),
  2111. ]),
  2112. this.kidsNode=createElement("div",{className:"subsection"}),
  2113. ]),
  2114. //egg kids subbox
  2115. createElement("div",{className:"line"},[
  2116. createElement("label",{textContent:"Egg Rules:", title:"Eggs are potential future rules. When 'hatched', these eggs take the place of the parent rule. The parent rule and its normal children are destroyed."}),
  2117. createElement("div",{className:"littleButton oddGreen",onclick:function(){self.addEgg();},title:"Add Egg"},[
  2118. createElement("img",{className:"resourceIcon plus"+WM.opts.littleButtonSize}),
  2119. ]),
  2120. this.eggsNode=createElement("div",{className:"subsection"}),
  2121. ]),
  2122. ]),
  2123. ])
  2124. );}catch(e){log("WM.rulesManager.Rule.init.drawRule: "+e);}
  2125.  
  2126. //list the actions for this rule
  2127. if (isArrayAndNotEmpty(params.actions)) for (var i=0,action; (action=params.actions[i]); i++) {
  2128. this.addAction(action);
  2129. }
  2130. //list the validators for this rule
  2131. if (isArrayAndNotEmpty(params.validators)) for (var i=0,validator; (validator=params.validators[i]); i++) {
  2132. this.addValidator(validator);
  2133. }
  2134. //list the kids for this rule
  2135. if (isArrayAndNotEmpty(params.kids)) for (var i=0,kid; (kid=params.kids[i]); i++) {
  2136. this.addChild(kid);
  2137. }
  2138. //list the egg kids for this rule
  2139. if (isArrayAndNotEmpty(params.eggs)) for (var i=0,egg; (egg=params.eggs[i]); i++) {
  2140. this.addEgg(egg);
  2141. }
  2142. //create cleanup function
  2143. this.cleanup=function(){try{
  2144. for (var t in this.timers) {
  2145. window.clearTimeout(this.timers[t]);
  2146. }
  2147. for (var i in this.intervals) {
  2148. window.clearInterval(this.intervals[i]);
  2149. }
  2150. var self=this;
  2151. removeEventListener("beforeunload",self.cleanup,false);
  2152. }catch(e){log("WM.rulesManager.Rule.cleanup: "+e);}};
  2153. addEventListener("beforeunload",self.cleanup,false);
  2154. this.onEvent("onRuleCreated");
  2155. return self;
  2156.  
  2157. }catch(e){log("WM.rulesManager.Rule.init: "+e);}};
  2158.  
  2159. })();

QingJ © 2025

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