1 var Class = require("../lib/mootools/mootools-node.js").Class; 2 var JsonRpcResult = require("../lib/core/jsonrpc/JsonRpcResult.js").JsonRpcResult; 3 var JsonRpcError = require("../lib/core/jsonrpc/JsonRpcError.js").JsonRpcError; 4 var JsonRpcAbstract = require("../lib/core/jsonrpc/JsonRpcAbstract.js").JsonRpcAbstract; 5 6 var EventDispatcher = require('../lib/core/event/EventDispatcher.js').EventDispatcher; 7 8 var Event = require('../lib/core/event/Event.js').Event; 9 var TemplateManager = require('../lib/TemplateManager.js').TemplateManager; 10 11 /** 12 * Representing template. 13 * @class Template Base template class. 14 * @extends EventDispatcher 15 * @requires Class 16 * @requires Event 17 * @requires EventDispatcher 18 * @requires JsonRpcAbstract 19 * @requires JsonRpcError 20 * @requires JsonRpcResult 21 * @requires TemplateManager 22 * @param {String} name 23 * @param {Object} configuration 24 * @throws {Template.Exception.CONFIG_INVALID} if given <i>name</i> or <i>configuration</i> are invalid. 25 */ 26 var Template = function(){ 27 /** @ignore */ 28 this.Extends = EventDispatcher; 29 30 /** 31 * Indicates if template is a child of parent. 32 * @public 33 * @type {Boolean} 34 */ 35 this.hasParent = false; 36 /** 37 * Indicates if template was rendered. 38 * @public 39 * @type {Boolean} 40 */ 41 this.isRendered = false; 42 43 /** 44 * configuration object 45 * @private 46 * @type {Object} 47 */ 48 this._configuration = null; 49 /** 50 * generated content 51 * @private 52 * @type {Object} 53 */ 54 this._content = null; 55 /** 56 * rendered children counter 57 * @private 58 * @type {Number} 59 */ 60 this._counter = 0; 61 /** 62 * template model 63 * @private 64 * @type {Object} 65 */ 66 this._data = null; 67 /** 68 * template name within configuration 69 * @private 70 * @type {Boolean} 71 */ 72 this._name = ""; 73 74 75 /** @ignore */ 76 this.initialize = function(name, configuration){ 77 78 if(!name || !configuration || !configuration.hasOwnProperty("template")){ 79 throw Template.Exception.CONFIG_INVALID; 80 } 81 //public 82 this.hasParent = false; 83 this.isRendered = false; 84 //private 85 this._configuration = configuration; 86 this._content = { 87 result: null 88 }; 89 this._counter = 0; 90 this._data = null; 91 this._name = name; 92 }; 93 94 /** 95 * Abstract method. Needed to be overriden - otherwise Template.Exception.NOT_IMPLEMENTED will be throwed. 96 * @public 97 * @param {Object} data 98 * @throw {Template.Exception.NOT_IMPLEMENTED} 99 */ 100 this.render = function(data){ 101 throw Template.Exception.NOT_IMPLEMENTED; 102 }; 103 104 /** 105 * Dispatchig render action and handles its errors and exceptions. 106 * @public 107 * @param {Object} data 108 * @throws {Template.Exception.NOT_IMPLEMENTED} if method render wasn't overriden 109 */ 110 this.dispatchRender = function(data){ 111 try{ 112 console.log(' -- Template '+this._name+': rendering...'); 113 this.render(data); 114 } 115 catch(e){ 116 console.log(' -- Template '+this._name+': error while rendering...', e); 117 if(e == Template.Exception.NOT_IMPLEMENTED){ 118 //fallback in case of not implementing 119 throw Template.Exception.NOT_IMPLEMENTED; 120 } 121 122 switch(this.getErrorAction()){ 123 case Template.ACTION_ERROR_PROPAGATE: 124 this.setRenderedData(JsonRpcError.factory(Template.Error.PROPAGATED).setData(e)); 125 break; 126 case Template.ACTION_ERROR_DISCARD: 127 this.setRenderedData(new JsonRpcResult("")); 128 break; 129 case Template.ACTION_ERROR_ABORT: 130 this._templateManager.abort(JsonRpcError.factory(Template.Error.ABORTED).setData(e)); 131 break; 132 } 133 } 134 }; 135 136 /** 137 * Handling model load. Called on DriverAbstract.LOADED 138 * @public 139 * @param {Event} e 140 */ 141 this.onData = function(e){ 142 if(this._templateManager.isAborted()){ 143 return; 144 } 145 146 console.log(' -- Template '+this._name+': received data'); 147 148 this._data = e.data; 149 150 if(this._data && this._data.hasOwnProperty('#body')){ 151 var children = this._data['#body']; 152 this._counter = children.length; 153 154 console.log(' -- Template '+this._name+': have '+children.length +' children'); 155 156 for( var i = 0, max = children.length; i < max; i++ ){ 157 console.log(' -- Template '+this._name+': waiting for children: '+children[i]); 158 var child = this.getTemplateManager().getTemplateByName(children[i]); 159 if(child){ 160 this.addChild(child); 161 }else{ 162 this._counter--; 163 } 164 } 165 }else{ 166 console.log(' -- Template '+this._name+': does\'nt have children'); 167 this.dispatchRender(this._data); 168 } 169 }; 170 171 /** 172 * Handling model error. Called on DriverAbstract.ERROR 173 * @public 174 * @param {ErrorEvent} e 175 */ 176 this.onDataError = function(e){ 177 console.log(' -- Template '+this._name+': data error'); 178 //TODO handle error 179 }; 180 181 /** 182 * Adding child template 183 * @public 184 * @param {Template} child 185 */ 186 this.addChild = function(child){ 187 child.addEventListener(Template.RENDERED, this._onTemplateRendered, this); 188 child.hasParent = true; 189 if(child.isRendered){ 190 this._onTemplateRendered(new Event(Template.RENDERED, child)); 191 } 192 }; 193 194 /** 195 * Setting rendering result 196 * @public 197 * @param {Object} data 198 */ 199 this.setRenderedData = function(data){ 200 console.log(' -- Template '+this._name+': rendered.'); 201 if(!(data instanceof JsonRpcAbstract)){ 202 throw Template.Exception.WRONG_RENDER_DATA; 203 } 204 205 this._content = data.toJson(); 206 207 console.log(' -- Template '+this._name+': dispaching...'); 208 this.isRendered = true; 209 this.dispatchEvent(new Event(Template.RENDERED, this)); 210 }; 211 212 /** 213 * Returns content generated by specific render engine 214 * @public 215 * @return {String} 216 */ 217 this.getContent = function(){ 218 return this._content; 219 }; 220 221 /** 222 * Returns error handler 223 * @public 224 * @return {CONST} 225 */ 226 this.getErrorAction = function(){ 227 return this._configuration.onerror ? this._configuration.onerror : Template.ACTION_ERROR_DEFAULT; 228 }; 229 230 /** 231 * Returns template manager who holds every template in the subtree 232 * @public 233 * @return {TemplateManager} 234 */ 235 this.getTemplateManager = function(){ 236 if(!this._templateManager){ 237 throw Template.Exception.TEMPLATEMANAGER_NULL; 238 } 239 return this._templateManager; 240 }; 241 242 /** 243 * Sets template manager object which holds every template in the subtree 244 * @public 245 * @param {TemplateManager} templateManager 246 */ 247 this.setTemplateManager = function(templateManager){ 248 //FIXME: tutaj trzeba to poprawic 249 if(!templateManager){ 250 throw Template.Exception.TEMPLATEMANAGER_NULL; 251 } 252 // else if(!(templateManager instanceof TemplateManager)){ 253 // throw Template.Exception.TEMPLATEMANAGER_NOT_CLASS_INSTANCE; 254 // return; 255 // } 256 this._templateManager = templateManager; 257 }; 258 259 /** 260 * Returns template name 261 * @public 262 * @return {String} 263 */ 264 this.getName = function(){ 265 return this._name; 266 }; 267 268 /** 269 * Returns template location path 270 * @public 271 * @return {String} template path 272 */ 273 this.getPath = function(){ 274 return this._configuration.template; 275 }; 276 277 /** 278 * Callback function called on rendered child template 279 * @private 280 * @param {Event} e 281 */ 282 this._onTemplateRendered = function(e){ 283 this._counter--; 284 285 console.log(' -- Template '+this._name+': received children: '+e.data.getName()); 286 287 if(this._counter === 0){ 288 289 console.log(' -- Template '+this._name+': have all children'); 290 291 if(this._data.hasOwnProperty('#body')){ 292 var children = this._data['#body']; 293 this._data.body = []; 294 295 for(var i=0,max=children.length;i<max;i++){ 296 this._data.body.push(this.getTemplateManager().getTemplateByName(children[i]).getContent()); 297 } 298 delete this._data['#body']; 299 } 300 301 this.dispatchRender(this._data); 302 } else { 303 console.log(' -- Template '+this._name+': children left: '+this._counter); 304 } 305 }; 306 }; 307 308 Template = new Class( new Template() ); 309 310 /** 311 * @static 312 * @constant 313 */ 314 Template.RENDERED = "Template_RENDERED"; 315 /** 316 * @static 317 * @constant 318 */ 319 Template.ERROR = "Template_ERROR"; 320 /** 321 * @static 322 * @constant 323 */ 324 Template.ACTION_ERROR_PROPAGATE = "propagate"; 325 /** 326 * @static 327 * @constant 328 */ 329 Template.ACTION_ERROR_DISCARD = "discard"; 330 /** 331 * @static 332 * @constant 333 */ 334 Template.ACTION_ERROR_ABORT = "abort"; 335 /** 336 * @static 337 * @constant 338 */ 339 Template.ACTION_ERROR_DEFAULT = Template.ACTION_ERROR_DISCARD; 340 /** 341 * Namespace for exeptions messages. 342 * @static 343 * @constant 344 * @namespace 345 */ 346 Template.Exception = {}; 347 /** 348 * @static 349 * @constant 350 */ 351 Template.Exception.CONFIG_INVALID = "Error - Template name and configuration are invalid."; 352 /** 353 * @static 354 * @constant 355 */ 356 Template.Exception.NOT_IMPLEMENTED = "Method:render() - Not implemented!"; 357 /** 358 * @static 359 * @constant 360 */ 361 Template.Exception.TEMPLATEMANAGER_NULL = "TemplateManager is null"; 362 /** 363 * @static 364 * @constant 365 */ 366 Template.Exception.TEMPLATEMANAGER_NOT_CLASS_INSTANCE = "templateManager must be instance of TemplateManager class"; 367 /** 368 * @static 369 * @constant 370 */ 371 Template.Exception.FILE_DOES_NOT_EXIST = function(fileName){ 372 return "Template: " + fileName + " doesn't exist"; 373 }; 374 /** 375 * @static 376 * @constant 377 */ 378 Template.Exception.WRONG_RENDER_DATA = "Given data has to be an instance of JsonRpcAbstract"; 379 /** 380 * Namespace for error objects; 381 * @static 382 * @constant 383 * @namespace 384 */ 385 Template.Error = {}; 386 /** 387 * @static 388 * @constant 389 */ 390 Template.Error.ABORTED = new JsonRpcError(-2201, "Aborting because of template error"); 391 /** 392 * @static 393 * @constant 394 */ 395 Template.Error.PROPAGATED = new JsonRpcError(-2202, "Error occured, propagating error."); 396 397 exports.Template = Template;