<commit_before>/*
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      This file is part of the Smart Developer Hub Project:
        http://www.smartdeveloperhub.org/
      Center for Open Middleware
            http://www.centeropenmiddleware.com/
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Copyright (C) 2015 Center for Open Middleware.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      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.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
*/

(function() {

    /**
     *
     * @param configuration
     * @returns {*}
     */
    var normalizeConfig = function normalizeConfig(configuration) {
        if (configuration == null) {
            configuration = {};
        }

        var defaultConfig = {
            columns: {
                type: 'object',
                default: []
            },
            height: {
                type: 'number',
                default: 240
            },
            filterControl: {
                type: 'boolean',
                default: false
            },
            paginationControl: {
                type: 'boolean',
                default: false
            },
            lengthControl: {
                type: 'boolean',
                default: false
            },
            tableInfo: {
                type: 'boolean',
                default: false
            },
            selectable: {
                type: 'boolean',
                default: true
            },
            maxRowsSelected: {
                type: 'number',
                default: 1
            },
            minRowsSelected: {
                type: 'number',
                default: 0
            },
            initialSelectedRows: {
                type: 'number',
                default: 0
            },
            updateContexts: {
                type: 'object',
                default: null
            }

        };

        for(var confName in defaultConfig) {
            var conf = defaultConfig[confName];
            if (typeof configuration[confName] != conf['type']) {
                configuration[confName] = conf['default'];
            }
        }

        return configuration;
    };

    /* Table constructor
     *   element: the DOM element that will contain the rangeNv
     *   data: the resources array. It should contain only a resource, or at least the same resources with different
     *      parameters.
     *   contextId: optional.
     *   configuration: additional table configuration:
     *      {
     *       ~ height: number - Height of the widget.
     *       ~ filterControl: boolean - Whether to display the search filter control or not.
     *       ~ paginationControl: boolean - Whether to display the pagination control or not.
     *       ~ lengthControl: boolean - Whether to display a selector with the number of rows to show or not.
     *       ~ tableInfo: boolean - Whether to show extra info about the table or not.
     *       ~ selectable: boolean - If true, the rows of this table can be selected. When selected, the contexts are
     *          are updated with the data updateContexts indicates.
     *       ~ maxRowsSelected: number - Maximum number of rows that can be selected at the same time. Default: 1.
     *       ~ minRowsSelected: number - Minimum number of rows that must be selected at the same time. Default: 0.
     *       ~ initialSelectedRows: number - Number of rows that must be selected at the beginning. Default: 0.
     *       ~ updateContexts: array - Array of objects that configure how to update the contexts. It must contain an id with
     *          the id of the context and a filter array with the data to send through the context update.
     *          Each filter must contain a 'property' property with the name of the property of the data retrieved from
     *          the framework and can optionally add an 'as' property to indicate the name that it must have in the
     *          object that will be sent through the updateContext.
     *          Format:
     *          {
     *               id: <String>,
     *               filter: [
     *                   {
     *                       property: <String>,
     *                       as: <String> //optional
     *                   }
     *               ]
     *          }
     *          Example (listing all the repositories):
     *          {
     *               id: "repoContext",
     *               filter: [
     *                   {
     *                       property: "repositoryid",
     *                       as: "rid"
     *                   }
     *               ]
     *          }
     *       ~ columns: array - Array of objects with the configuration of all the columns to display in the table.
     *          Column object contains a 'label' and a 'property' or a link. Additionally it can contain a 'width' that
     *          may take any CSS value (3em, 20px, 10%, etc). Please note that pixel perfect column width is virtually
     *          impossible to achieve in tables with dynamic content.
     *          In case of a property, it is the name of the property of the data retrieved from the framework that
     *          must be displayed in that column.
     *          In case of a link, it displays a link to change to other dashboard. A link is an object with multiple
     *          properties: a 'href' with the name of the dashboard to go to, an 'icon' (class of the icon to display)
     *          or a 'label' (text) to display, and an 'env' that configures the environment info to send to the
     *          new dashboard. The 'env' property is an array of objects that contains a 'property' and an optional 'as'.
     *          Format:
     *          {
     *               label: <String>,
     *               property: <String>
     *           },
     *           {
     *              label: "Show",
     *               link: {
     *                   icon: <String>, //or label: <String>
     *                   href: <String>,
     *                   env: [
     *                       {
     *                           property: <String>,
     *                           as: <String>
     *                       }
     *                   ]
     *               }
     *          }, ...
     *          Example (listing all the repositories and changing to the dashboard of the selected repository):
     *          {
     *               label: "Name",
     *               property: "name"
     *           },
     *           {
     *              label: "Go to",
     *               link: {
     *                   icon: "fa fa-share-square-o",
     *                   href: "repository-dashboard",
     *                   env: [
     *                       {
     *                           property: "repositoryid",
     *                           as: "rid"
     *                       }
     *                   ]
     *               }
     *          }
     *      }
     */
    var Table = function Table(element, metrics, contextId, configuration) {

        if(!framework.isReady()) {
            console.error("Table object could not be created because framework is not loaded.");
            return;
        }

        this.element = $(element); //Store as jquery object
        this.data = null;
        this.tableDom = null;
        this.table = null;

        // Extending widget
        framework.widgets.CommonWidget.call(this, false, this.element.get(0));

        // Configuration
        this.configuration = normalizeConfig(configuration);

        this.observeCallback = this.commonObserveCallback.bind(this);

        framework.data.observe(metrics, this.observeCallback , contextId);

    };

    Table.prototype = new framework.widgets.CommonWidget(true);

    /**
     *
     * @param framework_data
     */
    Table.prototype.updateData = function(framework_data) {

        if(this.tableDom == null) {

            //Create the html for the table
            this.element.append('

');
            this.tableDom = this.element.children("table");
            this.tableDom.get(0).style.maxHeight = this.configuration.height + "px";

            //Add click listener for links
            this.tableDom.on( 'click', '.dashboardLink', this, dashboardLinkClickHandler);

            //Handle clicks in rows to select them or not
            if(this.configuration.selectable) {
                this.tableDom.on('click', 'tbody tr', this, rowClickHandler);
            }
        }

        var normalizedData = getNormalizedData.call(this,framework_data);

        var head = this.tableDom.find("thead tr");
        head.empty();

        for(var i in this.configuration.columns) {
            head.append("" + this.configuration.columns[i]['label'] + "	")
        }

        //Create dom configuration string
        var dom = "";
        if(this.configuration.filterControl) dom += '<"table-search"f>';
        if(this.configuration.lengthControl) dom += 'l';
        dom += "t";
        if(this.configuration.tableInfo) dom += 'i';
        if(this.configuration.paginationControl) dom += 'p';

        // Get columns
        var columns = [];
        for(var i in this.configuration.columns) {

            var columnConfig = this.configuration.columns[i];
            var column = null;

            if(columnConfig['property'] != null) { //Is a property
                column = { data: columnConfig['property'] };

            } else if(columnConfig['link'] != null && columnConfig['link']['href'] != null) { //Is a link
                column = {
                    data: function(){ return columnConfig['link']; },
                    orderable: false,
                    searchable: false,
                    render: columnIconRenderer
                };

            }

            //If it has the required properties
            if(column != null) {

                if(columnConfig['width'] != null) {
                    column['width'] = columnConfig['width'];
                }

                columns.push(column);
            }

        }

        //Destroy the table it already exists
        if(this.table != null) {
            this.table.destroy();
        }

        //DataTable object
        this.table = this.tableDom.DataTable({
            data: normalizedData,
            dom: dom,
            columns: columns,
            "oLanguage": {
                "sSearch": ""
            }
        });

        // If some rows must be selected from the beginning
        if(this.configuration.selectable && this.configuration.initialSelectedRows > 0) {

            //Select the first n rows
            this.table.$('tr').slice(0, this.configuration.initialSelectedRows).addClass('selected');

            //Update the contexts with the new selected rows
            updateContexts.call(this);
        }

    };

    /**
     * Deletes the widget.
     */
    Table.prototype.delete = function() {

        //Stop observing for data changes
        framework.data.stopObserve(this.observeCallback);

        if(this.tableDom != null) {
            //Remove event listeners
            this.tableDom.off();

            //Destroy DataTable
            this.table.destroy();

            //Clear DOM
            this.tableDom.empty();
        }

        //Remove all DOM the elements added to element
        this.element.empty();

        this.tableDom = null;
        this.table = null;

    };

    // PRIVATE METHODS - - - - - - - - - - - - - - - - - - - - - -

    /**
     * Renderer for columns that contain links.
     * @param linkInfo Info about the link. Must contain an icon property (with the class of the icon to display)
     *           or a label property (with the text to display).
     *           See https://datatables.net/reference/option/columns.render#function
     * @param type See https://datatables.net/reference/option/columns.render#function
     * @param rowData See https://datatables.net/reference/option/columns.render#function
     * @returns {*}
     */
    var columnIconRenderer = function columnIconRenderer(linkInfo, type, rowData) {

        if ( type === 'display' ) {

            if (linkInfo['icon'] != null) { //It is an icon
                return '

';
            } else { //Just a label
                return '
' + linkInfo['label'] + '
';
            }

        }

        return linkInfo;

    };

    /**
     * Function that handles the click in a dashboard link.
     * @param e
     */
    var dashboardLinkClickHandler = function dashboardLinkClickHandler(e) {

        e.stopImmediatePropagation(); // stop the row selection when clicking on an icon

        var widget = e.data;
        var cell = $(this).parent();

        var linkInfo = widget.table.cell(cell).data();
        var rowData = widget.table.row(cell.parent()).data();

        //Generate the env
        var env = null;
        if (linkInfo['env'] != null) {
            env = generateEnv(linkInfo['env'], rowData);
        }

        //Change the dashboard
        framework.dashboard.changeTo(linkInfo['href'], env);

    };

    /**
     * Function that handles clicks in rows. When selecting a row it may be necessary to update contexts.
     * @param e
     */
    var rowClickHandler = function rowClickHandler(e) {
        e.stopImmediatePropagation();
        var widget = e.data;

        if ( $(this).hasClass('selected') ) { //It is already selected

            //Select it if the maximum of selected rows has not been achieved
            if(widget.table.$('tr.selected').length > widget.configuration.minRowsSelected) {
                $(this).removeClass('selected');
            }

        } else { //Not selected

            //Select it if the maximum of selected rows has not been achieved
            if(widget.configuration.maxRowsSelected > widget.table.$('tr.selected').length) {
                $(this).addClass('selected');
            }

        }

        // Update contexts with the selected rows
        updateContexts.call(widget);

    };

    /**
     * Update the contexts with the selected rows
     */
    var updateContexts = function updateContexts(){

        // Update contexts
        var contexts = this.configuration.updateContexts;
        if(contexts != null) {

            for(var i in contexts) {
                var context = contexts[i];

                if(context['id'] != null) {

                    // Data to send through the context
                    var data = {};

                    // Filter the data to send through the context update
                    if(context['filter'] != null) {
                        for(var f = 0; f < context['filter'].length; ++f) {

                            var filter = context['filter'][f];
                            var property = filter['property'];
                            var as = filter['as'] || property;

                            if(data[as] == null) {
                                data[as] = [];
                            }

                            //Selected items
                            var selected = this.table.$('tr.selected');

                            //Calculate the data to send for all the selected rows
                            for(var s = 0, len = selected.length; s < len; ++s) {

                                var selectedData = this.table.row(selected[s]).data();
                                var propertyValue = selectedData[property];

                                if(property != null && typeof propertyValue !== 'undefined') {
                                    data[as].push(propertyValue);
                                }

                            }
                        }

                    }

                    //Send the update context
                    framework.data.updateContext(context['id'], data);
                }
            }
        }

    };

    /**
     * Generates an environment object containing all the information of the environment
     * @param envProperty The env configuration property
     * @param rowData Al, the data of the row.
     * @returns {{}}
     */
    var generateEnv = function generateEnv(envProperty, rowData) {

        var env = {};

        for(var e = 0; e < envProperty.length; ++e) {

            var envEntry = envProperty[e];
            var property, as, envValue;

            if(envEntry['property'] != null) {

                property = envEntry['property'];
                as = envEntry['as'] || property;
                envValue = rowData[property];

            } else if(envEntry['currentEnv']) {

                property = envEntry['currentEnv'];
                as = envEntry['as'] || property;
                envValue = framework.dashboard.getEnv()[property];

            }

            if(typeof envValue !== 'undefined') {
                env[as] = envValue;
            }

        }

        return env;
    };

    /**
     * Gets a normalized array of data according to the chart expected input from the data returned by the framework.
     * @param framework_data
     * @returns {Array} Contains objects with 'label' and 'value'.
     */
    var getNormalizedData = function getNormalizedData(framework_data) {

        return this.extractAll(framework_data);

    };

    window.framework.widgets.Table = Table;

    // AMD compliant
    if ( typeof define === "function" && define.amd) {
        define( ['datatables',
            'css!sdh-framework/lib/jquery/datatables/css/jquery.dataTables.min'], function () { return Table; } );
    }

})();<commit_msg>[Widget][Table]Added img property<commit_after>/*
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      This file is part of the Smart Developer Hub Project:
        http://www.smartdeveloperhub.org/
      Center for Open Middleware
            http://www.centeropenmiddleware.com/
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      Copyright (C) 2015 Center for Open Middleware.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
      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.
    #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
*/

(function() {

    /**
     *
     * @param configuration
     * @returns {*}
     */
    var normalizeConfig = function normalizeConfig(configuration) {
        if (configuration == null) {
            configuration = {};
        }

        var defaultConfig = {
            columns: {
                type: 'object',
                default: []
            },
            height: {
                type: 'number',
                default: 240
            },
            filterControl: {
                type: 'boolean',
                default: false
            },
            paginationControl: {
                type: 'boolean',
                default: false
            },
            lengthControl: {
                type: 'boolean',
                default: false
            },
            tableInfo: {
                type: 'boolean',
                default: false
            },
            selectable: {
                type: 'boolean',
                default: true
            },
            maxRowsSelected: {
                type: 'number',
                default: 1
            },
            minRowsSelected: {
                type: 'number',
                default: 0
            },
            initialSelectedRows: {
                type: 'number',
                default: 0
            },
            updateContexts: {
                type: 'object',
                default: null
            }

        };

        for(var confName in defaultConfig) {
            var conf = defaultConfig[confName];
            if (typeof configuration[confName] != conf['type']) {
                configuration[confName] = conf['default'];
            }
        }

        return configuration;
    };

    /* Table constructor
     *   element: the DOM element that will contain the rangeNv
     *   data: the resources array. It should contain only a resource, or at least the same resources with different
     *      parameters.
     *   contextId: optional.
     *   configuration: additional table configuration:
     *      {
     *       ~ height: number - Height of the widget.
     *       ~ filterControl: boolean - Whether to display the search filter control or not.
     *       ~ paginationControl: boolean - Whether to display the pagination control or not.
     *       ~ lengthControl: boolean - Whether to display a selector with the number of rows to show or not.
     *       ~ tableInfo: boolean - Whether to show extra info about the table or not.
     *       ~ selectable: boolean - If true, the rows of this table can be selected. When selected, the contexts are
     *          are updated with the data updateContexts indicates.
     *       ~ maxRowsSelected: number - Maximum number of rows that can be selected at the same time. Default: 1.
     *       ~ minRowsSelected: number - Minimum number of rows that must be selected at the same time. Default: 0.
     *       ~ initialSelectedRows: number - Number of rows that must be selected at the beginning. Default: 0.
     *       ~ updateContexts: array - Array of objects that configure how to update the contexts. It must contain an id with
     *          the id of the context and a filter array with the data to send through the context update.
     *          Each filter must contain a 'property' property with the name of the property of the data retrieved from
     *          the framework and can optionally add an 'as' property to indicate the name that it must have in the
     *          object that will be sent through the updateContext.
     *          Format:
     *          {
     *               id: <String>,
     *               filter: [
     *                   {
     *                       property: <String>,
     *                       as: <String> //optional
     *                   }
     *               ]
     *          }
     *          Example (listing all the repositories):
     *          {
     *               id: "repoContext",
     *               filter: [
     *                   {
     *                       property: "repositoryid",
     *                       as: "rid"
     *                   }
     *               ]
     *          }
     *       ~ columns: array - Array of objects with the configuration of all the columns to display in the table.
     *          Column object contains a 'label' and a 'property' or a link. Additionally it can contain a 'width' that
     *          may take any CSS value (3em, 20px, 10%, etc). Please note that pixel perfect column width is virtually
     *          impossible to achieve in tables with dynamic content.
     *          In case of a property, it is the name of the property of the data retrieved from the framework that
     *          must be displayed in that column.
     *          In case of a link, it displays a link to change to other dashboard. A link is an object with multiple
     *          properties: a 'href' with the name of the dashboard to go to, an 'icon' (class of the icon to display),
     *          an 'img' whose value indicates the property that contains the url of the image to be displayed
     *          or a 'label' (text) to display, and an 'env' that configures the environment info to send to the
     *          new dashboard. The 'env' property is an array of objects that contains a 'property' and an optional 'as'.
     *          Format:
     *          {
     *               label: <String>,
     *               property: <String>
     *           },
     *           {
     *              label: "Show",
     *               link: {
     *                   icon: <String>, //or label: <String> or img: <String>
     *                   href: <String>,
     *                   env: [
     *                       {
     *                           property: <String>,
     *                           as: <String>
     *                       }
     *                   ]
     *               }
     *          }, ...
     *          Example (listing all the repositories and changing to the dashboard of the selected repository):
     *          {
     *               label: "Name",
     *               property: "name"
     *           },
     *           {
     *              label: "Go to",
     *               link: {
     *                   icon: "fa fa-share-square-o",
     *                   href: "repository-dashboard",
     *                   env: [
     *                       {
     *                           property: "repositoryid",
     *                           as: "rid"
     *                       }
     *                   ]
     *               }
     *          }
     *      }
     */
    var Table = function Table(element, metrics, contextId, configuration) {

        if(!framework.isReady()) {
            console.error("Table object could not be created because framework is not loaded.");
            return;
        }

        this.element = $(element); //Store as jquery object
        this.data = null;
        this.tableDom = null;
        this.table = null;

        // Extending widget
        framework.widgets.CommonWidget.call(this, false, this.element.get(0));

        // Configuration
        this.configuration = normalizeConfig(configuration);

        this.observeCallback = this.commonObserveCallback.bind(this);

        framework.data.observe(metrics, this.observeCallback , contextId);

    };

    Table.prototype = new framework.widgets.CommonWidget(true);

    /**
     *
     * @param framework_data
     */
    Table.prototype.updateData = function(framework_data) {

        if(this.tableDom == null) {

            //Create the html for the table
            this.element.append('

');
            this.tableDom = this.element.children("table");
            this.tableDom.get(0).style.maxHeight = this.configuration.height + "px";

            //Add click listener for links
            this.tableDom.on( 'click', '.dashboardLink', this, dashboardLinkClickHandler);

            //Handle clicks in rows to select them or not
            if(this.configuration.selectable) {
                this.tableDom.on('click', 'tbody tr', this, rowClickHandler);
            }
        }

        var normalizedData = getNormalizedData.call(this,framework_data);

        var head = this.tableDom.find("thead tr");
        head.empty();

        for(var i in this.configuration.columns) {
            head.append("" + this.configuration.columns[i]['label'] + "	")
        }

        //Create dom configuration string
        var dom = "";
        if(this.configuration.filterControl) dom += '<"table-search"f>';
        if(this.configuration.lengthControl) dom += 'l';
        dom += "t";
        if(this.configuration.tableInfo) dom += 'i';
        if(this.configuration.paginationControl) dom += 'p';

        // Get columns
        var columns = [];
        for(var i in this.configuration.columns) {

            var columnConfig = this.configuration.columns[i];
            var column = null;

            if(columnConfig['property'] != null) { //Is a property
                column = { data: columnConfig['property'] };

            } else if(columnConfig['link'] != null && columnConfig['link']['href'] != null) { //Is a link
                var _data = columnConfig['link'];
                column = {
                    data: function(){ return _data; },
                    orderable: false,
                    searchable: false,
                    render: columnIconRenderer
                };

            }

            //If it has the required properties
            if(column != null) {

                if(columnConfig['width'] != null) {
                    column['width'] = columnConfig['width'];
                }

                columns.push(column);
            }

        }

        //Destroy the table it already exists
        if(this.table != null) {
            this.table.destroy();
        }

        //DataTable object
        this.table = this.tableDom.DataTable({
            data: normalizedData,
            dom: dom,
            columns: columns,
            "oLanguage": {
                "sSearch": ""
            }
        });

        // If some rows must be selected from the beginning
        if(this.configuration.selectable && this.configuration.initialSelectedRows > 0) {

            //Select the first n rows
            this.table.$('tr').slice(0, this.configuration.initialSelectedRows).addClass('selected');

            //Update the contexts with the new selected rows
            updateContexts.call(this);
        }

    };

    /**
     * Deletes the widget.
     */
    Table.prototype.delete = function() {

        //Stop observing for data changes
        framework.data.stopObserve(this.observeCallback);

        if(this.tableDom != null) {
            //Remove event listeners
            this.tableDom.off();

            //Destroy DataTable
            this.table.destroy();

            //Clear DOM
            this.tableDom.empty();
        }

        //Remove all DOM the elements added to element
        this.element.empty();

        this.tableDom = null;
        this.table = null;

    };

    // PRIVATE METHODS - - - - - - - - - - - - - - - - - - - - - -

    /**
     * Renderer for columns that contain links.
     * @param linkInfo Info about the link. Must contain an icon property (with the class of the icon to display)
     *           or a label property (with the text to display).
     *           See https://datatables.net/reference/option/columns.render#function
     * @param type See https://datatables.net/reference/option/columns.render#function
     * @param rowData See https://datatables.net/reference/option/columns.render#function
     * @returns {*}
     */
    var columnIconRenderer = function columnIconRenderer(linkInfo, type, rowData) {

        if ( type === 'display' ) {

            if (linkInfo['icon'] != null) { //It is an icon
                return '

';
            } else if (linkInfo['img'] != null) { //It is an image
                return '

';
            }else { //Just a label
                return '
' + linkInfo['label'] + '
';
            }

        }

        return linkInfo;

    };

    /**
     * Function that handles the click in a dashboard link.
     * @param e
     */
    var dashboardLinkClickHandler = function dashboardLinkClickHandler(e) {

        e.stopImmediatePropagation(); // stop the row selection when clicking on an icon

        var widget = e.data;
        var cell = $(this).parent();

        var linkInfo = widget.table.cell(cell).data();
        var rowData = widget.table.row(cell.parent()).data();

        //Generate the env
        var env = null;
        if (linkInfo['env'] != null) {
            env = generateEnv(linkInfo['env'], rowData);
        }

        //Change the dashboard
        framework.dashboard.changeTo(linkInfo['href'], env);

    };

    /**
     * Function that handles clicks in rows. When selecting a row it may be necessary to update contexts.
     * @param e
     */
    var rowClickHandler = function rowClickHandler(e) {
        e.stopImmediatePropagation();
        var widget = e.data;

        if ( $(this).hasClass('selected') ) { //It is already selected

            //Select it if the maximum of selected rows has not been achieved
            if(widget.table.$('tr.selected').length > widget.configuration.minRowsSelected) {
                $(this).removeClass('selected');
            }

        } else { //Not selected

            //Select it if the maximum of selected rows has not been achieved
            if(widget.configuration.maxRowsSelected > widget.table.$('tr.selected').length) {
                $(this).addClass('selected');
            }

        }

        // Update contexts with the selected rows
        updateContexts.call(widget);

    };

    /**
     * Update the contexts with the selected rows
     */
    var updateContexts = function updateContexts(){

        // Update contexts
        var contexts = this.configuration.updateContexts;
        if(contexts != null) {

            for(var i in contexts) {
                var context = contexts[i];

                if(context['id'] != null) {

                    // Data to send through the context
                    var data = {};

                    // Filter the data to send through the context update
                    if(context['filter'] != null) {
                        for(var f = 0; f < context['filter'].length; ++f) {

                            var filter = context['filter'][f];
                            var property = filter['property'];
                            var as = filter['as'] || property;

                            if(data[as] == null) {
                                data[as] = [];
                            }

                            //Selected items
                            var selected = this.table.$('tr.selected');

                            //Calculate the data to send for all the selected rows
                            for(var s = 0, len = selected.length; s < len; ++s) {

                                var selectedData = this.table.row(selected[s]).data();
                                var propertyValue = selectedData[property];

                                if(property != null && typeof propertyValue !== 'undefined') {
                                    data[as].push(propertyValue);
                                }

                            }
                        }

                    }

                    //Send the update context
                    framework.data.updateContext(context['id'], data);
                }
            }
        }

    };

    /**
     * Generates an environment object containing all the information of the environment
     * @param envProperty The env configuration property
     * @param rowData Al, the data of the row.
     * @returns {{}}
     */
    var generateEnv = function generateEnv(envProperty, rowData) {

        var env = {};

        for(var e = 0; e < envProperty.length; ++e) {

            var envEntry = envProperty[e];
            var property, as, envValue;

            if(envEntry['property'] != null) {

                property = envEntry['property'];
                as = envEntry['as'] || property;
                envValue = rowData[property];

            } else if(envEntry['currentEnv']) {

                property = envEntry['currentEnv'];
                as = envEntry['as'] || property;
                envValue = framework.dashboard.getEnv()[property];

            }

            if(typeof envValue !== 'undefined') {
                env[as] = envValue;
            }

        }

        return env;
    };

    /**
     * Gets a normalized array of data according to the chart expected input from the data returned by the framework.
     * @param framework_data
     * @returns {Array} Contains objects with 'label' and 'value'.
     */
    var getNormalizedData = function getNormalizedData(framework_data) {

        return this.extractAll(framework_data);

    };

    window.framework.widgets.Table = Table;

    // AMD compliant
    if ( typeof define === "function" && define.amd) {
        define( ['datatables',
            'css!sdh-framework/lib/jquery/datatables/css/jquery.dataTables.min'], function () { return Table; } );
    }

})();<|endoftext|>


<commit_before>
<commit_msg><commit_after>HPieChart = HControl.extend({

  componentName: "piechart",

  constructor: function(_rect, _parentClass, _options) {

    if(this.isinherited) {
      this.base(_rect, _parentClass, _options);
    }
    else {
      this.isinherited = true;
      this.base(_rect, _parentClass, _options);
      this.isinherited = false;
    }

    this.type = '[HPieChart]';

    var _left = 0;
    var _top = 5;
    var _right = _left + _rect.width;
    var _bottom = _top + 20;
    var _newRect = new HRect(_left,_top,_right,_bottom);

    if (!this.label) {
      this.label = "Unknown";
    }

    this.pieTitle = new HStringView(
      new HRect(_newRect),
      this, {
        value: this.label
      }
    );

    this.pieTitle.setStyle("font-weight","bold");
    this.pieTitle.setStyle("text-align","center");

    if (!this.options.imgWidth) {
      this.options.imgWidth = 300;
    } else if (!this.options.imgHeight) {
      this.options.imgHeight = 300;
    }

    _newRect.offsetBy(10,40);
    _newRect.setSize(this.options.imgWidth,this.options.imgHeight);
    this.pieImage = new HImageView(
      new HRect(_newRect),
      this, {
        value: this.value
      }
    );

    _newRect.offsetBy(this.pieImage.rect.right,0);
    var _legWidth = _rect.width - _newRect.left - 15;
    var _legHeight = this.options.labels.length * 20;
    _newRect.setSize(_legWidth,_legHeight);

    this.pieLegend = new HView(
      new HRect(_newRect),
      this
    );
    this.pieLegend.setStyle("border","1px solid gray");

    var _labelRect = new HRect(30, 0, _legWidth, 20);
    var _ledRect = new HRect(10,3,20,13);

    for (var i=0;i<this.options.labels.length;i++) {
      this.legendLed = new HView(
        _ledRect,
        this.pieLegend
      );
      this.legendLed.setStyle("border","1px solid gray");
      _color = this.options.colors[i];
      this.legendLed.setStyle("background-color",_color);
      _ledRect.offsetBy(0,20);
      this.legendLabel = new HStringView(
        _labelRect,
        this.pieLegend,
        {value: this.options.labels[i]}
      );
    _labelRect.offsetBy(0,20);
    }

    if(!this.isinherited) {
      this.draw();
    }
  },

  draw: function() {
    this.base();
    this.drawRect();
  }

});
<|endoftext|>


<commit_before>define(function()
{
    "use strict";
    var Connector = {};

    Connector.BookTable = {
        mapStateToProps: function(state, ownProps)
        {
            var nominees = [];

            state.books.forEach(function(book)
            {
                // LOGGER.info("book = " + book);
                // LOGGER.info("nominations = " + state.bookToNomination[book]);
                nominees.push(
                {
                    book: book,
                    nominations: state.bookToNomination[book],
                });
            });

            return (
            {
                nominees: nominees,
            });
        },
    };

    if (Object.freeze)
    {
        Object.freeze(Connector);
    }

    return Connector;
});
<commit_msg>Added assessment feature.<commit_after>define(function()
{
    "use strict";
    var Connector = {};

    Connector.BookTable = {
        mapStateToProps: function(state, ownProps)
        {
            var nominees = [];

            state.books.forEach(function(book)
            {
                nominees.push(
                {
                    book: book,
                    nominations: state.bookToNomination[book],
                    assessmentKey: state.bookToAssessment[book],
                });
            });

            return (
            {
                nominees: nominees,
            });
        },
    };

    if (Object.freeze)
    {
        Object.freeze(Connector);
    }

    return Connector;
});
<|endoftext|>


<commit_before>/****************************************************************************
#
# This file is part of the Vilfredo Client.
#
# Copyright © 2009-2014 Pietro Speroni di Fenizio / Derek Paterson.
#
# VilfredoReloadedCore is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation version 3 of the License.
#
# VilfredoReloadedCore is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
# for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with VilfredoReloadedCore.  If not, see <http://www.gnu.org/licenses/>.
#
****************************************************************************/
var VILFREDO_URL = 'http://0.0.0.0:8080';

var API_VERSION = 'v1';

var ALGORITHM_VERSION = 1;

// Don't edit below
//
var VILFREDO_API = VILFREDO_URL + '/api/' + API_VERSION;

var STATIC_FILES = VILFREDO_URL + '/static';

var Q_READ = 0x1
var Q_VOTE = 0x2
var Q_PROPOSE = 0x4
var Q_INVITE = 0x8

<commit_msg>Add setting for vote radius<commit_after>/****************************************************************************
#
# This file is part of the Vilfredo Client.
#
# Copyright © 2009-2014 Pietro Speroni di Fenizio / Derek Paterson.
#
# VilfredoReloadedCore is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation version 3 of the License.
#
# VilfredoReloadedCore is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
# for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with VilfredoReloadedCore.  If not, see <http://www.gnu.org/licenses/>.
#
****************************************************************************/
var VILFREDO_URL = 'http://0.0.0.0:8080';

var API_VERSION = 'v1';

var ALGORITHM_VERSION = 1;

// radius of circle representing a vote
var radius = 10;

// Don't edit below
//
var VILFREDO_API = VILFREDO_URL + '/api/' + API_VERSION;

var STATIC_FILES = VILFREDO_URL + '/static';

var Q_READ = 0x1
var Q_VOTE = 0x2
var Q_PROPOSE = 0x4
var Q_INVITE = 0x8

<|endoftext|>


<commit_before>'use strict';

module.exports = function (grunt, options) {
    return {
        options: {
            files: ['package.json', 'bower.json'],
            updateConfigs: [],
            commit: true,
            commitMessage: 'Release v%VERSION%',
            commitFiles: [
                'package.json',
                'bower.json',
                'dist/angular-leaflet-directive.js',
                'dist/angular-leaflet-directive.min.js',
                'dist/angular-leaflet-directive_dev_mapped.js',
                'dist/angular-leaflet-directive_dev_mapped.js.map'
            ],
            createTag: true,
            tagName: 'v%VERSION%',
            tagMessage: 'Version %VERSION%',
            push: false,
            pushTo: 'origin',
            gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
        }
    };
};
<commit_msg>chore(bump): commit files added<commit_after>'use strict';

module.exports = function (grunt, options) {
    return {
        options: {
            files: ['package.json', 'bower.json'],
            updateConfigs: [],
            commit: true,
            commitMessage: 'Release v%VERSION%',
            commitFiles: [
                'CHANGELOG.md',
                'package.json',
                'bower.json',
                'dist/angular-leaflet-directive.js',
                'dist/angular-leaflet-directive.min.js',
                'dist/angular-leaflet-directive_dev_mapped.js',
                'dist/angular-leaflet-directive_dev_mapped.js.map',
                'dist/architecture/**/*'
            ],
            createTag: true,
            tagName: 'v%VERSION%',
            tagMessage: 'Version %VERSION%',
            push: false,
            pushTo: 'origin',
            gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
        }
    };
};
<|endoftext|>


<commit_before>document.addEventListener('DOMContentLoaded', ahoy_yo);

function ahoy_yo() {
    var a = document.querySelectorAll('[data-ahoy]');
    if (a && a.length) {
        for (var i in a) {
            if (a.hasOwnProperty(i) && a[i]) {
                a[i].addEventListener('click', function() {
                    yo(this.getAttribute('data-ahoy'));
                });
            }
        }
    }
    else {
        yo();
    }
}

function yo(sel) {
    var h, w, i, l, s, t = false, p = '';

    var yohoho_loading = document.querySelector('#yohoho-loading');
    if (yohoho_loading) {
        yohoho_loading.parentNode.removeChild(yohoho_loading);
    }
    var yohoho_iframe = document.querySelector('#yohoho-iframe');
    if (yohoho_iframe) {
        yohoho_iframe.parentNode.removeChild(yohoho_iframe);
    }
    var yohoho = document.querySelector('#' + ((sel) ? sel : 'yohoho'));
    if (!yohoho) {
        yohoho = document.querySelector('#yohoho-online');
        if (!yohoho) {
            yohoho = document.querySelector('#yohoho-torrent');
            if (!yohoho) {
                return false;
            }
            else {
                t = true;
            }
        }
    }

    var options = [].slice.call(yohoho.attributes).reduce(function (o, a) {
        return /^data-/.test(a.name) && (o[a.name.substr(5)] = a.value), o;
    }, {});

    if (options.title && options.title.indexOf('трейлер')+1 || t) {
        options.player = 'trailer';
    }

    options.player = (options.title && options.title.indexOf('трейлер')+1 || t)
        ? 'trailer'
        : (!options.player)
            ? 'moonwalk,hdgo,kodik,allserials,iframe,trailer,torrent'
            : options.player;

    var bg = (options.bg && options.bg.replace(/[^0-9a-z]/ig, ''))
        ? options.bg.replace(/[^0-9a-z]/ig, '')
        : '2A3440';

    var btns = {};
    if (options.button) {
        options.button.split(',').forEach(function (button) {
            var btn = button.split(':');
            if (btn.length === 2 && btn[0] && btn[1]) {
                btns[btn[0].trim().toLowerCase()] = btn[1].trim();
            }
        });
    }

    for (var data in options) {
        if (options.hasOwnProperty(data) && options[data]) {
            p += (p)
                ? '&' + data + '=' + encodeURIComponent(options[data])
                : data + '=' + encodeURIComponent(options[data]);
        }
        else {
            options[data] = '';
        }
    }

    if (!options.kinopoisk && !options.title) {
        return false;
    }

    var head = document.head || document.getElementsByTagName('head')[0];
    var css = '#yohoho{border:0;margin:0;padding:0;overflow:hidden;position:relative}#yohoho-loading{z-index:9999;position:absolute;left:0;top:0;width:100%;height:100%;background:#' + bg + ' url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjEyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiIGNsYXNzPSJ1aWwtc3BpcmFsIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgY2xhc3M9ImJrIiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTU0LjUgODkuOWMtOS42IDAtMTguNi0zLjktMjUuNC0xMSAtNi44LTcuMS0xMC41LTE2LjYtMTAuNS0yNi43IDAtOC45IDMuMy0xNy4yIDkuMi0yMy41UzQxLjcgMTkgNTAuMiAxOWM4LjQgMCAxNi40IDMuNCAyMi4zIDkuNyA2IDYuMyA5LjIgMTQuNiA5LjIgMjMuNSAwIDE1LjgtMTIuMiAyOC43LTI3LjMgMjguNyAtMTUgMC0yNy4zLTEyLjktMjcuMy0yOC43IDAtMTMuMyAxMC4zLTI0LjIgMjMtMjQuMnMyMyAxMC44IDIzIDI0LjJjMCAxMC44LTguNCAxOS42LTE4LjcgMTkuNiAtMTAuMyAwLTE4LjctOC44LTE4LjctMTkuNiAwLTguMyA2LjUtMTUuMSAxNC40LTE1LjEgNy45IDAgMTQuNCA2LjggMTQuNCAxNS4xIDAgNS44LTQuNSAxMC42LTEwLjEgMTAuNnMtMTAuMS00LjgtMTAuMS0xMC42YzAtMy40IDIuNi02LjEgNS44LTYuMSAzLjIgMCA1LjggMi43IDUuOCA2LjEgMCAwLjktMC43IDEuNi0xLjUgMS42IC0wLjggMC0xLjUtMC43LTEuNS0xLjYgMC0xLjYtMS4zLTIuOS0yLjgtMi45IC0xLjUgMC0yLjggMS4zLTIuOCAyLjkgMCA0LjEgMy4yIDcuNCA3LjEgNy40czcuMS0zLjMgNy4xLTcuNGMwLTYuNi01LjEtMTItMTEuNC0xMiAtNi4zIDAtMTEuNCA1LjQtMTEuNCAxMiAwIDkuMSA3IDE2LjUgMTUuNyAxNi41IDguNiAwIDE1LjctNy40IDE1LjctMTYuNSAwLTExLjYtOS0yMS0yMC0yMXMtMjAgOS40LTIwIDIxYzAgMTQuMSAxMC45IDI1LjUgMjQuMyAyNS41czI0LjMtMTEuNCAyNC4zLTI1LjVjMC0xNi42LTEyLjgtMzAtMjguNi0zMCAtMTUuOCAwLTI4LjYgMTMuNS0yOC42IDMwIDAgOS4yIDMuNCAxNy45IDkuNiAyNC40IDYuMiA2LjUgMTQuNSAxMC4xIDIzLjIgMTAuMXMxNy0zLjYgMjMuMi0xMC4xYzYuMi02LjUgOS42LTE1LjIgOS42LTI0LjQgMC0xMC40LTMuOS0yMC4yLTEwLjktMjcuNiAtNy03LjQtMTYuMy0xMS40LTI2LjMtMTEuNHMtMTkuMyA0LjEtMjYuMyAxMS40UzEzIDQxLjggMTMgNTIuMmMwIDAuOS0wLjcgMS42LTEuNSAxLjZTMTAgNTMuMSAxMCA1Mi4yYzAtMTEuMyA0LjItMjEuOSAxMS44LTI5LjkgNy42LTggMTcuNy0xMi40IDI4LjQtMTIuNCAxMC43IDAgMjAuOCA0LjQgMjguNCAxMi40IDcuNiA4IDExLjggMTguNiAxMS44IDI5LjkgMCAxMC4xLTMuNyAxOS41LTEwLjUgMjYuN0M3My4xIDg2IDY0LjEgODkuOSA1NC41IDg5Ljl6IiBmaWxsPSIjZmZmIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgZnJvbT0iMCA1MCA1MCIgdG89IjM2MCA1MCA1MCIgZHVyPSIxcyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz48L3BhdGg+PC9zdmc+) 50% 50% no-repeat}#yohoho-buttons{position:absolute;z-index:9999;right:0;top:50px;text-align:left}#yohoho-buttons:hover{right:0!important}#yohoho-buttons div{font-family:Verdana,sans-serif;font-weight:normal;text-shadow:none;line-height:normal;font-size:12px;color:#fff;background:#' + bg + ';border-radius:5px 0 0 5px;padding:5px;margin:5px 0 5px 5px;opacity:.7;}#yohoho-buttons div:hover,#yohoho-buttons div.yohoho-active{color:#fff;background:#' + bg + ';cursor:pointer;opacity:1}';
    s = document.createElement('style');
    s.type = 'text/css';
    if (s.styleSheet) {
        s.styleSheet.cssText = css;
    }
    else {
        s.appendChild(document.createTextNode(css));
    }
    head.appendChild(s);

    l = document.createElement('div');
    l.setAttribute('id', 'yohoho-loading');
    yohoho.innerHTML = '';
    yohoho.appendChild(l);

    i = document.createElement('iframe');
    i.setAttribute('id', 'yohoho-iframe');
    i.setAttribute('frameborder', '0');
    i.setAttribute('allowfullscreen', 'allowfullscreen');
    yohoho.appendChild(i);

    if (parseInt(yohoho.offsetWidth)) {
        w = parseInt(yohoho.offsetWidth);
    }
    else if (parseInt(yohoho.parentNode.offsetWidth)) {
        w = (yohoho.parentNode.offsetWidth);
    }
    else {
        w = 610;
    }

    if (parseInt(yohoho.offsetHeight) && w/3 < parseInt(yohoho.offsetHeight)) {
        h = parseInt(yohoho.offsetHeight);
    }
    else if (parseInt(yohoho.parentNode.offsetHeight) && w/3 < parseInt(yohoho.parentNode.offsetHeight)) {
        h = parseInt(yohoho.parentNode.offsetHeight);
    }
    else {
        h = w/2;
    }

    var style = 'width:' + w + 'px;height:' + h + 'px';
    i.setAttribute('style', style);
    i.setAttribute('width', w);
    i.setAttribute('height', h);
    yohoho.setAttribute('style', style);

    var protocol = window.top.location.protocol || 'http';
    httpGetAsync(protocol + '//4h0y.yohoho.cc', p,
        function (players) {
            var first = true;
            var buttons = document.createElement('div');
            buttons.setAttribute('id', 'yohoho-buttons');
            var keys = options.player.split(',');
            var j = 0;
            for (var i = 0, len = keys.length; i < len; i++) {
                var key = keys[i].toLowerCase().trim();
                if (players.hasOwnProperty(key) && players[key]) {
                    players[key] = (key === 'moonwalk' && options.start_time)
                        ? (players[key].indexOf('?')+1)
                            ? players[key] + '&start_time=' + options.start_time
                            : players[key] + '?start_time=' + options.start_time
                        : players[key];
                    var option = document.createElement('div');
                    option.setAttribute('onclick', 'showPlayer("' + players[key] + '", this)');
                    option.dataset.iframe = players[key];
                    if (btns.hasOwnProperty(key) && btns[key]) {
                        j++;
                        option.innerText = j + '►' + btns[key];
                    }
                    else if (key === 'trailer') {
                        j++;
                        option.innerText = j + '► ТРЕЙЛЕР';
                    }
                    else if (key === 'torrent') {
                        j++;
                        option.innerText = j + '► СКАЧАТЬ';
                    }
                    else {
                        j++;
                        option.innerText = j + '► ' + key.toUpperCase();
                    }
                    if (first) {
                        showPlayer(players[key], option, buttons);
                        first = false;
                    }
                    buttons.appendChild(option);
                }
            }
            if (j < 1) {
                var yohohoLoading = document.querySelector('#yohoho-loading');
                yohohoLoading.style.display = 'none';
            }
            else if (j > 1) {
                document.querySelector('#yohoho').appendChild(buttons);
            }
        });

}

function showPlayer(iframe, element, buttons) {
    var yohohoLoading = document.querySelector('#yohoho-loading');
    yohohoLoading.style.display = 'block';
    setTimeout(function () {
        yohohoLoading.style.display = 'none';
    },2000);
    var yohohoIframe = document.querySelector('#yohoho-iframe');
    yohohoIframe.style.display = 'block';
    yohohoIframe.setAttribute('src', iframe);
    yohohoIframe.setAttribute('class', '');
    if (typeof element.setAttribute === 'function') {
        var yohohoActive = document.querySelectorAll('.yohoho-active');
        if (yohohoActive) {
            for (var i = 0; i < yohohoActive.length; i++) {
                yohohoActive[i].setAttribute('class', '');
            }
        }
        element.setAttribute('class', 'yohoho-active');
    }
    var yohohoButtons = (buttons) ? buttons : document.querySelector('#yohoho-buttons');
    if (yohohoButtons) {
        yohohoButtons.style.right = 0;
        setTimeout(function () {
            var btn = setInterval(function () {
                if (parseInt(yohohoButtons.style.right) > -parseInt(yohohoButtons.offsetWidth)+30)  {
                    yohohoButtons.style.right = (parseInt(yohohoButtons.style.right)-1) + 'px';
                }
                else {
                    clearInterval(btn);
                }
            }, 5);
        }, 5000);
    }
}

function httpGetAsync(url, body, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            callback(tryParseJSON(xmlHttp.responseText));
        }
    };
    xmlHttp.open('POST', url, true);
    xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xmlHttp.send(body);
}

function tryParseJSON(jsonString) {
    try {
        var o = JSON.parse(jsonString);
        if (o && typeof o === "object") {
            return o;
        }
    }
    catch (e) { }
    return {};
}<commit_msg>data-ahoy del elem<commit_after>document.addEventListener('DOMContentLoaded', ahoy_yo);

function ahoy_yo() {
    var a = document.querySelectorAll('[data-ahoy]');
    if (a && a.length) {
        for (var i in a) {
            if (a.hasOwnProperty(i) && a[i]) {
                a[i].addEventListener('click', function() {
                    yo(this.getAttribute('data-ahoy'));
                });
            }
        }
    }
    else {
        yo();
    }
}

function yo(sel) {
    var h, w, i, l, s, t = false, p = '';

    var yohoho = document.querySelector('#' + ((sel) ? sel : 'yohoho'));
    if (!yohoho) {
        yohoho = document.querySelector('#yohoho-online');
        if (!yohoho) {
            yohoho = document.querySelector('#yohoho-torrent');
            if (!yohoho) {
                return false;
            }
            else {
                t = true;
            }
        }
    }

    var options = [].slice.call(yohoho.attributes).reduce(function (o, a) {
        return /^data-/.test(a.name) && (o[a.name.substr(5)] = a.value), o;
    }, {});

    if (options.title && options.title.indexOf('трейлер')+1 || t) {
        options.player = 'trailer';
    }

    options.player = (options.title && options.title.indexOf('трейлер')+1 || t)
        ? 'trailer'
        : (!options.player)
            ? 'moonwalk,hdgo,kodik,allserials,iframe,trailer,torrent'
            : options.player;

    var bg = (options.bg && options.bg.replace(/[^0-9a-z]/ig, ''))
        ? options.bg.replace(/[^0-9a-z]/ig, '')
        : '2A3440';

    var btns = {};
    if (options.button) {
        options.button.split(',').forEach(function (button) {
            var btn = button.split(':');
            if (btn.length === 2 && btn[0] && btn[1]) {
                btns[btn[0].trim().toLowerCase()] = btn[1].trim();
            }
        });
    }

    for (var data in options) {
        if (options.hasOwnProperty(data) && options[data]) {
            p += (p)
                ? '&' + data + '=' + encodeURIComponent(options[data])
                : data + '=' + encodeURIComponent(options[data]);
        }
        else {
            options[data] = '';
        }
    }

    if (!options.kinopoisk && !options.title) {
        return false;
    }

    var yohoho_loading = document.querySelector('#yohoho-loading');
    if (yohoho_loading) {
        yohoho_loading.parentNode.removeChild(yohoho_loading);
    }
    var yohoho_buttons = document.querySelector('#yohoho-buttons');
    if (yohoho_buttons) {
        yohoho_buttons.parentNode.removeChild(yohoho_buttons);
    }
    var yohoho_iframe = document.querySelector('#yohoho-iframe');
    if (yohoho_iframe) {
        yohoho_iframe.parentNode.removeChild(yohoho_iframe);
    }

    var head = document.head || document.getElementsByTagName('head')[0];
    var css = '#yohoho{border:0;margin:0;padding:0;overflow:hidden;position:relative}#yohoho-loading{z-index:9999;position:absolute;left:0;top:0;width:100%;height:100%;background:#' + bg + ' url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjEyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiIGNsYXNzPSJ1aWwtc3BpcmFsIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgY2xhc3M9ImJrIiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTU0LjUgODkuOWMtOS42IDAtMTguNi0zLjktMjUuNC0xMSAtNi44LTcuMS0xMC41LTE2LjYtMTAuNS0yNi43IDAtOC45IDMuMy0xNy4yIDkuMi0yMy41UzQxLjcgMTkgNTAuMiAxOWM4LjQgMCAxNi40IDMuNCAyMi4zIDkuNyA2IDYuMyA5LjIgMTQuNiA5LjIgMjMuNSAwIDE1LjgtMTIuMiAyOC43LTI3LjMgMjguNyAtMTUgMC0yNy4zLTEyLjktMjcuMy0yOC43IDAtMTMuMyAxMC4zLTI0LjIgMjMtMjQuMnMyMyAxMC44IDIzIDI0LjJjMCAxMC44LTguNCAxOS42LTE4LjcgMTkuNiAtMTAuMyAwLTE4LjctOC44LTE4LjctMTkuNiAwLTguMyA2LjUtMTUuMSAxNC40LTE1LjEgNy45IDAgMTQuNCA2LjggMTQuNCAxNS4xIDAgNS44LTQuNSAxMC42LTEwLjEgMTAuNnMtMTAuMS00LjgtMTAuMS0xMC42YzAtMy40IDIuNi02LjEgNS44LTYuMSAzLjIgMCA1LjggMi43IDUuOCA2LjEgMCAwLjktMC43IDEuNi0xLjUgMS42IC0wLjggMC0xLjUtMC43LTEuNS0xLjYgMC0xLjYtMS4zLTIuOS0yLjgtMi45IC0xLjUgMC0yLjggMS4zLTIuOCAyLjkgMCA0LjEgMy4yIDcuNCA3LjEgNy40czcuMS0zLjMgNy4xLTcuNGMwLTYuNi01LjEtMTItMTEuNC0xMiAtNi4zIDAtMTEuNCA1LjQtMTEuNCAxMiAwIDkuMSA3IDE2LjUgMTUuNyAxNi41IDguNiAwIDE1LjctNy40IDE1LjctMTYuNSAwLTExLjYtOS0yMS0yMC0yMXMtMjAgOS40LTIwIDIxYzAgMTQuMSAxMC45IDI1LjUgMjQuMyAyNS41czI0LjMtMTEuNCAyNC4zLTI1LjVjMC0xNi42LTEyLjgtMzAtMjguNi0zMCAtMTUuOCAwLTI4LjYgMTMuNS0yOC42IDMwIDAgOS4yIDMuNCAxNy45IDkuNiAyNC40IDYuMiA2LjUgMTQuNSAxMC4xIDIzLjIgMTAuMXMxNy0zLjYgMjMuMi0xMC4xYzYuMi02LjUgOS42LTE1LjIgOS42LTI0LjQgMC0xMC40LTMuOS0yMC4yLTEwLjktMjcuNiAtNy03LjQtMTYuMy0xMS40LTI2LjMtMTEuNHMtMTkuMyA0LjEtMjYuMyAxMS40UzEzIDQxLjggMTMgNTIuMmMwIDAuOS0wLjcgMS42LTEuNSAxLjZTMTAgNTMuMSAxMCA1Mi4yYzAtMTEuMyA0LjItMjEuOSAxMS44LTI5LjkgNy42LTggMTcuNy0xMi40IDI4LjQtMTIuNCAxMC43IDAgMjAuOCA0LjQgMjguNCAxMi40IDcuNiA4IDExLjggMTguNiAxMS44IDI5LjkgMCAxMC4xLTMuNyAxOS41LTEwLjUgMjYuN0M3My4xIDg2IDY0LjEgODkuOSA1NC41IDg5Ljl6IiBmaWxsPSIjZmZmIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgZnJvbT0iMCA1MCA1MCIgdG89IjM2MCA1MCA1MCIgZHVyPSIxcyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz48L3BhdGg+PC9zdmc+) 50% 50% no-repeat}#yohoho-buttons{position:absolute;z-index:9999;right:0;top:50px;text-align:left}#yohoho-buttons:hover{right:0!important}#yohoho-buttons div{font-family:Verdana,sans-serif;font-weight:normal;text-shadow:none;line-height:normal;font-size:12px;color:#fff;background:#' + bg + ';border-radius:5px 0 0 5px;padding:5px;margin:5px 0 5px 5px;opacity:.7;}#yohoho-buttons div:hover,#yohoho-buttons div.yohoho-active{color:#fff;background:#' + bg + ';cursor:pointer;opacity:1}';
    s = document.createElement('style');
    s.type = 'text/css';
    if (s.styleSheet) {
        s.styleSheet.cssText = css;
    }
    else {
        s.appendChild(document.createTextNode(css));
    }
    head.appendChild(s);

    l = document.createElement('div');
    l.setAttribute('id', 'yohoho-loading');
    yohoho.innerHTML = '';
    yohoho.appendChild(l);

    i = document.createElement('iframe');
    i.setAttribute('id', 'yohoho-iframe');
    i.setAttribute('frameborder', '0');
    i.setAttribute('allowfullscreen', 'allowfullscreen');
    yohoho.appendChild(i);

    if (parseInt(yohoho.offsetWidth)) {
        w = parseInt(yohoho.offsetWidth);
    }
    else if (parseInt(yohoho.parentNode.offsetWidth)) {
        w = (yohoho.parentNode.offsetWidth);
    }
    else {
        w = 610;
    }

    if (parseInt(yohoho.offsetHeight) && w/3 < parseInt(yohoho.offsetHeight)) {
        h = parseInt(yohoho.offsetHeight);
    }
    else if (parseInt(yohoho.parentNode.offsetHeight) && w/3 < parseInt(yohoho.parentNode.offsetHeight)) {
        h = parseInt(yohoho.parentNode.offsetHeight);
    }
    else {
        h = w/2;
    }

    var style = 'width:' + w + 'px;height:' + h + 'px';
    i.setAttribute('style', style);
    i.setAttribute('width', w);
    i.setAttribute('height', h);
    yohoho.setAttribute('style', style);

    var protocol = window.top.location.protocol || 'http';
    httpGetAsync(protocol + '//4h0y.yohoho.cc', p,
        function (players) {
            var first = true;
            var buttons = document.createElement('div');
            buttons.setAttribute('id', 'yohoho-buttons');
            var keys = options.player.split(',');
            var j = 0;
            for (var i = 0, len = keys.length; i < len; i++) {
                var key = keys[i].toLowerCase().trim();
                if (players.hasOwnProperty(key) && players[key]) {
                    players[key] = (key === 'moonwalk' && options.start_time)
                        ? (players[key].indexOf('?')+1)
                            ? players[key] + '&start_time=' + options.start_time
                            : players[key] + '?start_time=' + options.start_time
                        : players[key];
                    var option = document.createElement('div');
                    option.setAttribute('onclick', 'showPlayer("' + players[key] + '", this)');
                    option.dataset.iframe = players[key];
                    if (btns.hasOwnProperty(key) && btns[key]) {
                        j++;
                        option.innerText = j + '►' + btns[key];
                    }
                    else if (key === 'trailer') {
                        j++;
                        option.innerText = j + '► ТРЕЙЛЕР';
                    }
                    else if (key === 'torrent') {
                        j++;
                        option.innerText = j + '► СКАЧАТЬ';
                    }
                    else {
                        j++;
                        option.innerText = j + '► ' + key.toUpperCase();
                    }
                    if (first) {
                        showPlayer(players[key], option, buttons);
                        first = false;
                    }
                    buttons.appendChild(option);
                }
            }
            if (j < 1) {
                var yohohoLoading = document.querySelector('#yohoho-loading');
                yohohoLoading.style.display = 'none';
            }
            else if (j > 1) {
                document.querySelector('#yohoho').appendChild(buttons);
            }
        });

}

function showPlayer(iframe, element, buttons) {
    var yohohoLoading = document.querySelector('#yohoho-loading');
    yohohoLoading.style.display = 'block';
    setTimeout(function () {
        yohohoLoading.style.display = 'none';
    },2000);
    var yohohoIframe = document.querySelector('#yohoho-iframe');
    yohohoIframe.style.display = 'block';
    yohohoIframe.setAttribute('src', iframe);
    yohohoIframe.setAttribute('class', '');
    if (typeof element.setAttribute === 'function') {
        var yohohoActive = document.querySelectorAll('.yohoho-active');
        if (yohohoActive) {
            for (var i = 0; i < yohohoActive.length; i++) {
                yohohoActive[i].setAttribute('class', '');
            }
        }
        element.setAttribute('class', 'yohoho-active');
    }
    var yohohoButtons = (buttons) ? buttons : document.querySelector('#yohoho-buttons');
    if (yohohoButtons) {
        yohohoButtons.style.right = 0;
        setTimeout(function () {
            var btn = setInterval(function () {
                if (parseInt(yohohoButtons.style.right) > -parseInt(yohohoButtons.offsetWidth)+30)  {
                    yohohoButtons.style.right = (parseInt(yohohoButtons.style.right)-1) + 'px';
                }
                else {
                    clearInterval(btn);
                }
            }, 5);
        }, 5000);
    }
}

function httpGetAsync(url, body, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            callback(tryParseJSON(xmlHttp.responseText));
        }
    };
    xmlHttp.open('POST', url, true);
    xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xmlHttp.send(body);
}

function tryParseJSON(jsonString) {
    try {
        var o = JSON.parse(jsonString);
        if (o && typeof o === "object") {
            return o;
        }
    }
    catch (e) { }
    return {};
}<|endoftext|>


<commit_before>;(function(angular) {

    'use strict';

    angular.module('k15t.auiNg')
        .directive('anMessagesContainer', function(anMessages) {

            var defaultTemplate = [
                '
',
                '
',
                '
',
                '           ',
                '           ',
                '
',
                '

',
                '
',
                '
'
            ].join('\n');

            return {
                restrict: 'A',
                scope: {},
                require: 'anMessagesContainer',
                controllerAs: 'messagesCtrl',
                template: defaultTemplate,
                controller: function() {
                    var that = this;

                    var uniqueId = (function() {
                        var id = 0;
                        return function() {
                            return id++;
                        };
                    })();

                    this.messages = [];

                    var defaults = {
                        severity: 'info',
                        title: null,
                        message: null
                    };

                    this.addMessage = function(opts) {
                        var id = uniqueId();
                        that.messages.push(angular.extend({$id: id}, defaults, opts));

                        return function() {
                            for (var i = 0, len = that.messages.length; i < len; i++) {
                                if (that.messages[i].$id === id) {
                                    that.messages = that.messages.splice(i, 1);
                                    break;
                                }
                            }
                        };
                    };

                    this.clearMessages = function() {
                        that.messages.length = 0;
                    };
                },
                link: function(scope, elm, attrs, ctrl) {
                    var id = attrs.anMessagesContainer;

                    if (!id) {
                        throw new Error('container id missing');
                    }

                    var unregister = anMessages.register(id, ctrl);

                    scope.$on('$destroy', unregister);
                }
            };
        }
    );

})(angular);
<commit_msg>messages now can have a property details and support inline styles<commit_after>;(function(angular) {

    'use strict';

    angular.module('k15t.auiNg')
        .directive('anMessagesContainer', function(anMessages) {

            // jscs:disable
            var defaultTemplate = [
                '
',
                '
',
                '
',
                '           ',
                '           ',
                '
',
                '
',
                '

',
                '

',
                '
',
                '
',
                '
'
            ].join('\n');
            // jscs:enable

            return {
                restrict: 'A',
                scope: {},
                require: 'anMessagesContainer',
                controllerAs: 'messagesCtrl',
                template: defaultTemplate,
                controller: function() {
                    var that = this;

                    var uniqueId = (function() {
                        var id = 0;
                        return function() {
                            return id++;
                        };
                    })();

                    this.messages = [];

                    var defaults = {
                        severity: 'info',
                        title: null,
                        message: null
                    };

                    this.addMessage = function(opts) {
                        var id = uniqueId();
                        that.messages.push(angular.extend({$id: id}, defaults, opts));

                        return function() {
                            for (var i = 0, len = that.messages.length; i < len; i++) {
                                if (that.messages[i].$id === id) {
                                    that.messages = that.messages.splice(i, 1);
                                    break;
                                }
                            }
                        };
                    };

                    this.clearMessages = function() {
                        that.messages.length = 0;
                    };
                },
                link: function(scope, elm, attrs, ctrl) {
                    var id = attrs.anMessagesContainer;

                    if (!id) {
                        throw new Error('container id missing');
                    }

                    var unregister = anMessages.register(id, ctrl);

                    scope.$on('$destroy', unregister);
                }
            };
        }
    );

})(angular);
<|endoftext|>


