<commit_before>odoo.define('web.ControlPanelView', function (require) {
"use strict";

var ControlPanelController = require('web.ControlPanelController');
var ControlPanelModel = require('web.ControlPanelModel');
var ControlPanelRenderer = require('web.ControlPanelRenderer');
var controlPanelViewParameters = require('web.controlPanelViewParameters');
var mvc = require('web.mvc');
var pyUtils = require('web.py_utils');
var viewUtils = require('web.viewUtils');
var Domain = require('web.Domain');

var DEFAULT_INTERVAL = controlPanelViewParameters.DEFAULT_INTERVAL;
var DEFAULT_PERIOD = controlPanelViewParameters.DEFAULT_PERIOD;
var INTERVAL_OPTIONS = controlPanelViewParameters.INTERVAL_OPTIONS;
var PERIOD_OPTIONS = controlPanelViewParameters.PERIOD_OPTIONS;
const OPTION_GENERATORS = controlPanelViewParameters.OPTION_GENERATORS;

var Factory = mvc.Factory;

var ControlPanelView = Factory.extend({
    config: _.extend({}, Factory.prototype.config, {
        Controller: ControlPanelController,
        Model: ControlPanelModel,
        Renderer: ControlPanelRenderer,
    }),

    /**
     * @override
     * @param {Object} [params={}]
     * @param {Object} [params.action={}]
     * @param {Object} [params.context={}]
     * @param {string} [params.domain=[]]
     * @param {string} [params.modelName]
     * @param {string[]} [params.searchMenuTypes=[]]
     *   determines search menus displayed.
     * @param {Object} [params.state] used to determine the control panel model
     *   essential content at load. For instance, state can be the state of an
     *   other control panel model that we want to use.
     * @param {string} [params.title] the name of the action, to display in the
     *   breadcrumb
     * @param {string} [params.template] the QWeb template to render
     * @param {Object} [params.viewInfo={arch: '<search/>', fields: {}}] a
     *   search fieldsview
     * @param {string} [params.viewInfo.arch]
     * @param {boolean} [params.withBreadcrumbs=true] if set to false,
     *   breadcrumbs won't be rendered
     * @param {boolean} [params.withSearchBar=true] if set to false, no default
     *   search bar will be rendered
     * @param {Object[]} [params.dynamicFilters=[]] filters to add to the
     *   search (in addition to those described in the arch), each filter being
     *   an object with keys 'description' (what is displayed in the searchbar)
     *   and 'domain'
     */
    init: function (params) {
        var self = this;
        this._super();
        params = params || {};
        var viewInfo = params.viewInfo || {arch: '<search/>', fields: {}};
        var context = _.extend({}, params.context);
        var domain = params.domain || [];
        var action = params.action || {};

        this.searchDefaults = {};
        Object.keys(context).forEach(function (key) {
            var match = /^search_default_(.*)$/.exec(key);
            if (match) {
                self.searchDefaults[match[1]] = context[key];
                delete context[key];
            }
        });

        this.arch = viewUtils.parseArch(viewInfo.arch);
        this.fields = viewInfo.fields;

        this.referenceMoment = moment();
        this.optionGenerators = OPTION_GENERATORS.map(o => {
            const description = o.description ?
                                    o.description.toString () :
                                    this.referenceMoment.clone().set(o.setParam).add(o.addParam).format(o.format);
            return _.extend({}, o, {description:  description});
        });
        PERIOD_OPTIONS = PERIOD_OPTIONS.map(option =>
            _.extend({}, option, {description: option.description.toString()})
        );
        INTERVAL_OPTIONS = INTERVAL_OPTIONS.map(option =>
            _.extend({}, option, {description: option.description.toString()})
        );

        this.controllerParams.modelName = params.modelName;

        this.modelParams.context = context;
        this.modelParams.domain = domain;
        this.modelParams.modelName = params.modelName;
        this.modelParams.actionId = action.id;
        this.modelParams.fields = this.fields;

        this.rendererParams.action = action;
        this.rendererParams.breadcrumbs = params.breadcrumbs;
        this.rendererParams.context = context;
        this.rendererParams.searchMenuTypes = params.searchMenuTypes || [];
        this.rendererParams.template = params.template;
        this.rendererParams.title = params.title;
        this.rendererParams.withBreadcrumbs = params.withBreadcrumbs !== false;
        this.rendererParams.withSearchBar = 'withSearchBar' in params ? params.withSearchBar : true;

        this.loadParams.withSearchBar = 'withSearchBar' in params ? params.withSearchBar : true;
        this.loadParams.searchMenuTypes = params.searchMenuTypes || [];
        this.loadParams.activateDefaultFavorite = params.activateDefaultFavorite;
        if (this.loadParams.withSearchBar) {
            if (params.state) {
                this.loadParams.initialState = params.state;
            } else {
                // groups are determined in _parseSearchArch
                this.loadParams.groups = [];
                this.loadParams.timeRanges = context.time_ranges;
                this._parseSearchArch(this.arch);
            }
        }

        // add a filter group with the dynamic filters, if any
        if (params.dynamicFilters && params.dynamicFilters.length) {
            var dynamicFiltersGroup = params.dynamicFilters.map(function (filter) {
                return {
                    description: filter.description,
                    domain: JSON.stringify(filter.domain),
                    isDefault: true,
                    type: 'filter',
                };
            });
            this.loadParams.groups.unshift(dynamicFiltersGroup);
        }
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------

    /**
     * @private
     * @param {Object} child parsed arch node
     * @returns {Object}
     */
    _evalArchChild: function (child) {
        if (child.attrs.context) {
            try {
                var context = pyUtils.eval('context', child.attrs.context);
                if (context.group_by) {
                    // let us extract basic data since we just evaluated context
                    // and use a correct tag!
                    child.tag = 'groupBy';
                    child.attrs.fieldName = context.group_by.split(':')[0];
                    child.attrs.defaultInterval = context.group_by.split(':')[1];
                }
            } catch (e) {}
        }
        return child;
    },
    /**
     * @private
     * @param {Object} filter
     * @param {Object} attrs
     */
    _extractAttributes: function (filter, attrs) {
        filter.isDefault = this.searchDefaults[attrs.name] ? true : false;
        filter.description = attrs.string ||
                                attrs.help ||
                                attrs.name ||
                                attrs.domain ||
                                'Ω';
        if (filter.type === 'filter') {
            if (filter.isDefault) {
                filter.defaultRank = -5;
            }
            filter.domain = attrs.domain;
            filter.context = pyUtils.eval('context', attrs.context);
            if (attrs.date) {
                filter.fieldName = attrs.date;
                filter.fieldType = this.fields[attrs.date].type;
                filter.hasOptions = true;
                filter.options = this.optionGenerators;
                filter.defaultOptionId = attrs.default_period ||
                                            DEFAULT_PERIOD;
                filter.currentOptionIds = new Set();
                filter.basicDomains = this._getDateFilterBasicDomains(filter);
            }
            if (attrs.invisible) {
                filter.invisible = true;
            }
        } else if (filter.type === 'groupBy') {
            if (filter.isDefault) {
                const val = this.searchDefaults[attrs.name];
                filter.defaultRank = typeof val === 'number' ? val : 100;
            }
            filter.fieldName = attrs.fieldName;
            filter.fieldType = this.fields[attrs.fieldName].type;
            if (_.contains(['date', 'datetime'], filter.fieldType)) {
                filter.hasOptions = true;
                filter.options = INTERVAL_OPTIONS;
                filter.defaultOptionId = attrs.defaultInterval ||
                                            DEFAULT_INTERVAL;
                filter.currentOptionIds = new Set();
            }
        } else if (filter.type === 'field') {
            if (filter.isDefault) {
                filter.defaultRank = -10;
            }
            var field = this.fields[attrs.name];
            filter.attrs = attrs;
            filter.autoCompleteValues = [];
            if (filter.isDefault) {
                // on field, default can be used with a value
                filter.defaultValue = this.searchDefaults[filter.attrs.name];
            }
            if (!attrs.string) {
                attrs.string = field.string;
            }
        }
    },
    /**
     * Constructs an object containing various domains based on this.referenceMoment and
     * the field associated with the provided date filter.
     *
     * @private
     * @param {Object} filter
     * @returns {Object}
     */
    _getDateFilterBasicDomains: function (filter) {
        const _constructBasicDomain = (y, o) => {
            const addParam = _.extend({}, y.addParam, o ? o.addParam : {});
            const setParam = _.extend({}, y.setParam, o ? o.setParam : {});
            const granularity = o ? o.granularity : y.granularity;
            const date = this.referenceMoment.clone().set(setParam).add(addParam);
            let leftBound = date.clone().startOf(granularity);
            let rightBound = date.clone().endOf(granularity);

            if (filter.fieldType === 'date') {
                leftBound = leftBound.format("YYYY-MM-DD");
                rightBound = rightBound.format("YYYY-MM-DD");
            } else {
                leftBound = leftBound.utc().format("YYYY-MM-DD HH:mm:ss");
                rightBound = rightBound.utc().format("YYYY-MM-DD HH:mm:ss");
            }
            const domain = Domain.prototype.arrayToString([
                '&',
                [filter.fieldName, ">=", leftBound],
                [filter.fieldName, "<=", rightBound]
            ]);

            let description;
            if (o) {
                description = o.description + " " + y.description;
            } else {
                description = y.description;
            }

            return { domain, description };
        };

        const domains = {};
        this.optionGenerators.filter(y => y.groupId === 2).forEach(y => {
            domains[y.optionId] = _constructBasicDomain(y);
            this.optionGenerators.filter(y => y.groupId === 1).forEach(o => {
                domains[y.optionId + "__" + o.optionId] = _constructBasicDomain(y, o);
            });
        });
        return domains;
    },
    /**
     * Parse the arch of a 'search' view.
     *
     * @private
     * @param {Object} arch arch with root node <search>
     */
    _parseSearchArch: function (arch) {
        var self = this;
        // a searchview arch may contain a 'searchpanel' node, but this isn't
        // the concern of the ControlPanelView (the SearchPanel will handle it).
        // Ideally, this code should whitelist the tags to take into account
        // instead of blacklisting the others, but with the current (messy)
        // structure of a searchview arch, it's way simpler to do it that way.
        var children = arch.children.filter(function (child) {
            return child.tag !== 'searchpanel';
        });
        var preFilters = _.flatten(children.map(function (child) {
            return child.tag !== 'group' ?
                    self._evalArchChild(child) :
                    child.children.map(self._evalArchChild);
        }));
        preFilters.push({tag: 'separator'});

        var filter;
        var currentTag;
        var currentGroup = [];
        var groupOfGroupBys = [];
        var groupNumber = 1;

        _.each(preFilters, function (preFilter) {
            if (preFilter.tag !== currentTag || _.contains(['separator', 'field'], preFilter.tag)) {
                if (currentGroup.length) {
                    if (currentTag === 'groupBy') {
                        groupOfGroupBys = groupOfGroupBys.concat(currentGroup);
                    } else {
                        self.loadParams.groups.push(currentGroup);
                    }
                }
                currentTag = preFilter.tag;
                currentGroup = [];
                groupNumber++;
            }
            if (preFilter.tag !== 'separator') {
                filter = {
                    type: preFilter.tag,
                    // we need to codify here what we want to keep from attrs
                    // and how, for now I put everything.
                    // In some sence, some filter are active (totally determined, given)
                    // and others are passive (require input(s) to become determined)
                    // What is the right place to process the attrs?
                };
                if (filter.type === 'filter' || filter.type === 'groupBy') {
                    filter.groupNumber = groupNumber;
                }
                self._extractAttributes(filter, preFilter.attrs);
                currentGroup.push(filter);
            }
        });
        if (groupOfGroupBys.length) {
            this.loadParams.groups.push(groupOfGroupBys);
        }
    },
});

return ControlPanelView;

});
<commit_msg>[FIX] web: control panel date filter ok in arabic<commit_after>odoo.define('web.ControlPanelView', function (require) {
"use strict";

var ControlPanelController = require('web.ControlPanelController');
var ControlPanelModel = require('web.ControlPanelModel');
var ControlPanelRenderer = require('web.ControlPanelRenderer');
var controlPanelViewParameters = require('web.controlPanelViewParameters');
var mvc = require('web.mvc');
var pyUtils = require('web.py_utils');
var viewUtils = require('web.viewUtils');
var Domain = require('web.Domain');

var DEFAULT_INTERVAL = controlPanelViewParameters.DEFAULT_INTERVAL;
var DEFAULT_PERIOD = controlPanelViewParameters.DEFAULT_PERIOD;
var INTERVAL_OPTIONS = controlPanelViewParameters.INTERVAL_OPTIONS;
var PERIOD_OPTIONS = controlPanelViewParameters.PERIOD_OPTIONS;
const OPTION_GENERATORS = controlPanelViewParameters.OPTION_GENERATORS;

var Factory = mvc.Factory;

var ControlPanelView = Factory.extend({
    config: _.extend({}, Factory.prototype.config, {
        Controller: ControlPanelController,
        Model: ControlPanelModel,
        Renderer: ControlPanelRenderer,
    }),

    /**
     * @override
     * @param {Object} [params={}]
     * @param {Object} [params.action={}]
     * @param {Object} [params.context={}]
     * @param {string} [params.domain=[]]
     * @param {string} [params.modelName]
     * @param {string[]} [params.searchMenuTypes=[]]
     *   determines search menus displayed.
     * @param {Object} [params.state] used to determine the control panel model
     *   essential content at load. For instance, state can be the state of an
     *   other control panel model that we want to use.
     * @param {string} [params.title] the name of the action, to display in the
     *   breadcrumb
     * @param {string} [params.template] the QWeb template to render
     * @param {Object} [params.viewInfo={arch: '<search/>', fields: {}}] a
     *   search fieldsview
     * @param {string} [params.viewInfo.arch]
     * @param {boolean} [params.withBreadcrumbs=true] if set to false,
     *   breadcrumbs won't be rendered
     * @param {boolean} [params.withSearchBar=true] if set to false, no default
     *   search bar will be rendered
     * @param {Object[]} [params.dynamicFilters=[]] filters to add to the
     *   search (in addition to those described in the arch), each filter being
     *   an object with keys 'description' (what is displayed in the searchbar)
     *   and 'domain'
     */
    init: function (params) {
        var self = this;
        this._super();
        params = params || {};
        var viewInfo = params.viewInfo || {arch: '<search/>', fields: {}};
        var context = _.extend({}, params.context);
        var domain = params.domain || [];
        var action = params.action || {};

        this.searchDefaults = {};
        Object.keys(context).forEach(function (key) {
            var match = /^search_default_(.*)$/.exec(key);
            if (match) {
                self.searchDefaults[match[1]] = context[key];
                delete context[key];
            }
        });

        this.arch = viewUtils.parseArch(viewInfo.arch);
        this.fields = viewInfo.fields;

        this.referenceMoment = moment();
        this.optionGenerators = OPTION_GENERATORS.map(o => {
            const description = o.description ?
                                    o.description.toString () :
                                    this.referenceMoment.clone().set(o.setParam).add(o.addParam).format(o.format);
            return _.extend({}, o, {description:  description});
        });
        PERIOD_OPTIONS = PERIOD_OPTIONS.map(option =>
            _.extend({}, option, {description: option.description.toString()})
        );
        INTERVAL_OPTIONS = INTERVAL_OPTIONS.map(option =>
            _.extend({}, option, {description: option.description.toString()})
        );

        this.controllerParams.modelName = params.modelName;

        this.modelParams.context = context;
        this.modelParams.domain = domain;
        this.modelParams.modelName = params.modelName;
        this.modelParams.actionId = action.id;
        this.modelParams.fields = this.fields;

        this.rendererParams.action = action;
        this.rendererParams.breadcrumbs = params.breadcrumbs;
        this.rendererParams.context = context;
        this.rendererParams.searchMenuTypes = params.searchMenuTypes || [];
        this.rendererParams.template = params.template;
        this.rendererParams.title = params.title;
        this.rendererParams.withBreadcrumbs = params.withBreadcrumbs !== false;
        this.rendererParams.withSearchBar = 'withSearchBar' in params ? params.withSearchBar : true;

        this.loadParams.withSearchBar = 'withSearchBar' in params ? params.withSearchBar : true;
        this.loadParams.searchMenuTypes = params.searchMenuTypes || [];
        this.loadParams.activateDefaultFavorite = params.activateDefaultFavorite;
        if (this.loadParams.withSearchBar) {
            if (params.state) {
                this.loadParams.initialState = params.state;
            } else {
                // groups are determined in _parseSearchArch
                this.loadParams.groups = [];
                this.loadParams.timeRanges = context.time_ranges;
                this._parseSearchArch(this.arch);
            }
        }

        // add a filter group with the dynamic filters, if any
        if (params.dynamicFilters && params.dynamicFilters.length) {
            var dynamicFiltersGroup = params.dynamicFilters.map(function (filter) {
                return {
                    description: filter.description,
                    domain: JSON.stringify(filter.domain),
                    isDefault: true,
                    type: 'filter',
                };
            });
            this.loadParams.groups.unshift(dynamicFiltersGroup);
        }
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------

    /**
     * @private
     * @param {Object} child parsed arch node
     * @returns {Object}
     */
    _evalArchChild: function (child) {
        if (child.attrs.context) {
            try {
                var context = pyUtils.eval('context', child.attrs.context);
                if (context.group_by) {
                    // let us extract basic data since we just evaluated context
                    // and use a correct tag!
                    child.tag = 'groupBy';
                    child.attrs.fieldName = context.group_by.split(':')[0];
                    child.attrs.defaultInterval = context.group_by.split(':')[1];
                }
            } catch (e) {}
        }
        return child;
    },
    /**
     * @private
     * @param {Object} filter
     * @param {Object} attrs
     */
    _extractAttributes: function (filter, attrs) {
        filter.isDefault = this.searchDefaults[attrs.name] ? true : false;
        filter.description = attrs.string ||
                                attrs.help ||
                                attrs.name ||
                                attrs.domain ||
                                'Ω';
        if (filter.type === 'filter') {
            if (filter.isDefault) {
                filter.defaultRank = -5;
            }
            filter.domain = attrs.domain;
            filter.context = pyUtils.eval('context', attrs.context);
            if (attrs.date) {
                filter.fieldName = attrs.date;
                filter.fieldType = this.fields[attrs.date].type;
                filter.hasOptions = true;
                filter.options = this.optionGenerators;
                filter.defaultOptionId = attrs.default_period ||
                                            DEFAULT_PERIOD;
                filter.currentOptionIds = new Set();
                filter.basicDomains = this._getDateFilterBasicDomains(filter);
            }
            if (attrs.invisible) {
                filter.invisible = true;
            }
        } else if (filter.type === 'groupBy') {
            if (filter.isDefault) {
                const val = this.searchDefaults[attrs.name];
                filter.defaultRank = typeof val === 'number' ? val : 100;
            }
            filter.fieldName = attrs.fieldName;
            filter.fieldType = this.fields[attrs.fieldName].type;
            if (_.contains(['date', 'datetime'], filter.fieldType)) {
                filter.hasOptions = true;
                filter.options = INTERVAL_OPTIONS;
                filter.defaultOptionId = attrs.defaultInterval ||
                                            DEFAULT_INTERVAL;
                filter.currentOptionIds = new Set();
            }
        } else if (filter.type === 'field') {
            if (filter.isDefault) {
                filter.defaultRank = -10;
            }
            var field = this.fields[attrs.name];
            filter.attrs = attrs;
            filter.autoCompleteValues = [];
            if (filter.isDefault) {
                // on field, default can be used with a value
                filter.defaultValue = this.searchDefaults[filter.attrs.name];
            }
            if (!attrs.string) {
                attrs.string = field.string;
            }
        }
    },
    /**
     * Constructs an object containing various domains based on this.referenceMoment and
     * the field associated with the provided date filter.
     *
     * @private
     * @param {Object} filter
     * @returns {Object}
     */
    _getDateFilterBasicDomains: function (filter) {
        const _constructBasicDomain = (y, o) => {
            const addParam = _.extend({}, y.addParam, o ? o.addParam : {});
            const setParam = _.extend({}, y.setParam, o ? o.setParam : {});
            const granularity = o ? o.granularity : y.granularity;
            const date = this.referenceMoment.clone().set(setParam).add(addParam);
            let leftBound = date.clone().startOf(granularity).locale('en');
            let rightBound = date.clone().endOf(granularity).locale('en');

            if (filter.fieldType === 'date') {
                leftBound = leftBound.format("YYYY-MM-DD");
                rightBound = rightBound.format("YYYY-MM-DD");
            } else {
                leftBound = leftBound.utc().format("YYYY-MM-DD HH:mm:ss");
                rightBound = rightBound.utc().format("YYYY-MM-DD HH:mm:ss");
            }
            const domain = Domain.prototype.arrayToString([
                '&',
                [filter.fieldName, ">=", leftBound],
                [filter.fieldName, "<=", rightBound]
            ]);

            let description;
            if (o) {
                description = o.description + " " + y.description;
            } else {
                description = y.description;
            }

            return { domain, description };
        };

        const domains = {};
        this.optionGenerators.filter(y => y.groupId === 2).forEach(y => {
            domains[y.optionId] = _constructBasicDomain(y);
            this.optionGenerators.filter(y => y.groupId === 1).forEach(o => {
                domains[y.optionId + "__" + o.optionId] = _constructBasicDomain(y, o);
            });
        });
        return domains;
    },
    /**
     * Parse the arch of a 'search' view.
     *
     * @private
     * @param {Object} arch arch with root node <search>
     */
    _parseSearchArch: function (arch) {
        var self = this;
        // a searchview arch may contain a 'searchpanel' node, but this isn't
        // the concern of the ControlPanelView (the SearchPanel will handle it).
        // Ideally, this code should whitelist the tags to take into account
        // instead of blacklisting the others, but with the current (messy)
        // structure of a searchview arch, it's way simpler to do it that way.
        var children = arch.children.filter(function (child) {
            return child.tag !== 'searchpanel';
        });
        var preFilters = _.flatten(children.map(function (child) {
            return child.tag !== 'group' ?
                    self._evalArchChild(child) :
                    child.children.map(self._evalArchChild);
        }));
        preFilters.push({tag: 'separator'});

        var filter;
        var currentTag;
        var currentGroup = [];
        var groupOfGroupBys = [];
        var groupNumber = 1;

        _.each(preFilters, function (preFilter) {
            if (preFilter.tag !== currentTag || _.contains(['separator', 'field'], preFilter.tag)) {
                if (currentGroup.length) {
                    if (currentTag === 'groupBy') {
                        groupOfGroupBys = groupOfGroupBys.concat(currentGroup);
                    } else {
                        self.loadParams.groups.push(currentGroup);
                    }
                }
                currentTag = preFilter.tag;
                currentGroup = [];
                groupNumber++;
            }
            if (preFilter.tag !== 'separator') {
                filter = {
                    type: preFilter.tag,
                    // we need to codify here what we want to keep from attrs
                    // and how, for now I put everything.
                    // In some sence, some filter are active (totally determined, given)
                    // and others are passive (require input(s) to become determined)
                    // What is the right place to process the attrs?
                };
                if (filter.type === 'filter' || filter.type === 'groupBy') {
                    filter.groupNumber = groupNumber;
                }
                self._extractAttributes(filter, preFilter.attrs);
                currentGroup.push(filter);
            }
        });
        if (groupOfGroupBys.length) {
            this.loadParams.groups.push(groupOfGroupBys);
        }
    },
});

return ControlPanelView;

});
<|endoftext|>


<commit_before>var codeDisplayManager = new CodeDisplayManager("javascript", "fibonacci");
var lines = [];
var animationTime = 100;
var loadingSequence = [];

function runIterativeFib(n) {
    $("#fibonacci").empty();
    lines = [];
    loadingSequence = [];
    codeDisplayManager.loadFunctions("iterativeFib");
    codeDisplayManager.changeFunction("iterativeFib");
    for (var i = 0; i < 17; i++) {
        lines.push(codeDisplayManager.getVelocityFramesForHighlight(i, animationTime));
    }
    iterativeFib(n);
    animate();
}

function iterativeFib(n) {
    highlight(0, 2);
    if (n <= 0) {
        highlight(1, 2);
        throw new {name: "IllegalArgumentException", message: "The Fibonacci numbers start at 1."};
    }
    highlight(2, 2);
    if (n === 1) {
        return 1;
    }
    highlight(3, 2);
    if (n === 2) {
        return 1;
    }

    initialize();

    highlight(5, 0);
    var nMinusTwo = 1;
    fadeInAndMark("nMinusTwo", 0);
    highlight(5, 1);

    highlight(6, 0);
    var nMinusOne = 1;
    fadeInAndMark("nMinusOne", 1);
    highlight(6, 1);

    highlight(7, 2);
    var result = 0;

    for (var i = 3; i <= n; i++) {
        highlight(9, 2);

        highlight(10, 0);
        result = nMinusOne + nMinusTwo;
        forLoopAnimation(result, 0);
        highlight(10, 1);

        highlight(11, 0);
        nMinusTwo = nMinusOne;
        forLoopAnimation(result, 1);
        highlight(11, 1);

        highlight(12, 0);
        nMinusOne = result;
        forLoopAnimation(result, 2);
        highlight(12, 1);

        highlight(13, 2);
    }

    highlight(15, 0);
    markResult();
    highlight(15, 1);

    highlight(16, 2);

}

function initialize() {
    $("#fibonacci").append('

+

');
    $("#fibonacci").append('

1

');
    $("#fibonacci").append('

1

');

}

function fadeInAndMark(id, part) {
    loadingSequence.push({e: $("#" + id), p: {opacity: 1}, o: {duration: animationTime, display: 'inline-block'}});
    if (part === 0)
        loadingSequence.push({
            e: $("#nMinusMarker"),
            p: {opacity: 1},
            o: {duration: animationTime, display: 'inline-block', sequenceQueue: false}
        });

    else if (part === 1)
        loadingSequence.push({
            e: $("#nMinusMarker"),
            p: {width: "+= 4rem"},
            o: {duration: animationTime, display: 'inline-block', sequenceQueue: false}
        })
}

function highlight(line, type) {
    switch (type) {
        case 0:
            loadingSequence.push(lines[line][0]);
            break;
        case 1:
            loadingSequence.push(lines[line][1]);
            break;
        case 2:
            loadingSequence.push(lines[line][0], lines[line][1]);
            break;
    }
}

function forLoopAnimation(val, part) {
    if (part === 0) {
        loadingSequence.push({e: $("#nMinusMarker"), p: {boxShadowSpread: 3}, o: {duration: animationTime/2}});
        loadingSequence.push({e: $("#plusMark"), p: {opacity: 1}, o: {duration: animationTime, sequenceQueue: false}});
        loadingSequence.push({e: $("#nMinusMarker"), p: {boxShadowSpread: 0}, o: {duration: animationTime/2}});
        loadingSequence.push({e: $("#plusMark"), p: {opacity: 0}, o: {duration: animationTime, sequenceQueue: false}});
        $("#fibonacci").append('

' + val + '

');
        loadingSequence.push({
            e: $("#fibonacci").children().last(),
            p: {opacity: 1},
            o: {duration: animationTime, display: 'inline-block', sequenceQueue: false}
        });

    }
    else if (part === 1) {
        loadingSequence.push({
            e: $("#nMinusMarker"),
            p: {width: "-= 4rem", left: "+= 4rem"},
            o: {duration: animationTime}
        });
    }
    else if (part === 2) {
        loadingSequence.push({e: $("#nMinusMarker"), p: {width: "+= 4rem"}, o: {duration: animationTime}});
    }
}

function markResult() {
    var result = $("#fibonacci").children().last();
    loadingSequence.push({e: result, p: "callout.swing", o: {duration: animationTime}});
    loadingSequence.push({e: $("#fibonacci").children().first(), p: {opacity: 0}, o: {duration: animationTime/2, sequenceQueue: false}});
    loadingSequence.push({
        e: result.children().first(),
        p: {color: "#008b00", fontSize: "3rem"},
        o: {duration: animationTime, sequenceQueue: false}
    })
}

function animate() {
    $.Velocity.RunSequence(loadingSequence);
}

<commit_msg>Prepared fiboncciVisualization to use the new GSAP system in animationPlayer<commit_after>var codeDisplayManager = new CodeDisplayManager("javascript", "fibonacci");
//var lines = [];
var animationTime = 1;
//var loadingSequence = [];
var tl;

function runIterativeFib(n) {
    $("#fibonacci").empty();
    //lines = [];
    //loadingSequence = [];
    codeDisplayManager.loadFunctions("iterativeFib");
    codeDisplayManager.changeFunction("iterativeFib");
    /*for (var i = 0; i < 17; i++) {
        lines.push(codeDisplayManager.getVelocityFramesForHighlight(i, animationTime));
    }*/
    iterativeFib(n);
    animate();
}

function iterativeFib(n) {
    highlight(0, 2);
    if (n <= 0) {
        highlight(1, 2);
        throw new {name: "IllegalArgumentException", message: "The Fibonacci numbers start at 1."};
    }
    highlight(2, 2);
    if (n === 1) {
        return 1;
    }
    highlight(3, 2);
    if (n === 2) {
        return 1;
    }

    initialize();

    highlight(5, 0);
    var nMinusTwo = 1;
    fadeInAndMark("nMinusTwo", 0);
    highlight(5, 1);

    highlight(6, 0);
    var nMinusOne = 1;
    fadeInAndMark("nMinusOne", 1);
    highlight(6, 1);

    highlight(7, 2);
    var result = 0;

    for (var i = 3; i <= n; i++) {
        highlight(9, 2);

        highlight(10, 0);
        result = nMinusOne + nMinusTwo;
        forLoopAnimation(result, 0);
        highlight(10, 1);

        highlight(11, 0);
        nMinusTwo = nMinusOne;
        forLoopAnimation(result, 1);
        highlight(11, 1);

        highlight(12, 0);
        nMinusOne = result;
        forLoopAnimation(result, 2);
        highlight(12, 1);

        highlight(13, 2);
    }

    highlight(15, 0);
    markResult();
    highlight(15, 1);

    highlight(16, 2);

}

function initialize() {
    $("#fibonacci").append('

+

');
    $("#fibonacci").append('

1

');
    $("#fibonacci").append('

1

');

}

function fadeInAndMark(id, part) {
    var arr = [];
    arr.push({e: $("#" + id), p: {opacity: 1}, o: {duration: animationTime, display: 'inline-block'}});
    if (part === 0)
        arr.push({
            e: $("#nMinusMarker"),
            p: {opacity: 1},
            o: {duration: animationTime, display: 'inline-block', position: "-=" + animationTime}
        });

    else if (part === 1)
        arr.push({
            e: $("#nMinusMarker"),
            p: {width: "+= 4rem"},
            o: {duration: animationTime, display: 'inline-block', position: "-=" + animationTime}
        })
}

//STATUS: NOT CHANGED, may not need it anymore
function highlight(line, type) {
    switch (type) {
        case 0:
            loadingSequence.push(lines[line][0]);
            break;
        case 1:
            loadingSequence.push(lines[line][1]);
            break;
        case 2:
            loadingSequence.push(lines[line][0], lines[line][1]);
            break;
    }
}

//STATUS: DONE
// Returns an array of animation meant to be given to a method in animationPlayer.
function forLoopAnimation(val, part) {
    var arr = [];
    if (part === 0) {
        arr.push({e: "#nMinusMarker", p: {boxShadowSpread: 3}, o: {duration: animationTime/2}});
        arr.push({e: "#plusMark", p: {opacity: 1}, o: {duration: animationTime, position: "-=" + animationTime}});
        arr.push({e: "#nMinusMarker", p: {boxShadowSpread: 0}, o: {duration: animationTime/2}});
        arr.push({e: "#plusMark", p: {opacity: 0}, o: {duration: animationTime, position: "-=" + animationTime}});
        $("#fibonacci").append('

' + val + '

');
        arr.push({
            e: $("#fibonacci").children().last(),
            p: {opacity: 1},
            o: {duration: animationTime, display: 'inline-block', sequenceQueue: false}
        });

    }
    else if (part === 1) {
        arr.push({
            e: $("#nMinusMarker"),
            p: {width: "-= 4rem", left: "+= 4rem"},
            o: {duration: animationTime}
        });
    }
    else if (part === 2) {
        arr.push({e: $("#nMinusMarker"), p: {width: "+= 4rem"}, o: {duration: animationTime}});
    }
    return arr;
}

//STATUS: DONE
// Returns an array of animation meant to be given to a method in animationPlayer.
function markResult() {
    var arr = [];
    var result = $("#fibonacci").children().last();
    arr.push({e: result, p: "callout.swing", o: {duration: animationTime}});
    arr.push({e: $("#fibonacci").children().first(), p: {opacity: 0}, o: {duration: animationTime/2, sequenceQueue: false}});
    arr.push({
        e: result.children().first(),
        p: {color: "#008b00", fontSize: "3rem"},
        o: {duration: animationTime, position: "-=" + animationTime}
    })
}

function animate() {
    tl.play();
}

<|endoftext|>


<commit_before>/*jshint newcap:false*/
/*global diff_match_patch:true assetPath:true*/

/**
  This controller handles displaying of history

  @class HistoryController
  @extends Discourse.ObjectController
  @namespace Discourse
  @uses Discourse.ModalFunctionality
  @module Discourse
**/
Discourse.HistoryController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
  diffLibraryLoaded: false,
  diff: null,

  init: function(){
    this._super();
    var historyController = this;
    $LAB.script(assetPath('defer/google_diff_match_patch')).wait(function(){
      historyController.set('diffLibraryLoaded', true);
    });
  },

  loadSide: function(side) {
    if (this.get("version" + side)) {
      var orig = this.get('model');
      var version = this.get("version" + side + ".number");
      if (version === orig.get('version')) {
        this.set("post" + side, orig);
      } else {
        var historyController = this;
        Discourse.Post.loadVersion(orig.get('id'), version).then(function(post) {
          historyController.set("post" + side, post);
        });
      }
    }
  },

  changedLeftVersion: function() {
    this.loadSide("Left");
  }.observes('versionLeft'),

  changedRightVersion: function() {
    this.loadSide("Right");
  }.observes('versionRight'),

  loadedPosts: function() {
    if (this.get('diffLibraryLoaded') && this.get('postLeft') && this.get('postRight')) {
      var dmp = new diff_match_patch(),
          before = this.get("postLeft.cooked"),
          after = this.get("postRight.cooked"),
          diff = dmp.diff_main(before, after);
      dmp.diff_cleanupSemantic(diff);
      this.set('diff', dmp.diff_prettyHtml(diff));
    }
  }.observes('diffLibraryLoaded', 'postLeft', 'postRight'),

  refresh: function() {
    this.setProperties({
      loading: true,
      postLeft: null,
      postRight: null
    });

    var historyController = this;
    this.get('model').loadVersions().then(function(result) {
      _.each(result,function(item) {
        item.description = "v" + item.number + " - " + Discourse.Formatter.relativeAge(new Date(item.created_at), {format: 'medium', leaveAgo: true}) + " - " +
          Em.String.i18n("changed_by", { author: item.display_username });
      });

      historyController.setProperties({
        loading: false,
        versionLeft: result[0],
        versionRight: result[result.length-1],
        versions: result
      });
    });
  }

});

<commit_msg>FIX: Dates in the history window shouldn't wrap in spans<commit_after>/*jshint newcap:false*/
/*global diff_match_patch:true assetPath:true*/

/**
  This controller handles displaying of history

  @class HistoryController
  @extends Discourse.ObjectController
  @namespace Discourse
  @uses Discourse.ModalFunctionality
  @module Discourse
**/
Discourse.HistoryController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
  diffLibraryLoaded: false,
  diff: null,

  init: function(){
    this._super();
    var historyController = this;
    $LAB.script(assetPath('defer/google_diff_match_patch')).wait(function(){
      historyController.set('diffLibraryLoaded', true);
    });
  },

  loadSide: function(side) {
    if (this.get("version" + side)) {
      var orig = this.get('model');
      var version = this.get("version" + side + ".number");
      if (version === orig.get('version')) {
        this.set("post" + side, orig);
      } else {
        var historyController = this;
        Discourse.Post.loadVersion(orig.get('id'), version).then(function(post) {
          historyController.set("post" + side, post);
        });
      }
    }
  },

  changedLeftVersion: function() {
    this.loadSide("Left");
  }.observes('versionLeft'),

  changedRightVersion: function() {
    this.loadSide("Right");
  }.observes('versionRight'),

  loadedPosts: function() {
    if (this.get('diffLibraryLoaded') && this.get('postLeft') && this.get('postRight')) {
      var dmp = new diff_match_patch(),
          before = this.get("postLeft.cooked"),
          after = this.get("postRight.cooked"),
          diff = dmp.diff_main(before, after);
      dmp.diff_cleanupSemantic(diff);
      this.set('diff', dmp.diff_prettyHtml(diff));
    }
  }.observes('diffLibraryLoaded', 'postLeft', 'postRight'),

  refresh: function() {
    this.setProperties({
      loading: true,
      postLeft: null,
      postRight: null
    });

    var historyController = this;
    this.get('model').loadVersions().then(function(result) {
      _.each(result,function(item) {

        var age = Discourse.Formatter.relativeAge(new Date(item.created_at), {
          format: 'medium',
          leaveAgo: true,
          wrapInSpan: false});

        item.description = "v" + item.number + " - " + age + " - " + Em.String.i18n("changed_by", { author: item.display_username });
      });

      historyController.setProperties({
        loading: false,
        versionLeft: result[0],
        versionRight: result[result.length-1],
        versions: result
      });
    });
  }

});

<|endoftext|>


<commit_before>pageflow.EntryPreviewView = Backbone.Marionette.ItemView.extend({
  template: 'templates/entry_preview',
  className: 'container',

  ui: {
    header: '.header',
    entry: '.entry',
    overview: '.overview'
  },

  initialize: function() {
    this.widgets = $();
  },

  onRender: function() {
    this.pageViews = this.subview(new pageflow.CollectionView({
      el: this.ui.entry,
      collection: this.model.pages,
      itemViewConstructor: pageflow.PagePreviewView,
      blankSlateViewConstructor: pageflow.BlankEntryView
    }));

    this.ui.entry.append($('
Scrollen, um weiterzulesen
'));

    this.update();

    this.listenTo(pageflow.entry, 'sync:order sync:widgets', this.update);
    this.listenTo(pageflow.entry, 'change:configuration', function() {
      pageflow.entry.once('sync', this.update, this);
    });

    this.listenTo(pageflow.chapters, 'sync', this.update);
    this.listenTo(pageflow.pages, 'sync', this.update);

    this.listenTo(pageflow.audioFiles, 'sync', this.update);
    this.listenTo(pageflow.imageFiles, 'sync', this.update);
    this.listenTo(pageflow.videoFiles, 'sync', this.update);
  },

  onShow: function() {
    var slideshow = pageflow.slides =  new pageflow.Slideshow(this.ui.entry);
    slideshow.update();

    this.listenTo(this.model.pages, 'add', function() {
      slideshow.update();
    });

    this.listenTo(this.model.pages, 'remove', function() {
      slideshow.update();
    });

    this.listenTo(this.model.pages, 'edit', function(model) {
      slideshow.goTo(this.pageViews.itemViews.findByModel(model).$el);
    });

    this.listenTo(pageflow.app, 'resize', function() {
      slideshow.triggerResizeHooks();
      this.updateSimulatedMediaQueryClasses();
    });

    this.updateSimulatedMediaQueryClasses();
  },

  updateSimulatedMediaQueryClasses: function() {
    var width = this.$el.width();
    var portrait = this.$el.width() < this.$el.height();

    $('html')
      .toggleClass('simulate_mobile', width <= 900)
      .toggleClass('simulate_phone', width <= 700)
      .toggleClass('simulate_desktop', width > 700)
      .toggleClass('simulate_narrow_desktop', width <= 1200)
      .toggleClass('simulate_wide_desktop', width > 1600)
      .toggleClass('simulate_pad_portrait', width <= 768 && portrait)
      .toggleClass('simulate_phone_portrait', width <= 500 && portrait);
  },

  update: function() {
    var view = this;

    $.ajax(this.model.url() + '/partials').success(function(response) {
      var partials = $('
').html(response);

      view.ui.header.replaceWith(partials.find('.header'));
      view.ui.overview.replaceWith(partials.find('.overview'));
      view.bindUIElements();

      view.updateWidgets(partials);

      view.ui.header.header({
        slideshow: pageflow.slides
      });
      view.ui.overview.overview();
    });

    this.$el.toggleClass('emphasize_chapter_beginning', !!this.model.get('emphasize_chapter_beginning'));
  },

  updateWidgets: function(partials) {
    var widgets = partials.find('[data-widget]');
    this.updatePresentWidgetsCssClasses(widgets);

    this.widgets.remove();
    this.widgets = widgets;
    this.ui.entry.before(this.widgets);

    pageflow.widgetTypes.enhance(this.$el);
  },

  updatePresentWidgetsCssClasses: function(newWidgets) {
    var previousClasses = this.widgetNames(this.widgets);
    var newClasses = this.widgetNames(newWidgets);

    this.$el.removeClass(_.difference(previousClasses, newClasses).join(' '));
    this.$el.addClass(newClasses.join(' '));
  },

  widgetNames: function(widgets) {
    return widgets.map(function() {
      return 'widget_' + $(this).data('widget') + '_present';
    }).get();
  }
});<commit_msg>Read emphasize_chapter_beginning from Entry Configuration<commit_after>pageflow.EntryPreviewView = Backbone.Marionette.ItemView.extend({
  template: 'templates/entry_preview',
  className: 'container',

  ui: {
    header: '.header',
    entry: '.entry',
    overview: '.overview'
  },

  initialize: function() {
    this.widgets = $();
  },

  onRender: function() {
    this.pageViews = this.subview(new pageflow.CollectionView({
      el: this.ui.entry,
      collection: this.model.pages,
      itemViewConstructor: pageflow.PagePreviewView,
      blankSlateViewConstructor: pageflow.BlankEntryView
    }));

    this.ui.entry.append($('
Scrollen, um weiterzulesen
'));

    this.update();

    this.listenTo(pageflow.entry, 'sync:order sync:widgets', this.update);
    this.listenTo(pageflow.entry, 'change:configuration', function() {
      pageflow.entry.once('sync', this.update, this);
    });

    this.listenTo(pageflow.chapters, 'sync', this.update);
    this.listenTo(pageflow.pages, 'sync', this.update);

    this.listenTo(pageflow.audioFiles, 'sync', this.update);
    this.listenTo(pageflow.imageFiles, 'sync', this.update);
    this.listenTo(pageflow.videoFiles, 'sync', this.update);
  },

  onShow: function() {
    var slideshow = pageflow.slides =  new pageflow.Slideshow(this.ui.entry);
    slideshow.update();

    this.listenTo(this.model.pages, 'add', function() {
      slideshow.update();
    });

    this.listenTo(this.model.pages, 'remove', function() {
      slideshow.update();
    });

    this.listenTo(this.model.pages, 'edit', function(model) {
      slideshow.goTo(this.pageViews.itemViews.findByModel(model).$el);
    });

    this.listenTo(pageflow.app, 'resize', function() {
      slideshow.triggerResizeHooks();
      this.updateSimulatedMediaQueryClasses();
    });

    this.updateSimulatedMediaQueryClasses();
  },

  updateSimulatedMediaQueryClasses: function() {
    var width = this.$el.width();
    var portrait = this.$el.width() < this.$el.height();

    $('html')
      .toggleClass('simulate_mobile', width <= 900)
      .toggleClass('simulate_phone', width <= 700)
      .toggleClass('simulate_desktop', width > 700)
      .toggleClass('simulate_narrow_desktop', width <= 1200)
      .toggleClass('simulate_wide_desktop', width > 1600)
      .toggleClass('simulate_pad_portrait', width <= 768 && portrait)
      .toggleClass('simulate_phone_portrait', width <= 500 && portrait);
  },

  update: function() {
    var view = this;

    $.ajax(this.model.url() + '/partials').success(function(response) {
      var partials = $('
').html(response);

      view.ui.header.replaceWith(partials.find('.header'));
      view.ui.overview.replaceWith(partials.find('.overview'));
      view.bindUIElements();

      view.updateWidgets(partials);

      view.ui.header.header({
        slideshow: pageflow.slides
      });
      view.ui.overview.overview();
    });

    this.$el.toggleClass('emphasize_chapter_beginning', !!this.model.configuration.get('emphasize_chapter_beginning'));
  },

  updateWidgets: function(partials) {
    var widgets = partials.find('[data-widget]');
    this.updatePresentWidgetsCssClasses(widgets);

    this.widgets.remove();
    this.widgets = widgets;
    this.ui.entry.before(this.widgets);

    pageflow.widgetTypes.enhance(this.$el);
  },

  updatePresentWidgetsCssClasses: function(newWidgets) {
    var previousClasses = this.widgetNames(this.widgets);
    var newClasses = this.widgetNames(newWidgets);

    this.$el.removeClass(_.difference(previousClasses, newClasses).join(' '));
    this.$el.addClass(newClasses.join(' '));
  },

  widgetNames: function(widgets) {
    return widgets.map(function() {
      return 'widget_' + $(this).data('widget') + '_present';
    }).get();
  }
});<|endoftext|>


<commit_before>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { Component, PropTypes } from 'react';
import Immutable, { List, Map } from 'immutable';

import classNames from 'classnames';
import ConfGlobal from 'conf/local.json';
import selectn from 'selectn';

import provide from 'react-redux-provide';

import ProviderHelpers from 'common/ProviderHelpers';
import UIHelpers from 'common/UIHelpers';

import {RaisedButton, FlatButton, IconButton, FontIcon } from 'material-ui';

import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';
import Toggle from 'material-ui/lib/toggle';
import IconMenu from 'material-ui/lib/menus/icon-menu';
import Menu from 'material-ui/lib/menus/menu';
import MenuItem from 'material-ui/lib/menus/menu-item';
import NavigationExpandMoreIcon from 'material-ui/lib/svg-icons/navigation/expand-more';

import AuthorizationFilter from 'views/components/Document/AuthorizationFilter';

@provide
export default class PageToolbar extends Component {

  static defaultProps = {
    publishChangesAction: null,
    handleNavigateRequest: null,
    actions: [] // ['workflow', 'edit', 'add-child', 'publish-toggle', 'enable-toggle', 'publish', 'more-options']
  };

  static propTypes = {
    windowPath: PropTypes.string.isRequired,
    fetchTasks: PropTypes.func.isRequired,
    computeTasks: PropTypes.object.isRequired,
    computeEntity: PropTypes.object.isRequired,
    computePermissionEntity: PropTypes.object,
    computeLogin: PropTypes.object.isRequired,
    handleNavigateRequest: PropTypes.func,
    publishToggleAction: PropTypes.func,
    publishChangesAction: PropTypes.func,
    enableToggleAction: PropTypes.func,
    children: PropTypes.node,
    label: PropTypes.string,
    actions: PropTypes.array
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired
  };

  constructor(props, context){
    super(props, context);

    this.state = {
      enableActions: 0,
      disableActions: 0,
      publishActions: 0,
      unpublishActions: 0,
      showActionsMobile: false
    };

    // Bind methods to 'this'
    ['_documentActionsToggleEnabled', '_documentActionsTogglePublished', '_documentActionsStartWorkflow', '_publishChanges'].forEach( (method => this[method] = this[method].bind(this)) );
  }

  /**
  * Publish changes directly
  */
  _publishChanges() {
    if (this.props.publishChangesAction == null) {
      this.props.publishToggleAction(true, false, selectn('response.path', this.props.computeEntity));
    } else {
      this.props.publishChangesAction();
    }
  }

  /**
  * Toggle document (enabled/disabled)
  */
  _documentActionsToggleEnabled(event, toggled) {
    this.props.enableToggleAction(toggled, false, selectn('response.path', this.props.computeEntity));
  }

  /**
  * Toggle published document
  */
  _documentActionsTogglePublished(event, toggled) {
    this.props.publishToggleAction(toggled, false, selectn('response.path', this.props.computeEntity));
  }

  /**
  * Start a workflow
  */
  _documentActionsStartWorkflow(workflow, event) {

    const path = selectn('response.path', this.props.computeEntity);

    switch (workflow) {
      case 'enable':
        this.props.enableToggleAction(true, true, path);
        this.setState({enableActions: this.state.enableActions + 1});
      break;

      case 'disable':
        this.props.enableToggleAction(false, true, path);
        this.setState({disableActions: this.state.disableActions + 1});
      break;

      case 'publish':
        this.props.publishToggleAction(true, true, path);
        this.setState({publishActions: this.state.publishActions + 1});
      break;

      case 'unpublish':
        this.props.publishToggleAction(false, true, path);
        this.setState({unpublishActions: this.state.unpublishActions + 1});
      break;
    }
  }

  componentDidMount() {
    this.props.fetchTasks(selectn('response.uid', this.props.computeEntity));
  }

  render() {

    const { computeEntity, computePermissionEntity, computeLogin } = this.props;

    let enableTasks = [];
    let disableTasks = [];
    let publishTasks = [];
    let unpublishTasks = [];

    let toolbarGroupItem = {
      float: 'left',
      margin: `${(this.context.muiTheme.toolbar.height - this.context.muiTheme.button.height) / 2}px ${this.context.muiTheme.baseTheme.spacing.desktopGutter}px`,
      position: 'relative'
    }

    let documentEnabled = (selectn('response.state', computeEntity) == 'Enabled');
    let documentPublished = (selectn('response.state', computeEntity) == 'Published');

    const permissionEntity = (selectn('response', computePermissionEntity)) ? computePermissionEntity : computeEntity;

    // Compute related tasks
    const computeTasks = ProviderHelpers.getEntry(this.props.computeTasks, selectn('response.uid', this.props.computeEntity));

    if (selectn('response.entries', computeTasks)) {

      let taskList = new List(selectn('response.entries', computeTasks));

      taskList.forEach(function(value, key) {
        switch (selectn('properties.nt:type', value)) {
          case 'Task2300':
            enableTasks.push(value);
          break;

          case 'Task297b':
            disableTasks.push(value);
          break;

          case 'Task6b8':
            publishTasks.push(value);
          break;

          case 'Task11b1':
            unpublishTasks.push(value);
          break;
        }
      });
    }

    let showPublish = false;

    return <Toolbar className="page-toolbar">

                  <ToolbarGroup className="visible-xs" style={{textAlign: 'right'}}>
                    <IconButton iconClassName="material-icons" onTouchTap={(e) => {this.setState({showActionsMobile: !this.state.showActionsMobile}); e.preventDefault(); }}>menu</IconButton>
                  </ToolbarGroup>

                  <ToolbarGroup float="left" className={classNames({'hidden-xs': !this.state.showActionsMobile})}>

                    {this.props.children}

                    {(() => {
                      if (this.props.actions.includes('workflow')) {

                          return <AuthorizationFilter filter={{role: 'Record', entity: selectn('response', permissionEntity), login: computeLogin}} style={toolbarGroupItem}>

                              REQUEST:

                              <RaisedButton label={"Enable (" + (enableTasks.length + this.state.enableActions ) + ")"} disabled={selectn('response.state', computeEntity) != 'Disabled' && selectn('response.state', computeEntity) != 'New'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'enable')} />
                              <RaisedButton label={"Disable (" + (disableTasks.length + this.state.disableActions) + ")"} disabled={selectn('response.state', computeEntity) != 'Enabled' && selectn('response.state', computeEntity) != 'New'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'disable')} />
                              <RaisedButton label={"Publish (" + (publishTasks.length + this.state.publishActions) + ")"} disabled={selectn('response.state', computeEntity) != 'Enabled'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'publish')} />
                              <RaisedButton label={"Unpublish (" + (unpublishTasks.length + this.state.unpublishActions) + ")"} disabled={selectn('response.state', computeEntity) != 'Published'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'unpublish')} />

                          </AuthorizationFilter>;
                      }
                    })()}

                    {(() => {
                      if (this.props.actions.includes('enable-toggle')) {

                          return <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', permissionEntity)}} style={toolbarGroupItem}>

                              <Toggle
                                toggled={documentEnabled || documentPublished}
                                onToggle={this._documentActionsToggleEnabled}
                                ref="enabled"
                                disabled={documentPublished}
                                name="enabled"
                                value="enabled"
                                label="Enabled"/>

                          </AuthorizationFilter>;
                      }
                    })()}

                    {(() => {
                      if (this.props.actions.includes('publish-toggle')) {

                        if(showPublish) {

                          return <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', permissionEntity)}} style={toolbarGroupItem}>

                              <Toggle
                                toggled={documentPublished}
                                onToggle={this._documentActionsTogglePublished}
                                disabled={!documentEnabled && !documentPublished}
                                name="published"
                                value="published"
                                label="Published"/>

                          </AuthorizationFilter>;
                        }
                        else {
                          return (
Publishing temporarily unavailable.
);
                        }
                      }
                    })()}

                  </ToolbarGroup>

                  <ToolbarGroup float="right" className={classNames( {'hidden-xs': !this.state.showActionsMobile})}>

                    {(() => {
                      if (this.props.actions.includes('publish')) {

                        if(showPublish) {
                          return <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', permissionEntity)}} style={toolbarGroupItem}>
                            <RaisedButton data-guide-role="publish-changes" disabled={!documentPublished} label="Publish Changes" style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._publishChanges} />
                          </AuthorizationFilter>;
                        }
                        else {
                          return;
                        }
                      }
                    })()}

                    {(() => {
                      if (this.props.actions.includes('edit')) {
                        return <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeEntity)}} style={toolbarGroupItem}>
                          <RaisedButton label={"Edit " + this.props.label} style={{marginRight: '5px', marginLeft: '0'}} primary={true} onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath.replace('sections', 'Workspaces') + '/edit')} />
                        </AuthorizationFilter>;
                      }
                    })()}

                    {(() => {
                      if (this.props.actions.includes('add-child')) {
                        return <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeEntity)}} style={toolbarGroupItem}>
                                <RaisedButton label="Add New Page" style={{marginRight: '5px', marginLeft: '0'}} onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/create')} primary={true} />
                        </AuthorizationFilter>;
                      }
                    })()}

                    <ToolbarSeparator className="hidden-xs" />

                    {(() => {
                      if (this.props.actions.includes('more-options')) {

                        let children = [
                          <MenuItem onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/reports')} key="reports" primaryText="Reports" />,
                          <MenuItem onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/media')} key="media" primaryText="Media Browser" />,
                          <AuthorizationFilter key="users" filter={{permission: 'Write', entity: selectn('response', computeEntity)}}>
                            <MenuItem onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/users')} primaryText="Users" />
                          </AuthorizationFilter>];

                        return React.createElement(UIHelpers.isViewSize('xs') ? Menu : IconMenu, {
                          anchorOrigin: {horizontal: 'right', vertical: 'top'},
                          targetOrigin: {horizontal: 'right', vertical: 'top'},
                          iconButtonElement:
                            <IconButton tooltip="More Options" tooltipPosition="top-center" touch={true} className={classNames( {'hidden-xs': !this.state.showActionsMobile})}>
                              <NavigationExpandMoreIcon />
                            </IconButton>
                          }, children);
                      }
                    })()}

                  </ToolbarGroup>

                </Toolbar>;
  }
}
<commit_msg>FV-209: Going from 'Unpublish' to 'Publish' in Nisga'a archive produces 404 error.<commit_after>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { Component, PropTypes } from 'react';
import Immutable, { List, Map } from 'immutable';

import classNames from 'classnames';
import ConfGlobal from 'conf/local.json';
import selectn from 'selectn';

import provide from 'react-redux-provide';

import ProviderHelpers from 'common/ProviderHelpers';
import UIHelpers from 'common/UIHelpers';

import {RaisedButton, FlatButton, IconButton, FontIcon } from 'material-ui';

import Toolbar from 'material-ui/lib/toolbar/toolbar';
import ToolbarGroup from 'material-ui/lib/toolbar/toolbar-group';
import ToolbarSeparator from 'material-ui/lib/toolbar/toolbar-separator';
import Toggle from 'material-ui/lib/toggle';
import IconMenu from 'material-ui/lib/menus/icon-menu';
import Menu from 'material-ui/lib/menus/menu';
import MenuItem from 'material-ui/lib/menus/menu-item';
import NavigationExpandMoreIcon from 'material-ui/lib/svg-icons/navigation/expand-more';

import AuthorizationFilter from 'views/components/Document/AuthorizationFilter';

@provide
export default class PageToolbar extends Component {

  static defaultProps = {
    publishChangesAction: null,
    handleNavigateRequest: null,
    actions: [] // ['workflow', 'edit', 'add-child', 'publish-toggle', 'enable-toggle', 'publish', 'more-options']
  };

