1(function(root, factory) { 2 var _ = root._ || require('lodash'); 3 var dependencies = ['dustjs-linkedin', 'bluebird', 'lodash', 'jquery']; 4 5 if (typeof define === 'function' && define.amd) { 6 define(dependencies, factory); 7 } else if (typeof exports === 'object') { 8 module.exports = factory.apply(this, _.map(dependencies, require)); 9 } else { 10 root.FS = root.FS || {}; 11 root.FS.Template = factory(root.dust, root.Promise, root._, root.jQuery); 12 } 13}(this, function(dust, Promise, _, $) { 14 if(!dust || !dust.helpers) throw new Error('Dust.js is not available'); 15 if(!Promise) throw new Error('Bluebird.js is not available'); 16 if(!_) throw new Error('Underscore.js is not available'); 17 if(!$) throw new Error('jQuery.js is not available'); 18 19 // A unique incrementing ID for use by the dust.js @apib helper below 20 var appLoadingId = 0; 21 22 dust.iter = function(chk, ctx, bodies, params) { 23 var self = this; 24 var obj = ctx.current(); 25 var keys = []; 26 27 params = _.map(params || {}, function(param) { 28 return dust.helpers.tap(param, chk, ctx); 29 }); 30 31 for (var k in obj) { 32 if(obj.hasOwnProperty(k)) keys.push(k); 33 } 34 if(params.sort){ 35 var by = params.by || 'name'; 36 keys = keys.sort(function(ka, kb) { 37 var a = new String(obj[ka][by]).toLowerCase(), 38 b = new String(obj[kb][by]).toLowerCase(); 39 if(a > b) return 1; 40 if(a < b) return -1; 41 return 0; 42 }) 43 } 44 var l = keys.length; 45 for (var k in keys) { 46 var key = keys[k]; 47 chk = chk.render(bodies.block, ctx.push({ 48 iter: arguments.callee, 49 key: key, 50 value: obj[key], 51 index: k, 52 length: l 53 })); 54 } 55 return chk; 56 }; 57 58 var uuids = {}; 59 _.extend(dust.helpers, { 60 /** 61 * {@ifAuthenticated} 62 * User is authenticated 63 * {:else} 64 * User is anonymous 65 * {/ifAuthenticated} 66 */ 67 ifAuthenticated: function(chunk, context, bodies, params) { 68 if(bodies.block) { 69 return chunk.map(function(chunk) { 70 FS.Auth.isLoggedIn() 71 .then( 72 function() { 73 chunk.render(bodies.block, context).end(); 74 }, 75 function() { 76 if(bodies['else']) { 77 chunk.render(bodies['else'], context).end(); 78 } 79 } 80 ); 81 }); 82 } 83 return chunk; 84 }, 85 86 /** 87 * {@ifHasRole role="Petitions Admin"} 88 * User has the Petitions Admin role 89 * {:else} 90 * User does NOT have the Petitions Admin role 91 * {/ifAuthenticated} 92 */ 93 ifHasRole: function(chunk, context, bodies, params) { 94 params = params || {}; 95 96 if(!params.role || !params.module || !params.product) { 97 console.warn('Did not specify role | module | product'); 98 return chunk; 99 } 100 101 if(bodies.block) { 102 return chunk.map(function(chunk) { 103 FS.SecurityManager.hasRole(params.product, params.module, params.role) 104 .then(function() { 105 chunk.render(bodies.block, context).end(); 106 }) 107 .caught(function(error) { 108 if(bodies['else']) { 109 chunk.render(bodies['else'], context).end(); 110 } 111 }); 112 113 }); 114 } 115 return chunk; 116 }, 117 118 /** 119 * {@formUrl formID="sdfhksdfj" /} 120 */ 121 formUrl: function(chunk, context, bodies, params) { 122 params = params || {}; 123 124 var formID = params.formID, 125 returnModule = params.returnModule, 126 showMsg = params.showMsg, 127 engine = params.engine || 'FS2', 128 serviceName = params.oldFormName || params.oldProcessName || null; 129 130 return chunk.map(function(chunk) { 131 Promise.resolve(FS.Forms.getUrl(formID, params, engine, showMsg, returnModule, serviceName, null, null, params.returnUrls)) 132 .then( 133 function(formUrl) { 134 chunk.write(formUrl).end(); 135 }, 136 function() { 137 chunk.write(params.failUrl || '#').end(); 138 } 139 ); 140 }); 141 }, 142 143 /** 144 * {@apib name="Account_CTAX" type="html"} {.|s} {:else} ERROR! {/apib} 145 */ 146 apib: function(chunk, context, bodies, params, transform) { 147 params = params || {}; 148 149 if(!params.name) { 150 console.warn('Must specify an API name'); 151 return chunk; 152 } 153 var api = params.name; 154 delete params.name; 155 156 var dataType = 'json'; 157 if(params.type) { 158 dataType = params.type; 159 delete params.type; 160 } 161 162 var cache = false;
163 if(params.cache) { 164 cache = params.cache; 165 delete params.cache; 166 } 167 168 var loadingHtml = '<span class="muted">Loading…</span>'; 169 if(params.loadingText) { 170 loadingHtml = dust.escapeHtml(params.loadingText); 171 delete params.loadingText; 172 } else if(params.loadingHtml) { 173 loadingHtml = params.loadingHtml; 174 delete params.loadingHtml; 175 } 176 177 if(bodies.block) { 178 var id = ++appLoadingId, 179 placeholderContainer = $('<div><div data-fs-load="'+id+'">'+loadingHtml+'</div></div>'), 180 onrender = function(data, block) { 181 var locator = $('[data-fs-load="'+id+'"]'), 182 output; 183 184 if(!_.isFunction(bodies[block])) { 185 console.error('Trying to load non-existant block', block, bodies); 186 } else { 187 var localContext = context.push(data); 188 // TODO: Seems like a hack. Probably is a hack. Shouldn't be a hack 189 if(localContext && localContext.stack && localContext.stack.tail && localContext.stack.tail.head) { 190 _.extend(localContext.stack.head, localContext.stack.tail.head); 191 } 192 chunk.capture(bodies[block], localContext, function(output) { 193 setTimeout(function() { locator.html(output); }, 0); 194 }); 195 } 196 }; 197 198 FS.API.get(api, params, undefined, dataType) 199 .then( 200 function(data) { 201 var outputContext = {}; 202 if(_.isFunction(transform)) { 203 outputContext.transformed = transform(data); 204 outputContext.raw = data; 205 } else { 206 outputContext = data; 207 } 208 onrender(outputContext, 'block'); 209 }, 210 function(error) { 211 onrender(error, 'error'); 212 } 213 ); 214 return chunk.write(placeholderContainer.html()); 215 } 216 return chunk; 217 }, 218 219 /**
220 * {@limData api="CapitaLIMTest"} 221 * {#transformed} ... {/transformed} 222 * {/limData} 223 */ 224 limData: function(chunk, context, bodies, params) { 225 return dust.helpers.apib(chunk, context, bodies, params, function(input) { 226 return _.map(input, function(row) { 227 return _.object( 228 _.flattenDeep(_.map(row, _.keys)), 229 _.flattenDeep(_.map(row, _.values)) 230 ); 231 }); 232 }); 233 }, 234 235 /** 236 * {@sort input="arrayOfObjects" by="id"} 237 * arrayOfObjects is sorted by ID here 238 * {/sort} 239 */ 240 sort: function(chunk, context, bodies, params) { 241 params = params || {}; 242 if(!params.input || !_.isArray(params.input)) { 243 console.warn('Input parameter to @sort must be an array of objects.'); 244 } 245 246 if(bodies.block) { 247 var sortedOutput = params.input; 248 if(params.by) { 249 sortedOutput = sortObjects(sortedOutput, params.by, !!params.reverse); 250 } 251 chunk.render(bodies.block, context.push({sorted: sortedOutput})); 252 } 253 chunk.end(); 254 return chunk; 255 }, 256 257 /** 258 * {@objectKeys input=someObject} 259 * {key}: {value}<br /> 260 * {/objectKeys} 261 */ 262 objectKeys: function(chunk, context, bodies, params) { 263 params = params || {}; 264 if(!$.isPlainObject(params.input)) { 265 console.warn('Input parameter to @objectKeys must be a plain object'); 266 } 267 268 var isEmpty = true; 269 if(bodies.block) { 270 for(var key in params.input) { 271 isEmpty = false; 272 var localContext = context.push({key: key, value: params.input[key]}); 273 // TODO: Seems like a hack. Probably is a hack. Shouldn't be a hack 274 if(localContext && localContext.stack && localContext.stack.tail && localContext.stack.tail.head) { 275 localContext = localContext.push(localContext.stack.tail.head); 276 } 277 chunk.render(bodies.block, localContext); 278 } 279 } 280 if(isEmpty && bodies.empty) { 281 chunk.render(bodies.empty, context); 282 } 283 return chunk; 284 }, 285 286 /** 287 * {@uuid /} 288 * {@uuid id="formID" /} 289 */ 290 uuid: function(chunk, context, bodies, params) { 291 params = params || {}; 292 var ID = params.id, 293 UUID; 294 if(ID && uuids[ID]) { 295 UUID = uuids[ID]; 296 } 297 if(!UUID) { 298 UUID = uuid(); 299 if(ID) { 300 uuids[ID] = UUID; 301 } 302 } 303 return chunk.write(UUID); 304 }, 305 306 /** 307 * {@regex pat="([0-9]+)" mod="g" src="asdfh342342jfks"}{matches[1]}{/regex} 308 */ 309 regex: function(chunk, context, bodies, params) { 310 params = params || {}; 311 if(!params.pat) { 312 console.warn('No pattern supplied to @regex'); 313 } 314 if(!params.src) { 315 console.warn('No src supplied to @regex'); 316 } 317 var regex = new RegExp(params.pat, params.mod || ''); 318 var localContext = context.push({matches: regex.exec(params.src)}); 319 chunk.render(bodies.block, localContext); 320 return chunk; 321 } 322 }); 323 324 var TemplatePromise = function TemplatePromise() { 325 Promise.apply(this, arguments); 326 }; 327 328 TemplatePromise.prototype = Object.create(Promise.prototype); 329 TemplatePromise.prototype.constructor = TemplatePromise; 330 331 TemplatePromise.prototype.set = function(method, selector) { 332 return this 333 .then(function(output) { 334 return $(selector)[method](output); 335 }); 336 }; 337 338 TemplatePromise.prototype.methods = { 339 into: 'html', 340 append: 'append', 341 prepend: 'prepend', 342 after: 'after', 343 before: 'before', 344 replace: 'replaceWith' 345 }; 346 347 _.each(TemplatePromise.prototype.methods, function(jQueryMethod, templateMethod) { 348 TemplatePromise.prototype[templateMethod] = function(selector) { 349 return this.set(jQueryMethod, selector); 350 }; 351 }); 352 353 var TemplateManager = function(dust) { 354 this.dust = dust; 355 }; 356 357 TemplateManager.prototype.has = function(name) {
358 if(!name) throw new Error('No name supplied to FS.Template().has'); 359 return !!this.dust.cache[name]; 360 }; 361 362 TemplateManager.prototype.add = function(source, name) { 363 if(!source) throw new Error('No source supplied to FS.Template().add'); 364 if(!name) throw new Error('No name supplied to FS.Template().add'); 365 return this.dust.loadSource(this.dust.compile(source, name)); 366 }; 367 368 var TemplateFactory = function(dust) { 369 this.dust = dust; 370 this.local = _.bind(this.local, this); 371 this.server = _.bind(this.server, this); 372 this._render = Promise.promisify(this.dust.render); 373 374 return _.bind(this.render, this); 375 }; 376 377 TemplateFactory.prototype.local = function(template, context) { 378 return this._render(template, context); 379 }; 380 381 TemplateFactory.prototype.server = function(template, context) { 382 if(!FS.API.appName.match(/(AchieveForms|AF-Renderer)/)) return this.local(template, context); 383 384 return FS.API.post('CreateTemplate', { template: template }, context) 385 .then(function(ret){ 386 if(ret.error) throw new Error(ret.error); 387 return ret.html; 388 }).caught(function(err){ 389 throw new Error(err.error || err); 390 }) 391 }; 392 393 TemplateFactory.prototype.render = function(template, context, server) { 394 if(!template) return new TemplateManager(this.dust); 395 /*if(root.IE && root.IEVersion <= 7) server = true;*/ 396 397 var _this = this; 398 return new TemplatePromise(function (resolve, reject) { 399 return (server === true ? _this.server : _this.local) 400 (template, context || {}).then(resolve, reject); 401 }); 402 }; 403 404 var root = this; 405 return new TemplateFactory(dust); 406}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.