<commit_before>/*jslint indent: 2, onevar: false, eqeqeq: false, browser: true*/
/*globals testCase,
          sinon,
          fail,
          assert,
          assertNotNull,
          assertUndefined,
          assertArray,
          assertEquals,
          assertSame,
          assertNotSame,
          assertFunction,
          assertObject,
          assertException,
          assertNoException*/
/**
 * @author Christian Johansen (christian@cjohansen.no)
 * @license BSD
 *
 * Copyright (c) 2010 Christian Johansen
 */
(function () {
  testCase("SinonTestTest", {
    setUp: function () {
      sinon.config = {};
    },

    "should pass stub function to callback": function () {
      sinon.test(function (stub) {
        assertFunction(stub);
      })();
    },

    "should proxy return value": function () {
      var object = {};

      var result = sinon.test(function (stub) {
        return object;
      })();

      assertSame(object, result);
    },

    "should stub inside sandbox": function () {
      var method = function () {};
      var object = { method: method };

      sinon.test(function (stub) {
        stub(object, "method").returns(object);

        assertSame(object, object.method());
      })();
    },

    "should restore stubs": function () {
      var method = function () {};
      var object = { method: method };

      sinon.test(function (stub) {
        stub(object, "method");
      })();

      assertSame(method, object.method);
    },

    "should throw when method throws": function () {
      var method = function () {};
      var object = { method: method };

      assertException(function () {
        sinon.test(function (stub) {
          stub(object, "method");
          throw new Error();
        })();
      }, "Error");
    },

    "should restore stub when method throws": function () {
      var method = function () {};
      var object = { method: method };

      try {
        sinon.test(function (stub) {
          stub(object, "method");
          throw new Error();
        })();
      } catch (e) {}

      assertSame(method, object.method);
    },

    "should mock inside sandbox": function () {
      var method = function () {};
      var object = { method: method };

      sinon.test(function (stub, mock) {
        mock(object).expects("method").returns(object);

        assertSame(object, object.method());
      })();
    },

    "should verify mocks": function () {
      var method = function () {};
      var object = { method: method };

      assertException(function () {
        sinon.test(function (stub, mock) {
          mock(object).expects("method");
        })();
      }, "ExpectationError");

      assertSame(method, object.method);
    },

    "should restore mocks": function () {
      var method = function () {};
      var object = { method: method };

      try {
        sinon.test(function (stub, mock) {
          mock(object).expects("method");
        })();
      } catch (e) {}

      assertSame(method, object.method);
    },

    "should restore mock when method throws": function () {
      var method = function () {};
      var object = { method: method };

      try {
        sinon.test(function (stub, mock) {
          mock(object).expects("method").never();
          object.method();
        })();
      } catch (e) {}

      assertSame(method, object.method);
    },

    "should append helpers after normal arguments": function () {
      var object = { method: function () {} };

      sinon.test(function (obj, stub, mock) {
        mock(object).expects("method").once();
        object.method();

        assertSame(object, obj);
      })(object);
    },

    "should maintain the this value": function () {
      var testCase = {
        someTest: sinon.test(function (obj, stub, mock) {
          return this;
        })
      };

      assertSame(testCase, testCase.someTest());
    }
  });

  function assertSpy(obj) {
    assertNotNull(obj);
    assertFunction(obj.calledWith);
    assertUndefined(obj.returns);
  }

  function assertStub(obj) {
    assertNotNull(obj);
    assertFunction(obj.calledWith);
    assertFunction(obj.returns);
  }

  function assertMock(obj) {
    assertObject(obj);
    assertFunction(obj.verify);
    assertFunction(obj.expects);
  }

  function assertFakeServer(server) {
    assertObject(server);
    assertArray(server.requests);
    assertFunction(server.respondWith);
  }

  function assertClock(clock) {
    assertObject(clock);
    assertFunction(clock.tick);
    assertFunction(clock.setTimeout);
  }

  function boundTestCase() {
    var properties = {
      fn: function () {
        properties.self = this;
        properties.args = arguments;
        properties.spy = this.spy;
        properties.stub = this.stub;
        properties.mock = this.mock;
        properties.clock = this.clock;
        properties.server = this.server;
        properties.requests = this.requests;
      }
    };

    return properties;
  }

  testCase("ConfigurableTestWithSandboxTest", {
    "should yield stub, mock as arguments by default": function () {
      var stubbed, mocked;
      var obj = { meth: function () {} };

      sinon.test(function (stub, mock) {
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(2, arguments.length);
      })();

      assertStub(stubbed);
      assertMock(mocked);
    },

    "should yield spy, stub, mock as arguments": function () {
      var spied, stubbed, mocked;
      var obj = { meth: function () {} };

      sinon.config = {
        properties: ["spy", "stub", "mock"]
      };

      sinon.test(function (spy, stub, mock) {
        spied = spy(obj, "meth");
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(3, arguments.length);
      })();

      assertSpy(spied);
      assertStub(stubbed);
      assertMock(mocked);
    },

    "should not yield server when not faking xhr": function () {
      var stubbed, mocked;
      var obj = { meth: function () {} };

      sinon.config = {
        properties: ["server", "stub", "mock"]
      };

      sinon.test(function (stub, mock) {
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(2, arguments.length);
      })();

      assertStub(stubbed);
      assertMock(mocked);
    },

    "should yield server when faking xhr": function () {
      var stubbed, mocked, server;
      var obj = { meth: function () {} };

      sinon.config = {
        properties: ["server", "stub", "mock"],
        useFakeServer: true
      };

      sinon.test(function (serv, stub, mock) {
        server = serv;
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(3, arguments.length);
      })();

      assertFakeServer(server);
      assertStub(stubbed);
      assertMock(mocked);
    },

    "should yield clock when faking timers": function () {
      var server, clock;

      sinon.config = {
        properties: ["server", "clock"],
        useFakeTimers: true,
        useFakeServer: true
      };

      sinon.test(function (s, c) {
        server = s;
        clock = c;

        assertEquals(2, arguments.length);
      })();

      assertFakeServer(server);
      assertClock(clock);
    },

    "should inject properties into test case": function () {
      var testCase = boundTestCase();

      sinon.config = {
        injectIntoThis: true,
        properties: ["server", "clock"],
        useFakeTimers: true,
        useFakeServer: true
      };

      sinon.test(testCase.fn).call(testCase);

      assertSame(testCase, testCase.self);
      assertEquals(0, testCase.args.length);
      assertFakeServer(testCase.server);
      assertClock(testCase.clock);
      assertUndefined(testCase.spy);
      assertUndefined(testCase.stub);
      assertUndefined(testCase.mock);
      assertUndefined(testCase.requests);
    },

    "should inject properties into object": function () {
      var testCase = boundTestCase();
      var obj = {};

      sinon.config = {
        injectInto: obj,
        properties: ["server", "clock", "spy", "stub", "mock", "requests"],
        useFakeTimers: true,
        useFakeServer: true
      };

      sinon.test(testCase.fn).call(testCase);

      assertEquals(0, testCase.args.length);
      assertUndefined(testCase.server);
      assertUndefined(testCase.clock);
      assertUndefined(testCase.spy);
      assertUndefined(testCase.stub);
      assertUndefined(testCase.mock);
      assertUndefined(testCase.requests);
      assertFakeServer(obj.server);
      assertClock(obj.clock);
      assertFunction(obj.spy);
      assertFunction(obj.stub);
      assertFunction(obj.mock);
      assertArray(obj.requests);
    },

    "should use sinon.test to fake time": function () {
      sinon.config = {
        injectIntoThis: true,
        properties: ["clock", "spy", "stub", "mock"],
        useFakeTimers: true
      };

      var called;

      var testCase = {
        test: sinon.test(function () {
          var spy = this.spy();
          setTimeout(spy, 19);
          this.clock.tick(19);

          called = spy.called;
        })
      };

      testCase.test();

      assert(called);
    }
  });
}());
<commit_msg>Clean up in sinon.test tests, reset sinon.config after tests have run<commit_after>/*jslint indent: 2, onevar: false, eqeqeq: false, browser: true*/
/*globals testCase,
          sinon,
          fail,
          assert,
          assertNotNull,
          assertUndefined,
          assertArray,
          assertEquals,
          assertSame,
          assertNotSame,
          assertFunction,
          assertObject,
          assertException,
          assertNoException*/
