Last active
February 11, 2024 22:37
-
-
Save hashchange/f99dca479f91b55a61d7f4994ea5d438 to your computer and use it in GitHub Desktop.
Precompiled.Declarative.Handlebars.Templates – a plug-in for Backbone.Declarative.Views, enabling the use of precompiled Handlebars templates.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Precompiled.Declarative.Handlebars.Templates | |
* | |
* Plug-in for Backbone.Declarative.Views, enabling the use of precompiled Handlebars templates. | |
* | |
* For defining `el`-related properties along with a precompiled template, modify the template source. Add a special | |
* comment to the source, just as you would in a template string. An example: | |
* | |
* <!-- data-tag-name="ul" data-class-name="list" --> | |
* | |
* For more on that special comment, see the documentation of Backbone.Declarative.Views, in the section about "Setting | |
* the template property to a template string rather than a selector" (http://goo.gl/37GJmw). | |
*/ | |
;( function ( root, factory ) { | |
"use strict"; | |
// UMD for a Backbone plugin. Supports AMD, Node.js, CommonJS and globals. | |
// | |
// - Code lives in the Backbone namespace. | |
// - The module does not export a meaningful value. | |
// - The module does not create a global. | |
var supportsExports = typeof exports === "object" && exports && !exports.nodeType && typeof module === "object" && module && !module.nodeType; | |
// AMD: | |
// - Some AMD build optimizers like r.js check for condition patterns like the AMD check below, so keep it as is. | |
// - Check for `exports` after `define` in case a build optimizer adds an `exports` object. | |
// - The AMD spec requires the dependencies to be an array **literal** of module IDs. Don't use a variable there, | |
// or optimizers may fail. | |
if ( typeof define === "function" && typeof define.amd === "object" && define.amd ) { | |
// AMD module | |
define( [ "exports", "underscore", "backbone", "handlebars", "backbone.declarative.views" ], factory ); | |
} else if ( supportsExports ) { | |
// Node module, CommonJS module | |
factory( exports, require( "underscore" ), require( "backbone" ), require( "handlebars" ), require( "backbone.declarative.views" ) ); | |
} else { | |
// Global (browser or Rhino) | |
factory( {}, _, Backbone, Handlebars ); | |
} | |
}( this, function ( exports, _, Backbone, Handlebars ) { | |
"use strict"; | |
var infoMessage = "ATTN Temporary, bogus HTML, generated by the Precompiled.Declarative.Handlebars.Templates plugin. Do not use it. Use the compiled template instead.", | |
commentPrefix = "<!-- " + infoMessage + " -->"; | |
Backbone.DeclarativeViews.custom.loadTemplate = function ( templateProperty, view, viewOptions ) { | |
var precompiled, temporaryHtml, $template; | |
precompiled = getPrecompiledTemplate( templateProperty ); | |
if ( precompiled ) { | |
// We need to extract the comment defining the el. To get to it, we just call the compiled template without | |
// template variables, passing in an empty hash. | |
// | |
// The remaining HTML might be utter junk, and syntactically invalid. It doesn't matter. As soon as | |
// Backbone.Declarative.Views has checked the template for the presence of a special comment - and evaluated | |
// that comment -, the HTML won't be used anymore. | |
// | |
// (And immediately after the cache entry has come into existence, the bogus HTML is purged from it. See the | |
// event handler for the "cacheEntry:create" event, below.) | |
temporaryHtml = precompiled( {} ); | |
// We hand the bogus HTML to the default loader, and leave further processing to Backbone.Declarative.Views. | |
// | |
// The default loader will wrap the HTML into a script node. Later on, Backbone.Declarative.Views will | |
// create the cache entry. In the process, it extracts the el definition from the embedded special comment, | |
// if there is one. | |
// | |
// We also prepend an HTML comment to the bogus HTML, to make sure the content does not accidentally turn | |
// into a selector. Even though that is unlikely, it could happen if the special comment is absent and the | |
// template content evaluates to a selector for an existing DOM element ("#template"). | |
// | |
// The prepended comment also serves to identify the bogus HTML later on, during clean-up in the | |
// "cacheEntry:create" event handler. | |
$template = Backbone.DeclarativeViews.defaults.loadTemplate( commentPrefix + temporaryHtml ); | |
// On the generated $template node, we set a data attribute as a flag for the template compiler. It | |
// identifies the node as containing temporary HTML, which needs to be ignored. The flag also serves to | |
// store the template ID on the node. | |
$template.attr( "data-precompiled-template-id", templateProperty ); | |
} else { | |
// The template is not precompiled. Handle as usual. | |
$template = Backbone.DeclarativeViews.defaults.loadTemplate( templateProperty, view, viewOptions ); | |
} | |
return $template; | |
}; | |
Backbone.DeclarativeViews.custom.compiler = function ( templateHtml, $template ) { | |
// Check if we are dealing with temporary, bogus HTML from the custom loader, which should be ignored. | |
// | |
// - If we are dealing with bogus HTML, we use the template ID to retrieve the precompiled template. The | |
// template ID is stored as a data attribute on the template node (was created by the loader). | |
// | |
// - Otherwise, we are dealing with real template HTML. We don't have a precompiled template at our disposal, so | |
// we simply compile the HTML. | |
var templateId = $template && $template.data( "precompiled-template-id" ); | |
return templateId ? getPrecompiledTemplate( templateId ) : Handlebars.compile( templateHtml ); | |
}; | |
Backbone.DeclarativeViews.plugins.events.on( "cacheEntry:create", function ( cacheEntry, templateProperty ) { | |
// Clean up the cache entry. If the template has been precompiled and the loader has generated temporary, bogus | |
// HTML, remove that HTML from the cache and set cacheEntry.html to a clarifying message. | |
// | |
// This step might help to avoid confusion during debugging, but is completely optional otherwise. | |
if ( getPrecompiledTemplate( templateProperty ) && cacheEntry.html.indexOf( commentPrefix ) === 0 ) cacheEntry.html = infoMessage; | |
} ); | |
function getPrecompiledTemplate( templateId ) { | |
return Handlebars.templates[templateId]; | |
} | |
// Module return value | |
// ------------------- | |
// | |
// A return value may be necessary for AMD to detect that the module is loaded. It ony exists for that reason and is | |
// purely symbolic. Don't use it in client code. The functionality of this module lives in the Backbone namespace. | |
exports.info = "Precompiled.Declarative.Handlebars.Templates has loaded. Don't use the exported value of the module. Its functionality is available inside the Backbone.DeclarativeViews namespace."; | |
} ) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment