<commit_before>import $ from 'jquery';
import _ from 'underscore';

import PaginateWidget from 'girder/views/widgets/PaginateWidget';
import View from 'girder/views/View';
import router from 'girder/router';
import { restRequest } from 'girder/rest';
import { defineFlags, formatDate, DATE_SECOND } from 'girder/misc';
import eventStream from 'girder/utilities/EventStream';
import { getCurrentUser } from 'girder/auth';
import { SORT_DESC } from 'girder/constants';

import JobCollection from '../collections/JobCollection';
import JobStatus from '../JobStatus';
import JobListWidgetTemplate from '../templates/jobListWidget.pug';
import '../stylesheets/jobListWidget.styl';
import JobListTemplate from '../templates/jobList.pug';

import CheckBoxMenu from './CheckBoxMenu';
import JobGraphWidget from './JobGraphWidget';

var JobListWidget = View.extend({
    events: {
        'click .g-job-trigger-link': function (e) {
            var cid = $(e.target).attr('cid');
            this.trigger('g:jobClicked', this.collection.get(cid));
        },
        'change select.g-page-size': function (e) {
            this.collection.pageLimit = parseInt($(e.target).val());
            this.collection.fetch({}, true);
        }
    },

    initialize: function (settings) {
        var currentUser = getCurrentUser();
        this.showAllJobs = !!settings.allJobsMode;
        this.columns = settings.columns || this.columnEnum.COLUMN_ALL;
        this.userId = (settings.filter && !settings.allJobsMode) ? (settings.filter.userId ? settings.filter.userId : currentUser.id) : null;
        this.showGraphs = settings.showGraphs;
        this.showPageSizeSelector = settings.showPageSizeSelector;
        this.showFilters = settings.showFilters;
        this.typeFilter = null;
        this.statusFilter = null;
        this.timingFilter = JobStatus.getAll().reduce((obj, status) => {
            obj[status.text] = true;
            return obj;
        }, {});

        this.jobGraphWidget = null;

        this.pageSizes = [25, 50, 100, 250, 500, 1000];

        this.collection = new JobCollection();
        if (this.showAllJobs) {
            this.collection.resourceName = 'job/all';
        }
        this.collection.sortField = settings.sortField || 'created';
        this.collection.sortDir = settings.sortDir || SORT_DESC;
        this.collection.pageLimit = settings.pageLimit || this.collection.pageLimit;

        this.listenTo(this.collection, 'update reset', this._renderData);

        this._fetchWithFilter();

        this.currentView = settings.view ? settings.view : 'list';

        this.showHeader = _.has(settings, 'showHeader') ? settings.showHeader : true;
        this.showPaging = _.has(settings, 'showPaging') ? settings.showPaging : true;
        this.linkToJob = _.has(settings, 'linkToJob') ? settings.linkToJob : true;
        this.triggerJobClick = _.has(settings, 'triggerJobClick') ? settings.triggerJobClick : false;

        this.paginateWidget = new PaginateWidget({
            collection: this.collection,
            parentView: this
        });

        this.listenTo(eventStream, 'g:event.job_status', this._statusChange);
        this.listenTo(eventStream, 'g:event.job_created', this._jobCreated);

        this.timingFilterWidget = new CheckBoxMenu({
            title: 'Phases',
            items: {},
            parentView: this
        });

        this.typeFilterWidget = new CheckBoxMenu({
            title: 'Type',
            items: {},
            parentView: this
        });

        this.listenTo(this.typeFilterWidget, 'g:triggerCheckBoxMenuChanged', function (e) {
            this.typeFilter = _.keys(e).reduce((arr, key) => {
                if (e[key]) {
                    arr.push(key);
                }
                return arr;
            }, []);
            this._fetchWithFilter();
        });

        this.statusFilterWidget = new CheckBoxMenu({
            title: 'Status',
            items: {},
            parentView: this
        });

        let statusTextToStatusCode = {};
        this.listenTo(this.statusFilterWidget, 'g:triggerCheckBoxMenuChanged', function (e) {
            this.statusFilter = _.keys(e).reduce((arr, key) => {
                if (e[key]) {
                    arr.push(parseInt(statusTextToStatusCode[key]));
                }
                return arr;
            }, []);
            this._fetchWithFilter();
        });

        restRequest({
            path: this.showAllJobs ? 'job/typeandstatus/all' : 'job/typeandstatus',
            method: 'GET'
        }).done(result => {
            var typesFilter = result.types.reduce((obj, type) => {
                obj[type] = true;
                return obj;
            }, {});
            this.typeFilterWidget.setItems(typesFilter);

            var statusFilter = result.statuses.map(status => {
                let statusText = JobStatus.text(status);
                statusTextToStatusCode[statusText] = status;
                return statusText;
            }).reduce((obj, statusText) => {
                obj[statusText] = true;
                return obj;
            }, {});
            this.statusFilterWidget.setItems(statusFilter);
        });

        this.render();
    },

    columnEnum: defineFlags([
        'COLUMN_STATUS_ICON',
        'COLUMN_TITLE',
        'COLUMN_UPDATED',
        'COLUMN_OWNER',
        'COLUMN_TYPE',
        'COLUMN_STATUS'
    ], 'COLUMN_ALL'),

    render: function () {
        this.$el.html(JobListWidgetTemplate(_.extend({}, this, {
            pageSize: this.collection.pageLimit
        })));

        this.typeFilterWidget.setElement(this.$('.g-job-filter-container .type')).render();
        this.statusFilterWidget.setElement(this.$('.g-job-filter-container .status')).render();

        this.$('a[data-toggle="tab"]').on('shown.bs.tab', e => {
            this.currentView = $(e.target).attr('name');
            if (this.userId) {
                router.navigate(`jobs/user/${this.userId}/${this.currentView}`);
            } else {
                router.navigate(`jobs/${this.currentView}`);
            }
            this.render();
        });

        if (this.currentView === 'timing-history' || this.currentView === 'time') {
            if (this.jobGraphWidget) {
                this.jobGraphWidget.remove();
            }
            this.jobGraphWidget = new JobGraphWidget({
                parentView: this,
                el: this.$('.g-main-content'),
                collection: this.collection,
                view: this.currentView,
                timingFilter: this.timingFilter,
                timingFilterWidget: this.timingFilterWidget
            });
            this.jobGraphWidget.render();
        }

        this._renderData();

        return this;
    },

    _renderData: function () {
        if (!this.$('.g-main-content').length) {
            // Do nothing until render has been called
            return;
        }

        var jobs = this.collection.toArray();

        if (!jobs.length) {
            this.$('.g-main-content,.g-job-pagination').hide();
            this.$('.g-no-job-record').show();
            return;
        } else {
            this.$('.g-main-content,.g-job-pagination').show();
            this.$('.g-no-job-record').hide();
        }

        if (this.currentView === 'list') {
            this.$('.g-main-content').html(JobListTemplate({
                jobs: jobs,
                showHeader: this.showHeader,
                columns: this.columns,
                columnEnum: this.columnEnum,
                linkToJob: this.linkToJob,
                triggerJobClick: this.triggerJobClick,
                JobStatus: JobStatus,
                formatDate: formatDate,
                DATE_SECOND: DATE_SECOND
            }));
        }

        if (this.showPaging) {
            this.paginateWidget.setElement(this.$('.g-job-pagination')).render();
        }
    },

    _statusChange: function (event) {
        let job = _.find(this.collection.toArray(), job => job.get('_id') === event.data._id);
        if (!job) {
            return;
        }
        job.set(event.data);
        this._renderData();
        this._highlightRecordIfOnList(event.data._id);
    },

    _jobCreated: function (event) {
        this._fetchWithFilter()
            .done(() => {
                this._highlightRecordIfOnList(event.data._id);
            });
    },

    _highlightRecordIfOnList: function (jobId) {
        if (this.currentView === 'list') {
            var tr = this.$('tr[g-job-id=' + jobId + ']').addClass('g-highlight');
            setTimeout(() => tr.removeClass('g-highlight'), 1000);
        }
    },

    _fetchWithFilter() {
        var filter = {};
        if (this.userId) {
            filter.userId = this.userId;
        }
        if (this.typeFilter) {
            filter.types = JSON.stringify(this.typeFilter);
        }
        if (this.statusFilter) {
            filter.statuses = JSON.stringify(this.statusFilter);
        }
        this.collection.params = filter;
        return this.collection.fetch({}, true);
    }
});

export default JobListWidget;
<commit_msg>Explicitly pass arguments to templates<commit_after>import $ from 'jquery';
import _ from 'underscore';

import PaginateWidget from 'girder/views/widgets/PaginateWidget';
import View from 'girder/views/View';
import router from 'girder/router';
import { restRequest } from 'girder/rest';
import { defineFlags, formatDate, DATE_SECOND } from 'girder/misc';
import eventStream from 'girder/utilities/EventStream';
import { getCurrentUser } from 'girder/auth';
import { SORT_DESC } from 'girder/constants';

import JobCollection from '../collections/JobCollection';
import JobStatus from '../JobStatus';
import JobListWidgetTemplate from '../templates/jobListWidget.pug';
import '../stylesheets/jobListWidget.styl';
import JobListTemplate from '../templates/jobList.pug';

import CheckBoxMenu from './CheckBoxMenu';
import JobGraphWidget from './JobGraphWidget';

