<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
            },
            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.
     *       ~ 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.minHeight = this.configuration.height;

            //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
            $(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 configuration parameter: minRowsSelected<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)
     *          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.minHeight = this.configuration.height;

            //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; } );
    }

})();<|endoftext|>


<commit_before>'use strict';

var isNegativeInteger = require( './../lib' );

console.log( isNegativeInteger( -5.0 ) );
// returns true

console.log( isNegativeInteger( new Number( -5.0 ) ) );
// returns true

console.log( isNegativeInteger( 0.0 ) );
// returns false

console.log( isNegativeInteger( -3.14 ) );
// returns false

console.log( isNegativeInteger( 5.0 ) );
// returns false

console.log( isNegativeInteger( '-5' ) );
// returns false

console.log( isNegativeInteger( null ) );
// returns false
<commit_msg>Fix return annotation<commit_after>'use strict';

var isNegativeInteger = require( './../lib' );

console.log( isNegativeInteger( -5.0 ) );
// => true

console.log( isNegativeInteger( new Number( -5.0 ) ) );
// => true

console.log( isNegativeInteger( 0.0 ) );
// => false

console.log( isNegativeInteger( -3.14 ) );
// => false

console.log( isNegativeInteger( 5.0 ) );
// => false

console.log( isNegativeInteger( '-5' ) );
// => false

console.log( isNegativeInteger( null ) );
// => false
<|endoftext|>


<commit_before>import escapeTextContentForBrowser from 'escape-html';
import emojify from '../../features/emoji/emoji';
import { unescapeHTML } from '../../utils/html';
import { expandSpoilers } from '../../initial_state';

const domParser = new DOMParser();

const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
  obj[`:${emoji.shortcode}:`] = emoji;
  return obj;
}, {});

export function normalizeAccount(account) {
  account = { ...account };

  const emojiMap = makeEmojiMap(account);
  const displayName = account.display_name.length === 0 ? account.username : account.display_name;

  account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
  account.note_emojified = emojify(account.note, emojiMap);

  if (account.fields) {
    account.fields = account.fields.map(pair => ({
      ...pair,
      name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
      value_emojified: emojify(pair.value, emojiMap),
      value_plain: unescapeHTML(pair.value),
    }));
  }

  if (account.moved) {
    account.moved = account.moved.id;
  }

  return account;
}

export function normalizeStatus(status, normalOldStatus) {
  const normalStatus   = { ...status };
  normalStatus.account = status.account.id;

  if (status.reblog && status.reblog.id) {
    normalStatus.reblog = status.reblog.id;
  }

  // Only calculate these values when status first encountered
  // Otherwise keep the ones already in the reducer
  if (normalOldStatus) {
    normalStatus.search_index = normalOldStatus.get('search_index');
    normalStatus.contentHtml = normalOldStatus.get('contentHtml');
    normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml');
    normalStatus.hidden = normalOldStatus.get('hidden');
  } else {
    const spoilerText   = normalStatus.spoiler_text || '';
    const searchContent = [spoilerText, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
    const emojiMap      = makeEmojiMap(normalStatus);

    normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
    normalStatus.contentHtml  = emojify(normalStatus.content, emojiMap);
    normalStatus.spoilerHtml  = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
    normalStatus.hidden       = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
  }

  return normalStatus;
}
<commit_msg>Fix empty display name precedence over username in web UI (#9163)<commit_after>import escapeTextContentForBrowser from 'escape-html';
import emojify from '../../features/emoji/emoji';
import { unescapeHTML } from '../../utils/html';
import { expandSpoilers } from '../../initial_state';

const domParser = new DOMParser();

const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
  obj[`:${emoji.shortcode}:`] = emoji;
  return obj;
}, {});

export function normalizeAccount(account) {
  account = { ...account };

  const emojiMap = makeEmojiMap(account);
  const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name;

  account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
  account.note_emojified = emojify(account.note, emojiMap);

  if (account.fields) {
    account.fields = account.fields.map(pair => ({
      ...pair,
      name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
      value_emojified: emojify(pair.value, emojiMap),
      value_plain: unescapeHTML(pair.value),
    }));
  }

  if (account.moved) {
    account.moved = account.moved.id;
  }

  return account;
}

export function normalizeStatus(status, normalOldStatus) {
  const normalStatus   = { ...status };
  normalStatus.account = status.account.id;

  if (status.reblog && status.reblog.id) {
    normalStatus.reblog = status.reblog.id;
  }

  // Only calculate these values when status first encountered
  // Otherwise keep the ones already in the reducer
  if (normalOldStatus) {
    normalStatus.search_index = normalOldStatus.get('search_index');
    normalStatus.contentHtml = normalOldStatus.get('contentHtml');
    normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml');
    normalStatus.hidden = normalOldStatus.get('hidden');
  } else {
    const spoilerText   = normalStatus.spoiler_text || '';
    const searchContent = [spoilerText, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
    const emojiMap      = makeEmojiMap(normalStatus);

    normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
    normalStatus.contentHtml  = emojify(normalStatus.content, emojiMap);
    normalStatus.spoilerHtml  = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
    normalStatus.hidden       = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
  }

  return normalStatus;
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*jslint sloppy:true plusplus:true node:true rhino:true */

var fs = require('fs'),
    esprima = require('esprima'),
    dependencies = [];

function showUsage() {
    console.log('Usage:');
    console.log('   catgraph [options] file.js [...]');
    console.log();
    console.log('Available options:');
    console.log();
    console.log('  --format=text|deps|events');
    console.log('  -v, --version  Print program version');
    console.log();
    process.exit(1);
}

function handleArgs() {

    var options = {
        fnames:[],
        format:'deps'
    };
    var fmt = '--format=';

    if (process.argv.length <= 2) {
        showUsage();
    }

    process.argv.splice(2).forEach(function (entry) {

        if (entry === '-h' || entry === '--help') {
            showUsage();
        } else if (entry === '-v' || entry === '--version') {
            console.log('Version 1');
        } else if (entry.indexOf(fmt) == 0) {
            options.format = entry.slice(fmt.length);
        } else if (entry.slice(0, 2) === '--') {
            console.log('Error: unknown option ' + entry + '.');
            process.exit(1);
        } else {
            options.fnames.push(entry);
        }
    });

    if (options.format !== 'deps' &&
        options.format !== 'events' &&
        options.format !== 'text') {

        console.log('Error: format must be deps, events or text, not ' +
            options.format + '.');
        process.exit(1);
    }

    if (options.fnames.length === 0) {
        console.log('Error: no input file.');
        process.exit(1);
    }

    return options;

}

function repeat(s,n) {
    var r = '';
    for (; n>0; n--) {
        r += s;
    }
    return r;
}

function findDependencies(fname, syntax, depth, parent) {

    var rv, a, c, rest;
    var nextDepth = depth+1;
    var prefix = fname;
    //var prefix = repeat(' ',depth);
    var output = console.log.bind(console,prefix);
    var findNext = function (x) {
        return findDependencies (fname, x, nextDepth, syntax);
    };
    function dependency (type,target) {
        dependencies.push([fname,type,target]);
    }

    if (!syntax) { return '<nothing>'; }
    rv = '<' + syntax.type + '>';
    var displayName = syntax.name ? syntax.name :
                      typeof syntax.value !== 'object' ? syntax.value :
                      '';
    //output(syntax.type, displayName);//, Object.keys(syntax).join(' '));
    if (syntax.type == 'Program' ||
        syntax.type == 'BlockStatement') {
        syntax.body.forEach(findNext);
    } else if (syntax.type == 'MemberExpression') {
        rv = findNext(syntax.object) + '.' + findNext(syntax.property);
    } else if (syntax.type == 'VariableDeclaration') {
        syntax.declarations.forEach(findNext);
    } else if (syntax.type == 'ArrayExpression') {
        rv = syntax.elements.map(findNext);
    } else if (syntax.type == 'FunctionDeclaration') {
        findNext(syntax.body);
    } else if (syntax.type == 'FunctionExpression') {
        findNext(syntax.body);
        rv = '(function())';
    } else if (syntax.type == 'Identifier') {
        rv = syntax.name;
    } else if (syntax.type == 'ObjectExpression') {
        syntax.properties.forEach(findNext);
    } else if (syntax.type == 'ReturnStatement' ||
               syntax.type == 'UpdateExpression' ||
               syntax.type == 'ThrowStatement' ||
               syntax.type == 'UnaryExpression') {
        findNext(syntax.argument);
    } else if (syntax.type == 'ThisExpression') {
        rv = 'this';
    } else if (syntax.type == 'Property') {
        findNext(syntax.key);
        findNext(syntax.value);
    } else if (syntax.type == 'IfStatement' ||
               syntax.type == 'ConditionalExpression') {
        findNext(syntax.test);
        findNext(syntax.consequent);
        findNext(syntax.alternate);
    } else if (syntax.type == 'WhileStatement') {
        findNext(syntax.test);
        findNext(syntax.body);
    } else if (syntax.type == 'ForStatement') {
        findNext(syntax.init);
        findNext(syntax.test);
        findNext(syntax.update);
        findNext(syntax.body);
    } else if (syntax.type == 'ForInStatement') {
        findNext(syntax.left);
        findNext(syntax.right);
        findNext(syntax.body);
    } else if (syntax.type == 'VariableDeclarator') {
        findNext(syntax.init);
    } else if (syntax.type == 'AssignmentExpression') {
        findNext(syntax.left);
        findNext(syntax.right);
    } else if (syntax.type == 'ExpressionStatement') {
        findNext(syntax.expression);
    } else if (syntax.type == 'SwitchStatement') {
        findNext(syntax.discriminant);
        syntax.cases.forEach(findNext);
    } else if (syntax.type == 'SwitchCase') {
        findNext(syntax.test);
        syntax.consequent.forEach(findNext);
    } else if (syntax.type == 'TryStatement') {
        findNext(syntax.block);
        findNext(syntax.finalizer);
        syntax.handlers.forEach(findNext);
        syntax.guardedHandlers.forEach(findNext);
    } else if (syntax.type == 'CatchClause') {
        findNext(syntax.param);
        findNext(syntax.body);
    } else if (syntax.type == 'LogicalExpression' ||
               syntax.type == 'BinaryExpression') {
        findNext(syntax.left);
        findNext(syntax.right);
    } else if (syntax.type == 'Literal') {
        rv = syntax.value;
    } else if (syntax.type == 'ContinueStatement' ||
               syntax.type == 'BreakStatement' ||
               syntax.type == 'EmptyStatement') {
    } else if (syntax.type == 'CallExpression' ||
               syntax.type == 'NewExpression') {
        c = findNext(syntax.callee).toLowerCase();
        if (c == 'define') {
            var arg = findNext(syntax.arguments[0])
            for (a in arg) { dependency('require',arg[a]); }
            rest = syntax.arguments.slice(1);
        } else if (c == 'bus.on' || c == 'bus.emit' || c == 'require') {
            var arg = findNext(syntax.arguments[0])
            dependency(c.toLowerCase(),arg);
            rest = syntax.arguments.slice(1);
        } else {
            rest = syntax.arguments;
        }
        rest.forEach(findNext);
    } else {
        output('WHATSTHIS?',syntax);
    }
    return rv;

}

function handleFile(fname) {

    var content, timestamp, syntax, name, obj, json = false;

    if(fname.indexOf('json!') === 0) {
        json = true;
        fname = fname.slice(5);
    }

    content = fs.readFileSync(fname, 'utf-8');

    if(json) {

        obj = JSON.parse(content);

        for (var i in obj.items) {
            var item = obj.items[i];
            dependencies.push([fname,'bus.emit',item.event]);
        }

    } else {

        if (content[0] === '#' && content[1] === '!') {
            content = '//' + content.substr(2, content.length);
        }

        timestamp = Date.now();
        syntax = esprima.parse(content, { tolerant: true });
        module.syntax = syntax;
        findDependencies(fname,syntax,0);
        //console.log(syntax);

    }

}

function skipInGraph(id) {
    return  (id.indexOf('text!') === 0) ||
            (id === 'underscore') ||
            (id === 'core/L');
}

function createOutput(options) {

    var deps = options.format === 'deps';
    var events = options.format === 'events';
    var ev = {};
    var myRe = /[.\-\/]/g;
    var myRe2 = /.*\!/;

    if (deps||events) { console.log('digraph prof {'); }

    for (var i in dependencies) {
        var dep = dependencies[i];
        var subj = dep[0].replace(/\.js$/,'').replace(myRe,'_').replace(myRe2,''),
            pred = dep[1]
            obj = dep[2].replace(myRe,'_').replace(myRe2,'');

        if (deps) {
            if (pred === 'require' && !skipInGraph(obj)) {
                console.log(' ' + subj, '->', obj, ';');
            }
        } else if (events) {
            if (skipInGraph(obj)) { continue; }
            if (pred === 'bus.on') {
                console.log(' ' + obj, '->', subj, ';');
                ev[obj] = true;
            } else if (pred === 'bus.emit') {
                console.log(' ' + subj, '->', obj, ';');
                ev[obj] = true;
            }
        } else {
            console.log(subj,obj,pred);
        }
    }
    for (var event in ev) {
        console.log(event,'[shape=box];');
    }

    if (deps ||events) { console.log('}'); }

}

function main () {

    var options = handleArgs();
    options.fnames.forEach(handleFile);
    createOutput(options);

}

main();
<commit_msg>Remove template dependencies<commit_after>#!/usr/bin/env node

/*jslint sloppy:true plusplus:true node:true rhino:true */

var fs = require('fs'),
    esprima = require('esprima'),
    dependencies = [];

function showUsage() {
    console.log('Usage:');
    console.log('   catgraph [options] file.js [...]');
    console.log();
    console.log('Available options:');
    console.log();
    console.log('  --format=text|deps|events');
    console.log('  -v, --version  Print program version');
    console.log();
    process.exit(1);
}

function handleArgs() {

    var options = {
        fnames:[],
        format:'deps'
    };
    var fmt = '--format=';

    if (process.argv.length <= 2) {
        showUsage();
    }

    process.argv.splice(2).forEach(function (entry) {

        if (entry === '-h' || entry === '--help') {
            showUsage();
        } else if (entry === '-v' || entry === '--version') {
            console.log('Version 1');
        } else if (entry.indexOf(fmt) == 0) {
            options.format = entry.slice(fmt.length);
        } else if (entry.slice(0, 2) === '--') {
            console.log('Error: unknown option ' + entry + '.');
            process.exit(1);
        } else {
            options.fnames.push(entry);
        }
    });

    if (options.format !== 'deps' &&
        options.format !== 'events' &&
        options.format !== 'text') {

        console.log('Error: format must be deps, events or text, not ' +
            options.format + '.');
        process.exit(1);
    }

    if (options.fnames.length === 0) {
        console.log('Error: no input file.');
        process.exit(1);
    }

    return options;

}

function repeat(s,n) {
    var r = '';
    for (; n>0; n--) {
        r += s;
    }
    return r;
}

function findDependencies(fname, syntax, depth, parent) {

    var rv, a, c, rest;
    var nextDepth = depth+1;
    var prefix = fname;
    //var prefix = repeat(' ',depth);
    var output = console.log.bind(console,prefix);
    var findNext = function (x) {
        return findDependencies (fname, x, nextDepth, syntax);
    };
    function dependency (type,target) {
        dependencies.push([fname,type,target]);
    }

    if (!syntax) { return '<nothing>'; }
    rv = '<' + syntax.type + '>';
    var displayName = syntax.name ? syntax.name :
                      typeof syntax.value !== 'object' ? syntax.value :
                      '';
    //output(syntax.type, displayName);//, Object.keys(syntax).join(' '));
    if (syntax.type == 'Program' ||
        syntax.type == 'BlockStatement') {
        syntax.body.forEach(findNext);
    } else if (syntax.type == 'MemberExpression') {
        rv = findNext(syntax.object) + '.' + findNext(syntax.property);
    } else if (syntax.type == 'VariableDeclaration') {
        syntax.declarations.forEach(findNext);
    } else if (syntax.type == 'ArrayExpression') {
        rv = syntax.elements.map(findNext);
    } else if (syntax.type == 'FunctionDeclaration') {
        findNext(syntax.body);
    } else if (syntax.type == 'FunctionExpression') {
        findNext(syntax.body);
        rv = '(function())';
    } else if (syntax.type == 'Identifier') {
        rv = syntax.name;
    } else if (syntax.type == 'ObjectExpression') {
        syntax.properties.forEach(findNext);
    } else if (syntax.type == 'ReturnStatement' ||
               syntax.type == 'UpdateExpression' ||
               syntax.type == 'ThrowStatement' ||
               syntax.type == 'UnaryExpression') {
        findNext(syntax.argument);
    } else if (syntax.type == 'ThisExpression') {
        rv = 'this';
    } else if (syntax.type == 'Property') {
        findNext(syntax.key);
        findNext(syntax.value);
    } else if (syntax.type == 'IfStatement' ||
               syntax.type == 'ConditionalExpression') {
        findNext(syntax.test);
        findNext(syntax.consequent);
        findNext(syntax.alternate);
    } else if (syntax.type == 'WhileStatement') {
        findNext(syntax.test);
        findNext(syntax.body);
    } else if (syntax.type == 'ForStatement') {
        findNext(syntax.init);
        findNext(syntax.test);
        findNext(syntax.update);
        findNext(syntax.body);
    } else if (syntax.type == 'ForInStatement') {
        findNext(syntax.left);
        findNext(syntax.right);
        findNext(syntax.body);
    } else if (syntax.type == 'VariableDeclarator') {
        findNext(syntax.init);
    } else if (syntax.type == 'AssignmentExpression') {
        findNext(syntax.left);
        findNext(syntax.right);
    } else if (syntax.type == 'ExpressionStatement') {
        findNext(syntax.expression);
    } else if (syntax.type == 'SwitchStatement') {
        findNext(syntax.discriminant);
        syntax.cases.forEach(findNext);
    } else if (syntax.type == 'SwitchCase') {
        findNext(syntax.test);
        syntax.consequent.forEach(findNext);
    } else if (syntax.type == 'TryStatement') {
        findNext(syntax.block);
        findNext(syntax.finalizer);
        syntax.handlers.forEach(findNext);
        syntax.guardedHandlers.forEach(findNext);
    } else if (syntax.type == 'CatchClause') {
        findNext(syntax.param);
        findNext(syntax.body);
    } else if (syntax.type == 'LogicalExpression' ||
               syntax.type == 'BinaryExpression') {
        findNext(syntax.left);
        findNext(syntax.right);
    } else if (syntax.type == 'Literal') {
        rv = syntax.value;
    } else if (syntax.type == 'ContinueStatement' ||
               syntax.type == 'BreakStatement' ||
               syntax.type == 'EmptyStatement') {
    } else if (syntax.type == 'CallExpression' ||
               syntax.type == 'NewExpression') {
        c = findNext(syntax.callee).toLowerCase();
        if (c == 'define') {
            var arg = findNext(syntax.arguments[0])
            for (a in arg) { dependency('require',arg[a]); }
            rest = syntax.arguments.slice(1);
        } else if (c == 'bus.on' || c == 'bus.emit' || c == 'require') {
            var arg = findNext(syntax.arguments[0])
            dependency(c.toLowerCase(),arg);
            rest = syntax.arguments.slice(1);
        } else {
            rest = syntax.arguments;
        }
        rest.forEach(findNext);
    } else {
        output('WHATSTHIS?',syntax);
    }
    return rv;

}

function handleFile(fname) {

    var content, timestamp, syntax, name, obj, json = false;

    if(fname.indexOf('json!') === 0) {
        json = true;
        fname = fname.slice(5);
    }

    content = fs.readFileSync(fname, 'utf-8');

    if(json) {

        obj = JSON.parse(content);

        for (var i in obj.items) {
            var item = obj.items[i];
            dependencies.push([fname,'bus.emit',item.event]);
        }

    } else {

        if (content[0] === '#' && content[1] === '!') {
            content = '//' + content.substr(2, content.length);
        }

        timestamp = Date.now();
        syntax = esprima.parse(content, { tolerant: true });
        module.syntax = syntax;
        findDependencies(fname,syntax,0);
        //console.log(syntax);

    }

}

function skipInGraph(id) {
    return  (id.indexOf('text!') === 0) ||
            (id === 'underscore') ||
            (id === 'core/L');
}

function createOutput(options) {

    var deps = options.format === 'deps';
    var events = options.format === 'events';
    var ev = {};
    var myRe = /[.\-\/]/g;
    var myRe2 = /json\!/;

    if (deps||events) { console.log('digraph prof {'); }

    for (var i in dependencies) {
        var dep = dependencies[i];
        var subj = dep[0].replace(/\.js$/,'').replace(myRe,'_').replace(myRe2,''),
            pred = dep[1]
            obj = dep[2].replace(myRe,'_').replace(myRe2,'');

        if (deps) {
            if (pred === 'require' && !skipInGraph(obj)) {
                console.log(' ' + subj, '->', obj, ';');
            }
        } else if (events) {
            if (skipInGraph(obj)) { continue; }
            if (pred === 'bus.on') {
                console.log(' ' + obj, '->', subj, ';');
                ev[obj] = true;
            } else if (pred === 'bus.emit') {
                console.log(' ' + subj, '->', obj, ';');
                ev[obj] = true;
            }
        } else {
            console.log(subj,obj,pred);
        }
    }
    for (var event in ev) {
        console.log(event,'[shape=box];');
    }

    if (deps ||events) { console.log('}'); }

}

function main () {

    var options = handleArgs();
    options.fnames.forEach(handleFile);
    createOutput(options);

}

main();
<|endoftext|>


<commit_before>

chrome.extension.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.action == "getVideoSrc") {
            var videoSrc = $('div.play-video').attr('data-vid');
            if (!videoSrc) {
                videoSrc = decodeURIComponent($('div.slide-container param[name="flashvars"]').attr('value')).match("file=([^&]+)")[1];
            }
            sendResponse({videoSrc: videoSrc});
        }
    }
);<commit_msg>Fixed lynda.com support<commit_after>

chrome.extension.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.action == "getVideoSrc") {
            var videoSrc = $('div.play-video').attr('data-vid');
            if (!videoSrc) {
                var flashVars = decodeURIComponent($('div.slide-container param[name="flashvars"]').attr('value')).match("file=([^&]+)");
                if (flashVars && flashVars.length > 1) {
                    videoSrc = flashVars[1];
                }
            }
            if (!videoSrc) {
                videoSrc = $('.videoStage video').attr('h264');
            }
            sendResponse({videoSrc: videoSrc});
        }
    }
);<|endoftext|>


<commit_before>/*
Copyright 2014 Spotify AB

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.
*/

/* global document */

var EMPTY_STACK = "	<empty stack>\n";

// This method is called from HTML so we need to tell JSHint it's not unused
function analyzeTextfield() { // jshint ignore: line
    var text = document.getElementById("TEXTAREA").value;

    var analyzer = new Analyzer(text);
    setOutputText(analyzer.toString());
}

// Extracts a substring from a string.
//
// Returns an object with two properties:
// value = the first group of the extracted object
// shorterString = the string with the full contents of the regex removed
function _extract(regex, string) {
    var match = regex.exec(string);
    if (match === null) {
        return {value: undefined, shorterString: string};
    }

    return {value: match[1], shorterString: string.replace(regex, "")};
}