  static propTypes = {
    windowPath: PropTypes.string.isRequired,
    fetchTasks: PropTypes.func.isRequired,
    computeTasks: PropTypes.object.isRequired,
    computeEntity: PropTypes.object.isRequired,
    computePermissionEntity: PropTypes.object,
    computeLogin: PropTypes.object.isRequired,
    handleNavigateRequest: PropTypes.func,
    publishToggleAction: PropTypes.func,
    publishChangesAction: PropTypes.func,
    enableToggleAction: PropTypes.func,
    children: PropTypes.node,
    label: PropTypes.string,
    actions: PropTypes.array
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired
  };

  constructor(props, context){
    super(props, context);

    this.state = {
      enableActions: 0,
      disableActions: 0,
      publishActions: 0,
      unpublishActions: 0,
      showActionsMobile: false
    };

    // Bind methods to 'this'
    ['_documentActionsToggleEnabled', '_documentActionsTogglePublished', '_documentActionsStartWorkflow', '_publishChanges'].forEach( (method => this[method] = this[method].bind(this)) );
  }

  /**
  * Publish changes directly
  */
  _publishChanges() {
    if (this.props.publishChangesAction == null) {
      this.props.publishToggleAction(true, false, selectn('response.path', this.props.computeEntity));
    } else {
      this.props.publishChangesAction();
    }
  }

  /**
  * Toggle document (enabled/disabled)
  */
  _documentActionsToggleEnabled(event, toggled) {
    this.props.enableToggleAction(toggled, false, selectn('response.path', this.props.computeEntity));
  }

  /**
  * Toggle published document
  */
  _documentActionsTogglePublished(event, toggled) {
    this.props.publishToggleAction(toggled, false, selectn('response.path', this.props.computeEntity));
  }

  /**
  * Start a workflow
  */
  _documentActionsStartWorkflow(workflow, event) {

    const path = selectn('response.path', this.props.computeEntity);

    switch (workflow) {
      case 'enable':
        this.props.enableToggleAction(true, true, path);
        this.setState({enableActions: this.state.enableActions + 1});
      break;

      case 'disable':
        this.props.enableToggleAction(false, true, path);
        this.setState({disableActions: this.state.disableActions + 1});
      break;

      case 'publish':
        this.props.publishToggleAction(true, true, path);
        this.setState({publishActions: this.state.publishActions + 1});
      break;

      case 'unpublish':
        this.props.publishToggleAction(false, true, path);
        this.setState({unpublishActions: this.state.unpublishActions + 1});
      break;
    }
  }

  componentDidMount() {
    this.props.fetchTasks(selectn('response.uid', this.props.computeEntity));
  }