var JobListWidget = View.extend({
    events: {
        'click .g-job-trigger-link': function (e) {
            var cid = $(e.target).attr('cid');
            this.trigger('g:jobClicked', this.collection.get(cid));
        },
        'change select.g-page-size': function (e) {
            this.collection.pageLimit = parseInt($(e.target).val());
            this.collection.fetch({}, true);
        }
    },

    initialize: function (settings) {
        var currentUser = getCurrentUser();
        this.showAllJobs = !!settings.allJobsMode;
        this.columns = settings.columns || this.columnEnum.COLUMN_ALL;
        this.userId = (settings.filter && !settings.allJobsMode) ? (settings.filter.userId ? settings.filter.userId : currentUser.id) : null;
        this.showGraphs = settings.showGraphs;
        this.showPageSizeSelector = settings.showPageSizeSelector;
        this.showFilters = settings.showFilters;
        this.typeFilter = null;
        this.statusFilter = null;
        this.timingFilter = JobStatus.getAll().reduce((obj, status) => {
            obj[status.text] = true;
            return obj;
        }, {});

        this.jobGraphWidget = null;

        this.pageSizes = [25, 50, 100, 250, 500, 1000];

        this.collection = new JobCollection();
        if (this.showAllJobs) {
            this.collection.resourceName = 'job/all';
        }
        this.collection.sortField = settings.sortField || 'created';
        this.collection.sortDir = settings.sortDir || SORT_DESC;
        this.collection.pageLimit = settings.pageLimit || this.collection.pageLimit;

        this.listenTo(this.collection, 'update reset', this._renderData);

        this._fetchWithFilter();

        this.currentView = settings.view ? settings.view : 'list';

        this.showHeader = _.has(settings, 'showHeader') ? settings.showHeader : true;
        this.showPaging = _.has(settings, 'showPaging') ? settings.showPaging : true;
        this.linkToJob = _.has(settings, 'linkToJob') ? settings.linkToJob : true;
        this.triggerJobClick = _.has(settings, 'triggerJobClick') ? settings.triggerJobClick : false;

        this.paginateWidget = new PaginateWidget({
            collection: this.collection,
            parentView: this
        });

        this.listenTo(eventStream, 'g:event.job_status', this._statusChange);
        this.listenTo(eventStream, 'g:event.job_created', this._jobCreated);

        this.timingFilterWidget = new CheckBoxMenu({
            title: 'Phases',
            items: {},
            parentView: this
        });

        this.typeFilterWidget = new CheckBoxMenu({
            title: 'Type',
            items: {},
            parentView: this
        });

        this.listenTo(this.typeFilterWidget, 'g:triggerCheckBoxMenuChanged', function (e) {
            this.typeFilter = _.keys(e).reduce((arr, key) => {
                if (e[key]) {
                    arr.push(key);
                }
                return arr;
            }, []);
            this._fetchWithFilter();
        });

        this.statusFilterWidget = new CheckBoxMenu({
            title: 'Status',
            items: {},
            parentView: this
        });

        let statusTextToStatusCode = {};
        this.listenTo(this.statusFilterWidget, 'g:triggerCheckBoxMenuChanged', function (e) {
            this.statusFilter = _.keys(e).reduce((arr, key) => {
                if (e[key]) {
                    arr.push(parseInt(statusTextToStatusCode[key]));
                }
                return arr;
            }, []);
            this._fetchWithFilter();
        });

        restRequest({
            path: this.showAllJobs ? 'job/typeandstatus/all' : 'job/typeandstatus',
            method: 'GET'
        }).done(result => {
            var typesFilter = result.types.reduce((obj, type) => {
                obj[type] = true;
                return obj;
            }, {});
            this.typeFilterWidget.setItems(typesFilter);

            var statusFilter = result.statuses.map(status => {
                let statusText = JobStatus.text(status);
                statusTextToStatusCode[statusText] = status;
                return statusText;
            }).reduce((obj, statusText) => {
                obj[statusText] = true;
                return obj;
            }, {});
            this.statusFilterWidget.setItems(statusFilter);
        });

        this.render();
    },

    columnEnum: defineFlags([
        'COLUMN_STATUS_ICON',
        'COLUMN_TITLE',
        'COLUMN_UPDATED',
        'COLUMN_OWNER',
        'COLUMN_TYPE',
        'COLUMN_STATUS'
    ], 'COLUMN_ALL'),

    render: function () {
        this.$el.html(JobListWidgetTemplate({
            currentView: this.currentView,
            pageSize: this.collection.pageLimit,
            pageSizes: this.pageSizes,
            showFilters: this.showFilters,
            showGraphs: this.showGraphs,
            showPageSizeSelector: this.showPageSizeSelector
        }));

        this.typeFilterWidget.setElement(this.$('.g-job-filter-container .type')).render();
        this.statusFilterWidget.setElement(this.$('.g-job-filter-container .status')).render();

        this.$('a[data-toggle="tab"]').on('shown.bs.tab', e => {
            this.currentView = $(e.target).attr('name');
            if (this.userId) {
                router.navigate(`jobs/user/${this.userId}/${this.currentView}`);
            } else {
                router.navigate(`jobs/${this.currentView}`);
            }
            this.render();
        });

        if (this.currentView === 'timing-history' || this.currentView === 'time') {
            if (this.jobGraphWidget) {
                this.jobGraphWidget.remove();
            }
            this.jobGraphWidget = new JobGraphWidget({
                parentView: this,
                el: this.$('.g-main-content'),
                collection: this.collection,
                view: this.currentView,
                timingFilter: this.timingFilter,
                timingFilterWidget: this.timingFilterWidget
            });
            this.jobGraphWidget.render();
        }

        this._renderData();

        return this;
    },

    _renderData: function () {
        if (!this.$('.g-main-content').length) {
            // Do nothing until render has been called
            return;
        }

        var jobs = this.collection.toArray();

        if (!jobs.length) {
            this.$('.g-main-content,.g-job-pagination').hide();
            this.$('.g-no-job-record').show();
            return;
        } else {
            this.$('.g-main-content,.g-job-pagination').show();
            this.$('.g-no-job-record').hide();
        }

        if (this.currentView === 'list') {
            this.$('.g-main-content').html(JobListTemplate({
                jobs: jobs,
                showHeader: this.showHeader,
                columns: this.columns,
                columnEnum: this.columnEnum,
                linkToJob: this.linkToJob,
                triggerJobClick: this.triggerJobClick,
                JobStatus: JobStatus,
                formatDate: formatDate,
                DATE_SECOND: DATE_SECOND
            }));
        }

        if (this.showPaging) {
            this.paginateWidget.setElement(this.$('.g-job-pagination')).render();
        }
    },

    _statusChange: function (event) {
        let job = _.find(this.collection.toArray(), job => job.get('_id') === event.data._id);
        if (!job) {
            return;
        }
        job.set(event.data);
        this._renderData();
        this._highlightRecordIfOnList(event.data._id);
    },

    _jobCreated: function (event) {
        this._fetchWithFilter()
            .done(() => {
                this._highlightRecordIfOnList(event.data._id);
            });
    },

    _highlightRecordIfOnList: function (jobId) {
        if (this.currentView === 'list') {
            var tr = this.$('tr[g-job-id=' + jobId + ']').addClass('g-highlight');
            setTimeout(() => tr.removeClass('g-highlight'), 1000);
        }
    },

    _fetchWithFilter() {
        var filter = {};
        if (this.userId) {
            filter.userId = this.userId;
        }
        if (this.typeFilter) {
            filter.types = JSON.stringify(this.typeFilter);
        }
        if (this.statusFilter) {
            filter.statuses = JSON.stringify(this.statusFilter);
        }
        this.collection.params = filter;
        return this.collection.fetch({}, true);
    }
});

export default JobListWidget;
<|endoftext|>


<commit_before>define(['castrato'], function (castrato) {
	var exports = {};

	castrato.on('*', function (data, done, name) {
		if (name !== 'console:post' && name !== 'notification:send') {
			castrato.emit('console:post', {
				type: 'server',
				data: name + (data ? '(' + JSON.stringify(data) + ')' : ''),
				debug: 1
			});
		}

		done();
	});

	return exports;
});<commit_msg>Delete debug.js<commit_after><|endoftext|>


<commit_before>var settings_notifications = (function () {

var exports = {};

exports.set_up = function () {
    $("#notify-settings-status").hide();

    if (!page_params.realm_show_digest_email) {
        $("#other_notifications").hide();
    }

    function update_notification_settings_success(resp, statusText, xhr) {
        var result = JSON.parse(xhr.responseText);
        var notify_settings_status = $('#notify-settings-status').expectOne();

        // Stream notification settings.

        if (result.enable_stream_desktop_notifications !== undefined) {
            page_params.enable_stream_desktop_notifications =
                result.enable_stream_desktop_notifications;
        }
        if (result.enable_stream_sounds !== undefined) {
            page_params.enable_stream_sounds = result.enable_stream_sounds;
        }

        // PM and @-mention notification settings.

        if (result.enable_desktop_notifications !== undefined) {
            page_params.enable_desktop_notifications = result.enable_desktop_notifications;
        }
        if (result.enable_sounds !== undefined) {
            page_params.enable_sounds = result.enable_sounds;
        }

        if (result.enable_offline_email_notifications !== undefined) {
            page_params.enable_offline_email_notifications =
                result.enable_offline_email_notifications;
        }

        if (result.enable_offline_push_notifications !== undefined) {
            page_params.enable_offline_push_notifications =
                result.enable_offline_push_notifications;
        }

        if (result.enable_online_push_notifications !== undefined) {
            page_params.enable_online_push_notifications = result.enable_online_push_notifications;
        }

        if (result.pm_content_in_desktop_notifications !== undefined) {
            page_params.pm_content_in_desktop_notifications
                = result.pm_content_in_desktop_notifications;
        }
        // Other notification settings.

        if (result.enable_digest_emails !== undefined) {
            page_params.enable_digest_emails = result.enable_digest_emails;
        }

        ui_report.success(i18n.t("Updated notification settings!"), notify_settings_status);
    }

    function update_notification_settings_error(xhr) {
        ui_report.error(i18n.t("Error changing settings"), xhr, $('#notify-settings-status').expectOne());
    }

    function post_notify_settings_changes(notification_changes, success_func,
                                          error_func) {
        return channel.patch({
            url: "/json/settings/notifications",
            data: notification_changes,
            success: success_func,
            error: error_func,
        });
    }

    $("#change_notification_settings").on("click", function (e) {
        e.preventDefault();

        var updated_settings = {};
        _.each(["enable_stream_desktop_notifications", "enable_stream_sounds",
                "enable_desktop_notifications", "pm_content_in_desktop_notifications", "enable_sounds",
                "enable_offline_email_notifications",
                "enable_offline_push_notifications", "enable_online_push_notifications",
                "enable_digest_emails"],
               function (setting) {
                   updated_settings[setting] = $("#" + setting).is(":checked");
               });
        post_notify_settings_changes(updated_settings,
                                     update_notification_settings_success,
                                     update_notification_settings_error);
    });

    function update_global_stream_setting(notification_type, new_setting) {
        var data = {};
        data[notification_type] = new_setting;
        channel.patch({
            url: "/json/settings/notifications",
            data: data,
            success: update_notification_settings_success,
            error: update_notification_settings_error,
        });
    }

    function update_desktop_notification_setting(new_setting) {
        update_global_stream_setting("enable_stream_desktop_notifications", new_setting);
        stream_edit.set_all_stream_desktop_notifications_to(new_setting);
    }

    function update_audible_notification_setting(new_setting) {
        update_global_stream_setting("enable_stream_sounds", new_setting);
        stream_edit.set_all_stream_audible_notifications_to(new_setting);
    }

    function maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                           propagate_setting_function) {
        var html = templates.render("propagate_notification_change");
        // TODO: This seems broken!!!
        var control_group = notification_checkbox.closest(".control-group");
        var checkbox_status = notification_checkbox.is(":checked");
        control_group.find(".propagate_stream_notifications_change").html(html);
        control_group.find(".yes_propagate_notifications").on("click", function () {
            propagate_setting_function(checkbox_status);
            control_group.find(".propagate_stream_notifications_change").empty();
        });
        control_group.find(".no_propagate_notifications").on("click", function () {
            control_group.find(".propagate_stream_notifications_change").empty();
        });
    }

    $("#enable_stream_desktop_notifications").on("click", function () {
        var notification_checkbox = $("#enable_stream_desktop_notifications");
        maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                      update_desktop_notification_setting);
    });

    $("#enable_stream_sounds").on("click", function () {
        var notification_checkbox = $("#enable_stream_sounds");
        maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                      update_audible_notification_setting);
    });

};

function _update_page() {
    $("#enable_stream_desktop_notifications").prop('checked', page_params.enable_stream_desktop_notifications);
    $("#enable_stream_sounds").prop('checked', page_params.enable_stream_sounds);
    $("#enable_desktop_notifications").prop('checked', page_params.enable_desktop_notifications);
    $("#enable_sounds").prop('checked', page_params.enable_sounds);
    $("#enable_offline_email_notifications").prop('checked', page_params.enable_offline_email_notifications);
    $("#enable_offline_push_notifications").prop('checked', page_params.enable_offline_push_notifications);
    $("#enable_online_push_notifications").prop('checked', page_params.enable_online_push_notifications);
    $("#pm_content_in_desktop_notifications").prop('checked', page_params.pm_content_in_desktop_notifications);
    $("#enable_digest_emails").prop('checked', page_params.enable_digest_emails);
}

