Source: mvc/parser/storageUtils.js

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