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