exports.update_page = function () {
    i18n.ensure_i18n(_update_page);
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = settings_notifications;
}
<commit_msg>settings_notifications.js: Refactor using notification_settings variable.<commit_after>var settings_notifications = (function () {

var exports = {};

var notification_settings = [
    "enable_desktop_notifications",
    "enable_digest_emails",
    "enable_offline_email_notifications",
    "enable_offline_push_notifications",
    "enable_online_push_notifications",
    "enable_sounds",
    "enable_stream_desktop_notifications",
    "enable_stream_sounds",
    "pm_content_in_desktop_notifications",
];

exports.set_up = function () {
    $("#notify-settings-status").hide();

    if (!page_params.realm_show_digest_email) {
        $("#other_notifications").hide();
    }

    function update_notification_settings_success(resp, statusText, xhr) {
        var result = JSON.parse(xhr.responseText);
        var notify_settings_status = $('#notify-settings-status').expectOne();

        // Stream notification settings.

        _.each(result, function  (v, k) {
            if (_.has(notification_settings, k) && result[k] !== undefined) {
                page_params[k] = result[k];
            }
        });
        ui_report.success(i18n.t("Updated notification settings!"), notify_settings_status);
    }

    function update_notification_settings_error(xhr) {
        ui_report.error(i18n.t("Error changing settings"), xhr, $('#notify-settings-status').expectOne());
    }

    function post_notify_settings_changes(notification_changes, success_func,
                                          error_func) {
        return channel.patch({
            url: "/json/settings/notifications",
            data: notification_changes,
            success: success_func,
            error: error_func,
        });
    }

    $("#change_notification_settings").on("click", function (e) {
        e.preventDefault();

        var updated_settings = {};
        _.each(notification_settings, function (setting) {
            updated_settings[setting] = $("#" + setting).is(":checked");
        });
        post_notify_settings_changes(updated_settings,
                                     update_notification_settings_success,
                                     update_notification_settings_error);
    });

    function update_global_stream_setting(notification_type, new_setting) {
        var data = {};
        data[notification_type] = new_setting;
        channel.patch({
            url: "/json/settings/notifications",
            data: data,
            success: update_notification_settings_success,
            error: update_notification_settings_error,
        });
    }

    function update_desktop_notification_setting(new_setting) {
        update_global_stream_setting("enable_stream_desktop_notifications", new_setting);
        stream_edit.set_all_stream_desktop_notifications_to(new_setting);
    }

    function update_audible_notification_setting(new_setting) {
        update_global_stream_setting("enable_stream_sounds", new_setting);
        stream_edit.set_all_stream_audible_notifications_to(new_setting);
    }

    function maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                           propagate_setting_function) {
        var html = templates.render("propagate_notification_change");
        // TODO: This seems broken!!!
        var control_group = notification_checkbox.closest(".control-group");
        var checkbox_status = notification_checkbox.is(":checked");
        control_group.find(".propagate_stream_notifications_change").html(html);
        control_group.find(".yes_propagate_notifications").on("click", function () {
            propagate_setting_function(checkbox_status);
            control_group.find(".propagate_stream_notifications_change").empty();
        });
        control_group.find(".no_propagate_notifications").on("click", function () {
            control_group.find(".propagate_stream_notifications_change").empty();
        });
    }

    $("#enable_stream_desktop_notifications").on("click", function () {
        var notification_checkbox = $("#enable_stream_desktop_notifications");
        maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                      update_desktop_notification_setting);
    });

    $("#enable_stream_sounds").on("click", function () {
        var notification_checkbox = $("#enable_stream_sounds");
        maybe_bulk_update_stream_notification_setting(notification_checkbox,
                                                      update_audible_notification_setting);
    });

};

function _update_page() {
    _.each(notification_settings, function (setting) {
        $("#" + setting).prop('checked', page_params[setting]);
    });
}

exports.update_page = function () {
    i18n.ensure_i18n(_update_page);
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = settings_notifications;
}
<|endoftext|>


<commit_before>/* -*- mode: javascript; c-basic-offset: 4; indent-tabs-mode: nil -*- */

//
// Dalliance Genome Explorer
// (c) Thomas Down 2006-2013
//
// overlay.js: featuresources composed from multiple underlying sources
//

"use strict";

if (typeof(require) !== 'undefined') {
    var utils = require('./utils');
    var shallowCopy = utils.shallowCopy;
}

function OverlayFeatureSource(sources, opts) {
    this.sources = sources;
    this.opts = opts || {};
    this.activityListeners = [];
    this.readinessListeners = [];
    this.changeListeners = [];
    this.business = [];
    this.readiness = [];

    for (var i = 0; i < this.sources.length; ++i) {
        this.initN(i);
    }

    if (typeof(opts.merge) === 'function') {
        this.merge = opts.merge;
    } else if (opts.merge == 'concat') {
        this.merge = OverlayFeatureSource_merge_concat;
    } else {
        this.merge = OverlayFeatureSource_merge_byKey;
    }
}

OverlayFeatureSource.prototype.initN = function(n) {
    var s = this.sources[n];
    var thisB = this;
    this.business[n] = 0;

    if (s.addActivityListener) {
        s.addActivityListener(function(b) {
            thisB.business[n] = b;
            thisB.notifyActivity();
        });
    }
    if (s.addChangeListener) {
        s.addChangeListener(function() {
            thisB.notifyChange();
        });
    }
    if (s.addReadinessListener) {
        s.addReadinessListener(function(r) {
            thisB.readiness[n] = r;
            thisB.notifyReadiness();
        });
    }
}

OverlayFeatureSource.prototype.addReadinessListener = function(l) {
    this.readinessListeners.push(l);
    this.notifyReadinessListener(l);
}

OverlayFeatureSource.prototype.notifyReadiness = function() {
    for (var i = 0; i < this.readinessListeners.length; ++i) {
        this.notifyReadinessListener(this.readinessListeners[i]);
    }
}

OverlayFeatureSource.prototype.notifyReadinessListener = function(l) {
    var r = null;
    for (var i = 0; i < this.readiness.length; ++i) {
        if (this.readiness[i] != null) {
            r = this.readiness[i]; break;
        }
    }
    try {
        l(r);
    } catch (e) {
        console.log(e);
    }
}

OverlayFeatureSource.prototype.addActivityListener = function(l) {
    this.activityListeners.push(l);
}

OverlayFeatureSource.prototype.notifyActivity = function() {
    var busy = 0;
    for (var i = 0; i < this.business.length; ++i) {
        busy += this.business[i];
    }

    for (var li = 0; li < this.activityListeners.length; ++li) {
        try {
            this.activityListeners[li](busy);
        } catch (e) {
            console.log(e);
        }
    }
}

OverlayFeatureSource.prototype.addChangeListener = function(listener) {
    this.changeListeners.push(listener);
}

OverlayFeatureSource.prototype.notifyChange = function() {
    for (var li = 0; li < this.changeListeners.length; ++li) {
        try {
            this.changeListeners[li](this.busy);
        } catch (e) {
            console.log(e);
        }
    }
}

OverlayFeatureSource.prototype.getScales = function() {
    return this.sources[0].getScales();
}

OverlayFeatureSource.prototype.getStyleSheet = function(callback) {
    return this.sources[0].getStyleSheet(callback);
}

OverlayFeatureSource.prototype.capabilities = function() {
    var caps = {};
    var s0 = this.sources[0];
    if (s0.capabilities)
        caps = shallowCopy(s0.capabilities());

    for (var i = 1; i < this.sources.length; ++i) {
        var si = this.sources[i];
        if (si.capabilities) {
            var co = si.capabilities();
            if (co.search) {
                caps.search = co.search;
            }
        }
    }

    return caps;
}

OverlayFeatureSource.prototype.search = function(query, callback) {
    for (var i = 0; i < this.sources.length; ++i) {
        if (sourceAdapterIsCapable(this.sources[i], 'search')) {
            return this.sources[i].search(query, callback);
        }
    }
}

OverlayFeatureSource.prototype.fetch = function(chr, min, max, scale, types, pool, callback) {
    var baton = new OverlayBaton(this, callback, this.sources.length);
    for (var si = 0; si < this.sources.length; ++si) {
	this.fetchN(baton, si, chr, min, max, scale, types, pool);
    }
}

OverlayFeatureSource.prototype.fetchN = function(baton, si, chr, min, max, scale, types, pool) {
    this.sources[si].fetch(chr, min, max, scale, types, pool, function(status, features, scale) {
	return baton.completed(si, status, features, scale);
    });
}

OverlayFeatureSource.prototype.quantFindNextFeature = function(chr, pos, dir, threshold, callback) {
    return this.sources[0].quantFindNextFeature(chr, pos, dir, threshold, callback);
}

OverlayFeatureSource.prototype.findNextFeature = function(chr, pos, dir, callback) {
    return this.sources[0].findNextFeature(chr, pos, dir, callback);
}

function OverlayBaton(source, callback, count) {
    this.source = source;
    this.callback = callback;
    this.count = count;

    this.returnCount = 0;
    this.statusCount = 0;
    this.returns = [];
    this.features = []
    this.statuses = [];
    this.scale = null;
}

OverlayBaton.prototype.completed = function(index, status, features, scale) {
    if (this.scale == null || index == 0)
	   this.scale = scale;

    if (this.returns[index])
	   throw 'Multiple returns for source ' + index;

    this.returns[index] = true;
    this.returnCount++;

    this.features[index] = features;

    if (status) {
    	this.statuses[index] = status;
    	this.statusCount++;
    }

    if (this.returnCount == this.count) {
    	if (this.statusCount > 0) {
    	    var message = '';
    	    for (var si = 0; si < this.count; ++si) {
        		var s = this.statuses[si];
        		if (s) {
        		    if (message.length > 0)
        			message += ', ';
        		    message += s;
        		}
    	    }
    	    return this.callback(message, null, this.scale);
    	} else {
    	    this.callback(null, this.source.merge(this.features), this.scale);
    	}
    }
}

OverlayFeatureSource.prototype.getDefaultFIPs = function(callback) {
    for (var si = 0; si < this.sources.length; ++si) {
        var s = this.sources[si];
        if (s.getDefaultFIPs)
            s.getDefaultFIPs(callback);
    }
}

OverlayFeatureSource.prototype.keyForFeature = function(feature) {
    return '' + feature.min + '..' + feature.max;
}

function OverlayFeatureSource_merge_byKey(featureSets) {
    var omaps = [];

    for (var fsi = 1; fsi < featureSets.length; ++fsi) {
        var om = {};
        var of = featureSets[fsi];
        for (var fi = 0; fi < of.length; ++fi) {
    	   om[this.keyForFeature(of[fi])] = of[fi];
        }
        omaps.push(om);
    }

    var mf = [];
    var fl = featureSets[0];
    for (var fi = 0; fi < fl.length; ++fi) {
    	var f = fl[fi];

        for (var oi = 0; oi < omaps.length; ++oi) {
            var om = omaps[oi];
        	of = om[this.keyForFeature(f)]
        	if (of) {
                for (var k in of) {
                    if (k === 'score') {
                        f.score2 = of.score;
                    } else if (k === 'min' || k === 'max' || k === 'segment' || k === '_cachedStyle') {
                        // do nothing
                    } else {
                        f[k] = of[k];
                    }
                }
        	}
        }
    	mf.push(f);
    }
    return mf;
}

function OverlayFeatureSource_merge_concat(featureSets) {
    var features = [];
    for (var fsi = 0; fsi < featureSets.length; ++fsi) {
        var fs = featureSets[fsi];
        var name = this.sources[fsi].name;
        for (var fi = 0; fi < fs.length; ++fi) {
            var f = fs[fi];
            f.method = name;
            features.push(f);
        }
    }
    return features;
}