function setOutputText(unescaped) {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode(unescaped));
    var escaped = div.innerHTML;

    var outputPre = document.getElementById("OUTPUT");
    outputPre.innerHTML = escaped;

    var outputDiv = document.getElementById('OUTPUT_DIV');
    outputDiv.style.display = 'inline';
}

function Thread(line) {
    this.toString = function() {
        return this.toHeaderString() + '\n' + this.toStackString();
    };

    this.isValid = function() {
        return this.hasOwnProperty('name') && this.name !== undefined;
    };

    // Return true if the line was understood, false otherwise
    this.addStackLine = function(line) {
        var FRAME = /^\s+at .*/;
        if (line.match(FRAME) === null) {
            return false;
        }
        this._frames.push(line);
        return true;
    };

    this.toStackString = function() {
        var string = "";
        for (var i = 0; i < this._frames.length; i++) {
            var frame = this._frames[i];
            string += frame + '\n';
        }

        if (string === '') {
            return EMPTY_STACK;
        }

        return string;
    };

    this.toHeaderString = function() {
        var headerString = "";
        if (this.group !== undefined) {
            headerString += '"' + this.group + '"/';
        }
        headerString += '"' + this.name + '": ' + (this.daemon ? "daemon, " : "") + this.state;
        return headerString;
    };

    var match;
    match = _extract(/\[([0-9a-fx,]+)\]$/, line);
    this.dontKnow = match.value;
    line = match.shorterString;

    match = _extract(/ nid=([0-9a-fx,]+)/, line);
    this.nid = match.value;
    line = match.shorterString;

    match = _extract(/ tid=([0-9a-fx,]+)/, line);
    this.tid = match.value;
    line = match.shorterString;

    match = _extract(/ prio=([0-9]+)/, line);
    this.prio = match.value;
    line = match.shorterString;

    match = _extract(/ os_prio=([0-9a-fx,]+)/, line);
    this.osPrio = match.value;
    line = match.shorterString;

    match = _extract(/ (daemon)/, line);
    this.daemon = (match.value !== undefined);
    line = match.shorterString;

    match = _extract(/ #([0-9]+)/, line);
    this.number = match.value;
    line = match.shorterString;

    match = _extract(/ group="(.*)"/, line);
    this.group = match.value;
    line = match.shorterString;

    match = _extract(/^"(.*)" /, line);
    this.name = match.value;
    line = match.shorterString;

    this.state = line.trim();

    if (this.name === undefined) {
        return undefined;
    }

    this._frames = [];
}

function toStackWithHeadersString(stack, threads) {
    var string = '';
    if (threads.length > 4) {
        string += "" + threads.length + " threads with this stack:\n";
    }

    // Print thread headers for this stack in alphabetic order
    var headers = [];
    for (var k = 0; k < threads.length; k++) {
        headers.push(threads[k].toHeaderString());
    }
    headers.sort();
    for (var l = 0; l < headers.length; l++) {
        string += headers[l] + '\n';
    }

    string += stack;

    return string;
}

// Create an analyzer object
function Analyzer(text) {
    this._analyze = function(text) {
        var lines = text.split('\n');
        var currentThread = null;
        for (var i = 0; i < lines.length; i++) {
            var line = lines[i];
            while (line.charAt(0) === '"' && line.indexOf('prio=') === -1) {
                // Multi line thread name
                i++;
                if (i >= lines.length) {
                    break;
                }

                // Replace thread name newline with ", "
                line += ', ' + lines[i];
            }

            var thread = new Thread(line);
            if (thread.isValid()) {
                this.threads.push(thread);
                currentThread = thread;
            } else if (currentThread !== null) {
                currentThread.addStackLine(line);
            }
        }
    };

    this.toString = function() {
        // Map stacks to which threads have them
        var stacksToThreads = {};
        for (var i = 0; i < this.threads.length; i++) {
            var thread = this.threads[i];
            var stackString = thread.toStackString();
            if (!stacksToThreads.hasOwnProperty(stackString)) {
                stacksToThreads[stackString] = [];
            }
            stacksToThreads[stackString].push(thread);
        }

        // List stacks by popularity
        var stacks = [];
        for (var stack in stacksToThreads) {
            stacks.push(stack);
        }
        stacks.sort(function(a, b) {
            if (a === b) {
                return 0;
            }

            var scoreA = stacksToThreads[a].length;
            if (a === EMPTY_STACK) {
                scoreA = -123456;
            }

            var scoreB = stacksToThreads[b].length;
            if (b === EMPTY_STACK) {
                scoreB = -123456;
            }

            if (scoreB !== scoreA) {
                return scoreB - scoreA;
            }

            // Use stack contents as secondary sort key. This is
            // needed to get deterministic enough output for being
            // able to run our unit tests in both Node.js and in
            // Chrome.
            if (a < b) {
                return -1;
            } else {
                return 1;
            }
        });

        // Iterate over stacks and for each stack, print first all
        // threads that have it, and then the stack itself.
        var asString = "";
        asString += "" + this.threads.length + " threads found:\n";
        for (var j = 0; j < stacks.length; j++) {
            var currentStack = stacks[j];
            var threads = stacksToThreads[currentStack];
            asString += '\n' + toStackWithHeadersString(currentStack, threads);
        }

        return asString;
    };

    this.threads = [];
    this._analyze(text);
}
<commit_msg>Thread._analyze(): keep track of unparsable lines<commit_after>/*
Copyright 2014 Spotify AB

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.
*/

/* global document */

var EMPTY_STACK = "	<empty stack>\n";

// This method is called from HTML so we need to tell JSHint it's not unused
function analyzeTextfield() { // jshint ignore: line
    var text = document.getElementById("TEXTAREA").value;

    var analyzer = new Analyzer(text);
    setOutputText(analyzer.toString());
}

// Extracts a substring from a string.
//
// Returns an object with two properties:
// value = the first group of the extracted object
// shorterString = the string with the full contents of the regex removed
function _extract(regex, string) {
    var match = regex.exec(string);
    if (match === null) {
        return {value: undefined, shorterString: string};
    }

    return {value: match[1], shorterString: string.replace(regex, "")};
}

function setOutputText(unescaped) {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode(unescaped));
    var escaped = div.innerHTML;

    var outputPre = document.getElementById("OUTPUT");
    outputPre.innerHTML = escaped;

    var outputDiv = document.getElementById('OUTPUT_DIV');
    outputDiv.style.display = 'inline';
}