/**
 * @author Christian Johansen (christian@cjohansen.no)
 * @license BSD
 *
 * Copyright (c) 2010 Christian Johansen
 */
(function () {
  testCase("SinonTestTest", {
    tearDown: function () {
      sinon.config = {};
    },

    "should pass stub function to callback": function () {
      sinon.test(function (stub) {
        assertFunction(stub);
      })();
    },

    "should proxy return value": function () {
      var object = {};

      var result = sinon.test(function (stub) {
        return object;
      })();

      assertSame(object, result);
    },

    "should stub inside sandbox": function () {
      var method = function () {};
      var object = { method: method };

      sinon.test(function (stub) {
        stub(object, "method").returns(object);

        assertSame(object, object.method());
      })();
    },

    "should restore stubs": function () {
      var method = function () {};
      var object = { method: method };

      sinon.test(function (stub) {
        stub(object, "method");
      })();

      assertSame(method, object.method);
    },

    "should throw when method throws": function () {
      var method = function () {};
      var object = { method: method };

      assertException(function () {
        sinon.test(function (stub) {
          stub(object, "method");
          throw new Error();
        })();
      }, "Error");
    },

    "should restore stub when method throws": function () {
      var method = function () {};
      var object = { method: method };

      try {
        sinon.test(function (stub) {
          stub(object, "method");
          throw new Error();
        })();
      } catch (e) {}

      assertSame(method, object.method);
    },

    "should mock inside sandbox": function () {
      var method = function () {};
      var object = { method: method };

      sinon.test(function (stub, mock) {
        mock(object).expects("method").returns(object);

        assertSame(object, object.method());
      })();
    },

    "should verify mocks": function () {
      var method = function () {};
      var object = { method: method };

      assertException(function () {
        sinon.test(function (stub, mock) {
          mock(object).expects("method");
        })();
      }, "ExpectationError");

      assertSame(method, object.method);
    },

    "should restore mocks": function () {
      var method = function () {};
      var object = { method: method };

      try {
        sinon.test(function (stub, mock) {
          mock(object).expects("method");
        })();
      } catch (e) {}

      assertSame(method, object.method);
    },

    "should restore mock when method throws": function () {
      var method = function () {};
      var object = { method: method };

      try {
        sinon.test(function (stub, mock) {
          mock(object).expects("method").never();
          object.method();
        })();
      } catch (e) {}

      assertSame(method, object.method);
    },

    "should append helpers after normal arguments": function () {
      var object = { method: function () {} };

      sinon.test(function (obj, stub, mock) {
        mock(object).expects("method").once();
        object.method();

        assertSame(object, obj);
      })(object);
    },

    "should maintain the this value": function () {
      var testCase = {
        someTest: sinon.test(function (obj, stub, mock) {
          return this;
        })
      };

      assertSame(testCase, testCase.someTest());
    }
  });

  function assertSpy(obj) {
    assertNotNull(obj);
    assertFunction(obj.calledWith);
    assertUndefined(obj.returns);
  }

  function assertStub(obj) {
    assertNotNull(obj);
    assertFunction(obj.calledWith);
    assertFunction(obj.returns);
  }

  function assertMock(obj) {
    assertObject(obj);
    assertFunction(obj.verify);
    assertFunction(obj.expects);
  }

  function assertFakeServer(server) {
    assertObject(server);
    assertArray(server.requests);
    assertFunction(server.respondWith);
  }

  function assertClock(clock) {
    assertObject(clock);
    assertFunction(clock.tick);
    assertFunction(clock.setTimeout);
  }

  function boundTestCase() {
    var properties = {
      fn: function () {
        properties.self = this;
        properties.args = arguments;
        properties.spy = this.spy;
        properties.stub = this.stub;
        properties.mock = this.mock;
        properties.clock = this.clock;
        properties.server = this.server;
        properties.requests = this.requests;
      }
    };

    return properties;
  }

  testCase("ConfigurableTestWithSandboxTest", {
    tearDown: function () {
      sinon.config = {};
    },

    "should yield stub, mock as arguments by default": function () {
      var stubbed, mocked;
      var obj = { meth: function () {} };

      sinon.test(function (stub, mock) {
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(2, arguments.length);
      })();

      assertStub(stubbed);
      assertMock(mocked);
    },

    "should yield spy, stub, mock as arguments": function () {
      var spied, stubbed, mocked;
      var obj = { meth: function () {} };

      sinon.config = {
        properties: ["spy", "stub", "mock"]
      };

      sinon.test(function (spy, stub, mock) {
        spied = spy(obj, "meth");
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(3, arguments.length);
      })();

      assertSpy(spied);
      assertStub(stubbed);
      assertMock(mocked);
    },

    "should not yield server when not faking xhr": function () {
      var stubbed, mocked;
      var obj = { meth: function () {} };

      sinon.config = {
        properties: ["server", "stub", "mock"]
      };

      sinon.test(function (stub, mock) {
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(2, arguments.length);
      })();

      assertStub(stubbed);
      assertMock(mocked);
    },

    "should yield server when faking xhr": function () {
      var stubbed, mocked, server;
      var obj = { meth: function () {} };

      sinon.config = {
        properties: ["server", "stub", "mock"],
        useFakeServer: true
      };

      sinon.test(function (serv, stub, mock) {
        server = serv;
        stubbed = stub(obj, "meth");
        mocked = mock(obj);

        assertEquals(3, arguments.length);
      })();

      assertFakeServer(server);
      assertStub(stubbed);
      assertMock(mocked);
    },

    "should yield clock when faking timers": function () {
      var server, clock;

      sinon.config = {
        properties: ["server", "clock"],
        useFakeTimers: true,
        useFakeServer: true
      };

      sinon.test(function (s, c) {
        server = s;
        clock = c;

        assertEquals(2, arguments.length);
      })();

      assertFakeServer(server);
      assertClock(clock);
    },

    "should inject properties into test case": function () {
      var testCase = boundTestCase();

      sinon.config = {
        injectIntoThis: true,
        properties: ["server", "clock"],
        useFakeTimers: true,
        useFakeServer: true
      };

      sinon.test(testCase.fn).call(testCase);

      assertSame(testCase, testCase.self);
      assertEquals(0, testCase.args.length);
      assertFakeServer(testCase.server);
      assertClock(testCase.clock);
      assertUndefined(testCase.spy);
      assertUndefined(testCase.stub);
      assertUndefined(testCase.mock);
      assertUndefined(testCase.requests);
    },

    "should inject properties into object": function () {
      var testCase = boundTestCase();
      var obj = {};

      sinon.config = {
        injectInto: obj,
        properties: ["server", "clock", "spy", "stub", "mock", "requests"],
        useFakeTimers: true,
        useFakeServer: true
      };

      sinon.test(testCase.fn).call(testCase);

      assertEquals(0, testCase.args.length);
      assertUndefined(testCase.server);
      assertUndefined(testCase.clock);
      assertUndefined(testCase.spy);
      assertUndefined(testCase.stub);
      assertUndefined(testCase.mock);
      assertUndefined(testCase.requests);
      assertFakeServer(obj.server);
      assertClock(obj.clock);
      assertFunction(obj.spy);
      assertFunction(obj.stub);
      assertFunction(obj.mock);
      assertArray(obj.requests);
    },

    "should use sinon.test to fake time": function () {
      sinon.config = {
        injectIntoThis: true,
        properties: ["clock", "spy", "stub", "mock"],
        useFakeTimers: true
      };

      var called;

      var testCase = {
        test: sinon.test(function () {
          var spy = this.spy();
          setTimeout(spy, 19);
          this.clock.tick(19);

          called = spy.called;
        })
      };

      testCase.test();

      assert(called);
    }
  });
}());
<|endoftext|>