  render() {

    const { computeEntity, computePermissionEntity, computeLogin } = this.props;

    let showPublish = false; // Temporarily Hide/Show the Publish Dialect Toggle Switch

    let enableTasks = [];
    let disableTasks = [];
    let publishTasks = [];
    let unpublishTasks = [];

    let toolbarGroupItem = {
      float: 'left',
      margin: `${(this.context.muiTheme.toolbar.height - this.context.muiTheme.button.height) / 2}px ${this.context.muiTheme.baseTheme.spacing.desktopGutter}px`,
      position: 'relative'
    }

    let documentEnabled = (selectn('response.state', computeEntity) == 'Enabled');
    let documentPublished = (selectn('response.state', computeEntity) == 'Published');

    const permissionEntity = (selectn('response', computePermissionEntity)) ? computePermissionEntity : computeEntity;

    // Compute related tasks
    const computeTasks = ProviderHelpers.getEntry(this.props.computeTasks, selectn('response.uid', this.props.computeEntity));

    if (selectn('response.entries', computeTasks)) {

      let taskList = new List(selectn('response.entries', computeTasks));

      taskList.forEach(function(value, key) {
        switch (selectn('properties.nt:type', value)) {
          case 'Task2300':
            enableTasks.push(value);
          break;

          case 'Task297b':
            disableTasks.push(value);
          break;

          case 'Task6b8':
            publishTasks.push(value);
          break;

          case 'Task11b1':
            unpublishTasks.push(value);
          break;
        }
      });
    }

    return (
      <Toolbar className="page-toolbar">

        <ToolbarGroup className="visible-xs" style={{textAlign: 'right'}}>
          <IconButton iconClassName="material-icons" onTouchTap={(e) => {this.setState({showActionsMobile: !this.state.showActionsMobile}); e.preventDefault(); }}>menu</IconButton>
        </ToolbarGroup>

        <ToolbarGroup float="left" className={classNames({'hidden-xs': !this.state.showActionsMobile})}>

          {this.props.children}

          {(() => {
            if (this.props.actions.includes('workflow')) {
              return (
                <AuthorizationFilter filter={{role: 'Record', entity: selectn('response', permissionEntity), login: computeLogin}} style={toolbarGroupItem}>

                    REQUEST:
                    <RaisedButton label={"Enable (" + (enableTasks.length + this.state.enableActions ) + ")"} disabled={selectn('response.state', computeEntity) != 'Disabled' && selectn('response.state', computeEntity) != 'New'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'enable')} />
                    <RaisedButton label={"Disable (" + (disableTasks.length + this.state.disableActions) + ")"} disabled={selectn('response.state', computeEntity) != 'Enabled' && selectn('response.state', computeEntity) != 'New'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'disable')} />
                    <RaisedButton label={"Publish (" + (publishTasks.length + this.state.publishActions) + ")"} disabled={selectn('response.state', computeEntity) != 'Enabled'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'publish')} />
                    <RaisedButton label={"Unpublish (" + (unpublishTasks.length + this.state.unpublishActions) + ")"} disabled={selectn('response.state', computeEntity) != 'Published'} style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._documentActionsStartWorkflow.bind(this, 'unpublish')} />

                </AuthorizationFilter>
              );
            }
          })()}

          {(() => {
            if (this.props.actions.includes('enable-toggle')) {
              return (
                <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', permissionEntity)}} style={toolbarGroupItem}>

                    <Toggle
                      toggled={documentEnabled || documentPublished}
                      onToggle={this._documentActionsToggleEnabled}
                      ref="enabled"
                      disabled={documentPublished}
                      name="enabled"
                      value="enabled"
                      label="Enabled"/>

                </AuthorizationFilter>
              );
            }
          })()}

          {(() => {
            if (this.props.actions.includes('publish-toggle')) {
              if(showPublish) {
                return (
                  <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', permissionEntity)}} style={toolbarGroupItem}>

                      <Toggle
                        toggled={documentPublished}
                        onToggle={this._documentActionsTogglePublished}
                        disabled={!documentEnabled && !documentPublished}
                        name="published"
                        value="published"
                        label="Published"/>

                  </AuthorizationFilter>
                );
              }
              else {
                return (
Publishing temporarily unavailable.
);
              }
            }
          })()}

        </ToolbarGroup>

        <ToolbarGroup float="right" className={classNames( {'hidden-xs': !this.state.showActionsMobile})}>

          {(() => {
            if (this.props.actions.includes('publish')) {
              return (
                <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', permissionEntity)}} style={toolbarGroupItem}>
                  <RaisedButton data-guide-role="publish-changes" disabled={!documentPublished} label="Publish Portal Changes" style={{marginRight: '5px', marginLeft: '0'}} secondary={true} onTouchTap={this._publishChanges} />
                </AuthorizationFilter>
              );
            }
          })()}

          {(() => {
            if (this.props.actions.includes('edit')) {
              return (
                <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeEntity)}} style={toolbarGroupItem}>
                  <RaisedButton label={"Edit " + this.props.label} style={{marginRight: '5px', marginLeft: '0'}} primary={true} onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath.replace('sections', 'Workspaces') + '/edit')} />
                </AuthorizationFilter>
              );
            }
          })()}

          {(() => {
            if (this.props.actions.includes('add-child')) {
              return (
                <AuthorizationFilter filter={{permission: 'Write', entity: selectn('response', computeEntity)}} style={toolbarGroupItem}>
                  <RaisedButton label="Add New Page" style={{marginRight: '5px', marginLeft: '0'}} onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/create')} primary={true} />
                </AuthorizationFilter>
              );
            }
          })()}

          <ToolbarSeparator className="hidden-xs" />

          {(() => {
            if (this.props.actions.includes('more-options')) {

              let children = [
                <MenuItem onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/reports')} key="reports" primaryText="Reports" />,
                <MenuItem onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/media')} key="media" primaryText="Media Browser" />,
                <AuthorizationFilter key="users" filter={{permission: 'Write', entity: selectn('response', computeEntity)}}>
                  <MenuItem onTouchTap={this.props.handleNavigateRequest.bind(this, this.props.windowPath + '/users')} primaryText="Users" />
                </AuthorizationFilter>];

              return React.createElement(UIHelpers.isViewSize('xs') ? Menu : IconMenu, {
                anchorOrigin: {horizontal: 'right', vertical: 'top'},
                targetOrigin: {horizontal: 'right', vertical: 'top'},
                iconButtonElement:
                  <IconButton tooltip="More Options" tooltipPosition="top-center" touch={true} className={classNames( {'hidden-xs': !this.state.showActionsMobile})}>
                    <NavigationExpandMoreIcon />
                  </IconButton>
                }, children);
            }
          })()}

        </ToolbarGroup>

      </Toolbar>
    );
  }
}
<|endoftext|>


