1 /** 2 * @fileOverview File contains AMI.Module base class that allows to create module with asynchronous components on page. 3 */ 4 5 /** 6 * Class required for creating module on page with asyncronous components work. 7 * 8 * @class Create components, process actions, handle components events. 9 * @param {string} moduleId Id of current module. 10 * @param {object} oModuleComponents Associative array of components that should be added in module. 11 */ 12 AMI.Module = function(moduleId, oModuleComponents){ 13 this.moduleId = moduleId; 14 this.moduleComponents = {}; 15 this.oContainer = null; 16 17 this.scheduleListReload = false; 18 19 /** 20 * Set module container, add message handlers and add components of module 21 * 22 * @constructs 23 * @param {object} oComponents Associative array that describes components placed in module. Format is {componentId1:componentType1, componentId2:componentType2, etc..} where componentType one of "filter_form", "list", "form". 24 * @returns {void} 25 */ 26 this.init = function(oComponents){ 27 var moduleIdDoc = 'module_' + this.moduleId; 28 this.oContainer = AMI.find('#' + moduleIdDoc); 29 if(this.oContainer == null){ 30 AMI.Browser.DOM.create( 31 'DIV', 32 moduleIdDoc, 33 'modPageArea' 34 ); 35 } 36 37 AMI.Message.addListener('ON_COMPONENT_GET_REQUEST_DATA', function(_this){return function(oComponent, oParameters){_this.onComponentGetRequestData(oComponent, oParameters)}}(this)); 38 AMI.Message.addListener('ON_COMPONENT_CONTENT_PLACED', function(_this){return function(oComponent, oData){_this.onComponentContentPlaced(oComponent, oData)}}(this)); 39 40 for(componentId in oComponents){ 41 this.addComponent(componentId, oComponents[componentId]); 42 } 43 } 44 45 /** 46 * Get module container (DOM element that contains module content). 47 * 48 * @returns {DOM object} DOM element that contains module content. 49 */ 50 this.getContainer = function(){ 51 return this.oContainer; 52 } 53 54 /** 55 * Found and return components by type as array. 56 * 57 * @param {string} type Type of component (filter_form, list, form or other). 58 * @returns {array} Found components array. 59 */ 60 this.getComponentsByType = function(type){ 61 var aComponents = []; 62 for(componentId in this.moduleComponents){ 63 if(this.moduleComponents[componentId].componentType == type){ 64 aComponents.push(this.moduleComponents[componentId]); 65 } 66 } 67 68 return aComponents; 69 } 70 71 /** 72 * Add and place component to module. 73 * 74 * @param {string} componentId Id of the components. 75 * @param {string} componentType One of filter_form, list, form. 76 * @returns {void} 77 */ 78 this.addComponent = function(componentId, componentType){ 79 var oComponent = null; 80 switch(componentType){ 81 case 'form': 82 oComponent = new AMI.ModuleComponentForm(this, componentType, componentId); 83 oComponent.getContent(); 84 break; 85 case 'form_filter': 86 oComponent = new AMI.ModuleComponentFilter(this, componentType, componentId); 87 oComponent.getContent(); 88 break; 89 case 'list': 90 oComponent = new AMI.ModuleComponentList(this, componentType, componentId); 91 oComponent.getContent(); 92 break; 93 } 94 if(oComponent){ 95 this.moduleComponents[componentId] = oComponent; 96 } 97 } 98 99 /** 100 * Add custom data when component requested before loading its content. Method called when ON_COMPONENT_GET_REQUEST_DATA message received. 101 * To create your own callback create ON_COMPONENT_GET_REQUEST_DATA handler in your code. 102 * 103 * @param {AMI.ModuleComponent} oComponent Component object that sended request to data. 104 * @param {object} oParameters Associative array of data that will be submitted on component content request. Add data to this object if required. 105 * @returns {void} 106 */ 107 this.onComponentGetRequestData = function(oComponent, oParameters){ 108 if(oComponent.getModuleId() == this.moduleId){ 109 var oHashValues = AMI.Page.getHashData(this.moduleId); 110 var hashFilterRX = new RegExp(oComponent.getHashDataFilter(), 'i'); 111 112 for(key in oHashValues){ 113 if(key != 'mid'){ 114 if(hashFilterRX.test(key)){ 115 oParameters[key] = oHashValues[key]; 116 } 117 } 118 } 119 } 120 } 121 122 /** 123 * @private 124 */ 125 this.highlightListParameters = {}; 126 127 /** 128 * Callback method that listens ON_COMPONENT_CONTENT_PLACED message and makes required actions (like other components reload, rows higlighting, etc) when component content places. 129 * To create your own callback create ON_COMPONENT_CONTENT_PLACED handler in your code. 130 * 131 * @param {AMI.ModuleComponent} oComponent Component object that sended request to data. 132 * @param {object} oData Reserved, always null. 133 * @returns {void} 134 */ 135 this.onComponentContentPlaced = function(oComponent, oData /* oData is null */){ 136 if(oComponent.getModuleId() == this.moduleId){ 137 if(oComponent.componentType == 'form'){ 138 this.highlightListParameters = oComponent.getAppliedData(); 139 if(this.scheduleListReload){ 140 this.reloadList(null); 141 this.scheduleListReload = false; 142 }else if(typeof(this.highlightListParameters.id) != 'undefined'){ 143 this.getComponentsByType('list')[0].setRowClassById(this.highlightListParameters.id, this.highlightListParameters.type == 'edit' ? 'onedit' : 'onsaved'); 144 this.highlightListParameters = {}; 145 } 146 } 147 if(oComponent.componentType == 'list'){ 148 if(typeof(this.highlightListParameters.id) != 'undefined'){ 149 oComponent.setRowClassById(this.highlightListParameters.id, this.highlightListParameters.type == 'edit' ? 'onedit' : 'onsaved'); 150 this.highlightListParameters = {}; 151 }else if(oComponent.modActionId != null){ 152 oComponent.setRowClassById(oComponent.modActionId, 'onedit'); 153 } 154 } 155 156 /* 157 var aLinks = AMI.find('.amiPageLink', oComponent.getContainer()); 158 for(var i = 0; i < aLinks.length; i++){ 159 alert(aLinks[i].onclick); 160 } 161 */ 162 } 163 } 164 165 /** 166 * Find clicked component and check if this should create action. Calling AMI.Module.processModuleAction if required. 167 * 168 * @param {object} oEvent Event object. 169 * @param {AMI.ModuleComponent} oComponent Component that owns clicked DOM object. 170 * @returns {bool} true if no actions should be done and false otherwise. Return is required for event processing. 171 */ 172 this.onComponentClick = function(oEvent, oComponent){ 173 var oTarget = AMI.Browser.Event.getTarget(oEvent); 174 if(oTarget != null && oTarget.className.indexOf('amiModuleLink') == 0){ 175 var action = oTarget.getAttribute('data-ami-action'); 176 var parameters = oTarget.getAttribute('data-ami-parameters'); 177 178 this.processModuleAction(oComponent, action, parameters); 179 180 AMI.Browser.Event.stopProcessing(oEvent); 181 return false; 182 } 183 return true; 184 } 185 186 /** 187 * Get component object by component id. 188 * 189 * @param {mixed} mComponent Component id. This parameter could also be the component object. 190 * @returns {AMI.ModuleComponent} Component object. 191 */ 192 this.getActionComponent = function(mComponent){ 193 var oComponent = null; 194 if(typeof(mComponent) != 'undefined'){ 195 if(typeof(mComponent) == 'object'){ 196 oComponent = mComponent; 197 }else if(typeof(this.moduleComponents[mComponent]) != 'undefined'){ 198 oComponent = this.moduleComponents[mComponent]; 199 } 200 } 201 202 return oComponent; 203 } 204 205 /** 206 * Get action parameters from the GET string or associative array. 207 * 208 * @param {mixed} parameters Search part of get string (a=b&c=d etc) or associative array. 209 * @returns {object} Associative array of parameters. 210 */ 211 this.getActionParameters = function(parameters){ 212 var oParameters = parameters; 213 if(typeof(oParameters) != 'object'){ 214 oParameters = AMI.Page.getParametersFromString(parameters); 215 } 216 217 return oParameters; 218 } 219 220 /** 221 * Do module action. There are several cases in the method. Almost all methods uses AMI.Module.addHashDataAndReloadList. 222 * 223 * @param {mixed} mComponent Component id. This parameter could also be the component object. 224 * @param {string} action Module action. 225 * @param {mixed} parameters Search part of get string (a=b&c=d etc) or associative array. 226 * @returns {void} 227 */ 228 this.processModuleAction = function(mComponent, action, parameters){ 229 var oParameters = this.getActionParameters(parameters); 230 var oComponent = this.getActionComponent(mComponent); 231 232 switch(action){ 233 case 'changePageNumber': 234 case 'filter': 235 oParameters['offset'] = 0; 236 case 'gotoPage': 237 /* 238 var aComponents = this.getComponentsByType('list'); 239 if(aComponents.length > 0){ 240 aComponents[0].modAction = 'list_view'; 241 } 242 */ 243 this.addHashDataAndReloadList(oComponent, oParameters); 244 break; 245 case 'list_edit': 246 if(oComponent != null){ 247 oComponent.setRowClassById(oParameters.id, 'onedit'); 248 } 249 oComponent.modActionId = oParameters.id; 250 this.openEditForm(oParameters); 251 break; 252 case 'list_delete': 253 if(!confirm(AMI.Template.Locale.get('list_confirm_deletion'))){ 254 break; 255 } 256 oComponent.modAction = action; 257 oComponent.modActionId = oParameters.id; 258 this.addHashDataAndReloadList(oComponent, oParameters); 259 oParameters.id = ''; 260 this.openEditForm(oParameters, false); 261 oComponent.modAction = 'list_view'; 262 break; 263 case 'form_reset': 264 var aListComponent = this.getComponentsByType('list'); 265 if(aListComponent.length > 0){ 266 aListComponent[0].setRowClassById(0, ''); 267 } 268 oParameters.id = ''; 269 this.openEditForm(oParameters, false); 270 break; 271 case 'form_save': 272 this.scheduleListReload = true; 273 if(AMI.Message.send('ON_FORM_SUBMIT', oComponent, parameters)){ 274 oComponent.submitForm(parameters); 275 } 276 break; 277 case 'filter_reset': 278 oComponent.resetFilter(parameters); 279 this.reloadList(null); 280 break; 281 default: 282 AMI.Message.send('ON_AMI_' + action.toUpperCase() + '_ACTION', this); 283 oComponent.modAction = action; 284 oComponent.modActionId = oParameters.id; 285 this.reloadList(oComponent); 286 break; 287 } 288 } 289 290 /** 291 * Reload default or exact module list component. 292 * 293 * @param {AMI.ModuleComponent} oComponent Module component object. Can be null - in this case method will get the default list component. 294 * @returns {void} 295 */ 296 this.reloadList = function(oComponent){ 297 if(oComponent == null){ 298 var aComponents = this.getComponentsByType('list'); 299 if(aComponents.length > 0){ 300 oComponent = aComponents[0]; 301 } 302 } 303 if(oComponent != null){ 304 oComponent.getContent(); 305 } 306 } 307 308 /** 309 * Add data to hash and reload list after that. 310 * 311 * @param {AMI.ModuleComponent} oComponent List component object. 312 * @param {object} oParameters Associative array of parameters that will be set to hash. 313 * @returns {void} 314 */ 315 this.addHashDataAndReloadList = function(oComponent, oParameters){ 316 AMI.Page.addHashData(this.moduleId, oParameters); 317 this.reloadList(oComponent); 318 } 319 320 /** 321 * Open edit form by id in oParameters and scroll to. 322 * 323 * @param {object} oParameters Associative array where id key should esists. 324 * @param {bool} skipScrollToForm If true page will not be scrolled to form. false is default. 325 * @returns {void} 326 */ 327 this.openEditForm = function(oParameters, skipScrollToForm){ 328 // TODO: data-ami-component="news_2" <- get the component by object id 329 AMI.Page.addHashData(this.moduleId, { id: oParameters.id } ); 330 331 //if(typeof(oParameters.id) != 'undefined' && oParameters.id > 0){ 332 var aComponents = this.getComponentsByType('form'); 333 if(aComponents.length > 0){ 334 aComponents[0].loadForm(true); 335 } 336 //} 337 } 338 339 this.init(oModuleComponents); 340 } 341