JSFiddle - React, Tailwind, and code Playground

by bombo

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.0.0beta.js"></script>
<script src="http://rawgithub.com/rniemeyer/knockout-postbox/v0.3.1/build/knockout-postbox.js"></script>
<script type="text/html" id="theTemplate">
    <!-- ko jsModel: { package: 'MyPackage', version: '1.0.0.0', name: 'test' } -->
        <span data-bind="text: text"></span>
    <!-- /ko -->
</script>

<h1>Test</h1>
<span>Model value: <!-- ko text: test --><!-- /ko --></span>
<div data-bind="sitTemplate: { name: 'theTemplate', target: 'innerModel' }"></div>

JavaScript

var unwrap = ko.unwrap,
    scriptCreators = {};

addScriptCreatorListener = function (scriptId, listener) {
    var creatorParams = scriptCreators[scriptId];
    
    if (!creatorParams) {
        creatorParams = {
            creator: null,
            listeners: []
        }
        scriptCreators[scriptId] = creatorParams;
    }
    if (creatorParams.creator === null) {
        creatorParams.listeners.push(listener);
        return false;
    } else {
        listener(creatorParams.creator());
        return true;
    }
}

addScriptCreator = function (scriptId, creator) {
    var creatorParams = scriptCreators[scriptId],
        i, j, creatorResult;
    
    if (!creatorParams) {
        creatorParams = {
            creator: creator,
            listeners: []
        }
        scriptCreators[scriptId] = creatorParams;
    }
    if (creatorParams.listeners.length > 0) {
        for (i = 0, j = creatorParams.listeners.length; i < j; i++) {
            creatorParams.listeners[i](creator());
        }
        creatorParams.listeners.splice(0, creatorParams.listeners.length);
    }
}

ko.bindingHandlers.jsModel = {
    init: ko.bindingHandlers.with.init,
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var params = valueAccessor(),
            pkg = params.package,
            version = params.version,
            name = params.name,
            jsId = pkg + '/' + version + '/' + name;
        if (!addScriptCreatorListener(jsId, bindingContext.modelCreator)) {
            $.getScript('http://sitrion.com/pandora/js/lala.js');
        }
        ko.bindingHandlers.with.update(element, function () { return bindingContext.modelData; }, allBindings, viewModel, bindingContext);
    }
}

ko.virtualElements.allowedBindings.jsModel = true;

ko.bindingHandlers.sitTemplate = {
    init: ko.bindingHandlers.template.init,
    update: function(element, valueAccessor, allBindingsAccessor, context, bindingContext) {
        var...