1 2 3 4 define(['jquery', 'parserModule'], 5 /** 6 * Extends the parser-module with helper functions for 7 * storing/restoring compiled templates (eHTML -> layout, view, partial etc) 8 * 9 * Dependencies: 10 * 11 * @requires jQuery.extend 12 * 13 * alternatively: set <code>mmir.parser.CLASS_EXTENDER</code> with an object that 14 * exposes a function <tt>extend(obj1,obj1)</tt>, i.e. 15 * 16 * <code>mmir.parser.CLASS_EXTENDER.extend(obj1, obj2)</code> 17 * 18 * @class 19 * @name StorageUtils 20 * @memberOf mmir.parser 21 * 22 */ 23 function($, parser){ 24 25 /** 26 * @public 27 * @constant 28 * @memberOf mmir.parser 29 */ 30 var STORAGE_FILE_FORMAT_NUMBER = 2; 31 parser.STORAGE_FILE_FORMAT_NUMBER = STORAGE_FILE_FORMAT_NUMBER; 32 33 /** 34 * Creates the appropriate object from a JSON-like <tt>storedObject</tt>. 35 * 36 * <p> 37 * NOTE that in difference to a real JSON object, the <tt>storedObject</tt> 38 * may contain function definitions. 39 * 40 * <p> 41 * The storedObject must have a String property <strong>classConstructor</strong> 42 * <ul> 43 * <li>that must correspond to a constructor function (which will be invoked with <tt>new</tt>)</li> 44 * <li>the constructor function must be invokable without parameters</li> 45 * <li>the constructor function must be accessable from the global namespace 46 * (or <tt>classConstuctor</tt> must contain the code for retrieving the constructor 47 * function from the global namespace)</li> 48 * </ul> 49 * 50 * 51 * <p> 52 * If <tt>storedObject</tt> contains a function <tt>init</tt>, then this function will be invoked 53 * before returning the new newly created object. 54 * 55 * 56 * @function 57 * @static 58 * @public 59 * @memberOf mmir.parser 60 * 61 * @param {Object} storedObject 62 * a JSON-like object with fields and functions (which will be transfered to the returned object). 63 * @param {Boolean} [isTriggerPublish] OPTIONAL 64 * if <code>true</code> then the restore function call 65 * <code>initPublish()</code> on the restored object before returning. 66 * This should only be <code>true</code> for the root-object 67 * (e.g. the View-object or Partial-object; nested objects should NOT invoke 68 * restoreObject() with this argument set to true). 69 * @param {Number} [fileFormatNo] OPTIONAL 70 * NOTE: if argument <code>isTriggerPublish</code> was used with value <code>true</code>, 71 * then this argument MUST be used too! 72 * If the number given does not match {@link parser.STORAGE_FILE_FORMAT_NUMBER} 73 * the file format is assumed to be out-dated and an Error will be thrown. 74 * @returns {Object} 75 * an new instance created with the constructor <tt>classConstructor</tt> and 76 * set with all properties (fields and functions) from <tt>storedObject</tt>. 77 * 78 * @throws Error if <code>fileFormatNo</code> does not match STORAGE_FILE_FORMAT_NUMBER. 79 * 80 */ 81 function restoreObject(storedObject, isTriggerPublish, fileFormatNo){ 82 83 if(isTriggerPublish && fileFormatNo != parser.STORAGE_FILE_FORMAT_NUMBER){ 84 85 throw new Error('Compiled template file has wrong format: need file with format version ' 86 + parser.STORAGE_FILE_FORMAT_NUMBER +', but got: '+ fileFormatNo 87 + '. Please re-compile views / templates.' 88 ); 89 90 } 91 92 var classExtender; 93 if(parser.CLASS_EXTENDER && typeof parser.CLASS_EXTENDER.extend === 'function'){ 94 classExtender = parser.CLASS_EXTENDER; 95 } 96 else { 97 classExtender = $; 98 } 99 100 // //NOTE: classConstructor contains a list of Strings: 101 // // * the constructor-function is either in global namespace 102 // // e.g. "View" -> then the list contains exactly one entry ["View"] 103 // // 104 // // * if the constructor-function is in a sub-namespace (e.g. "sub-module") 105 // // then the list contains the "path" to the constructorf-function 106 // // starting with the module that is in the global namespace 107 // // e.g. "mobileDS.parser.ParsingResult" -> ["mobileDS, "parser", "ParsingResult"] 108 // // 109 // var constructor = window[storedObject.classConstructor[0]];//FIXME need to convert this to require 110 // for(var i=1, size = storedObject.classConstructor.length; i < size; ++i){ 111 // constructor = constructor[storedObject.classConstructor[i]]; 112 // } 113 114 //requirejs version (for this to work, all Classe (i.e. JS-files) need to already have been loaded & required!) 115 var constructor = require(storedObject.classConstructor); 116 117 var obj = classExtender.extend( new constructor(), storedObject); 118 if(typeof obj.init === 'function'){ 119 obj.init(); 120 } 121 122 if(isTriggerPublish && typeof obj.initPublish === 'function'){ 123 obj.initPublish(); 124 } 125 126 return obj; 127 }; 128 parser.restoreObject = restoreObject; 129 130 /** 131 * Creates String-representations (JSON-like) for the specified properties and appends them to the StringBuffer. 132 * 133 * <p> 134 * This function iterates over the Array <tt>propertyNames</tt>: 135 * If a property with that name exists in <tt>obj</tt>, a JSON-like String-representation is generated 136 * and appended at the end of the array <tt>stringBuffer</tt>. 137 * <br> 138 * Multiple representations are separated by comma entry <code>','</code> in <tt>stringBuffer</tt>. 139 * <br> 140 * The last entry in <tt>stringBuffer</tt> is a comma entry <code>','</code> if at least one property 141 * entry was inserted in <tt>stringBuffer</tt>. 142 * 143 * <p> 144 * NOTE that the String-representation inserted into <tt>stringBuffer</tt> may not have a 1:1 correspondence 145 * with properties (only the last entry is guaranteed to be <code>','</code>, if a property was inserted). 146 * <br> 147 * For pratical use, the returned (or modified) <tt>stringBuffer</tt> should be converted into a String 148 * e.g. by <code>stringBuffer.join('')</code>. 149 * 150 * 151 * @function 152 * @static 153 * @public 154 * @memberOf mmir.parser 155 * 156 * @param {Object} obj 157 * the object, that contains the properties for which String representations should be generated. 158 * @param {Array<String>} propertyNames 159 * the names of the properties, for which String-representations should be generated. 160 * @param {Array<String>} stringBuffer 161 * the buffer: String-representations will be appended as entries at the end of the buffer 162 * @param {String} [propertyNamePostfix] 163 * OPTIONAL if present, this postfix will be appended to each property name, before processing it. 164 * This is a convenience method, e.g. if all properties in <tt>propertyNames</tt> should end with 165 * the same String / postfix. 166 * @param {Function} [valueFunc] 167 * OPTIONAL by default, value representations are generated using the <code>JSON.stringify</code> 168 * function. If instead this argument is present, this function will be invoked for creating 169 * the string representation of the property-value. 170 * The function signature is <code>valueFunc(propertyName : String, propertyValue : Object) : String</code>. 171 * If the function returns <code>void</code>, then the corresponding property will not be added/stringified. 172 * 173 * @returns {Array<String>} the modified <tt>stringBuffer</tt> 174 * 175 * @requires JSON.stringify 176 * 177 * @example 178 * 179 * var obj = { 180 * some: "properties", 181 * including: function(arg1,arg2){ return 'functions' } 182 * }; 183 * 184 * var sb = mobileDS.parser.appendStringified(obj, ['some'], []); 185 * var str = sb.join(','); 186 * //str will be: "some:\"properties\"," 187 * 188 */ 189 function appendStringified(obj, propertyNames, stringBuffer, propertyNamePostfix, valueFunc){ 190 191 //"shift" arguments, if necessary 192 if(typeof propertyNamePostfix === 'function' && ! valueFunc){ 193 valueFunc = propertyNamePostfix; 194 propertyNamePostfix = null; 195 } 196 197 var prop, val; 198 for(var i=0, size = propertyNames.length; i < size; ++i){ 199 prop = propertyNames[i]; 200 201 if(propertyNamePostfix){ 202 prop += propertyNamePostfix; 203 } 204 205 if(typeof obj[prop] === 'undefined'){ 206 continue; 207 } 208 209 210 if(valueFunc){ 211 val = valueFunc(prop, obj[prop]); 212 } 213 else { 214 val = JSON.stringify(obj[prop]); 215 } 216 217 if(typeof val === 'undefined'){ 218 continue; 219 } 220 221 stringBuffer.push( prop ); 222 stringBuffer.push( ':' ); 223 stringBuffer.push( val ); 224 225 stringBuffer.push( ',' ); 226 } 227 228 return stringBuffer; 229 }; 230 parser.appendStringified = appendStringified; 231 232 return parser; 233 234 });//END: define(..., function(){