if (typeof(module) !== 'undefined') {
    module.exports = {
        OverlayFeatureSource: OverlayFeatureSource
    };
}
<commit_msg>Fix capabilities bug in overlay code.<commit_after>/* -*- mode: javascript; c-basic-offset: 4; indent-tabs-mode: nil -*- */

//
// Dalliance Genome Explorer
// (c) Thomas Down 2006-2013
//
// overlay.js: featuresources composed from multiple underlying sources
//

"use strict";

if (typeof(require) !== 'undefined') {
    var utils = require('./utils');
    var shallowCopy = utils.shallowCopy;
}

function OverlayFeatureSource(sources, opts) {
    this.sources = sources;
    this.opts = opts || {};
    this.activityListeners = [];
    this.readinessListeners = [];
    this.changeListeners = [];
    this.business = [];
    this.readiness = [];

    for (var i = 0; i < this.sources.length; ++i) {
        this.initN(i);
    }

    if (typeof(opts.merge) === 'function') {
        this.merge = opts.merge;
    } else if (opts.merge == 'concat') {
        this.merge = OverlayFeatureSource_merge_concat;
    } else {
        this.merge = OverlayFeatureSource_merge_byKey;
    }
}

OverlayFeatureSource.prototype.initN = function(n) {
    var s = this.sources[n];
    var thisB = this;
    this.business[n] = 0;

    if (s.addActivityListener) {
        s.addActivityListener(function(b) {
            thisB.business[n] = b;
            thisB.notifyActivity();
        });
    }
    if (s.addChangeListener) {
        s.addChangeListener(function() {
            thisB.notifyChange();
        });
    }
    if (s.addReadinessListener) {
        s.addReadinessListener(function(r) {
            thisB.readiness[n] = r;
            thisB.notifyReadiness();
        });
    }
}

OverlayFeatureSource.prototype.addReadinessListener = function(l) {
    this.readinessListeners.push(l);
    this.notifyReadinessListener(l);
}

OverlayFeatureSource.prototype.notifyReadiness = function() {
    for (var i = 0; i < this.readinessListeners.length; ++i) {
        this.notifyReadinessListener(this.readinessListeners[i]);
    }
}

OverlayFeatureSource.prototype.notifyReadinessListener = function(l) {
    var r = null;
    for (var i = 0; i < this.readiness.length; ++i) {
        if (this.readiness[i] != null) {
            r = this.readiness[i]; break;
        }
    }
    try {
        l(r);
    } catch (e) {
        console.log(e);
    }
}

OverlayFeatureSource.prototype.addActivityListener = function(l) {
    this.activityListeners.push(l);
}

OverlayFeatureSource.prototype.notifyActivity = function() {
    var busy = 0;
    for (var i = 0; i < this.business.length; ++i) {
        busy += this.business[i];
    }

    for (var li = 0; li < this.activityListeners.length; ++li) {
        try {
            this.activityListeners[li](busy);
        } catch (e) {
            console.log(e);
        }
    }
}

OverlayFeatureSource.prototype.addChangeListener = function(listener) {
    this.changeListeners.push(listener);
}

OverlayFeatureSource.prototype.notifyChange = function() {
    for (var li = 0; li < this.changeListeners.length; ++li) {
        try {
            this.changeListeners[li](this.busy);
        } catch (e) {
            console.log(e);
        }
    }
}

OverlayFeatureSource.prototype.getScales = function() {
    return this.sources[0].getScales();
}

OverlayFeatureSource.prototype.getStyleSheet = function(callback) {
    return this.sources[0].getStyleSheet(callback);
}

OverlayFeatureSource.prototype.capabilities = function() {
    var caps = {};
    var s0 = this.sources[0];
    if (s0.capabilities)
        caps = shallowCopy(s0.capabilities());

    for (var i = 1; i < this.sources.length; ++i) {
        var si = this.sources[i];
        if (si.capabilities) {
            var co = si.capabilities();
            if (co.search) {
                caps.search = co.search;
            }
        }
    }

    return caps;
}

OverlayFeatureSource.prototype.search = function(query, callback) {
    for (var i = 0; i < this.sources.length; ++i) {
        if (_sourceAdapterIsCapable(this.sources[i], 'search')) {
            return this.sources[i].search(query, callback);
        }
    }
}

OverlayFeatureSource.prototype.fetch = function(chr, min, max, scale, types, pool, callback) {
    var baton = new OverlayBaton(this, callback, this.sources.length);
    for (var si = 0; si < this.sources.length; ++si) {
	   this.fetchN(baton, si, chr, min, max, scale, types, pool);
    }
}

OverlayFeatureSource.prototype.fetchN = function(baton, si, chr, min, max, scale, types, pool) {
    this.sources[si].fetch(chr, min, max, scale, types, pool, function(status, features, scale) {
	   return baton.completed(si, status, features, scale);
    });
}

OverlayFeatureSource.prototype.quantFindNextFeature = function(chr, pos, dir, threshold, callback) {
    return this.sources[0].quantFindNextFeature(chr, pos, dir, threshold, callback);
}

OverlayFeatureSource.prototype.findNextFeature = function(chr, pos, dir, callback) {
    return this.sources[0].findNextFeature(chr, pos, dir, callback);
}

function OverlayBaton(source, callback, count) {
    this.source = source;
    this.callback = callback;
    this.count = count;

    this.returnCount = 0;
    this.statusCount = 0;
    this.returns = [];
    this.features = []
    this.statuses = [];
    this.scale = null;
}

OverlayBaton.prototype.completed = function(index, status, features, scale) {
    if (this.scale == null || index == 0)
	   this.scale = scale;

    if (this.returns[index])
	   throw 'Multiple returns for source ' + index;

    this.returns[index] = true;
    this.returnCount++;

    this.features[index] = features;

    if (status) {
    	this.statuses[index] = status;
    	this.statusCount++;
    }

    if (this.returnCount == this.count) {
    	if (this.statusCount > 0) {
    	    var message = '';
    	    for (var si = 0; si < this.count; ++si) {
        		var s = this.statuses[si];
        		if (s) {
        		    if (message.length > 0)
        			message += ', ';
        		    message += s;
        		}
    	    }
    	    return this.callback(message, null, this.scale);
    	} else {
    	    this.callback(null, this.source.merge(this.features), this.scale);
    	}
    }
}

OverlayFeatureSource.prototype.getDefaultFIPs = function(callback) {
    for (var si = 0; si < this.sources.length; ++si) {
        var s = this.sources[si];
        if (s.getDefaultFIPs)
            s.getDefaultFIPs(callback);
    }
}

OverlayFeatureSource.prototype.keyForFeature = function(feature) {
    return '' + feature.min + '..' + feature.max;
}

function OverlayFeatureSource_merge_byKey(featureSets) {
    var omaps = [];

    for (var fsi = 1; fsi < featureSets.length; ++fsi) {
        var om = {};
        var of = featureSets[fsi];
        for (var fi = 0; fi < of.length; ++fi) {
    	   om[this.keyForFeature(of[fi])] = of[fi];
        }
        omaps.push(om);
    }

    var mf = [];
    var fl = featureSets[0];
    for (var fi = 0; fi < fl.length; ++fi) {
    	var f = fl[fi];

        for (var oi = 0; oi < omaps.length; ++oi) {
            var om = omaps[oi];
        	of = om[this.keyForFeature(f)]
        	if (of) {
                for (var k in of) {
                    if (k === 'score') {
                        f.score2 = of.score;
                    } else if (k === 'min' || k === 'max' || k === 'segment' || k === '_cachedStyle') {
                        // do nothing
                    } else {
                        f[k] = of[k];
                    }
                }
        	}
        }
    	mf.push(f);
    }
    return mf;
}

function OverlayFeatureSource_merge_concat(featureSets) {
    var features = [];
    for (var fsi = 0; fsi < featureSets.length; ++fsi) {
        var fs = featureSets[fsi];
        var name = this.sources[fsi].name;
        for (var fi = 0; fi < fs.length; ++fi) {
            var f = fs[fi];
            f.method = name;
            features.push(f);
        }
    }
    return features;
}

function _sourceAdapterIsCapable(s, cap) {
    if (!s.capabilities)
        return false;
    else
        return s.capabilities()[cap];
}

if (typeof(module) !== 'undefined') {
    module.exports = {
        OverlayFeatureSource: OverlayFeatureSource
    };
}

<|endoftext|>


