Source: tabs.js

'use strict';

define('tabs', ['jquery', 'ko'], function($, ko) {
    /**
     * This class describes the behavior of a tab.
     *
     * @class Tab
     * @param {int} id The unique tab id
     */
    function Tab(id) {
        this.id = ko.observable(id);
        this.uri = ko.observable('');
        this.content = ko.observable('');
        this.route = ko.observable('');

        this.title = ko.computed({
            read : function() {
                return $('.page-name', this.content()).first().val() || '';
            }.bind(this)
        });

        this.icon = ko.computed({
            read : function() {
                return $('.page-icon', this.content()).first().val() || '';
            }.bind(this)
        });

        this.history = [];

        this.onclose = null;
    }

    // export Tab to window
    window.Tab = Tab;


    /**
     * This class is the tabs manager of the application. It is accessible by `app.tabset`
     *
     * @class  Tabset
     */
    function Tabset() {
        this.tabs = ko.observableArray([]);

        this.activeId = ko.observable();

        this.activeTab = ko.computed({
            read : function() {
                var i;

                for (i = 0; i < this.tabs().length; i++) {
                    if (this.tabs()[i].id() === this.activeId()) {
                        return this.tabs()[i];
                    }
                }
                return this.tabs()[0];
            }.bind(this),

            write : function(tab) {
                this.activeId(tab.id());
            }.bind(this)
        });

        this.activeTab.subscribe(function(tab) {
            if (tab.history.length) {
                history.replaceState({}, '', '#!' + tab.history[tab.history.length - 1]);
            }
        });
    }

    /**
     * This index is incremented each time a tab is created, to generate a unique id for each tab
     *
     * @static
     * @private
     */
    Tabset.index = 0;


    /**
     * Push a new tab in the tabset
     *
     * @memberOf Tabset
     */
    Tabset.prototype.push = function() {
        // Create the tab
        var tab = new Tab(Tabset.index ++);

        this.tabs.push(tab);

        // Activate the newly created tab
        this.activeId(tab.id());
    };


    /**
     * Remove a tab by it index in the tabset
     *
     * @param {int} index The tab index in the tabset
     * @memberOf Tabset
     */
    Tabset.prototype.remove = function(index) {
        if (this.tabs().length > 1) {
            if (this.activeTab() === this.tabs()[index]) {
                var next = index === this.tabs().length - 1 ? this.tabs()[index - 1] : this.tabs()[index + 1];

                if (next) {
                    // Activate the next tab
                    this.activeId(next.id());
                }
            }

            if (this.tabs()[index].onclose) {
                this.tabs()[index].onclose.call(this.tabs()[index]);
            }

            // Delete the tab nodes
            this.tabs.splice(index, 1);

            // Register the new list of tabs
            this.registerTabs();
        }
    };


    /**
     * Save the tabs last urls in a cookie
     *
     * @memberOf Tabset
     */
    Tabset.prototype.registerTabs = function() {
        var data = [],
            i;

        for (i = 0; i < this.tabs().length; i++) {
            data.push(this.tabs()[i].uri());
        }

        $.cookie('open-tabs', JSON.stringify(data), {expires : 365, path : '/'});
    };


    /**
     * Perform click action on tab title
     *
     * @param {int} $index The tab index in the tabset
     * @param {Event} event The triggered event
     * @returns {boolean} False
     * @memberOf Tabset
     */
    Tabset.prototype.clickTab = function($index, event) {
        if (event.which === 2) {
            this.remove($index);
        }
        else {
            this.activeId(this.tabs()[$index].id());
        }
        return false;
    };

    return Tabset;
});