JSFiddle - React, Tailwind, and code Playground

by manchagnu

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.1.0/knockout-min.js"></script>
<ul class='links'>
    <li><a href='#addserver'>Add server</a></li>
    <li><a href='#projects'>Projects</a></li>
    <li><a href='#help'>Help</a></li>
</ul>

<div class="content" data-bind="with: $data">
    <div data-bind="view: {data: $data.Selected}"></div>
</div>

JavaScript

//
// Extender to setup selectable views and the bucket of views
//
ko.extenders.viewManager = function (target, options) {
    if (target() === null || target() === undefined) {
        target({});
    }

    if (ko.isObservable(target.Selected) == false ) {
        target().Selected = ko.observable(null);
    }

    if (ko.isObservable(target.Select) == false) {
        target.Select = ko.observable(null);
    }

    target.Select.subscribe(function (newValue) {
        var views = target();
        var newView = views[newValue] || false;

        // If the view does not exist, then we just exit out.
        if (newView === false) {
            return;
        }

        target().Selected(newView);
    });


    target.push = function () {
        var args = arguments;
        target.valueWillMutate();
        var _target = target();

        for (var arg in args) {
            var items = args[arg];
            for (var item in items) {
                _target[item] = items[item];
            }
        }

        target.valueHasMutated();
    }

    return target;
};


//
// Custom binding to setup the view handler itself.
//
ko.bindingHandlers.view = {
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var options = ko.utils.unwrapObservable(valueAccessor()) || {};
        var data = ko.utils.unwrapObservable(options['data']) || {};

        if (typeof data.init === 'function') {
            // Provide a container to host any new html added in the init callback.
            data.element = $("<div>").appendTo(element);
            data.init.call(data, data.element);
            
            // Make sure we only call init once.
            delete data.init;
        }

        if (typeof data.update === 'function') {
            data.update.call(data, data.element);
        }

        // Customize this logic if you want to move the element containers around
        // when selecting a new view.
       ...