1 /* 2 * Copyright (C) 2012-2013 DFKI GmbH 3 * Deutsches Forschungszentrum fuer Kuenstliche Intelligenz 4 * German Research Center for Artificial Intelligence 5 * http://www.dfki.de 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28 define ( [ 'commonUtils', 'helper', 'logger', 'module' ], 29 //this comment is needed by jsdoc2 [copy of comment for: function Controller(...] 30 /** 31 * The Controller Class is a kind of interface-class which gives access to the methods of a controller and its helper. <br> 32 * Also holds information about views and partials associated with the controller. 33 * 34 * @param {String} name Name of the Controller 35 * @param {Object} jsonDef Information about the controllers views and partials 36 * 37 * @name Controller 38 * @class 39 */ 40 function ( 41 commonUtils, Helper, Logger, module 42 ){ 43 44 /** 45 * @private 46 * @type Logger 47 * @memberOf Controller# 48 * @see mmir.Logging#create 49 */ 50 var logger = Logger.create(module); 51 52 //the next comment enables JSDoc2 to map all functions etc. to the correct class description 53 /** @scope Controller.prototype */ 54 55 //set to @ignore in order to avoid doc-duplication in jsdoc3 56 /** 57 * @ignore 58 * 59 * The Controller Class is a kind of interface-class which gives access to the methods of a controller and its helper. <br> 60 * Also holds information about views and partials associated with the controller. 61 * 62 * @constructs Controller 63 * @param {String} name Name of the Controller 64 * @param {Object} jsonDef Information about the controllers views and partials 65 */ 66 function Controller(name, jsonDef){ 67 // console.log("controller name " + name); 68 /** 69 * The definition of the controller object, containing all properties and functions of the controller.<br> 70 * A method of the controller can be called via: 71 72 this.script.methodController(parameter); 73 74 * 75 * @type Object 76 * @public 77 */ 78 // this can only be invoked, if a function with the name "name" exists 79 this.script = new window[name](); 80 81 /** 82 * The json definition of the views and partials associated with the controller. Also contains paths to controller and its views/partials. 83 * 84 * @type Object 85 * @public 86 */ 87 this.def = jsonDef;//new JPath(jsonDef); 88 89 /** 90 * The name of the controller. 91 * 92 * @type String 93 * @public 94 */ 95 this.name = name; 96 97 var viewDefs = this.def.views;//.query('views'); 98 99 /** 100 * An array holding the names of all views associated with the controller. 101 * 102 * @type Array<String> 103 * @public 104 */ 105 this.views = new Array(); 106 this.parseViews(viewDefs); 107 108 // parsing the partials and saving the names in an array 109 var partialDefs = this.def.partials;//.query('partials'); 110 111 112 /** 113 * An array holding the names of all partials associated with the controller. 114 * 115 * @type Array<String> 116 * @public 117 */ 118 this.partials = new Array(); 119 this.parsePartials(partialDefs); 120 121 122 /** 123 * The instance of the with the controller associated helper. 124 * 125 * @type Helper 126 * @public 127 */ 128 this.helper; 129 130 /** 131 * The layout (info) for this controller (if undefined, the default layout should be used) 132 * @type Object 133 */ 134 this.layout = this.def.layout; 135 } 136 137 138 /** 139 * This function loads the helper of the controller - if it exists. 140 * 141 * @function 142 * @param {String} name Name of the Helper to be loaded 143 * @param {String} helperPath Path to the helper file to load 144 * @public 145 */ 146 Controller.prototype.loadHelper = function(name, helperPath){ 147 var self = this; 148 149 //TODO move check of helper existance to Controller.foundControllersCallBack ? 150 151 //determine if there is a helper for the controller: 152 var path = helperPath; 153 var fileName = path; 154 var lastPathSeparatorIndex = path.lastIndexOf('/'); 155 if(lastPathSeparatorIndex !== -1){ 156 path = path.substring(0,lastPathSeparatorIndex); 157 fileName = fileName.substring( lastPathSeparatorIndex + 1 ); 158 } 159 //get contents of the helper directory: 160 var dirContents = commonUtils.getDirectoryContents(path); 161 if(!dirContents){ 162 logger.warn('Could not determine contents for directory "'+path+'"'); 163 return; ////////////////////// EARLY EXIT ////////////////////////////// 164 } 165 else if(! commonUtils.isArray(dirContents) || dirContents.length < 1){ 166 logger.warn('Invalid information for contents of directory "'+path+'": '+dirContents); 167 return; ////////////////////// EARLY EXIT ////////////////////////////// 168 } 169 170 //check, if there is an implementation file for this helper: 171 var helperIsSpecified = false; 172 for(var i=0, size= dirContents.length; i < size; ++i){ 173 if(dirContents[i] === fileName){ 174 helperIsSpecified = true; 175 break; 176 } 177 } 178 179 if( ! helperIsSpecified){ 180 if(logger.isVerbose()) logger.v("[HELPER] no helper available (not implemented) at '"+ helperPath+"'"); 181 return; ////////////////////// EARLY EXIT ////////////////////////////// 182 } 183 184 //if there is a file: load the helper 185 commonUtils.getLocalScript(helperPath, function(data, textStatus, jqxhr){ 186 187 if(logger.isVerbose()) logger.v("[HELPER] load "+ helperPath);//debug 188 189 self.helper = new Helper(self, name);//new window["GoogleMapHelper"](); 190 }, 191 function(exception) { 192 // print out an error message 193 logger.error("[WARN] Could not load helper -> '"+ helperPath + "'", exception); //failure 194 } 195 ); 196 }; 197 198 199 /** 200 * This function performs an action of a controller - which is represented by this instance of the Controller <br> 201 * class - by calling the method from the corresponding controller, e.g. assets/www/controllers/application.js 202 * 203 * @function 204 * @param {String} actionName Name of the method to be executed 205 * @param {Object} data Data to pass to the method of the controller as argument 206 * @returns {Object} The return value of the executed method 207 * @public 208 */ 209 Controller.prototype.perform = function(actionName, data){ 210 211 if(logger.isVerbose()) logger.v("should perform '" + actionName + "' of '" + this.name + "'"+ ((typeof data !== 'undefined' && data !== null)? " with data: "+JSON.stringify(data): ""));//debug 212 213 if(arguments.length > 2){ 214 return this.script[actionName](data, arguments[2]); 215 } 216 else { 217 return this.script[actionName](data); 218 } 219 }; 220 221 /** 222 * 223 * This function performs an action of a controller, but only if an action with this name exists; otherwise nothing is done. 224 * 225 * In difference to perform(..), the method does not trigger an ERROR, if the action does not exist / is not implemented. 226 * As a consequence, this method refers to "optionally" implemented functions, whereas perform(..) refers to mandatory functions. 227 * 228 * @function 229 * @param {String} actionName Name of the method to be executed 230 * @param {Object} data Data to pass to the method of the controller as argument 231 * @returns {Object} The return value of the executed method 232 * @public 233 */ 234 Controller.prototype.performIfPresent = function(actionName, data){ 235 if(typeof this.script[actionName] === 'function'){ 236 237 if(logger.isVerbose()) logger.v("performing '" + actionName + "' of '" + this.name + "'"+ ((typeof data !== 'undefined' && data !== null)? " with data: "+JSON.stringify(data): ""));//debug 238 239 return this.perform.apply(this, arguments); 240 241 } else if(typeof this.script[actionName] !== 'undefined'){ 242 if(logger.isVerbose()) logger.info("could not perform '" + actionName + "' of '" + this.name + "'"+ ((typeof data !== 'undefined' && data !== null)? " with data: "+JSON.stringify(data): "")+": no function ("+typeof this.script[actionName]+")");//debug 243 } else { 244 if(logger.isVerbose()) logger.debug("could not perform '" + actionName + "' of '" + this.name + "'"+ ((typeof data !== 'undefined' && data !== null)? " with data: "+JSON.stringify(data): "")+": not implemented (undefined)");//debug 245 } 246 }; 247 248 249 /** 250 * This function performs a helper action of a controller by calling the appropriate method<br> 251 * {@link Helper#perform} of the instance of the helper class associated with the controller. 252 * 253 * @function 254 * @param {String} actionName Name of the helper method to be executed 255 * @param {Object} data Data to pass to the helper method as argument 256 * @returns {Object} The return value of the executed method 257 * @public 258 */ 259 Controller.prototype.performHelper = function(actionName, data){ 260 if(arguments.length > 2){ 261 return this.helper.perform(actionName, data, arguments[2]); 262 } 263 else { 264 return this.helper.perform(actionName, data); 265 } 266 }; 267 268 269 /** 270 * Returns the helper of the controller instance. 271 * 272 * @function 273 * @returns {Object} The helper instance 274 * @public 275 */ 276 Controller.prototype.getHelper = function(){ 277 return this.helper; 278 }; 279 280 281 /** 282 * Stores all names of the views of the controller by iterating over the array of the views definition.<br> 283 * This function is called by the constructor of the {@link mmir.Controller} class. 284 * 285 * @function 286 * @param {Array} viewDefs Array of the json-definition of the controllers views - containing name of the views and their corresponding path to the js-files 287 * @public 288 */ 289 Controller.prototype.parseViews = function(viewDefs){ 290 291 for(var i=0, size = viewDefs.length; i < size; ++i){ 292 this.views.push(viewDefs[i].name); 293 } 294 295 }; 296 297 298 /** 299 * Stores all names of the partials of the controller by iterating over the array of the partials definition.<br> 300 * This function is called by the constructor of the {@link mmir.Controller} class. 301 * 302 * @function 303 * @param {Array} partialDefs Array of the json-definition of the controllers partials - containing name of the partials and their corresponding path to the js-files 304 * @public 305 */ 306 Controller.prototype.parsePartials = function(partialDefs){ 307 308 for(var i=0, size = partialDefs.length; i < size; ++i){ 309 this.partials.push(partialDefs[i].name); 310 } 311 312 }; 313 314 315 /** 316 * Returns the view names for the controller instance. 317 * 318 * @function 319 * @returns {Array<String>} An array of the controllers views 320 * @public 321 */ 322 Controller.prototype.getViewNames = function(){ 323 return this.views; 324 }; 325 326 /** 327 * Returns the view names for the controller instance. 328 * 329 * TODO should this be private/hidden? -> provides "internal" JSON-details object (used in PresentationManager) 330 * 331 * Each info object has properties: 332 * {String} name 333 * {String} path 334 * 335 * @function 336 * @returns {Array<Object>} An array of the controllers views 337 * @public 338 */ 339 Controller.prototype.getViews = function(){ 340 return this.def.views; 341 }; 342 343 /** 344 * Returns the partial names for the controller instance. 345 * 346 * @function 347 * @returns {Array<String>} An array of the controllers partials 348 * @public 349 */ 350 Controller.prototype.getPartialNames = function(){ 351 return this.partials; 352 }; 353 354 /** 355 * Returns the partial info object for the controller instance. 356 * 357 * TODO should this be private/hidden? -> provides "internal" JSON-details object (used in PresentationManager) 358 * 359 * Each info object has properties: 360 * {String} name 361 * {String} path 362 * 363 * @function 364 * @returns {Array<Object>} An array of the controllers partials 365 * @public 366 */ 367 Controller.prototype.getPartials = function(){ 368 return this.def.partials; 369 }; 370 371 /** 372 * Returns the layout of the controller instance. 373 * 374 * If undefined, the default layout should be used. 375 * 376 * TODO should this be private/hidden? -> provides "internal" JSON-details object (used in PresentationManager) 377 * 378 * The info object has properties: 379 * {String} name 380 * {String} path 381 * {String} fileName 382 * 383 * @function 384 * @returns {Object} The controller's layout (may be undefined) 385 * @public 386 */ 387 Controller.prototype.getLayout = function(){ 388 return this.layout; 389 }; 390 391 /** 392 * Returns the layout name for the controller instance. 393 * 394 * This is equal to the controller name. 395 * 396 * If undefined, the default layout should be used. 397 * 398 * @function 399 * @returns {String} The controller's layout name (may be undefined) 400 * @public 401 */ 402 Controller.prototype.getLayoutName = function(){ 403 return this.layout? this.layout.name : this.layout; 404 }; 405 406 /** 407 * Returns the name of the controller instance. 408 * 409 * @function 410 * @returns {String} The name of the controller 411 * @public 412 */ 413 Controller.prototype.getName = function(){ 414 return this.name; 415 }; 416 417 return Controller; 418 419 }); 420