function Thread(line) {
    this.toString = function() {
        return this.toHeaderString() + '\n' + this.toStackString();
    };

    this.isValid = function() {
        return this.hasOwnProperty('name') && this.name !== undefined;
    };

    // Return true if the line was understood, false otherwise
    this.addStackLine = function(line) {
        var FRAME = /^\s+at .*/;
        if (line.match(FRAME) === null) {
            return false;
        }
        this._frames.push(line);
        return true;
    };

    this.toStackString = function() {
        var string = "";
        for (var i = 0; i < this._frames.length; i++) {
            var frame = this._frames[i];
            string += frame + '\n';
        }

        if (string === '') {
            return EMPTY_STACK;
        }

        return string;
    };

    this.toHeaderString = function() {
        var headerString = "";
        if (this.group !== undefined) {
            headerString += '"' + this.group + '"/';
        }
        headerString += '"' + this.name + '": ' + (this.daemon ? "daemon, " : "") + this.state;
        return headerString;
    };

    var match;
    match = _extract(/\[([0-9a-fx,]+)\]$/, line);
    this.dontKnow = match.value;
    line = match.shorterString;

    match = _extract(/ nid=([0-9a-fx,]+)/, line);
    this.nid = match.value;
    line = match.shorterString;

    match = _extract(/ tid=([0-9a-fx,]+)/, line);
    this.tid = match.value;
    line = match.shorterString;

    match = _extract(/ prio=([0-9]+)/, line);
    this.prio = match.value;
    line = match.shorterString;

    match = _extract(/ os_prio=([0-9a-fx,]+)/, line);
    this.osPrio = match.value;
    line = match.shorterString;

    match = _extract(/ (daemon)/, line);
    this.daemon = (match.value !== undefined);
    line = match.shorterString;

    match = _extract(/ #([0-9]+)/, line);
    this.number = match.value;
    line = match.shorterString;

    match = _extract(/ group="(.*)"/, line);
    this.group = match.value;
    line = match.shorterString;

    match = _extract(/^"(.*)" /, line);
    this.name = match.value;
    line = match.shorterString;

    this.state = line.trim();

    if (this.name === undefined) {
        return undefined;
    }

    this._frames = [];
}

function toStackWithHeadersString(stack, threads) {
    var string = '';
    if (threads.length > 4) {
        string += "" + threads.length + " threads with this stack:\n";
    }

    // Print thread headers for this stack in alphabetic order
    var headers = [];
    for (var k = 0; k < threads.length; k++) {
        headers.push(threads[k].toHeaderString());
    }
    headers.sort();
    for (var l = 0; l < headers.length; l++) {
        string += headers[l] + '\n';
    }

    string += stack;

    return string;
}

// Create an analyzer object
function Analyzer(text) {
    this._handleLine = function(line) {
        var thread = new Thread(line);
        var parsed = false;
        if (thread.isValid()) {
            this.threads.push(thread);
            this._currentThread = thread;
            parsed = true;
        } else if (this._currentThread !== null) {
            parsed = this._currentThread.addStackLine(line);
        }

        if (!parsed) {
            this.unparsables.push(line);
        }
    };

    this._analyze = function(text) {
        var lines = text.split('\n');
        for (var i = 0; i < lines.length; i++) {
            var line = lines[i];
            while (line.charAt(0) === '"' && line.indexOf('prio=') === -1) {
                // Multi line thread name
                i++;
                if (i >= lines.length) {
                    break;
                }

                // Replace thread name newline with ", "
                line += ', ' + lines[i];
            }

            this._handleLine(line);
        }
    };

    this.toString = function() {
        // Map stacks to which threads have them
        var stacksToThreads = {};
        for (var i = 0; i < this.threads.length; i++) {
            var thread = this.threads[i];
            var stackString = thread.toStackString();
            if (!stacksToThreads.hasOwnProperty(stackString)) {
                stacksToThreads[stackString] = [];
            }
            stacksToThreads[stackString].push(thread);
        }

        // List stacks by popularity
        var stacks = [];
        for (var stack in stacksToThreads) {
            stacks.push(stack);
        }
        stacks.sort(function(a, b) {
            if (a === b) {
                return 0;
            }

            var scoreA = stacksToThreads[a].length;
            if (a === EMPTY_STACK) {
                scoreA = -123456;
            }

            var scoreB = stacksToThreads[b].length;
            if (b === EMPTY_STACK) {
                scoreB = -123456;
            }

            if (scoreB !== scoreA) {
                return scoreB - scoreA;
            }

            // Use stack contents as secondary sort key. This is
            // needed to get deterministic enough output for being
            // able to run our unit tests in both Node.js and in
            // Chrome.
            if (a < b) {
                return -1;
            } else {
                return 1;
            }
        });

        // Iterate over stacks and for each stack, print first all
        // threads that have it, and then the stack itself.
        var asString = "";
        asString += "" + this.threads.length + " threads found:\n";
        for (var j = 0; j < stacks.length; j++) {
            var currentStack = stacks[j];
            var threads = stacksToThreads[currentStack];
            asString += '\n' + toStackWithHeadersString(currentStack, threads);
        }

        return asString;
    };

    this.threads = [];
    this.unparsables = [];
    this._currentThread = null;

    this._analyze(text);
}
<|endoftext|>


<commit_before>/**
 * This file is part of Superdesk.
 *
 * Copyright 2013, 2014 Sourcefabric z.u. and contributors.
 *
 * For the full copyright and license information, please see the
 * AUTHORS and LICENSE files distributed with this source code, or
 * at https://www.sourcefabric.org/superdesk/license
 */
(function() {

'use strict';

FindReplaceDirective.$inject = ['$timeout', '$rootScope', 'editor'];
/**
 * using directive here so that it can return focus
 */
function FindReplaceDirective($timeout, $rootScope, editor) {
    return {
        controller: function($scope) {
        },
        link: function(scope, elem) {
            scope.to = '';
            scope.from = '';

            scope.next = function() {
                editor.command.next();
            };

            scope.prev = function() {
                editor.command.prev();
            };

            scope.replace = function() {
                editor.command.replace(scope.to || '');
            };

            scope.replaceAll = function() {
                editor.command.replaceAll(scope.to || '');
                scope.closeWidget(scope.widget);
            };

            scope.$watch('from', function(needle) {
                editor.command.find(needle);

                // return focus to input - just focus() doesn't work here for some reason
                var input = document.getElementById('find-replace-what');
                input.focus();
                input.select();
                document.getSelection().collapseToEnd();
            });

            editor.startCommand();
            scope.$on('$destroy', function() {
                editor.stopCommand();
            });
        }
    };
}

angular.module('superdesk.authoring.find-replace', ['superdesk.editor', 'superdesk.authoring.widgets'])
    .directive('sdFindReplace', FindReplaceDirective)
    .config(['authoringWidgetsProvider', function(authoringWidgetsProvider) {
        authoringWidgetsProvider
            .widget('find-replace', {
                icon: 'find-replace',
                label: gettext('Find and Replace'),
                template: 'scripts/superdesk-authoring/editor/views/find-replace.html',
                side: 'right',
                display: {authoring: true, packages: false}
            });
    }]);

})();
<commit_msg>fix(find-replace): stop closing the  widget on replace all<commit_after>/**
 * This file is part of Superdesk.
 *
 * Copyright 2013, 2014 Sourcefabric z.u. and contributors.
 *
 * For the full copyright and license information, please see the
 * AUTHORS and LICENSE files distributed with this source code, or
 * at https://www.sourcefabric.org/superdesk/license
 */
(function() {

'use strict';

FindReplaceDirective.$inject = ['$timeout', '$rootScope', 'editor'];
/**
 * using directive here so that it can return focus
 */
function FindReplaceDirective($timeout, $rootScope, editor) {
    return {
        controller: function($scope) {
        },
        link: function(scope, elem) {
            scope.to = '';
            scope.from = '';

            scope.next = function() {
                editor.command.next();
            };

            scope.prev = function() {
                editor.command.prev();
            };

            scope.replace = function() {
                editor.command.replace(scope.to || '');
            };

            scope.replaceAll = function() {
                editor.command.replaceAll(scope.to || '');
            };

            scope.$watch('from', function(needle) {
                editor.command.find(needle);

                // return focus to input - just focus() doesn't work here for some reason
                var input = document.getElementById('find-replace-what');
                input.focus();
                input.select();
                document.getSelection().collapseToEnd();
            });

            editor.startCommand();
            scope.$on('$destroy', function() {
                editor.stopCommand();
            });
        }
    };
}

angular.module('superdesk.authoring.find-replace', ['superdesk.editor', 'superdesk.authoring.widgets'])
    .directive('sdFindReplace', FindReplaceDirective)
    .config(['authoringWidgetsProvider', function(authoringWidgetsProvider) {
        authoringWidgetsProvider
            .widget('find-replace', {
                icon: 'find-replace',
                label: gettext('Find and Replace'),
                template: 'scripts/superdesk-authoring/editor/views/find-replace.html',
                side: 'right',
                display: {authoring: true, packages: false}
            });
    }]);

})();
<|endoftext|>