/*global jQuery, window */ (function ($, window) { 'use strict'; var templateMap = {}, instance = null, options = { // Should an error be thrown if an attempt is made to render a non-existent template. If false, the // operation will fail silently. warnOnMissingTemplates: false, // Should an error be thrown if an attempt is made to overwrite a template which has already been added. // If true the original template will be overwritten with the new value. allowOverwrite: true, // The 'type' attribute which you use to denoate a Mustache Template in the DOM; eg: // `` domTemplateType: 'text/html', // Specifies the `dataType` attribute used when external templates are loaded. externalTemplateDataType: 'text' }; function getMustache() { // Lazily retrieve Mustache from the window global if it hasn't been defined by // the User. if (instance === null) { instance = window.Mustache; if (instance === void 0) { $.error("Failed to locate Mustache instance, are you sure it has been loaded?"); } } return instance; } /** * Returns true if the supplied templateName has been added. */ function has(templateName) { return templateMap[templateName] !== void 0; } /** * Registers a template so that it can be used by $.Mustache. * * @param templateName A name which uniquely identifies this template. * @param templateHtml The HTML which makes us the template; this will be rendered by Mustache when render() * is invoked. * @throws If options.allowOverwrite is false and the templateName has already been registered. */ function add(templateName, templateHtml) { if (!options.allowOverwrite && has(templateName)) { $.error('TemplateName: ' + templateName + ' is already mapped.'); return; } templateMap[templateName] = $.trim(templateHtml); } /** * Adds one or more tempaltes from the DOM using either the supplied templateElementIds or by retrieving all script * tags of the 'domTemplateType'. Templates added in this fashion will be registered with their elementId value. * * @param [...templateElementIds] List of element id's present on the DOM which contain templates to be added; * if none are supplied all script tags that are of the same type as the * `options.domTemplateType` configuration value will be added. */ function addFromDom() { var templateElementIds; // If no args are supplied, all script blocks will be read from the document. if (arguments.length === 0) { templateElementIds = $('script[type="' + options.domTemplateType + '"]').map(function () { return this.id; }); } else { templateElementIds = $.makeArray(arguments); } $.each(templateElementIds, function() { var templateElement = document.getElementById(this); if (templateElement === null) { $.error('No such elementId: #' + this); } else { add(this, $(templateElement).html()); } }); } /** * Removes a template, the contents of the removed Template will be returned. * * @param templateName The name of the previously registered Mustache template that you wish to remove. * @returns String which represents the raw content of the template. */ function remove(templateName) { var result = templateMap[templateName]; delete templateMap[templateName]; return result; } /** * Removes all templates and tells Mustache to flush its cache. */ function clear() { templateMap = {}; getMustache().clearCache(); } /** * Renders a previously added Mustache template using the supplied templateData object. Note if the supplied * templateName doesn't exist an empty String will be returned. */ function render(templateName, templateData) { if (!has(templateName)) { if (options.warnOnMissingTemplates) { $.error('No template registered for: ' + templateName); } return ''; } return getMustache().to_html(templateMap[templateName], templateData, templateMap); } /** * Loads the external Mustache templates located at the supplied URL and registers them for later use. This method * returns a jQuery Promise and also support an `onComplete` callback. * * @param url URL of the external Mustache template file to load. * @param onComplete Optional callback function which will be invoked when the templates from the supplied URL * have been loaded and are ready for use. * @returns jQuery deferred promise which will complete when the templates have been loaded and are * ready for use. */ function load(url, onComplete) { return $.ajax({ url: url, dataType: options.externalTemplateDataType }).done(function (templates) { $(templates).filter('script').each(function (i, el) { add(el.id, $(el).html()); }); if ($.isFunction(onComplete)) { onComplete(); } }); } /** * Returns an Array of templateNames which have been registered and can be retrieved via * $.Mustache.render() or $(element).mustache(). */ function templates() { return $.map(templateMap, function (value, key) { return key; }); } // Expose the public methods on jQuery.Mustache $.Mustache = { options: options, load: load, add: add, addFromDom: addFromDom, remove: remove, clear: clear, render: render, templates: templates, instance: instance }; /** * Renders one or more viewModels into the current jQuery element. * * @param templateName The name of the Mustache template you wish to render, Note that the * template must have been previously loaded and / or added. * @param templateData One or more JavaScript objects which will be used to render the Mustache * template. * @param options.method jQuery method to use when rendering, defaults to 'append'. */ $.fn.mustache = function (templateName, templateData, options) { var settings = $.extend({ method: 'append' }, options); var renderTemplate = function (obj, viewModel) { $(obj)[settings.method](render(templateName, viewModel)); }; return this.each(function () { var element = this; // Render a collection of viewModels. if ($.isArray(templateData)) { $.each(templateData, function () { renderTemplate(element, this); }); } // Render a single viewModel. else { renderTemplate(element, templateData); } }); }; }(jQuery, window));