agentItemsListener.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /********************************************************************************************************************************
  2. * Licensed Materials - Property of IBM *
  3. * *
  4. * IBM Cognos Products: AGS *
  5. * *
  6. * (C) Copyright IBM Corp. 2005, 2008 *
  7. * *
  8. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *
  9. *********************************************************************************************************************************/
  10. /*
  11. this file holds the agent items listener the agent listener
  12. the items listener, watches for topic changes in the text and adjusts the
  13. agent items tree when text corresponding to topics is deleted.... this also checks all other references
  14. to topics within all tasks in the agent... and the state is restored onload
  15. the text listener, keeps stacks of the versions of text in each dropzone visible.... the state of these stacks are not
  16. maintained from page to page or on save or load as they are only used by the undo / redo functionality.
  17. /**
  18. when a page is created, the dropzone fields are registered here and the contents cached. we recieve onBlur events
  19. with the updated contents and do a diff to see the changes in model item references. we also track whole groups of dz fields
  20. whose names are dynamically generated and liable tom change from visit to visit (to the relevant page)there is a unique group id that is used when the group is created or added....
  21. the id is currently just the unique task id, so were making the rather bold assumption that there is only one group of dynamic form fields per task
  22. @author mannn
  23. */
  24. function AgentItemsListener(){
  25. //quick count of how many refs per topic
  26. this.referenceTracker = new AgentItemsReferenceTracker();
  27. //hold on to the field-contents in groups by id
  28. this.all_field_sets = new Object();
  29. //hold on to the dynamic field-contents in groups by id
  30. this.dynamic_field_group = new Object();
  31. //this is the working set.... of currently visible fields - organised by holding frames
  32. this.frameIds = new FrameIdentification();
  33. //report task list
  34. this.reportTasks = new Object()
  35. }
  36. /*
  37. a little light debuggage....
  38. */
  39. AgentItemsListener.prototype.displayState = function(){
  40. var message = " ******* agent items tracking ******* \n";
  41. for(var field_set_id in this.all_field_sets){
  42. message += field_set_id + "\n";
  43. var field_set = this.all_field_sets[field_set_id];
  44. for(var field_name in field_set){
  45. var topics = field_set[field_name].getTopics();
  46. message += " " + field_name;
  47. var topics_section = " (";
  48. for(var i = 0; i < topics.length; i++){
  49. topics_section += i == 0 ? "" : ", ";
  50. topics_section += topics[i];
  51. }
  52. message += topics_section + ")\n";
  53. }
  54. var dynamic_group = this.dynamic_field_group[field_set_id];
  55. if(dynamic_group){
  56. message += " field group ";
  57. var group_section = " (";
  58. for(var i = 0; i < dynamic_group.fieldContents.length; i++){
  59. group_section += i == 0 ? "" : ", ";
  60. group_section += dynamic_group.fieldContents[i].fieldName;
  61. }
  62. message += group_section + ")\n";
  63. }
  64. if(getRedoUndoManager().taskDeleteHistory.peek()){
  65. message += " tracking " + getRedoUndoManager().taskDeleteHistory.members.length + "deleted tasks\n";
  66. }
  67. }
  68. //ref counts
  69. message += this.referenceTracker.toString();
  70. for(var id in this.reportTasks){
  71. message += "\n" + this.reportTasks[id].toString();
  72. }
  73. alert(message);
  74. }
  75. /*
  76. sort of singleton method to retutrn the one instance*
  77. */
  78. function getAgentItemsListener(){
  79. if(!agentItemsListener){
  80. agentItemsListener = new AgentItemsListener()
  81. }
  82. return agentItemsListener;
  83. }
  84. //a frame has been hidden... the drop zones registered against it
  85. //are no longer showing
  86. AgentItemsListener.prototype.frameHidden = function(frameName){
  87. this.frameIds.clearFrame(frameName);
  88. }
  89. //some groups of dropzones can change their ids... i.e. calculations
  90. //can be renamed and their name is used to track the references
  91. AgentItemsListener.prototype.updateId = function(new_id, old_id, frameName){
  92. var field_set = this.all_field_sets[old_id];
  93. delete this.all_field_sets[old_id];
  94. this.all_field_sets[new_id] = field_set;
  95. for(var aName in field_set){
  96. field_set[aName].id = new_id;
  97. }
  98. //now let the frameIds holder know
  99. this.frameIds.addFrameId(new_id, frameName);
  100. }
  101. //called from the report and agent pages
  102. //holds data about report tasks and the paths
  103. AgentItemsListener.prototype.setReportTask = function(id, name, reportPath){
  104. var reportTask = new ReportTaskAssignments(id, name, reportPath);
  105. this.reportTasks[id] = reportTask;
  106. }
  107. AgentItemsListener.prototype.getReportTaskAssignments = function(){
  108. var reportTasksPa = new Array();
  109. for(var field_set_id in this.reportTasks){
  110. var reportTask = this.reportTasks[field_set_id];
  111. //dont do nuffink for duds
  112. if(!reportTask)continue;
  113. //update the pas
  114. reportTask.parameterAssignments = new Array();
  115. var field_set = this.all_field_sets[field_set_id];
  116. for(var field_name in field_set){
  117. var topics = field_set[field_name].getTopics();
  118. for(var i = 0; topics && i < topics.length; i++){
  119. reportTask.parameterAssignments.push(new ParameterAssignment(field_name, topics[i]));
  120. }
  121. }
  122. reportTasksPa.push(reportTask);
  123. }
  124. return reportTasksPa;
  125. }
  126. //this can be called when deleting a task...
  127. // we remove all references to any topics held against that task id
  128. //and add them to the special task action stack
  129. AgentItemsListener.prototype.removeAllReferencesById = function(id){
  130. var field_set = this.getFieldSet(id);
  131. if(getRedoUndoManager().isDeletedTask(id)){
  132. //weve seen this one before;
  133. return;
  134. }
  135. var task_deletes = new Array();
  136. for(var field in field_set){
  137. //this removes references
  138. task_deletes = task_deletes.concat(this.removeField(field, id));
  139. }
  140. var eab = new TaskEditActionBundle(null, id);
  141. for(var i = 0; i < task_deletes.length; i++){
  142. eab.addEditAction(new DeleteItemEditAction(task_deletes[i]));
  143. }
  144. //save the deletes in case we change our mind
  145. getRedoUndoManager().taskDeleteHistory.push(eab);
  146. delete this.all_field_sets[id];
  147. delete this.dynamic_field_group[id];
  148. if(this.reportTasks[id]){
  149. delete this.reportTasks[id];
  150. }
  151. }
  152. //here we check that we have the id....and field if not create it and / or add the field and any value...
  153. //question is.. do we add the agent item here in this case?? I think we just hang on to the ref
  154. //if we have the id and field, then just flag the id as the current one
  155. //use a frame name to distinguish dialogd open in diffent frames on the page
  156. AgentItemsListener.prototype.registerField = function(fieldName, id, initialValue, frameName){
  157. if(!id){
  158. //bin out
  159. return;
  160. }
  161. //track which tabs are showing
  162. this.frameIds.addFrameId(id, frameName);
  163. var field = this.getFieldSet(id)[fieldName];
  164. if(!field){
  165. field = new FieldContent(fieldName, id, initialValue)
  166. //probably a new field from a new task
  167. this.addField(field, id);
  168. }
  169. //check that the field contents havent changed
  170. this.updateField(fieldName, initialValue);
  171. }
  172. /*
  173. topic has been dropped into this field
  174. */
  175. AgentItemsListener.prototype.addItemToField = function(fieldName, item) {
  176. //DataItems we created (calculations) should not be deleted when
  177. //They are removed from drop zones.
  178. if (item && item != "undefined") {
  179. this.addTopicToField(fieldName, item.getDropValue());
  180. }
  181. }
  182. /*
  183. topic has been dropped into this field
  184. */
  185. AgentItemsListener.prototype.addTopicToField = function(fieldName, topic_value){
  186. //alert("add topic");
  187. var current_field_set = this.getCurrentFieldSet();
  188. //Check if we can add the topic
  189. var canAdd = (topic_value && topic_value.length && topic_value.length > 2 && topic_value.charAt(0) == "[" && topic_value.charAt(topic_value.length - 1) == "]");
  190. if(!current_field_set[fieldName] || !canAdd){
  191. //alert("delete listener trying to update unregistered field");
  192. return;
  193. }
  194. //add the reference to the field
  195. current_field_set[fieldName].addTopic(topic_value);
  196. //hang on to the count
  197. this.referenceTracker.addReference(topic_value);
  198. }
  199. /*
  200. topics have been dropped into this field (by an undo)
  201. so we dont add topics if we already know about them
  202. */
  203. AgentItemsListener.prototype.redoUndoTopicsUpdate = function(fieldName, new_value){
  204. //alert("redoUndoTopicsUpdate");
  205. var current_field_set = this.getCurrentFieldSet();
  206. if(!current_field_set[fieldName]){
  207. //alert("delete listener trying to update unregistered field");
  208. return;
  209. }
  210. if(!new_value){
  211. new_value = "";
  212. }
  213. var topic_objects = findTopicsInContent(new_value);
  214. for(var i = 0; i < current_field_set[fieldName].getTopics().length; i++){
  215. for(var j = 0; j < topic_objects.length; j++) {
  216. if(topic_objects[j] == current_field_set[fieldName].getTopics()[i]){
  217. topic_objects.splice(j, 1);
  218. break;
  219. }
  220. }
  221. }
  222. for(var i = 0; i < topic_objects.length; i++){
  223. //add the reference to the field
  224. current_field_set[fieldName].addTopic(topic_objects[i]);
  225. //hang on to the count
  226. this.referenceTracker.addReference(topic_objects[i]);
  227. }
  228. current_field_set[fieldName].setContent(new_value);
  229. var removed_topics = current_field_set[fieldName].checkForRemovedTopics();
  230. //remove the topics
  231. var deleted_ref_objects = this.referenceTracker.removeReferences(removed_topics);
  232. }
  233. /*
  234. topic has been dropped into this field
  235. */
  236. AgentItemsListener.prototype.removeTopicFromField = function(fieldName, topic_value){
  237. //alert("remove topic");
  238. var current_field_set = this.getCurrentFieldSet();
  239. if(!current_field_set[fieldName]){
  240. //alert("delete listener trying to update unregistered field");
  241. return;
  242. }
  243. //add the reference to the field
  244. current_field_set[fieldName].removeTopic(topic_value);
  245. //hang on to the count
  246. this.referenceTracker.removeReference(topic_value);
  247. }
  248. /*
  249. we have a possible chane to the contents fo a field, so look for the topics we think
  250. are in the field. If we cant find them... assume they have been blattered and
  251. remove the referenece
  252. */
  253. AgentItemsListener.prototype.updateField = function(fieldName, new_value){
  254. var current_field_set = this.getCurrentFieldSet();
  255. var field = current_field_set[fieldName];
  256. if(!field || field.getContent() == new_value){
  257. return
  258. }
  259. getRedoUndoManager().updateField(fieldName, new_value, field.getContent());
  260. field.setContent(new_value);
  261. var removed_topics = field.checkForRemovedTopics();
  262. //remove the topic refs
  263. this.referenceTracker.removeReferences(removed_topics);
  264. }
  265. AgentItemsListener.prototype.isValidField = function(fieldName, id){
  266. return this.getFieldSet(id)[fieldName];
  267. }
  268. //return the set of fields by id
  269. AgentItemsListener.prototype.getFieldSet = function(id){
  270. var field_set = this.all_field_sets[id];
  271. if(!field_set){
  272. field_set = new Object();
  273. this.all_field_sets[id] = field_set;
  274. }
  275. return field_set;
  276. }
  277. //this returns an amalgam of field sets
  278. //containing the field contents of all visible frames
  279. AgentItemsListener.prototype.getCurrentFieldSet = function(){
  280. var currentFieldSet = new Object();
  281. var ids = this.frameIds.getCurrentIds();
  282. for(var i = 0; i < ids.length; i++){
  283. var field_set = this.all_field_sets[ids[i]];
  284. if(!field_set){
  285. field_set = new Object();
  286. this.all_field_sets[id] = field_set;
  287. }else{
  288. for(var field in field_set){
  289. //copy the field set reference to the return object
  290. currentFieldSet[field] = field_set[field];
  291. }
  292. }
  293. }
  294. return currentFieldSet;
  295. }
  296. //return the set of fields by id
  297. AgentItemsListener.prototype.getFieldContent = function(fieldName, id){
  298. return this.getFieldSet(id)[fieldName];
  299. }
  300. //we are interested in tracking the changes that happened dynamically to this group of
  301. //dynamic fields.... the changes to individual fields will
  302. //take place through the other update method.. and should already be registered
  303. //so this is only interested in removal of a whole field
  304. //NB this kind of thing is forced externally, and so is not undoable
  305. AgentItemsListener.prototype.registerDynamicGroup = function(updatedFieldContents, id, frameName){
  306. //track which tabs are showing
  307. this.frameIds.addFrameId(id, frameName);
  308. if(!id || id == ""){
  309. //shhh
  310. //alert("delete listener trying to use an undefined id");
  311. }
  312. var dfg = this.dynamic_field_group[id];
  313. if(!dfg){
  314. //this is a new task
  315. dfg = this.makeFieldGroup(updatedFieldContents, id);
  316. this.dynamic_field_group[id] = dfg;
  317. }else{
  318. //do the diffs
  319. new_dfg = this.makeFieldGroup(updatedFieldContents, id);
  320. new_dfg.update();
  321. this.dynamic_field_group[id] = new_dfg;
  322. }
  323. }
  324. /////////////////////
  325. // initialisation and update methods for use on load, and when the agent changes to remove fields from the
  326. ////////////////////
  327. /**
  328. fieldName - an env param name to hold on to as valid
  329. **/
  330. AgentItemsListener.prototype.addField = function(fieldContents){
  331. var current_field_set = this.getFieldSet(fieldContents.id);
  332. if(current_field_set){
  333. var existingFieldContents = current_field_set[fieldContents.fieldName];
  334. if(!existingFieldContents){
  335. //ask the wise old tree
  336. var topics = findTopicsInContent(fieldContents.fieldContent);
  337. fieldContents.topics = topics;
  338. current_field_set[fieldContents.fieldName] = fieldContents;
  339. //tot up the topics
  340. this.referenceTracker.addReferences(topics);
  341. }
  342. }
  343. }
  344. /*
  345. get rid of a field that has been registered and take its references with it
  346. we hang on to the agent item changes but not the text changes here.... as its task delete
  347. or a field removed from a field group
  348. */
  349. AgentItemsListener.prototype.removeField = function(fieldName, task_id){
  350. var current_field_set = this.getFieldSet(task_id);
  351. var deleted_items;
  352. if(current_field_set){
  353. var fieldContents = current_field_set[fieldName];
  354. if (fieldContents != undefined){
  355. deleted_items = this.referenceTracker.removeReferences(fieldContents.getTopics());
  356. }
  357. delete current_field_set[fieldName];
  358. }
  359. return deleted_items;
  360. }
  361. AgentItemsListener.prototype.addDynamicGroup = function(fieldContentArray, id){
  362. this.dynamic_field_group[id] = this.makeFieldGroup(fieldContentArray, id);
  363. }
  364. AgentItemsListener.prototype.makeFieldGroup = function(fieldContentArray, id){
  365. var dfg;
  366. //this is a new dynamic group
  367. dfg = new DynamicFieldGroup(fieldContentArray, id);
  368. return dfg;
  369. }
  370. /*
  371. this holds one id per frame
  372. for as many frames as you care to have
  373. */
  374. function FrameIdentification(){
  375. this.frameSet = new Object();
  376. }
  377. //return all current ids
  378. FrameIdentification.prototype.getCurrentIds = function(){
  379. var allFrames = new Array();
  380. for(var aFrame in this.frameSet){
  381. if(this.frameSet[aFrame]){
  382. allFrames.push(this.frameSet[aFrame]);
  383. }
  384. }
  385. return allFrames;
  386. }
  387. //clear the id assoc with a frame and return the deleted id
  388. FrameIdentification.prototype.clearFrame = function(frameName){
  389. var current_id = this.frameSet[frameName];
  390. delete this.frameSet[frameName];
  391. return current_id;
  392. }
  393. //set a new registration and return any old ones
  394. FrameIdentification.prototype.addFrameId = function(id, frameName){
  395. var current_id = this.frameSet[frameName];
  396. var old_id;
  397. if(current_id && current_id != id){
  398. old_id = current_id;
  399. }
  400. //this is a new registration
  401. this.frameSet[frameName] = id;
  402. return old_id;
  403. }
  404. var agentItemsListener;;