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', 'contentElement', 'storageUtils'],  
 29 	//this comment is needed by jsdoc2 [copy of comment for: function Partial(...]
 30 	/**
 31 	 * The Partial class is a containing the definition of the partial and methods to access the definition.
 32 	 * 
 33 	 * @param {Object} ctrl 
 34 	 * 			Controller instance / object
 35 	 * @param {String} name
 36 	 * 			Name of the Partial 
 37 	 * @param {String} definition
 38 	 * 			Partial description, i.e. the raw template code that will be processed.
 39 	 * 			May be empty: in this case the processed contents must be
 40 	 * 						  added manually (cf. parser.StorageUtils)
 41 	 * 
 42 	 * @requires if param definition is NOT empty: parser.RenderUtils (must be loaded beforehand via <code>require(["renderUtils"]...</code>)
 43 	 * @requires if param definition is NOT empty: parser.ParseUtils (must be loaded beforehand via <code>require(["parseUtils"]...</code>)
 44 	 * 
 45 	 * @name Partial
 46 	 * @class
 47 	 */
 48 	function (
 49 			commonUtils, ContentElement, parser
 50 ){
 51 	/** @scope Partial.prototype *///for jsdoc2
 52 	
 53 	//set to @ignore in order to avoid doc-duplication in jsdoc3
 54 	/**
 55 	 * @ignore
 56 	 * 
 57 	 * The Partial class is a containing the definition of the partial and methods to access the definition.
 58 	 * 
 59 	 * @constructs Partial
 60 	 * @param {Object} ctrl 
 61 	 * 			Controller instance / object
 62 	 * @param {String} name
 63 	 * 			Name of the Partial 
 64 	 * @param {String} definition
 65 	 * 			Partial description, i.e. the raw template code that will be processed.
 66 	 * 			May be empty: in this case the processed contents must be
 67 	 * 						  added manually (cf. parser.StorageUtils)
 68 	 * 
 69 	 * @requires if param definition is NOT empty: parser.RenderUtils (must be loaded beforehand via <code>require(["renderUtils"]...</code>)
 70 	 * @requires if param definition is NOT empty: parser.ParseUtils (must be loaded beforehand via <code>require(["parseUtils"]...</code>)
 71 	 * 
 72 	 */
 73 	function Partial(ctrl, name, definition){
 74 //	    var HTMLCommentRegExp = /<!--[\s\S]*?-->/g;
 75 		
 76 		if(definition){
 77 			//remove HTML comments:
 78 	    	definition = definition.replace(commonUtils.regexHTMLComment, '');
 79 	    }
 80 		
 81 	    this.controller = ctrl;
 82 	    this.def = definition;
 83 	    this.name = name;
 84 //	    console.log("[Partial] parsed Partial '" +this.controller + "-"+this.name+ "'.");
 85 	    
 86 	    if(definition){
 87 		    
 88 		    var contentElementInfo = {
 89 		    		//this name is purely informational:
 90 		    		name : this.controller.getName() + 'Partial',
 91 		    		content : this.def
 92 		    	};
 93 		    this.contentElement = new ContentElement(contentElementInfo, this, require('parseUtils'), require('renderUtils'));
 94 	    }
 95 	}
 96 	
 97 
 98 	/**
 99 	 * Gets the definition of a partial.
100 	 * 
101 	 * @function
102 	 * @returns {String} The partial description string
103 	 */
104 	Partial.prototype.getDefinition = function(){
105 	    return this.def;
106 	};
107 
108 	/**
109 	 * Gets the name of a partial. 
110 	 * 
111 	 * @function
112 	 * @returns {String} The name of the partial
113 	 */
114 	Partial.prototype.getName = function(){
115 		return this.name;
116 	};
117 
118 	/**
119 	 * Gets the controller of a partial - each partial is assigned to a specific controller, although they can be used from different controllers.
120 	 * 
121 	 * @function
122 	 * @returns {Object} The controller of the partial
123 	 */
124 	Partial.prototype.getController = function(){
125 	    return this.controller;
126 	};
127 
128 	/**
129 	 * Gets the {@link mmir.ContentElement}, i.e. the content that this instance represents.
130 	 * 
131 	 * @function
132 	 * @returns {mmir.ContentElement} The ContentElement object
133 	 */
134 	Partial.prototype.getContentElement = function(){
135 	    return this.contentElement;
136 	};
137 	
138 	Partial.prototype.stringify = function(){
139 
140 		// "plain properties" list
141 		var propList = [
142 		     'name', 
143 		     'def'
144 		];
145 
146 		//Array-properties
147 		var stringifyablePropList = [
148 	   	     'contentElement' //element type: ContentElement (stringify-able)
149 	   	];
150 
151 		//function for iterating over the property-list and generating JSON-like entries in the string-buffer
152 		var appendStringified = parser.appendStringified;
153 		
154 		var moduleNameString = '"'+this.name+this.getController().getName()+'Partial"';
155 		
156 		//TODO use requirejs mechanism? (NOTE there may occur timing problems for loading/registering the JS file, and querying the PresentationManager for it ...)
157 //		var sb = ['define('+moduleNameString+', ["storageUtils"], function(parser){ return parser.restoreObject({ classConstructor: "partial"', ','];
158 		var sb = ['require("storageUtils").restoreObject({ classConstructor: "partial"', ','];
159 		
160 		appendStringified(this, propList, sb);
161 		
162 		//non-primitives properties with stringify() function:
163 		appendStringified(this, stringifyablePropList, sb, null, function arrayValueExtractor(name, stringifyableValue){
164 			return stringifyableValue.stringify();
165 		});
166 		
167 
168 		//TODO should require() be replaced by define()-dependency declaration?
169 		//     NOTE the use of require() here, assumes that the dependency has already been loaded (i.e. has already been request by some other module!)
170 		sb.push( 'initPublish: function(){ require("presentationManager").addPartial(this.getController(), this); }');
171 		sb.push(',');
172 		
173 		//TODO is there a better way to store the controller? -> by its contoller's name, and add a getter function...
174 		if(this['controller']){
175 			
176 			//getter/setter function for controller
177 			//  (NOTE: this init-function needs to be called before controller can be accessed!)
178 			sb.push( 'initController: function(){');
179 
180 			// store controller-name:
181 			sb.push( ' var ctrlName = ');
182 			sb.push( JSON.stringify(this.getController().getName()) );
183 			
184 			// ... and the getter/setter code:
185 			sb.push( '; this.controller = require("controllerManager").getController(ctrlName); },' );//TODO see remark about use of require() above
186 			
187 			
188 			//add initializer function
189 			//  (NOTE: needs to be called before controller or renderer can be accessed!)
190 			sb.push( 'init: function(){');
191 			sb.push( ' this.initController(); ' );
192 			sb.push( ' }' );
193 			
194 			//NOTE: need to add comma in a separate entry 
195 			//      (-> in order to not break the removal method of last comma, see below)
196 			sb.push( ',' );
197 		}
198 		
199 		//if last element is a comma, remove it
200 		if(sb[sb.length - 1] === ','){
201 			sb.splice( sb.length - 1, 1);
202 		}
203 		
204 		//TODO use requirejs mechanism? (see remark above)
205 //		sb.push(' }, true); });\n require([' //<- add require-call, so that this JS-file adds itself to the loaded dependencies in requirejs
206 //				+ moduleNameString + ']);');
207 		
208 		sb.push(' }, true, '+parser.STORAGE_FILE_FORMAT_NUMBER+');');
209 		return sb.join('');
210 	};
211 
212 	return Partial;
213 	
214 });
215 
216