<commit_before>(function($TDP){
  //
  // Block: Setup a simple JavaScript object configuration loader.
  //
  window.TDPF_loadConfigurationFile = function(pluginObject, fileNameUser, fileNameDefault, onSuccess, onFailure){
    var identifier = pluginObject.$id;
    var token = pluginObject.$token;

    $TDP.checkFileExists(token, fileNameUser).then(exists => {
      var fileName = exists ? fileNameUser : fileNameDefault;

      $TDP.readFile(token, fileName, true).then(contents => {
        var obj;

        try{
          obj = eval("("+contents+")");
        }catch(err){
          if (!(onFailure && onFailure(err.message))){
            $TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin, the JavaScript syntax is invalid: "+err.message);
          }

          return;
        }

        onSuccess && onSuccess(obj);
      }).catch(err => {
        if (!(onFailure && onFailure(err))){
          $TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin: "+err.message);
        }
      });
    }).catch(err => {
      if (!(onFailure && onFailure(err))){
        $TD.alert("warning", "Problem checking '"+fileNameUser+"' file for '"+identifier+"' plugin: "+err.message);
      }
    });
  };

  //
  // Block: Setup a function to add/remove custom CSS.
  //
  window.TDPF_createCustomStyle = function(pluginObject){
    var element = document.createElement("style");
    element.id = "plugin-"+pluginObject.$id+"-"+Math.random().toString(36).substring(2, 7);
    document.head.appendChild(element);

    var obj = {
      insert: (rule) => element.sheet.insertRule(rule, 0),
      remove: () => $(element).remove()
    };

    obj.element = element;
    return obj;
  };
})($TDP);<commit_msg>Fix inconsistency with loadConfigurationFile's onFailure parameter<commit_after>(function($TDP){
  //
  // Block: Setup a simple JavaScript object configuration loader.
  //
  window.TDPF_loadConfigurationFile = function(pluginObject, fileNameUser, fileNameDefault, onSuccess, onFailure){
    var identifier = pluginObject.$id;
    var token = pluginObject.$token;

    $TDP.checkFileExists(token, fileNameUser).then(exists => {
      var fileName = exists ? fileNameUser : fileNameDefault;

      $TDP.readFile(token, fileName, true).then(contents => {
        var obj;

        try{
          obj = eval("("+contents+")");
        }catch(err){
          if (!(onFailure && onFailure(err))){
            $TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin, the JavaScript syntax is invalid: "+err.message);
          }

          return;
        }

        onSuccess && onSuccess(obj);
      }).catch(err => {
        if (!(onFailure && onFailure(err))){
          $TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin: "+err.message);
        }
      });
    }).catch(err => {
      if (!(onFailure && onFailure(err))){
        $TD.alert("warning", "Problem checking '"+fileNameUser+"' file for '"+identifier+"' plugin: "+err.message);
      }
    });
  };

  //
  // Block: Setup a function to add/remove custom CSS.
  //
  window.TDPF_createCustomStyle = function(pluginObject){
    var element = document.createElement("style");
    element.id = "plugin-"+pluginObject.$id+"-"+Math.random().toString(36).substring(2, 7);
    document.head.appendChild(element);

    var obj = {
      insert: (rule) => element.sheet.insertRule(rule, 0),
      remove: () => $(element).remove()
    };

    obj.element = element;
    return obj;
  };
})($TDP);<|endoftext|>