<commit_before>(function(){
	var idDiv = document.getElementById('main');

	function getPartial(originalHref){
		var partialHref = 'partials/' + originalHref;
		window.fetch(partialHref)
		.then(function(resp){
			return resp.text()
		})
		.then(function(pageText){
			idDiv.innerHTML = pageText;
			window.prettyPrint();
			var scrollTo = originalHref.split('#')[1],
				elm;
			if (scrollTo){
				elm = document.getElementById(scrollTo);
			} else {
				elm = idDiv;
			}
			if (elm) elm.scrollIntoView();
			if (needUpdateURL) {
				history.pushState({href: originalHref}, "", originalHref);
			}
		});
	}

	function isPartial(href){
		var res = Boolean(href);
		if (res) res = (href.indexOf('.js.html') === -1)
			&& (href.indexOf('http://') === -1)
			&& (href.indexOf('https://') === -1)
			&& (href.charAt(0) !== '/');
		return res;
	}
	var needUpdateURL = false;

	if (window && window.fetch && window.history && history.pushState) {
		document.body.onclick = function( e ) {
			var evt = e || window.event,
				target = evt.target || evt.srcElement,
				originalHref;

			// If the element clicked is an anchor
			if ( target.nodeName === 'A' ) {
				originalHref = target.getAttribute('href');
				if (isPartial(originalHref)){
					needUpdateURL = true;
					getPartial(originalHref);
					e.preventDefault();
				}
                document.getElementById('search-trigger').checked = false;
                document.getElementById('nav-trigger').checked = false;
			}
		};
		window.onpopstate = function(event) {
			needUpdateURL = false;
			if (event.state && event.state.href){
				getPartial(event.state.href);
			}
		}
	}

if (!window.exports) window.exports = {};
    /**
     * Set a position of source to line, specified as a URL hash tag
     */
window.exports["gotoLine"] = function() {
    var source = document.getElementsByClassName('prettyprint source linenums');
    var i = 0;
    var lineNumber = 0;
    var lineId;
    var lines;
    var totalLines;
    var anchorHash;

    if (source && source[0]) {
        anchorHash = document.location.hash.substring(1);
        lines = source[0].getElementsByTagName('li');
        totalLines = lines.length;

        for (; i < totalLines; i++) {
            lineNumber++;
            lineId = 'line' + lineNumber;
            lines[i].id = lineId;
            if (lineId === anchorHash) {
                lines[i].className += ' selected';
            }
        }
    }
};

var ftsData = null, searchInProgress = false;
function buildSearchResultHTML(data, level){
    var result='', keys, i, l;
    keys = Object.keys(data);
    for (i=0, l=keys.length; i<l; i++) {
        if (typeof data[keys[i]] === 'string') {
            result +='
' + data[keys[i]] + '
';
        } else {
            result += '
<h' + level + '>' + keys[i] + '</h' + level + '>';
            result += buildSearchResultHTML(data[keys[i]], keys[i], level + 1);
            result += '
';
        }
    }
    return result;
}
function fullTextSearch(textToSearch){
    var searchData;
    if (searchInProgress) return;
    if (!textToSearch){
        document.getElementById('search-trigger').checked = false;
    }
    searchInProgress = true;
    if (!ftsData) { //fetch data
        searchData = Promise.all([window.fetch('ftsIndex.json'), window.fetch('ftsData.json')])
            .then(function(values) {
                return Promise.all([values[0].json(), values[1].json()]);
            })
            .then(function(valuesInJSON){
                ftsData = {
                    ftsIndex: lunr.Index.load(valuesInJSON[0]),
                    ftsData: valuesInJSON[1]
                };
                return ftsData;
            })
    } else {
        searchData = Promise.resolve(ftsData)
    }
    searchData.then(function(data){
        var search = data.ftsIndex.search(textToSearch),
            allData = data.ftsData,
            res = {},
            pathSplitRe = /[:~#\.]/,
            member, memberPath, currentNode, i, j, l, jl, resHTML;
        for(i= 0, l=search.length; i<l && search[i].score > 0.001; i++){
            member = allData[search[i].ref];
            memberPath = member.path.split(pathSplitRe);
            if (memberPath[0] === 'module'){ // almost all element are inside module, so let's remove a `module` keyword
                memberPath.shift();
            }
            if (memberPath.length<2){ // add a grouping
                memberPath.unshift(member.group);
            }
            currentNode = res;
            for(j=0, jl = memberPath.length; j < jl-1; j++){ // without leaf
                if (!currentNode[memberPath[j]]){
                    currentNode[memberPath[j]] = {}
                }
                currentNode = currentNode[memberPath[j]];
            }
            currentNode[memberPath[j]] = '' + memberPath[j] + '';
        }
        if (search.length) {
            resHTML = buildSearchResultHTML(res, 2)
        } else {
            resHTML = 'Not found'
        }
        var sElm = document.getElementById('search-result-inner');
        sElm.innerHTML = resHTML;
        var trigger = document.getElementById('search-trigger');
        trigger.checked = true;
    }).then(function(){
        searchInProgress = false;
    })
}
window.exports["fullTextSearch"] = fullTextSearch;

/** realisation of debounce from lodash */
function debounce(func, wait, options) {
    var lastArgs,
        lastThis,
        maxWait,
        result,
        timerId,
        lastCallTime = 0,
        lastInvokeTime = 0,
        leading = false,
        maxing = false,
        trailing = true;

    wait = wait || 0;
    if (typeof options === 'object') {
        leading = !!options.leading;
        maxing = 'maxWait' in options;
        maxWait = maxing ?  Math.max(options.maxWait || 0, wait) : maxWait;
        trailing = 'trailing' in options ? !!options.trailing : trailing;
    }

    function invokeFunc(time) {
        var args = lastArgs,
            thisArg = lastThis;

        lastArgs = lastThis = undefined;
        lastInvokeTime = time;
        result = func.apply(thisArg, args);
        return result;
    }

    function leadingEdge(time) {
        // Reset any `maxWait` timer.
        lastInvokeTime = time;
        // Start the timer for the trailing edge.
        timerId = setTimeout(timerExpired, wait);
        // Invoke the leading edge.
        return leading ? invokeFunc(time) : result;
    }

    function remainingWait(time) {
        var timeSinceLastCall = time - lastCallTime,
            timeSinceLastInvoke = time - lastInvokeTime,
            result = wait - timeSinceLastCall;

        return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
    }

    function shouldInvoke(time) {
        var timeSinceLastCall = time - lastCallTime,
            timeSinceLastInvoke = time - lastInvokeTime;

        // Either this is the first call, activity has stopped and we're at the
        // trailing edge, the system time has gone backwards and we're treating
        // it as the trailing edge, or we've hit the `maxWait` limit.
        return (!lastCallTime || (timeSinceLastCall >= wait) ||
        (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
    }

    function timerExpired() {
        var time = Date.now();
        if (shouldInvoke(time)) {
            return trailingEdge(time);
        }
        // Restart the timer.
        timerId = setTimeout(timerExpired, remainingWait(time));
    }

    function trailingEdge(time) {
        clearTimeout(timerId);
        timerId = undefined;

        // Only invoke if we have `lastArgs` which means `func` has been
        // debounced at least once.
        if (trailing && lastArgs) {
            return invokeFunc(time);
        }
        lastArgs = lastThis = undefined;
        return result;
    }

    function cancel() {
        if (timerId !== undefined) {
            clearTimeout(timerId);
        }
        lastCallTime = lastInvokeTime = 0;
        lastArgs = lastThis = timerId = undefined;
    }

    function flush() {
        return timerId === undefined ? result : trailingEdge(Date.now());
    }

    function debounced() {
        var time =  Date.now(),
            isInvoking = shouldInvoke(time);

        lastArgs = arguments;
        lastThis = this;
        lastCallTime = time;

        if (isInvoking) {
            if (timerId === undefined) {
                return leadingEdge(lastCallTime);
            }
            if (maxing) {
                // Handle invocations in a tight loop.
                clearTimeout(timerId);
                timerId = setTimeout(timerExpired, wait);
                return invokeFunc(lastCallTime);
            }
        }
        if (timerId === undefined) {
            timerId = setTimeout(timerExpired, wait);
        }
        return result;
    }
    debounced.cancel = cancel;
    debounced.flush = flush;
    return debounced;
}

var searchInput = document.getElementById('search-input');
function doFTS(){
  var textToSearch = searchInput.value;
  fullTextSearch(textToSearch);
}
var debouncedFTS = debounce(doFTS, 300);
searchInput.addEventListener('input', debouncedFTS);
searchInput.addEventListener('focus', debouncedFTS);

})();
<commit_msg>prevent empty text search<commit_after>(function(){
	var idDiv = document.getElementById('main');

	function getPartial(originalHref){
		var partialHref = 'partials/' + originalHref;
		window.fetch(partialHref)
		.then(function(resp){
			return resp.text()
		})
		.then(function(pageText){
			idDiv.innerHTML = pageText;
			window.prettyPrint();
			var scrollTo = originalHref.split('#')[1],
				elm;
			if (scrollTo){
				elm = document.getElementById(scrollTo);
			} else {
				elm = idDiv;
			}
			if (elm) elm.scrollIntoView();
			if (needUpdateURL) {
				history.pushState({href: originalHref}, "", originalHref);
			}
		});
	}

	function isPartial(href){
		var res = Boolean(href);
		if (res) res = (href.indexOf('.js.html') === -1)
			&& (href.indexOf('http://') === -1)
			&& (href.indexOf('https://') === -1)
			&& (href.charAt(0) !== '/');
		return res;
	}
	var needUpdateURL = false;

	if (window && window.fetch && window.history && history.pushState) {
		document.body.onclick = function( e ) {
			var evt = e || window.event,
				target = evt.target || evt.srcElement,
				originalHref;

			// If the element clicked is an anchor
			if ( target.nodeName === 'A' ) {
				originalHref = target.getAttribute('href');
				if (isPartial(originalHref)){
					needUpdateURL = true;
					getPartial(originalHref);
					e.preventDefault();
				}
                document.getElementById('search-trigger').checked = false;
                document.getElementById('nav-trigger').checked = false;
			}
		};
		window.onpopstate = function(event) {
			needUpdateURL = false;
			if (event.state && event.state.href){
				getPartial(event.state.href);
			}
		}
	}

if (!window.exports) window.exports = {};
    /**
     * Set a position of source to line, specified as a URL hash tag
     */
window.exports["gotoLine"] = function() {
    var source = document.getElementsByClassName('prettyprint source linenums');
    var i = 0;
    var lineNumber = 0;
    var lineId;
    var lines;
    var totalLines;
    var anchorHash;

    if (source && source[0]) {
        anchorHash = document.location.hash.substring(1);
        lines = source[0].getElementsByTagName('li');
        totalLines = lines.length;

        for (; i < totalLines; i++) {
            lineNumber++;
            lineId = 'line' + lineNumber;
            lines[i].id = lineId;
            if (lineId === anchorHash) {
                lines[i].className += ' selected';
            }
        }
    }
};

var ftsData = null, searchInProgress = false;
function buildSearchResultHTML(data, level){
    var result='', keys, i, l;
    keys = Object.keys(data);
    for (i=0, l=keys.length; i<l; i++) {
        if (typeof data[keys[i]] === 'string') {
            result +='
' + data[keys[i]] + '
';
        } else {
            result += '
<h' + level + '>' + keys[i] + '</h' + level + '>';
            result += buildSearchResultHTML(data[keys[i]], keys[i], level + 1);
            result += '
';
        }
    }
    return result;
}
function fullTextSearch(textToSearch){
    var searchData;
    if (searchInProgress) return;
    if (!textToSearch){
        document.getElementById('search-trigger').checked = false;
        return;
    }
    searchInProgress = true;
    if (!ftsData) { //fetch data
        searchData = Promise.all([window.fetch('ftsIndex.json'), window.fetch('ftsData.json')])
            .then(function(values) {
                return Promise.all([values[0].json(), values[1].json()]);
            })
            .then(function(valuesInJSON){
                ftsData = {
                    ftsIndex: lunr.Index.load(valuesInJSON[0]),
                    ftsData: valuesInJSON[1]
                };
                return ftsData;
            })
    } else {
        searchData = Promise.resolve(ftsData)
    }
    searchData.then(function(data){
        var search = data.ftsIndex.search(textToSearch),
            allData = data.ftsData,
            res = {},
            pathSplitRe = /[:~#\.]/,
            member, memberPath, currentNode, i, j, l, jl, resHTML;
        for(i= 0, l=search.length; i<l && search[i].score > 0.001; i++){
            member = allData[search[i].ref];
            memberPath = member.path.split(pathSplitRe);
            if (memberPath[0] === 'module'){ // almost all element are inside module, so let's remove a `module` keyword
                memberPath.shift();
            }
            if (memberPath.length<2){ // add a grouping
                memberPath.unshift(member.group);
            }
            currentNode = res;
            for(j=0, jl = memberPath.length; j < jl-1; j++){ // without leaf
                if (!currentNode[memberPath[j]]){
                    currentNode[memberPath[j]] = {}
                }
                currentNode = currentNode[memberPath[j]];
            }
            currentNode[memberPath[j]] = '' + memberPath[j] + '';
        }
        if (search.length) {
            resHTML = buildSearchResultHTML(res, 2)
        } else {
            resHTML = 'Not found'
        }
        var sElm = document.getElementById('search-result-inner');
        sElm.innerHTML = resHTML;
        var trigger = document.getElementById('search-trigger');
        trigger.checked = true;
    }).then(function(){
        searchInProgress = false;
    })
}
window.exports["fullTextSearch"] = fullTextSearch;

/** realisation of debounce from lodash */
function debounce(func, wait, options) {
    var lastArgs,
        lastThis,
        maxWait,
        result,
        timerId,
        lastCallTime = 0,
        lastInvokeTime = 0,
        leading = false,
        maxing = false,
        trailing = true;

    wait = wait || 0;
    if (typeof options === 'object') {
        leading = !!options.leading;
        maxing = 'maxWait' in options;
        maxWait = maxing ?  Math.max(options.maxWait || 0, wait) : maxWait;
        trailing = 'trailing' in options ? !!options.trailing : trailing;
    }

    function invokeFunc(time) {
        var args = lastArgs,
            thisArg = lastThis;

        lastArgs = lastThis = undefined;
        lastInvokeTime = time;
        result = func.apply(thisArg, args);
        return result;
    }

    function leadingEdge(time) {
        // Reset any `maxWait` timer.
        lastInvokeTime = time;
        // Start the timer for the trailing edge.
        timerId = setTimeout(timerExpired, wait);
        // Invoke the leading edge.
        return leading ? invokeFunc(time) : result;
    }

    function remainingWait(time) {
        var timeSinceLastCall = time - lastCallTime,
            timeSinceLastInvoke = time - lastInvokeTime,
            result = wait - timeSinceLastCall;

        return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
    }

    function shouldInvoke(time) {
        var timeSinceLastCall = time - lastCallTime,
            timeSinceLastInvoke = time - lastInvokeTime;

        // Either this is the first call, activity has stopped and we're at the
        // trailing edge, the system time has gone backwards and we're treating
        // it as the trailing edge, or we've hit the `maxWait` limit.
        return (!lastCallTime || (timeSinceLastCall >= wait) ||
        (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
    }

    function timerExpired() {
        var time = Date.now();
        if (shouldInvoke(time)) {
            return trailingEdge(time);
        }
        // Restart the timer.
        timerId = setTimeout(timerExpired, remainingWait(time));
    }

    function trailingEdge(time) {
        clearTimeout(timerId);
        timerId = undefined;

        // Only invoke if we have `lastArgs` which means `func` has been
        // debounced at least once.
        if (trailing && lastArgs) {
            return invokeFunc(time);
        }
        lastArgs = lastThis = undefined;
        return result;
    }

    function cancel() {
        if (timerId !== undefined) {
            clearTimeout(timerId);
        }
        lastCallTime = lastInvokeTime = 0;
        lastArgs = lastThis = timerId = undefined;
    }

    function flush() {
        return timerId === undefined ? result : trailingEdge(Date.now());
    }

    function debounced() {
        var time =  Date.now(),
            isInvoking = shouldInvoke(time);

        lastArgs = arguments;
        lastThis = this;
        lastCallTime = time;

        if (isInvoking) {
            if (timerId === undefined) {
                return leadingEdge(lastCallTime);
            }
            if (maxing) {
                // Handle invocations in a tight loop.
                clearTimeout(timerId);
                timerId = setTimeout(timerExpired, wait);
                return invokeFunc(lastCallTime);
            }
        }
        if (timerId === undefined) {
            timerId = setTimeout(timerExpired, wait);
        }
        return result;
    }
    debounced.cancel = cancel;
    debounced.flush = flush;
    return debounced;
}

var searchInput = document.getElementById('search-input');
function doFTS(){
  var textToSearch = searchInput.value;
  fullTextSearch(textToSearch);
}
var debouncedFTS = debounce(doFTS, 300);
searchInput.addEventListener('input', debouncedFTS);
searchInput.addEventListener('focus', debouncedFTS);

})();
<|endoftext|>


<commit_before>;(function(undefined) {
  'use strict';

  if (typeof sigma === 'undefined')
    throw 'sigma is not declared';

  /**
   * Sigma ForceAtlas2.5 Supervisor
   * =============================
   *
   * Author: Guillaume Plique (Yomguithereal)
   * Version: 0.1
   */

  /**
   * Feature detection
   * ------------------
   */
  var webWorkers = 'Worker' in window;

  /**
   * Supervisor Object
   * ------------------
   */
  function Supervisor(sigInst, options) {
    var _this = this,
        workerFn = sigInst.getForceAtlas2Worker();

    // Window URL Polyfill
    window.URL = window.URL || window.webkitURL;

    // Properties
    this.sigInst = sigInst;
    this.graph = this.sigInst.graph;
    this.ppn = 10;
    this.ppe = 3;
    this.config = {};

    // State
    this.started = false;
    this.running = false;

    // Web worker or classic DOM events?
    if (webWorkers) {
      var blob = this.makeBlob(workerFn);
      this.worker = new Worker(URL.createObjectURL(blob));

      // Post Message Polyfill
      this.worker.postMessage =
        this.worker.webkitPostMessage || this.worker.postMessage;
    }
    else {

      // TODO: do we crush?
      eval(workerFn);
    }

    // Worker message receiver
    var msgName = (this.worker) ? 'message' : 'newCoords';
    (this.worker || document).addEventListener(msgName, function(e) {

      // Retrieving data
      _this.nodesByteArray = new Float32Array(e.data.nodes);

      // If ForceAtlas2 is running, we act accordingly
      if (_this.running) {

        // Applying layout
        _this.applyLayoutChanges();

        // Send data back to worker and loop
        _this.sendByteArrayToWorker();

        // Rendering graph
        _this.sigInst.refresh();
      }
    });

    // Filling byteArrays
    this.graphToByteArrays();
  }

  Supervisor.prototype.makeBlob = function(workerFn) {
    var blob;

    try {
      blob = new Blob([workerFn], {type: 'application/javascript'});
    }
    catch (e) {
      window.BlobBuilder = window.BlobBuilder ||
                           window.WebKitBlobBuilder ||
                           window.MozBlobBuilder;

      blob = new BlobBuilder();
      blob.append(workerFn);
      blob = blob.getBlob();
    }

    return blob;
  };

  Supervisor.prototype.graphToByteArrays = function() {
    var nodes = this.graph.nodes(),
        edges = this.graph.edges(),
        nbytes = nodes.length * this.ppn,
        ebytes = edges.length * this.ppe,
        nIndex = {},
        i,
        j,
        l;

    // Allocating Byte arrays with correct nb of bytes
    this.nodesByteArray = new Float32Array(nbytes);
    this.edgesByteArray = new Float32Array(ebytes);

    // Iterate through nodes
    for (i = j = 0, l = nodes.length; i < l; i++) {

      // Populating index
      nIndex[nodes[i].id] = j;

      // Populating byte array
      this.nodesByteArray[j] = nodes[i].x;
      this.nodesByteArray[j + 1] = nodes[i].y;
      this.nodesByteArray[j + 2] = 0;
      this.nodesByteArray[j + 3] = 0;
      this.nodesByteArray[j + 4] = 0;
      this.nodesByteArray[j + 5] = 0;
      this.nodesByteArray[j + 6] = 1 + this.graph.degree(nodes[i].id);
      this.nodesByteArray[j + 7] = 1;
      this.nodesByteArray[j + 8] = nodes[i].size;
      this.nodesByteArray[j + 9] = 0;
      j += this.ppn;
    }

    // Iterate through edges
    for (i = j = 0, l = edges.length; i < l; i++) {
      this.edgesByteArray[j] = nIndex[edges[i].source];
      this.edgesByteArray[j + 1] = nIndex[edges[i].target];
      this.edgesByteArray[j + 2] = edges[i].weight || 0;
      j += this.ppe;
    }
  };

  // TODO: make a better send function
  Supervisor.prototype.applyLayoutChanges = function() {
    var nodes = this.graph.nodes(),
        j = 0,
        realIndex;

    // Moving nodes
    for (var i = 0, l = this.nodesByteArray.length; i < l; i += this.ppn) {
      nodes[j].x = this.nodesByteArray[i];
      nodes[j].y = this.nodesByteArray[i + 1];
      j++;
    }
  };

  Supervisor.prototype.sendByteArrayToWorker = function(action, config) {
    var content = {
      action: action || 'loop',
      nodes: this.nodesByteArray.buffer
    };

    var buffers = [this.nodesByteArray.buffer];

    if (action === 'start') {
      content.config = this.config || {};
      content.edges = this.edgesByteArray.buffer;
      buffers.push(this.edgesByteArray.buffer);
    }

    if (webWorkers)
      this.worker.postMessage(content, buffers);
    else
      window.postMessage(content, '*');
  };

  Supervisor.prototype.start = function() {
    if (this.running)
      return;

    this.running = true;

    if (!this.started) {

      // Sending init message to worker
      this.sendByteArrayToWorker('start');
      this.started = true;
    }
    else {
      this.sendByteArrayToWorker();
    }
  };

  Supervisor.prototype.stop = function() {
    if (!this.running)
      return;

    this.running = false;
  };

  // TODO: kill polyfill when worker is not true worker
  Supervisor.prototype.killWorker = function() {
    this.worker.terminate();
  };

  Supervisor.prototype.configure = function(config) {

    // Setting configuration
    this.config = config;

    if (!this.started)
      return;

    var data = {action: 'config', config: this.config};

    if (webWorkers)
      this.worker.postMessage(data);
    else
      window.postMessage(data, '*');
  };

  /**
   * Interface
   * ----------
   */
  var supervisor = null;

  sigma.prototype.startForceAtlas2 = function(config) {

    // Create supervisor if undefined
    if (!supervisor)
      supervisor = new Supervisor(this);

    // Start algorithm
    supervisor.start(config);

    return this;
  };

  sigma.prototype.stopForceAtlas2 = function() {
    if (!supervisor)
      return this;

    // Pause algorithm
    supervisor.stop();

    return this;
  };

  sigma.prototype.killForceAtlas2 = function() {
    if (!supervisor)
      return this;

    // Stop Algorithm
    supervisor.stop();

    // Kill Worker
    supervisor.killWorker();

    // Kill supervisor
    supervisor = null;

    return this;
  };

  sigma.prototype.configForceAtlas2 = function(config) {
    if (!supervisor)
      supervisor = new Supervisor(this);

    supervisor.configure(config);

    return this;
  };

  sigma.prototype.isForceAtlas2Running = function(config) {
    return supervisor && supervisor.running;
  };
}).call(this);
<commit_msg>Fixing FA2 config issues<commit_after>;(function(undefined) {
  'use strict';

  if (typeof sigma === 'undefined')
    throw 'sigma is not declared';

  /**
   * Sigma ForceAtlas2.5 Supervisor
   * =============================
   *
   * Author: Guillaume Plique (Yomguithereal)
   * Version: 0.1
   */

  /**
   * Feature detection
   * ------------------
   */
  var webWorkers = 'Worker' in window;

  /**
   * Supervisor Object
   * ------------------
   */
  function Supervisor(sigInst, options) {
    var _this = this,
        workerFn = sigInst.getForceAtlas2Worker();

    // Window URL Polyfill
    window.URL = window.URL || window.webkitURL;

    // Properties
    this.sigInst = sigInst;
    this.graph = this.sigInst.graph;
    this.ppn = 10;
    this.ppe = 3;
    this.config = {};

    // State
    this.started = false;
    this.running = false;

    // Web worker or classic DOM events?
    if (webWorkers) {
      var blob = this.makeBlob(workerFn);
      this.worker = new Worker(URL.createObjectURL(blob));

      // Post Message Polyfill
      this.worker.postMessage =
        this.worker.webkitPostMessage || this.worker.postMessage;
    }
    else {

      // TODO: do we crush?
      eval(workerFn);
    }

    // Worker message receiver
    var msgName = (this.worker) ? 'message' : 'newCoords';
    (this.worker || document).addEventListener(msgName, function(e) {

      // Retrieving data
      _this.nodesByteArray = new Float32Array(e.data.nodes);

      // If ForceAtlas2 is running, we act accordingly
      if (_this.running) {

        // Applying layout
        _this.applyLayoutChanges();

        // Send data back to worker and loop
        _this.sendByteArrayToWorker();

        // Rendering graph
        _this.sigInst.refresh();
      }
    });

    // Filling byteArrays
    this.graphToByteArrays();
  }

  Supervisor.prototype.makeBlob = function(workerFn) {
    var blob;

    try {
      blob = new Blob([workerFn], {type: 'application/javascript'});
    }
    catch (e) {
      window.BlobBuilder = window.BlobBuilder ||
                           window.WebKitBlobBuilder ||
                           window.MozBlobBuilder;

      blob = new BlobBuilder();
      blob.append(workerFn);
      blob = blob.getBlob();
    }

    return blob;
  };

  Supervisor.prototype.graphToByteArrays = function() {
    var nodes = this.graph.nodes(),
        edges = this.graph.edges(),
        nbytes = nodes.length * this.ppn,
        ebytes = edges.length * this.ppe,
        nIndex = {},
        i,
        j,
        l;

    // Allocating Byte arrays with correct nb of bytes
    this.nodesByteArray = new Float32Array(nbytes);
    this.edgesByteArray = new Float32Array(ebytes);

    // Iterate through nodes
    for (i = j = 0, l = nodes.length; i < l; i++) {

      // Populating index
      nIndex[nodes[i].id] = j;

      // Populating byte array
      this.nodesByteArray[j] = nodes[i].x;
      this.nodesByteArray[j + 1] = nodes[i].y;
      this.nodesByteArray[j + 2] = 0;
      this.nodesByteArray[j + 3] = 0;
      this.nodesByteArray[j + 4] = 0;
      this.nodesByteArray[j + 5] = 0;
      this.nodesByteArray[j + 6] = 1 + this.graph.degree(nodes[i].id);
      this.nodesByteArray[j + 7] = 1;
      this.nodesByteArray[j + 8] = nodes[i].size;
      this.nodesByteArray[j + 9] = 0;
      j += this.ppn;
    }

    // Iterate through edges
    for (i = j = 0, l = edges.length; i < l; i++) {
      this.edgesByteArray[j] = nIndex[edges[i].source];
      this.edgesByteArray[j + 1] = nIndex[edges[i].target];
      this.edgesByteArray[j + 2] = edges[i].weight || 0;
      j += this.ppe;
    }
  };

  // TODO: make a better send function
  Supervisor.prototype.applyLayoutChanges = function() {
    var nodes = this.graph.nodes(),
        j = 0,
        realIndex;

    // Moving nodes
    for (var i = 0, l = this.nodesByteArray.length; i < l; i += this.ppn) {
      nodes[j].x = this.nodesByteArray[i];
      nodes[j].y = this.nodesByteArray[i + 1];
      j++;
    }
  };

  Supervisor.prototype.sendByteArrayToWorker = function(action) {
    var content = {
      action: action || 'loop',
      nodes: this.nodesByteArray.buffer
    };

    var buffers = [this.nodesByteArray.buffer];

    if (action === 'start') {
      content.config = this.config || {};
      content.edges = this.edgesByteArray.buffer;
      buffers.push(this.edgesByteArray.buffer);
    }

    if (webWorkers)
      this.worker.postMessage(content, buffers);
    else
      window.postMessage(content, '*');
  };

  Supervisor.prototype.start = function() {
    if (this.running)
      return;

    this.running = true;

    if (!this.started) {

      // Sending init message to worker
      this.sendByteArrayToWorker('start');
      this.started = true;
    }
    else {
      this.sendByteArrayToWorker();
    }
  };

  Supervisor.prototype.stop = function() {
    if (!this.running)
      return;

    this.running = false;
  };

  // TODO: kill polyfill when worker is not true worker
  Supervisor.prototype.killWorker = function() {
    this.worker.terminate();
  };

  Supervisor.prototype.configure = function(config) {

    // Setting configuration
    this.config = config;

    if (!this.started)
      return;

    var data = {action: 'config', config: this.config};

    if (webWorkers)
      this.worker.postMessage(data);
    else
      window.postMessage(data, '*');
  };

  /**
   * Interface
   * ----------
   */
  var supervisor = null;

  sigma.prototype.startForceAtlas2 = function(config) {

    // Create supervisor if undefined
    if (!supervisor)
      supervisor = new Supervisor(this);

    // Configuration provided?
    if (config)
      supervisor.configure(config);

    // Start algorithm
    supervisor.start();

    return this;
  };

  sigma.prototype.stopForceAtlas2 = function() {
    if (!supervisor)
      return this;

    // Pause algorithm
    supervisor.stop();

    return this;
  };

  sigma.prototype.killForceAtlas2 = function() {
    if (!supervisor)
      return this;

    // Stop Algorithm
    supervisor.stop();

    // Kill Worker
    supervisor.killWorker();

    // Kill supervisor
    supervisor = null;

    return this;
  };

  sigma.prototype.configForceAtlas2 = function(config) {
    if (!supervisor)
      supervisor = new Supervisor(this);

    supervisor.configure(config);

    return this;
  };

  sigma.prototype.isForceAtlas2Running = function(config) {
    return supervisor && supervisor.running;
  };
}).call(this);
<|endoftext|>


<commit_before>/**
 * Path element
 * @module zrender/graphic/Path
 *
 * TODO adjustRect for resize and centering
 */

define(function (require) {

    var Displayable = require('./Displayable');
    var zrUtil = require('../core/util');
    var PathProxy = require('../core/PathProxy');
    var pathContain = require('../contain/path');
    var rectContain = require('../contain/rect');

    function pathHasFill(style) {
        return style.fill != null;
    }

    function pathHasStroke(style) {
        return style.stroke != null;
    }
    /**
     * @alias module:zrender/graphic/Path
     * @extends module:zrender/graphic/Displayable
     * @constructor
     * @param {Object} opts
     */
    var Path = function (opts) {
        Displayable.call(this, opts);

        this._path = new PathProxy();
    };

    Path.prototype = {

        constructor: Path,

        type: 'path',

        __dirtyPath: true,

        brush: function (ctx) {
            this.beforeBrush(ctx);

            var style = this.style;

            var path = this._path;
            var hasStroke = pathHasStroke(style);
            var hasFill = pathHasFill(style);

            var lineDash = style.lineDash;
            var lineDashOffset = style.lineDashOffset;

            var ctxLineDash = !!ctx.setLineDash;
            // Proxy context
            // Rebuild path in following 2 cases
            // 1. Path is dirty
            // 2. Path needs javascript implemented lineDash stroking.
            //    In this case, lineDash information will not be saved in PathProxy
            if (this.__dirtyPath || (
                lineDash && !ctxLineDash && hasStroke
            )) {
                path = this._path.beginPath(ctx);

                // Setting line dash before build path
                if (lineDash && !ctxLineDash) {
                    path.setLineDash(lineDash);
                    path.setLineDashOffset(lineDashOffset);
                }

                this.buildPath(path, this.shape);

                // Clear path dirty flag
                this.__dirtyPath = false;
            }
            else {
                // Replay path building
                ctx.beginPath();
                this._path.rebuildPath(ctx);
            }

            hasFill && path.fill();

            if (lineDash && ctxLineDash) {
                ctx.setLineDash(lineDash);
                ctx.lineDashOffset = lineDashOffset;
            }

            hasStroke && path.stroke();

            // Draw rect text
            if (style.text) {
                this.drawRectText(ctx, this.getBoundingRect());
            }

            this.afterBrush(ctx);
        },

        buildPath: function (ctx, shapeCfg) {},

        getBoundingRect: function () {
            if (! this._rect) {
                this._rect = this._path.getBoundingRect();
            }
            if (pathHasStroke(this.style)) {
                var rect = this._rect;
                var w = this.style.lineWidth;
                // Consider line width
                rect.width += w;
                rect.height += w;
                rect.x -= w / 2;
                rect.y -= w / 2;
            }
            return this._rect;
        },

        contain: function (x, y) {
            var localPos = this.transformCoordToLocal(x, y);
            var rect = this.getBoundingRect();
            var style = this.style;
            x = localPos[0];
            y = localPos[1];

            if (rectContain.contain(rect, x, y)) {
                var pathData = this._path.data;
                if (pathHasStroke(style)) {
                    if (pathContain.containStroke(
                        pathData, style.lineWidth, x, y
                    )) {
                        return true;
                    }
                }
                if (pathHasFill(style)) {
                    return pathContain.contain(pathData, x, y);
                }
            }
            return false;
        },

        /**
         * @param  {boolean} dirtyPath
         */
        dirty: function (dirtyPath) {
            if (arguments.length ===0) {
                dirtyPath = true;
            }
            // Only mark dirty, not mark clean
            if (dirtyPath) {
                this.__dirtyPath = dirtyPath;
            }

            Displayable.prototype.dirty.call(this);
        }
    };

    /**
     * 扩展一个 Path element, 比如星形，圆等。
     * Extending a path element
     * @param {Object} props
     * @param {string} props.type Path type
     * @param {Function} props.init Initialize
     * @param {Function} props.buildPath Overwrite buildPath method
     * @param {Object} [props.style] Extended default style config
     * @param {Object} [props.shape] Extended default shape config
     */
    Path.extend = function (defaults) {
        var Sub = function (opts) {
            Path.call(this, opts);

            if (defaults.style) {
                // Extend default style
                this.style.extendFrom(defaults.style, false);
            }

            // Extend default shape
            var defaultShape = defaults.shape;
            if (defaultShape) {
                this.shape = this.shape || {};
                var thisShape = this.shape;
                for (var name in defaultShape) {
                    if (
                        ! thisShape.hasOwnProperty(name)
                        && defaultShape.hasOwnProperty(name)
                    ) {
                        thisShape[name] = defaultShape[name];
                    }
                }
            }

            defaults.init && defaults.init.call(this, opts);
        };

        zrUtil.inherits(Sub, Path);

        // FIXME 不能 extend position, rotation 等引用对象
        for (var name in defaults) {
            // Extending prototype values and methods
            if (name !== 'style' && name !== 'shape') {
                Sub.prototype[name] = defaults[name];
            }
        }

        return Sub;
    };

    zrUtil.inherits(Path, Displayable);

    return Path;
});<commit_msg>dirtyPath can affect refreshing of rect cache<commit_after>/**
 * Path element
 * @module zrender/graphic/Path
 *
 * TODO adjustRect for resize and centering
 */

define(function (require) {

    var Displayable = require('./Displayable');
    var zrUtil = require('../core/util');
    var PathProxy = require('../core/PathProxy');
    var pathContain = require('../contain/path');
    var rectContain = require('../contain/rect');

    function pathHasFill(style) {
        return style.fill != null;
    }

    function pathHasStroke(style) {
        return style.stroke != null;
    }
    /**
     * @alias module:zrender/graphic/Path
     * @extends module:zrender/graphic/Displayable
     * @constructor
     * @param {Object} opts
     */
    var Path = function (opts) {
        Displayable.call(this, opts);

        this._path = new PathProxy();
    };

    Path.prototype = {

        constructor: Path,

        type: 'path',

        __dirtyPath: true,

        brush: function (ctx) {
            this.beforeBrush(ctx);

            var style = this.style;

            var path = this._path;
            var hasStroke = pathHasStroke(style);
            var hasFill = pathHasFill(style);

            var lineDash = style.lineDash;
            var lineDashOffset = style.lineDashOffset;

            var ctxLineDash = !!ctx.setLineDash;
            // Proxy context
            // Rebuild path in following 2 cases
            // 1. Path is dirty
            // 2. Path needs javascript implemented lineDash stroking.
            //    In this case, lineDash information will not be saved in PathProxy
            if (this.__dirtyPath || (
                lineDash && !ctxLineDash && hasStroke
            )) {
                path = this._path.beginPath(ctx);

                // Setting line dash before build path
                if (lineDash && !ctxLineDash) {
                    path.setLineDash(lineDash);
                    path.setLineDashOffset(lineDashOffset);
                }

                this.buildPath(path, this.shape);

                // Clear path dirty flag
                this.__dirtyPath = false;
            }
            else {
                // Replay path building
                ctx.beginPath();
                this._path.rebuildPath(ctx);
            }

            hasFill && path.fill();

            if (lineDash && ctxLineDash) {
                ctx.setLineDash(lineDash);
                ctx.lineDashOffset = lineDashOffset;
            }

            hasStroke && path.stroke();

            // Draw rect text
            if (style.text) {
                this.drawRectText(ctx, this.getBoundingRect());
            }

            this.afterBrush(ctx);
        },

        buildPath: function (ctx, shapeCfg) {},

        getBoundingRect: function () {
            if (! this._rect) {
                this._rect = this._path.getBoundingRect();
            }
            if (pathHasStroke(this.style)) {
                var rect = this._rect;
                var w = this.style.lineWidth;
                // Consider line width
                rect.width += w;
                rect.height += w;
                rect.x -= w / 2;
                rect.y -= w / 2;
            }
            return this._rect;
        },

        contain: function (x, y) {
            var localPos = this.transformCoordToLocal(x, y);
            var rect = this.getBoundingRect();
            var style = this.style;
            x = localPos[0];
            y = localPos[1];

            if (rectContain.contain(rect, x, y)) {
                var pathData = this._path.data;
                if (pathHasStroke(style)) {
                    if (pathContain.containStroke(
                        pathData, style.lineWidth, x, y
                    )) {
                        return true;
                    }
                }
                if (pathHasFill(style)) {
                    return pathContain.contain(pathData, x, y);
                }
            }
            return false;
        },

        /**
         * @param  {boolean} dirtyPath
         */
        dirty: function (dirtyPath) {
            if (arguments.length ===0) {
                dirtyPath = true;
            }
            // Only mark dirty, not mark clean
            if (dirtyPath) {
                this.__dirtyPath = dirtyPath;

                this._rect = null;
            }

            this.__dirty = true;

            if (this.__zr) {
                this.__zr.refreshNextFrame();
            }
        }
    };

    /**
     * 扩展一个 Path element, 比如星形，圆等。
     * Extending a path element
     * @param {Object} props
     * @param {string} props.type Path type
     * @param {Function} props.init Initialize
     * @param {Function} props.buildPath Overwrite buildPath method
     * @param {Object} [props.style] Extended default style config
     * @param {Object} [props.shape] Extended default shape config
     */
    Path.extend = function (defaults) {
        var Sub = function (opts) {
            Path.call(this, opts);

            if (defaults.style) {
                // Extend default style
                this.style.extendFrom(defaults.style, false);
            }

            // Extend default shape
            var defaultShape = defaults.shape;
            if (defaultShape) {
                this.shape = this.shape || {};
                var thisShape = this.shape;
                for (var name in defaultShape) {
                    if (
                        ! thisShape.hasOwnProperty(name)
                        && defaultShape.hasOwnProperty(name)
                    ) {
                        thisShape[name] = defaultShape[name];
                    }
                }
            }

            defaults.init && defaults.init.call(this, opts);
        };

        zrUtil.inherits(Sub, Path);

        // FIXME 不能 extend position, rotation 等引用对象
        for (var name in defaults) {
            // Extending prototype values and methods
            if (name !== 'style' && name !== 'shape') {
                Sub.prototype[name] = defaults[name];
            }
        }

        return Sub;
    };

    zrUtil.inherits(Path, Displayable);

    return Path;
});<|endoftext|>


<commit_before>// Karma configuration
/* eslint-disable max-len, no-console */
require('babel-register');

const fs = require('fs');

const babelrc = fs.readFileSync('./.babelrc');
const babelQuery = JSON.parse(babelrc);
const webpack = require('webpack');
const webpackConfigProd = require('./webpack.prod.config.babel').default;
const config = require('config');
const getClientConfig = require('src/core/utils').getClientConfig;
const clientConfig = getClientConfig(config);

const coverageReporters = [{
  type: 'text-summary',
}];

const newWebpackConfig = Object.assign({}, webpackConfigProd, {
  plugins: [
    new webpack.DefinePlugin({
      CLIENT_CONFIG: JSON.stringify(clientConfig),
    }),
    // Replaces server config module with the subset clientConfig object.
    new webpack.NormalModuleReplacementPlugin(/config$/, 'core/client/config.js'),
    // Substitutes client only config.
    new webpack.NormalModuleReplacementPlugin(/core\/logger$/, 'core/client/logger.js'),
    // Use the browser's window for window.
    new webpack.NormalModuleReplacementPlugin(/core\/window/, 'core/browserWindow.js'),
  ],
  devtool: 'inline-source-map',
  module: {
    preLoaders: [{
      test: /\.jsx?$/,
      loader: 'babel-istanbul',
      include: /src\//,
      exclude: /node_modules/,
    }],
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: babelQuery,
      }, {
        test: /\.scss$/,
        loader: 'style!css?importLoaders=2!postcss!sass?outputStyle=expanded',
      }, {
        test: /\.svg$/,
        loader: 'url?limit=10000&mimetype=image/svg+xml',
      }, {
        test: /\.jpg$/,
        loader: 'url?limit=10000&mimetype=image/jpeg',
      }, {
        test: /\.webm$/,
        loader: 'url?limit=10000&mimetype=video/webm',
      }, {
        test: /\.mp4$/,
        loader: 'url?limit=10000&mimetype=video/mp4',
      }, {
        test: /\.otf$/,
        loader: 'url?limit=10000&mimetype=application/font-sfnt',
      }, {
        test: /\.woff$/,
        loader: 'url?limit=10000&mimetype=application/font-woff',
      }, {
        test: /\.woff2$/,
        loader: 'url?limit=10000&mimetype=application/font-woff2',
      },
    ],
  },
  output: undefined,
  entry: undefined,
});

const reporters = [
  'mocha',
  'coverage',
];

if (process.env.TRAVIS) {
  console.log('On Travis sending coveralls');
  coverageReporters.push({ type: 'lcov', dir: 'coverage' });
  reporters.push('coveralls');
} else {
  console.log('Not on Travis so not sending coveralls');
  coverageReporters.push({ type: 'html', dir: 'coverage', subdir: '.' });
}

module.exports = function karmaConf(conf) {
  conf.set({
    coverageReporter: {
      reporters: coverageReporters,
    },
    frameworks: ['mocha', 'chai', 'sinon'],
    files: [
      'test-runner.js',
    ],
    preprocessors: {
      'test-runner.js': ['webpack', 'sourcemap'],
    },
    reporters,
    colors: true,
    port: 9876,
    plugins: [
      'karma-chai',
      'karma-coverage',
      'karma-coveralls',
      'karma-firefox-launcher',
      'karma-mocha',
      'karma-mocha-reporter',
      'karma-sinon',
      'karma-sourcemap-loader',
      'karma-webpack',
    ],
    autoWatch: true,
    browsers: ['Firefox'],
    singleRun: false,
    concurrency: Infinity,
    webpack: newWebpackConfig,
    webpackServer: {
      noInfo: true,
      quiet: true,
    },
  });
};
<commit_msg>Bail test runs on test syntax error<commit_after>// Karma configuration
/* eslint-disable max-len, no-console, strict */
'use strict';

require('babel-register');

const fs = require('fs');

const babelrc = fs.readFileSync('./.babelrc');
const babelQuery = JSON.parse(babelrc);
const webpack = require('webpack');
const webpackConfigProd = require('./webpack.prod.config.babel').default;
const config = require('config');
const getClientConfig = require('src/core/utils').getClientConfig;
const clientConfig = getClientConfig(config);

const coverageReporters = [{
  type: 'text-summary',
}];

const newWebpackConfig = Object.assign({}, webpackConfigProd, {
  plugins: [
    new webpack.DefinePlugin({
      CLIENT_CONFIG: JSON.stringify(clientConfig),
    }),
    // Replaces server config module with the subset clientConfig object.
    new webpack.NormalModuleReplacementPlugin(/config$/, 'core/client/config.js'),
    // Substitutes client only config.
    new webpack.NormalModuleReplacementPlugin(/core\/logger$/, 'core/client/logger.js'),
    // Use the browser's window for window.
    new webpack.NormalModuleReplacementPlugin(/core\/window/, 'core/browserWindow.js'),
    // Plugin to show any webpack warnings and prevent tests from running
    // Based on: https://gist.github.com/Stuk/6b574049435df532e905
    function WebpackWarningPlugin() {
      this.plugin('done', (_stats) => {
        const stats = _stats;
        let flagError;

        if (stats.compilation.warnings.length) {
          // Log each of the warnings
          stats.compilation.warnings.forEach((_warning) => {
            const warning = _warning.message || _warning || '';
            if (warning.indexOf('SyntaxError') > -1) {
              console.log(warning);
              flagError = true;
            }
          });

          // Bail if syntax errors were encountered.
          if (flagError) {
            throw new Error('Syntax error encountered, bailing');
          }
        }
      });
    },
  ],
  devtool: 'inline-source-map',
  module: {
    preLoaders: [{
      test: /\.jsx?$/,
      loader: 'babel-istanbul',
      include: /src\//,
      exclude: /node_modules/,
    }],
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: babelQuery,
      }, {
        test: /\.scss$/,
        loader: 'style!css?importLoaders=2!postcss!sass?outputStyle=expanded',
      }, {
        test: /\.svg$/,
        loader: 'url?limit=10000&mimetype=image/svg+xml',
      }, {
        test: /\.jpg$/,
        loader: 'url?limit=10000&mimetype=image/jpeg',
      }, {
        test: /\.webm$/,
        loader: 'url?limit=10000&mimetype=video/webm',
      }, {
        test: /\.mp4$/,
        loader: 'url?limit=10000&mimetype=video/mp4',
      }, {
        test: /\.otf$/,
        loader: 'url?limit=10000&mimetype=application/font-sfnt',
      }, {
        test: /\.woff$/,
        loader: 'url?limit=10000&mimetype=application/font-woff',
      }, {
        test: /\.woff2$/,
        loader: 'url?limit=10000&mimetype=application/font-woff2',
      },
    ],
  },
  output: undefined,
  entry: undefined,
});

const reporters = [
  'mocha',
  'coverage',
];

if (process.env.TRAVIS) {
  console.log('On Travis sending coveralls');
  coverageReporters.push({ type: 'lcov', dir: 'coverage' });
  reporters.push('coveralls');
} else {
  console.log('Not on Travis so not sending coveralls');
  coverageReporters.push({ type: 'html', dir: 'coverage', subdir: '.' });
}

module.exports = function karmaConf(conf) {
  conf.set({
    coverageReporter: {
      reporters: coverageReporters,
    },
    frameworks: ['mocha', 'chai', 'sinon'],
    files: [
      'test-runner.js',
    ],
    preprocessors: {
      'test-runner.js': ['webpack', 'sourcemap'],
    },
    reporters,
    colors: true,
    port: 9876,
    plugins: [
      'karma-chai',
      'karma-coverage',
      'karma-coveralls',
      'karma-firefox-launcher',
      'karma-mocha',
      'karma-mocha-reporter',
      'karma-sinon',
      'karma-sourcemap-loader',
      'karma-webpack',
    ],
    autoWatch: true,
    browsers: ['Firefox'],
    singleRun: false,
    concurrency: Infinity,
    webpack: newWebpackConfig,
    webpackServer: {
      noInfo: true,
      quiet: true,
    },
  });
};
<|endoftext|>