<commit_before>(function() {
  "use strict";

  // Module properties
  // -----------------
  // caching references
  // existing Skin is kept as oldSkin
  var that    = this,
      oldSkin = that.Skin;

  // Skin class definition
  // ---------------------
  var Skin = that.Skin = function() {
    // private
    // -------
    var options = {};
    var recipes = {};
    var parseOptionString = function(optionString) {};
    var parseOptions = function(options) {};
    var set = function(key, value) {};
    var loadModule = function(module) {};

    // public interface
    // ----------------
    return {
      // capture ('option'), ('key', value) and ({key: value}) formats
      configure: function(key, value) {
        if (value && typeof(key) === 'string') set(key, value);
      }
    };
  };

  // Skin static properties
  // ----------------------
  Skin.VERSION = '0.0.0';
  Skin.defaults = {
    // plugin name, unique id prefix etc.
    alias: 'skin',
    // include the parser or not
    // parser will scan HTML,
    // detects Skin data and
    // wires up events to states and actions
    parse: true,
    // include the sensor or not
    // sensor will detect browsers supported events
    // and hooks them into more complex ones
    sense: true,
    // default method mapping
    // if null, a default map will be used to jQuery or Zepto methods
    // otherwise it should be the name of the module which implements mapping
    // or provides adapter for required methods such as
    // $(), extend(), addClass(), removeClass(), bind() etc.
    hooks: null
  };

  // Skin static methods
  // ----------------------
  // assign cached Skin back and return this object
  // e.g. var newSkin = Skin.noConflict();
  //      var Skin    = { someOtherObject: 'should be defined after Skin.noConflict()' }
  Skin.noConflict = function() {
    that.Skin = oldSkin;
    return this;
  };

  // View class definition
  // ---------------------
  Skin.View = function(options, extras) {
    // private
    // uniqueId
    // reuseClass
    //
    // $owner
    // $element
    // $target
    //
    // data:
    // template:
    //
    // options: {
    //
    // }
    //
    // create:
    // initialize:
    // configure:
    // refresh:
    // finalize:
    //
    // show:
    // hide:
    // enable:
    // disable:
    // activate:
    // inactivate:
    // expose:
    // silent:
    // state: function(state) {}

    // public
    return {

    };
  };

}).call(this);<commit_msg>amd loader method should be configurable<commit_after>(function() {
  "use strict";

  // Module properties
  // -----------------
  // caching references
  // existing Skin is kept as oldSkin
  var that    = this,
      oldSkin = that.Skin;

  // Skin class definition
  // ---------------------
  var Skin = that.Skin = function(options) {
    // private
    // -------
    var options = {};
    var recipes = {};
    var initialize = function() {
      // initialize, parse options, load modules
      console.log('initializing..22');

    }
    var parseOptionString = function(optionString) {};
    var parseOptions = function(options) {};
    var set = function(key, value) {};

    // execute initialize
    initialize();

    // public interface
    // ----------------
    return {
      // capture ('option'), ('key', value) and ({key: value}) formats
      configure: function(key, value) {
        if (value && typeof(key) === 'string') set(key, value);
      }
    };
  };

  // Skin static properties
  // ----------------------
  Skin.VERSION = '0.0.0';
  Skin.defaults = {
    // plugin name, unique id prefix etc.
    alias: 'skin',
    // include the parser or not
    // parser will scan HTML,
    // detects Skin data and
    // wires up events to states and actions
    parse: true,
    // include the sensor or not
    // sensor will detect browsers supported events
    // and hooks them into more complex ones
    sense: true,
    // default method to load modules
    load: function(name, dependencies, callback) {
      // based on define() method proposed by CommonJS
      // for Asynchronous Module Definition (AMD)
      define(modules);
    },
    // default method mapping to other libraries such as
    // jQuery, Zepto, Backbone, Underscore etc.
    // also can be the module name which implements mapping
    // in this case it will be loaded by loader
    plugin: that.$,
    select: that.$,
    extend: that.$.extend
  };

  // Skin static methods
  // ----------------------
  // assign cached Skin back and return this object
  // should be at the beginning of other codes
  // e.g. var NewSkin = Skin.noConflict();
  //      var newSkin = new NewSkin({alias: 'newSkin'});
  //      var Skin    = { someOtherObject: 'should be defined after Skin.noConflict()' }
  Skin.noConflict = function() {
    that.Skin = oldSkin;
    return this;
  };

  // View class definition
  // ---------------------
  Skin.View = function(options, extras) {
    // private
    // uniqueId
    // reuseClass
    //
    // $owner
    // $element
    // $target
    //
    // data:
    // template:
    //
    // options: {
    //
    // }
    //
    // create:
    // initialize:
    // configure:
    // refresh:
    // finalize:
    //
    // show:
    // hide:
    // enable:
    // disable:
    // activate:
    // inactivate:
    // expose:
    // silent:
    // state: function(state) {}

    // public
    return {

    };
  };

}).call(this);<|endoftext|>