/******************************************************************************************************************************** * Licensed Materials - Property of IBM * * * * IBM Cognos Products: AGS * * * * (C) Copyright IBM Corp. 2005, 2008 * * * * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * *********************************************************************************************************************************/ /* this file holds the agent items listener the agent listener the items listener, watches for topic changes in the text and adjusts the agent items tree when text corresponding to topics is deleted.... this also checks all other references to topics within all tasks in the agent... and the state is restored onload the text listener, keeps stacks of the versions of text in each dropzone visible.... the state of these stacks are not maintained from page to page or on save or load as they are only used by the undo / redo functionality. /** when a page is created, the dropzone fields are registered here and the contents cached. we recieve onBlur events with the updated contents and do a diff to see the changes in model item references. we also track whole groups of dz fields 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.... 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 @author mannn */ function AgentItemsListener(){ //quick count of how many refs per topic this.referenceTracker = new AgentItemsReferenceTracker(); //hold on to the field-contents in groups by id this.all_field_sets = new Object(); //hold on to the dynamic field-contents in groups by id this.dynamic_field_group = new Object(); //this is the working set.... of currently visible fields - organised by holding frames this.frameIds = new FrameIdentification(); //report task list this.reportTasks = new Object() } /* a little light debuggage.... */ AgentItemsListener.prototype.displayState = function(){ var message = " ******* agent items tracking ******* \n"; for(var field_set_id in this.all_field_sets){ message += field_set_id + "\n"; var field_set = this.all_field_sets[field_set_id]; for(var field_name in field_set){ var topics = field_set[field_name].getTopics(); message += " " + field_name; var topics_section = " ("; for(var i = 0; i < topics.length; i++){ topics_section += i == 0 ? "" : ", "; topics_section += topics[i]; } message += topics_section + ")\n"; } var dynamic_group = this.dynamic_field_group[field_set_id]; if(dynamic_group){ message += " field group "; var group_section = " ("; for(var i = 0; i < dynamic_group.fieldContents.length; i++){ group_section += i == 0 ? "" : ", "; group_section += dynamic_group.fieldContents[i].fieldName; } message += group_section + ")\n"; } if(getRedoUndoManager().taskDeleteHistory.peek()){ message += " tracking " + getRedoUndoManager().taskDeleteHistory.members.length + "deleted tasks\n"; } } //ref counts message += this.referenceTracker.toString(); for(var id in this.reportTasks){ message += "\n" + this.reportTasks[id].toString(); } alert(message); } /* sort of singleton method to retutrn the one instance* */ function getAgentItemsListener(){ if(!agentItemsListener){ agentItemsListener = new AgentItemsListener() } return agentItemsListener; } //a frame has been hidden... the drop zones registered against it //are no longer showing AgentItemsListener.prototype.frameHidden = function(frameName){ this.frameIds.clearFrame(frameName); } //some groups of dropzones can change their ids... i.e. calculations //can be renamed and their name is used to track the references AgentItemsListener.prototype.updateId = function(new_id, old_id, frameName){ var field_set = this.all_field_sets[old_id]; delete this.all_field_sets[old_id]; this.all_field_sets[new_id] = field_set; for(var aName in field_set){ field_set[aName].id = new_id; } //now let the frameIds holder know this.frameIds.addFrameId(new_id, frameName); } //called from the report and agent pages //holds data about report tasks and the paths AgentItemsListener.prototype.setReportTask = function(id, name, reportPath){ var reportTask = new ReportTaskAssignments(id, name, reportPath); this.reportTasks[id] = reportTask; } AgentItemsListener.prototype.getReportTaskAssignments = function(){ var reportTasksPa = new Array(); for(var field_set_id in this.reportTasks){ var reportTask = this.reportTasks[field_set_id]; //dont do nuffink for duds if(!reportTask)continue; //update the pas reportTask.parameterAssignments = new Array(); var field_set = this.all_field_sets[field_set_id]; for(var field_name in field_set){ var topics = field_set[field_name].getTopics(); for(var i = 0; topics && i < topics.length; i++){ reportTask.parameterAssignments.push(new ParameterAssignment(field_name, topics[i])); } } reportTasksPa.push(reportTask); } return reportTasksPa; } //this can be called when deleting a task... // we remove all references to any topics held against that task id //and add them to the special task action stack AgentItemsListener.prototype.removeAllReferencesById = function(id){ var field_set = this.getFieldSet(id); if(getRedoUndoManager().isDeletedTask(id)){ //weve seen this one before; return; } var task_deletes = new Array(); for(var field in field_set){ //this removes references task_deletes = task_deletes.concat(this.removeField(field, id)); } var eab = new TaskEditActionBundle(null, id); for(var i = 0; i < task_deletes.length; i++){ eab.addEditAction(new DeleteItemEditAction(task_deletes[i])); } //save the deletes in case we change our mind getRedoUndoManager().taskDeleteHistory.push(eab); delete this.all_field_sets[id]; delete this.dynamic_field_group[id]; if(this.reportTasks[id]){ delete this.reportTasks[id]; } } //here we check that we have the id....and field if not create it and / or add the field and any value... //question is.. do we add the agent item here in this case?? I think we just hang on to the ref //if we have the id and field, then just flag the id as the current one //use a frame name to distinguish dialogd open in diffent frames on the page AgentItemsListener.prototype.registerField = function(fieldName, id, initialValue, frameName){ if(!id){ //bin out return; } //track which tabs are showing this.frameIds.addFrameId(id, frameName); var field = this.getFieldSet(id)[fieldName]; if(!field){ field = new FieldContent(fieldName, id, initialValue) //probably a new field from a new task this.addField(field, id); } //check that the field contents havent changed this.updateField(fieldName, initialValue); } /* topic has been dropped into this field */ AgentItemsListener.prototype.addItemToField = function(fieldName, item) { //DataItems we created (calculations) should not be deleted when //They are removed from drop zones. if (item && item != "undefined") { this.addTopicToField(fieldName, item.getDropValue()); } } /* topic has been dropped into this field */ AgentItemsListener.prototype.addTopicToField = function(fieldName, topic_value){ //alert("add topic"); var current_field_set = this.getCurrentFieldSet(); //Check if we can add the topic var canAdd = (topic_value && topic_value.length && topic_value.length > 2 && topic_value.charAt(0) == "[" && topic_value.charAt(topic_value.length - 1) == "]"); if(!current_field_set[fieldName] || !canAdd){ //alert("delete listener trying to update unregistered field"); return; } //add the reference to the field current_field_set[fieldName].addTopic(topic_value); //hang on to the count this.referenceTracker.addReference(topic_value); } /* topics have been dropped into this field (by an undo) so we dont add topics if we already know about them */ AgentItemsListener.prototype.redoUndoTopicsUpdate = function(fieldName, new_value){ //alert("redoUndoTopicsUpdate"); var current_field_set = this.getCurrentFieldSet(); if(!current_field_set[fieldName]){ //alert("delete listener trying to update unregistered field"); return; } if(!new_value){ new_value = ""; } var topic_objects = findTopicsInContent(new_value); for(var i = 0; i < current_field_set[fieldName].getTopics().length; i++){ for(var j = 0; j < topic_objects.length; j++) { if(topic_objects[j] == current_field_set[fieldName].getTopics()[i]){ topic_objects.splice(j, 1); break; } } } for(var i = 0; i < topic_objects.length; i++){ //add the reference to the field current_field_set[fieldName].addTopic(topic_objects[i]); //hang on to the count this.referenceTracker.addReference(topic_objects[i]); } current_field_set[fieldName].setContent(new_value); var removed_topics = current_field_set[fieldName].checkForRemovedTopics(); //remove the topics var deleted_ref_objects = this.referenceTracker.removeReferences(removed_topics); } /* topic has been dropped into this field */ AgentItemsListener.prototype.removeTopicFromField = function(fieldName, topic_value){ //alert("remove topic"); var current_field_set = this.getCurrentFieldSet(); if(!current_field_set[fieldName]){ //alert("delete listener trying to update unregistered field"); return; } //add the reference to the field current_field_set[fieldName].removeTopic(topic_value); //hang on to the count this.referenceTracker.removeReference(topic_value); } /* we have a possible chane to the contents fo a field, so look for the topics we think are in the field. If we cant find them... assume they have been blattered and remove the referenece */ AgentItemsListener.prototype.updateField = function(fieldName, new_value){ var current_field_set = this.getCurrentFieldSet(); var field = current_field_set[fieldName]; if(!field || field.getContent() == new_value){ return } getRedoUndoManager().updateField(fieldName, new_value, field.getContent()); field.setContent(new_value); var removed_topics = field.checkForRemovedTopics(); //remove the topic refs this.referenceTracker.removeReferences(removed_topics); } AgentItemsListener.prototype.isValidField = function(fieldName, id){ return this.getFieldSet(id)[fieldName]; } //return the set of fields by id AgentItemsListener.prototype.getFieldSet = function(id){ var field_set = this.all_field_sets[id]; if(!field_set){ field_set = new Object(); this.all_field_sets[id] = field_set; } return field_set; } //this returns an amalgam of field sets //containing the field contents of all visible frames AgentItemsListener.prototype.getCurrentFieldSet = function(){ var currentFieldSet = new Object(); var ids = this.frameIds.getCurrentIds(); for(var i = 0; i < ids.length; i++){ var field_set = this.all_field_sets[ids[i]]; if(!field_set){ field_set = new Object(); this.all_field_sets[id] = field_set; }else{ for(var field in field_set){ //copy the field set reference to the return object currentFieldSet[field] = field_set[field]; } } } return currentFieldSet; } //return the set of fields by id AgentItemsListener.prototype.getFieldContent = function(fieldName, id){ return this.getFieldSet(id)[fieldName]; } //we are interested in tracking the changes that happened dynamically to this group of //dynamic fields.... the changes to individual fields will //take place through the other update method.. and should already be registered //so this is only interested in removal of a whole field //NB this kind of thing is forced externally, and so is not undoable AgentItemsListener.prototype.registerDynamicGroup = function(updatedFieldContents, id, frameName){ //track which tabs are showing this.frameIds.addFrameId(id, frameName); if(!id || id == ""){ //shhh //alert("delete listener trying to use an undefined id"); } var dfg = this.dynamic_field_group[id]; if(!dfg){ //this is a new task dfg = this.makeFieldGroup(updatedFieldContents, id); this.dynamic_field_group[id] = dfg; }else{ //do the diffs new_dfg = this.makeFieldGroup(updatedFieldContents, id); new_dfg.update(); this.dynamic_field_group[id] = new_dfg; } } ///////////////////// // initialisation and update methods for use on load, and when the agent changes to remove fields from the //////////////////// /** fieldName - an env param name to hold on to as valid **/ AgentItemsListener.prototype.addField = function(fieldContents){ var current_field_set = this.getFieldSet(fieldContents.id); if(current_field_set){ var existingFieldContents = current_field_set[fieldContents.fieldName]; if(!existingFieldContents){ //ask the wise old tree var topics = findTopicsInContent(fieldContents.fieldContent); fieldContents.topics = topics; current_field_set[fieldContents.fieldName] = fieldContents; //tot up the topics this.referenceTracker.addReferences(topics); } } } /* get rid of a field that has been registered and take its references with it we hang on to the agent item changes but not the text changes here.... as its task delete or a field removed from a field group */ AgentItemsListener.prototype.removeField = function(fieldName, task_id){ var current_field_set = this.getFieldSet(task_id); var deleted_items; if(current_field_set){ var fieldContents = current_field_set[fieldName]; if (fieldContents != undefined){ deleted_items = this.referenceTracker.removeReferences(fieldContents.getTopics()); } delete current_field_set[fieldName]; } return deleted_items; } AgentItemsListener.prototype.addDynamicGroup = function(fieldContentArray, id){ this.dynamic_field_group[id] = this.makeFieldGroup(fieldContentArray, id); } AgentItemsListener.prototype.makeFieldGroup = function(fieldContentArray, id){ var dfg; //this is a new dynamic group dfg = new DynamicFieldGroup(fieldContentArray, id); return dfg; } /* this holds one id per frame for as many frames as you care to have */ function FrameIdentification(){ this.frameSet = new Object(); } //return all current ids FrameIdentification.prototype.getCurrentIds = function(){ var allFrames = new Array(); for(var aFrame in this.frameSet){ if(this.frameSet[aFrame]){ allFrames.push(this.frameSet[aFrame]); } } return allFrames; } //clear the id assoc with a frame and return the deleted id FrameIdentification.prototype.clearFrame = function(frameName){ var current_id = this.frameSet[frameName]; delete this.frameSet[frameName]; return current_id; } //set a new registration and return any old ones FrameIdentification.prototype.addFrameId = function(id, frameName){ var current_id = this.frameSet[frameName]; var old_id; if(current_id && current_id != id){ old_id = current_id; } //this is a new registration this.frameSet[frameName] = id; return old_id; } var agentItemsListener;;