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 define ( ['commonUtils', 'contentElement', 'storageUtils'], 28 //this comment is needed by jsdoc2 [copy of comment for: function View(...] 29 /** 30 * The View class is a kind of interface-class which gives access to the methods and data of a helper (which itself belongs to a controller)<br> 31 * Apart from initializing some properties, the constructor also parses the view description and looks for needed helper methods. 32 * 33 * @constructs View 34 * @param {Object} ctrl 35 * Controller instance / object 36 * @param {String} name 37 * Name of the View 38 * @param {String} definition 39 * View description, i.e. the raw template code that will be processed. 40 * May be empty: in this case the processed contents must be 41 * added manually (cf. parser.StorageUtils) 42 * 43 * @requires if param definition is NOT empty: parser.RenderUtils (must be loaded beforehand via <code>require(["renderUtils"]...</code>) 44 * @requires if param definition is NOT empty: parser.ParseUtils (must be loaded beforehand via <code>require(["parseUtils"]...</code>) 45 * 46 * @name View 47 * @class 48 */ 49 function( 50 commonUtils, ContentElement, parser 51 ){ 52 /** @scope View.prototype *///for jsdoc2 53 54 //set to @ignore in order to avoid doc-duplication in jsdoc3 55 /** 56 * @ignore 57 * 58 * The View class is a kind of interface-class which gives access to the methods and data of a helper (which itself belongs to a controller)<br> 59 * Apart from initializing some properties, the constructor also parses the view description and looks for needed helper methods. 60 * 61 * @constructs View 62 * @param {Object} ctrl 63 * Controller instance / object 64 * @param {String} name 65 * Name of the View 66 * @param {String} definition 67 * View description, i.e. the raw template code that will be processed. 68 * May be empty: in this case the processed contents must be 69 * added manually (cf. parser.StorageUtils) 70 * 71 * @requires if param definition is NOT empty: parser.RenderUtils (must be loaded beforehand via <code>require(["renderUtils"]...</code>) 72 * @requires if param definition is NOT empty: parser.ParseUtils (must be loaded beforehand via <code>require(["parseUtils"]...</code>) 73 * 74 */ 75 function View(ctrl, name, definition){ 76 77 // console.log("[View] '" + name + "' loaded."); 78 if(definition){ 79 // remove HTML comments from View 80 definition = definition.replace(commonUtils.regexHTMLComment, ''); 81 } 82 83 /** 84 * The controller to which this view belongs. 85 * 86 * @type Controller 87 * @public 88 */ 89 this.controller = ctrl; 90 91 /** 92 * The description of the view in eHTML. 93 * 94 * @type String 95 * @public 96 */ 97 this.def = definition; 98 99 /** 100 * The name of the view. 101 * 102 * @type String 103 * @public 104 */ 105 this.name = name; 106 107 108 /** 109 * An array of all the views {@link mmir.ContentElement} objects.<br> 110 * 111 * @type Array<ContentElement> 112 * @public 113 */ 114 this.contentFors = new Array(); 115 116 117 /** 118 * 119 * An array of all names of the for the view required helper methods. 120 * 121 * @deprecated helper methods must now explicitly called in template definition (using syntax <code>@helper(name,args)</code>) 122 * 123 * @type Array 124 * @public 125 */ 126 this.helperMethods = new Array(); 127 128 if(this.def){ 129 130 var parserUtils = require('parseUtils'); 131 var renderUtils = require('renderUtils'); 132 133 var parseResult = parserUtils.parse(this.def, this); 134 135 for(var i=0, size = parseResult.contentFors.length; i < size ; ++i){ 136 this.contentFors.push(new ContentElement(parseResult.contentFors[i], this, parserUtils, renderUtils)); 137 } 138 } 139 140 }; 141 142 /** 143 * Gets the definition of a view. 144 * 145 * @function 146 * @returns {String} The view description string 147 */ 148 View.prototype.getDefinition = function(){ 149 return this.def; 150 }; 151 152 153 /** 154 * Gets the name of a view. 155 * 156 * @function 157 * @returns {String} The name of the view 158 */ 159 View.prototype.getName = function(){ 160 return this.name; 161 }; 162 163 /** 164 * Gets the name of a view. 165 * 166 * @function 167 * @returns {Object} The controller for the view 168 */ 169 View.prototype.getController = function(){ 170 return this.controller; 171 }; 172 173 174 /** 175 * Gets a specific {@link mmir.ContentElement} object by name. 176 * 177 * @function 178 * @param {String} name Name of the ContentElement object 179 * @returns {object} The wanted ContentElement object or null 180 */ 181 View.prototype.getContentElement = function( name){ 182 183 for(var i=0, size = this.contentFors.length; i < size ; ++i){ 184 if(this.contentFors[i].getName() == name){ 185 return this.contentFors[i];/////////////////////// EARLY EXIT ///////////////////////////// 186 } 187 } 188 189 return null; 190 191 }; 192 193 /** 194 * Gets an array of all helper methods. 195 * 196 * @function 197 * @returns {Array} Array of all helper methods 198 */ 199 View.prototype.getHelperMethods = function(){ 200 return this.helperMethods; 201 }; 202 203 View.prototype.stringify = function(){ 204 205 // "plain properties" list 206 var propList = [ 207 'name', 208 'def' 209 // , 'helperMethods'//DISABLE: this field is deprecated! 210 ]; 211 212 //Array-properties 213 var arrayPropList = [ 214 'contentFors' //element type: ContentElement (stringify-able) 215 ]; 216 217 //function for iterating over the property-list and generating JSON-like entries in the string-buffer 218 var appendStringified = parser.appendStringified; 219 220 var moduleNameString = '"'+this.name+this.getController().getName()+'View"'; 221 222 223 //TODO use requirejs mechanism? (NOTE there may occur timing problems for loading/registering the JS file, and querying the PresentationManager for it ...) 224 //TODO(2) should all dependencies be added? 225 // eg. -> [...,"presentationManager","controllerManager","view"] 226 // and function(...,presentationManager,controllerManager,View) 227 //... this would require to gather all nested dependencies and "apply" them here... 228 // 229 // var sb = ['define('+moduleNameString+', ["storageUtils"], function(parser){ return parser.restoreObject({ classConstructor: "view"', ',']; 230 231 var sb = ['require("storageUtils").restoreObject({ classConstructor: "view"', ',']; 232 233 appendStringified(this, propList, sb); 234 235 //non-primitives array-properties with stringify() function: 236 appendStringified(this, arrayPropList, sb, null, function arrayValueExtractor(name, arrayValue){ 237 238 var buf =['[']; 239 for(var i=0, size = arrayValue.length; i < size; ++i){ 240 buf.push(arrayValue[i].stringify()); 241 buf.push(','); 242 } 243 //remove last comma 244 if(arrayValue.length > 0){ 245 buf.splice( buf.length - 1, 1); 246 } 247 buf.push(']'); 248 249 return buf.join(''); 250 }); 251 252 //TODO should require() be replaced by define()-dependency declaration? 253 // NOTE the use of require() here, assumes that the dependency has already been loaded (i.e. has already been request by some other module!) 254 sb.push( 'initPublish: function(){ require("presentationManager").addView(this.getController(), this); }'); 255 sb.push(','); 256 257 //TODO is there a better way to store the controller? -> by its contoller's name, and add a getter function... 258 if(this['controller']){ 259 260 //getter/setter function for controller 261 // (NOTE: this init-function needs to be called before controller can be accessed!) 262 sb.push( 'initController: function(){'); 263 264 // store controller-name: 265 sb.push( ' var ctrlName = '); 266 sb.push( JSON.stringify(this.getController().getName()) ); 267 268 // ... and the getter/setter code: 269 sb.push( '; this.controller = require("controllerManager").getController(ctrlName); },' );//TODO see remark about use of require() above 270 271 //add initializer function 272 // (NOTE: needs to be called before controller or renderer can be accessed!) 273 sb.push( 'init: function(){'); 274 sb.push( ' this.initController(); ' ); 275 sb.push( ' }' ); 276 277 //NOTE: need to add comma in a separate entry 278 // (-> in order to not break the removal method of last comma, see below) 279 sb.push( ',' ); 280 } 281 282 //if last element is a comma, remove it 283 if(sb[sb.length - 1] === ','){ 284 sb.splice( sb.length - 1, 1); 285 } 286 287 //TODO use requirejs mechanism? (see remark above) 288 // sb.push(' }, true); });\n require(['//<- add require-call, so that this JS-file adds itself to the loaded dependencies in requirejs 289 // + moduleNameString + ']);'); 290 291 sb.push(' }, true, '+parser.STORAGE_FILE_FORMAT_NUMBER+');'); 292 293 return sb.join(''); 294 }; 295 296 297 298 /** 299 * Gets an array of all helper methods. 300 * 301 * @deprecated helper methods must now explicitly called in template definition (using syntax <code>@helper(name,args)</code>) 302 * 303 * @function 304 * @returns {Array} Array of all helper methods 305 */ 306 View.prototype.getHelperMethods = function(){ 307 return this.helperMethods; 308 }; 309 310 /** 311 * Executes all helper methods that were specified / referenced in the view; with **data** as parameter. 312 * 313 * @deprecated helper methods must now explicitly called in template definition (using syntax <code>@helper(name,args)</code>) 314 * 315 * @function 316 * @param {Object} data Parameter to pass to the helper methods 317 */ 318 View.prototype.executeHelperMethods = function(data){ 319 for(var i=0, size = this.getHelperMethods().length; i < size ; ++i){ 320 this.controller.performHelper(this.getHelperMethods()[i], data); 321 } 322 }; 323 324 return View; 325 326 });//END: define(..., function(){ 327