<commit_before>/*
 * Copyright 2016 SimplifyOps, Inc. (http://simplifyops.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//= require knockout.min
//= require knockout-mapping
//= require knockout-onenter
//= require ko/binding-url-path-param
//= require ko/binding-message-template
//= require ko/binding-popover
//= require jquery.waypoints.min
//= require menu/project-model

function HomeData(data) {
    var self = this;
    self.baseUrl = data.baseUrl;
    self.summaryUrl = data.summaryUrl;
    self.projectNamesUrl = data.projectNamesUrl;
    self.loaded = ko.observable(data.loaded?true:false);
    self.jobCount = ko.observable(0);
    self.execCount = ko.observable(data.execCount||0);
    self.totalFailedCount = ko.observable(data.totalFailedCount||0);
    self.projectNames = ko.observableArray(data.projectNames || []);
    self.projectNamesTotal = ko.observable(data.projectNamesTotal || 0);
    self.loadedProjectNames = ko.observable(false);
    self.projects = ko.observableArray([]);
    self.projects.extend({rateLimit: 500});

    self.recentUsers = ko.observableArray(data.recentUsers||[]);
    self.recentProjects = ko.observableArray(data.recentProjects||[]);
    self.frameworkNodeName = ko.observable(null);
    self.doRefresh = ko.observable(false);
    self.doPaging = ko.observable(false);
    self.pagingMax = ko.observable(20);
    self.pagingRepeatMax = ko.observable(20);
    self.pagingDelay = ko.observable(2000);
    self.pagingOffset = ko.observable(0);
    self.refreshDelay = ko.observable(30000);
    self.search=ko.observable(null);

    //batch of project data to load
    self.batchList=ko.observableArray([]);
    self.batchList.extend({ rateLimit: 500 });
    self.batches=ko.observableArray([]);

    self.recentUsersCount = ko.pureComputed(function () {
        return self.recentUsers().length;
    });
    self.recentProjectsCount = ko.pureComputed(function () {
        return self.recentProjects().length;
    });
    self.searchedProjects=ko.pureComputed(function(){
        "use strict";
        var search=self.search();
        var names=self.projectNames();
        if(null==search){
            return names;
        }
        var regex;
        if (search.charAt(0) === '/' && search.charAt(search.length - 1) === '/') {
            regex = new RegExp(search.substring(1, search.length - 1),'i');
        }else{
            //simple match which is case-insensitive, escaping special regex chars
            regex = new RegExp(search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'),'i');
        }
        return ko.utils.arrayFilter(names,function(val,ndx){
            var proj = self.projectForName(val);
            var label = proj.label();
            return val.match(regex) || label && label.match(regex);
        });
    });
    self.searchedProjectsCount = ko.pureComputed(function () {
        return self.searchedProjects().length;
    });
    self.projectCount = ko.pureComputed(function () {
        return self.projectNames().length;
    });
    self.projectsByName = ko.pureComputed(function () {
        var obj = {};
        ko.utils.arrayForEach(self.projects(), function (elem, ndx) {
            obj[ko.unwrap(elem.name)] = elem;
        });
        return obj;
    });
    self.searchProjectsByName = ko.pureComputed(function () {
        var obj = {};
        ko.utils.arrayForEach(self.searchedProjects(), function (elem, ndx) {
            obj[ko.unwrap(elem.name)] = elem;
        });
        return obj;
    });
    self.projectInSearch=function(name){
        "use strict";
        return !self.search() || self.searchProjectsByName()[name]!=null;
    };
    self.prototypeProject = new Project({page: 'projectList'});
    self.projectForName = function (name) {
        var projectsByName = self.projectsByName()[name];
        if(null==projectsByName){
            return self.prototypeProject;
        }
        return projectsByName;
    };
    self.mapping = {
        'projects': {
            key: function (data) {
                return ko.utils.unwrapObservable(data.name);
            },
            create: function (data) {
                "use strict";
                return new Project(options.data);
            },
            update: function (options) {
                var updateArray = [];
                var found = options.parent.projectForName(options.data.name);
                if (found) {
                    return ko.mapping.fromJS(options.data, {}, found);
                } else {
                    return ko.mapping.fromJS(options.data, {}, {});
                }
            }
        }
    };
    self.loadSummary = function () {
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.summaryUrl, {}),
            success: function (data, status, jqxhr) {

                ko.mapping.fromJS(data, self.mapping, self);
                self.loaded(true);

                if (self.doRefresh()) {
                    setTimeout(self.loadSummary, self.refreshDelay());
                }
            }
        });
    };
    self.loadProjects = function (projs) {
        for (var i = 0; i < projs.length; i++) {
            var newproj = projs[i];
            var found = self.projectForName(newproj.name);
            if (found && found.name()==newproj.name) {
                ko.mapping.fromJS(newproj, null, found);
                found.loaded(true);
            } else {
                self.projects.push(
                    new Project(jQuery.extend(newproj, {loaded: true, page: 'projectList'}))
                );
            }
        }
    };
    self.load = function (refresh) {
        var params = {};//refresh?{refresh:true}:{};
        if (self.doPaging()) {
            jQuery.extend(params, {
                offset: self.pagingOffset(),
                max: self.pagingMax()
            });
            self.pagingMax(self.pagingRepeatMax());
        }
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.baseUrl, params),
            success: function (data, status, jqxhr) {
                if (data.projects) {
                    self.loadProjects(data.projects);
                }
                // ko.mapping.fromJS(data, self.mapping, self);
                if (self.doPaging() && data.nextoffset) {
                    self.pagingOffset(data.nextoffset);
                    if (self.pagingOffset() === -1) {
                        self.pagingOffset(0);
                    } else {
                        setTimeout(self.load.curry(true), self.pagingDelay());
                        return;
                    }
                }
            }
        });
    };
    self.pullBatch=function(){
        "use strict";
        //pull up to max number of items from batchList
        var items=self.batchList.splice(0,self.pagingMax());
        if(items.length>0) {
            self.batches.push(items);
        }
    };
    self.batchList.subscribe(function(newValue){
        "use strict";
        if(newValue.length>0){
            setTimeout(self.pullBatch,100);
        }
    });
    self.batches.subscribe(function(newValue){
        if(!self.batchLoading && newValue.length>0){
            self.batchLoading=true;
            setTimeout(self.loadBatch,100);
        }
    });
    self.clearBatchLoad=function(){
        "use strict";

        self.batchList([]);
        self.batches([]);
    };
    self.search.subscribe(self.clearBatchLoad);
    self.batchLoading=false;
    self.loadBatch = function () {
        self.batchLoading=true;
        var projects=self.batches.shift();
        if(null==projects || projects.length<1){
            self.batchLoading=false;
            return;
        }
        var params = {projects:projects.join(',')};//refresh?{refresh:true}:{};
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.baseUrl, params),
            success: function (data, status, jqxhr) {
                if (data.projects) {
                    self.loadProjects(data.projects);
                }
                //...
                if(self.batches().length>0){
                    self.loadBatch();
                }else{
                    self.batchLoading=false;
                }
            }
        });
    };

    /**
     * bound via the ko/binding-waypoints knockout binding
     * example:
     * <span data-bind="waypoints: $root.waypointHandler" >
     */
    self.waypointHandler=function(){
        "use strict";
        var projectName = jQuery(this.element).data('project');
        if(!self.projectForName(projectName).loaded()) {
            self.batchList.push(projectName);
        }

        this.destroy();
    };
    //initial setup
    self.beginLoad = function () {

        if (self.doRefresh()) {
            setTimeout(self.loadSummary, self.refreshDelay());
        }
    };
    self.loadProjectNames = function () {
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.projectNamesUrl, {}),
            success: function (data, status, jqxhr) {
                self.projectNames(data.projectNames);
                self.projectNamesTotal(data.projectNames.length);
                self.loadedProjectNames(true);
            }
        });
    };
    self.init = function () {
        self.beginLoad();
        if (self.projectCount() != self.projectNamesTotal()) {
            self.loadProjectNames();
        }
    };
}
var _waypointBatchTimer;
function batchInitWaypoints(arr,handler,count){
    "use strict";
    var arr2=arr.splice(0,count);
    if(arr2.length>0) {
        jQuery(arr2).waypoint(handler, {context:'#main-panel',offset: '100%'});
        if (arr.length > 0) {
            _waypointBatchTimer=setTimeout(batchInitWaypoints.curry(arr, handler,count), 1500);
        }
    }
}
function initWaypoints(homedata,reset){
    "use strict";
    if(reset){
        if(_waypointBatchTimer){
            clearTimeout(_waypointBatchTimer);
            _waypointBatchTimer=null;
        }
        Waypoint.destroyAll();
    }

    batchInitWaypoints(jQuery('.project_list_item[data-project]'),homedata.waypointHandler,50);
}

/**
 * START page init
 */
var homedata;
function init() {
    // ko.options.deferUpdates = true;
    var pageparams = loadJsonData('homeDataPagingParams') || {};
    var projectNamesData = loadJsonData('projectNamesData');
    if (projectNamesData.projectNames == null) {
        projectNamesData.projectNames = [];
    }
    var statsdata = loadJsonData('statsData') || {};
    homedata = new HomeData(jQuery.extend({
        baseUrl: appLinks.menuHomeAjax,
        summaryUrl: appLinks.menuHomeSummaryAjax,
        projectNamesUrl: appLinks.menuProjectNamesAjax,
        projectNames: projectNamesData.projectNames.sort(),
        projectNamesTotal: projectNamesData.projectNamesTotal || 0
    },statsdata));
    homedata.loadedProjectNames(projectNamesData.projectNames.length == projectNamesData.projectNamesTotal);
    ko.applyBindings(homedata);

    homedata.pagingMax(pageparams.pagingInitialMax || 15);
    homedata.pagingRepeatMax(pageparams.pagingRepeatMax || 50);
    homedata.doRefresh(pageparams.summaryRefresh != null ? pageparams.summaryRefresh : true);
    homedata.refreshDelay(pageparams.refreshDelay || 60000);
    homedata.doPaging(pageparams.doPaging != null ? pageparams.doPaging : true);
    homedata.pagingDelay(pageparams.pagingDelay || 2000);
    homedata.searchedProjects.subscribe(function(val){
        "use strict";
        //when search results change, refresh waypoints
        ko.tasks.schedule(initWaypoints.curry(homedata,true));
    });
    if(homedata.loadedProjectNames()){
        //load waypoints manually
        initWaypoints(homedata);
    }
    homedata.loaded.subscribe(Waypoint.refreshAll);
    homedata.projects.subscribe(Waypoint.refreshAll);
    homedata.init();
}
jQuery(init);
<commit_msg>cleanup: remove prototype .curry<commit_after>/*
 * Copyright 2016 SimplifyOps, Inc. (http://simplifyops.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//= require knockout.min
//= require knockout-mapping
//= require knockout-onenter
//= require ko/binding-url-path-param
//= require ko/binding-message-template
//= require ko/binding-popover
//= require jquery.waypoints.min
//= require menu/project-model

function HomeData(data) {
    var self = this;
    self.baseUrl = data.baseUrl;
    self.summaryUrl = data.summaryUrl;
    self.projectNamesUrl = data.projectNamesUrl;
    self.loaded = ko.observable(data.loaded?true:false);
    self.jobCount = ko.observable(0);
    self.execCount = ko.observable(data.execCount||0);
    self.totalFailedCount = ko.observable(data.totalFailedCount||0);
    self.projectNames = ko.observableArray(data.projectNames || []);
    self.projectNamesTotal = ko.observable(data.projectNamesTotal || 0);
    self.loadedProjectNames = ko.observable(false);
    self.projects = ko.observableArray([]);
    self.projects.extend({rateLimit: 500});

    self.recentUsers = ko.observableArray(data.recentUsers||[]);
    self.recentProjects = ko.observableArray(data.recentProjects||[]);
    self.frameworkNodeName = ko.observable(null);
    self.doRefresh = ko.observable(false);
    self.doPaging = ko.observable(false);
    self.pagingMax = ko.observable(20);
    self.pagingRepeatMax = ko.observable(20);
    self.pagingDelay = ko.observable(2000);
    self.pagingOffset = ko.observable(0);
    self.refreshDelay = ko.observable(30000);
    self.search=ko.observable(null);

    //batch of project data to load
    self.batchList=ko.observableArray([]);
    self.batchList.extend({ rateLimit: 500 });
    self.batches=ko.observableArray([]);

    self.recentUsersCount = ko.pureComputed(function () {
        return self.recentUsers().length;
    });
    self.recentProjectsCount = ko.pureComputed(function () {
        return self.recentProjects().length;
    });
    self.searchedProjects=ko.pureComputed(function(){
        "use strict";
        var search=self.search();
        var names=self.projectNames();
        if(null==search){
            return names;
        }
        var regex;
        if (search.charAt(0) === '/' && search.charAt(search.length - 1) === '/') {
            regex = new RegExp(search.substring(1, search.length - 1),'i');
        }else{
            //simple match which is case-insensitive, escaping special regex chars
            regex = new RegExp(search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'),'i');
        }
        return ko.utils.arrayFilter(names,function(val,ndx){
            var proj = self.projectForName(val);
            var label = proj.label();
            return val.match(regex) || label && label.match(regex);
        });
    });
    self.searchedProjectsCount = ko.pureComputed(function () {
        return self.searchedProjects().length;
    });
    self.projectCount = ko.pureComputed(function () {
        return self.projectNames().length;
    });
    self.projectsByName = ko.pureComputed(function () {
        var obj = {};
        ko.utils.arrayForEach(self.projects(), function (elem, ndx) {
            obj[ko.unwrap(elem.name)] = elem;
        });
        return obj;
    });
    self.searchProjectsByName = ko.pureComputed(function () {
        var obj = {};
        ko.utils.arrayForEach(self.searchedProjects(), function (elem, ndx) {
            obj[ko.unwrap(elem.name)] = elem;
        });
        return obj;
    });
    self.projectInSearch=function(name){
        "use strict";
        return !self.search() || self.searchProjectsByName()[name]!=null;
    };
    self.prototypeProject = new Project({page: 'projectList'});
    self.projectForName = function (name) {
        var projectsByName = self.projectsByName()[name];
        if(null==projectsByName){
            return self.prototypeProject;
        }
        return projectsByName;
    };
    self.mapping = {
        'projects': {
            key: function (data) {
                return ko.utils.unwrapObservable(data.name);
            },
            create: function (data) {
                "use strict";
                return new Project(options.data);
            },
            update: function (options) {
                var updateArray = [];
                var found = options.parent.projectForName(options.data.name);
                if (found) {
                    return ko.mapping.fromJS(options.data, {}, found);
                } else {
                    return ko.mapping.fromJS(options.data, {}, {});
                }
            }
        }
    };
    self.loadSummary = function () {
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.summaryUrl, {}),
            success: function (data, status, jqxhr) {

                ko.mapping.fromJS(data, self.mapping, self);
                self.loaded(true);

                if (self.doRefresh()) {
                    setTimeout(self.loadSummary, self.refreshDelay());
                }
            }
        });
    };
    self.loadProjects = function (projs) {
        for (var i = 0; i < projs.length; i++) {
            var newproj = projs[i];
            var found = self.projectForName(newproj.name);
            if (found && found.name()==newproj.name) {
                ko.mapping.fromJS(newproj, null, found);
                found.loaded(true);
            } else {
                self.projects.push(
                    new Project(jQuery.extend(newproj, {loaded: true, page: 'projectList'}))
                );
            }
        }
    };
    self.load = function (refresh) {
        var params = {};//refresh?{refresh:true}:{};
        if (self.doPaging()) {
            jQuery.extend(params, {
                offset: self.pagingOffset(),
                max: self.pagingMax()
            });
            self.pagingMax(self.pagingRepeatMax());
        }
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.baseUrl, params),
            success: function (data, status, jqxhr) {
                if (data.projects) {
                    self.loadProjects(data.projects);
                }
                // ko.mapping.fromJS(data, self.mapping, self);
                if (self.doPaging() && data.nextoffset) {
                    self.pagingOffset(data.nextoffset);
                    if (self.pagingOffset() === -1) {
                        self.pagingOffset(0);
                    } else {
                        setTimeout(function(){self.load(true);}, self.pagingDelay());
                    }
                }
            }
        });
    };
    self.pullBatch=function(){
        "use strict";
        //pull up to max number of items from batchList
        var items=self.batchList.splice(0,self.pagingMax());
        if(items.length>0) {
            self.batches.push(items);
        }
    };
    self.batchList.subscribe(function(newValue){
        "use strict";
        if(newValue.length>0){
            setTimeout(self.pullBatch,100);
        }
    });
    self.batches.subscribe(function(newValue){
        if(!self.batchLoading && newValue.length>0){
            self.batchLoading=true;
            setTimeout(self.loadBatch,100);
        }
    });
    self.clearBatchLoad=function(){
        "use strict";

        self.batchList([]);
        self.batches([]);
    };
    self.search.subscribe(self.clearBatchLoad);
    self.batchLoading=false;
    self.loadBatch = function () {
        self.batchLoading=true;
        var projects=self.batches.shift();
        if(null==projects || projects.length<1){
            self.batchLoading=false;
            return;
        }
        var params = {projects:projects.join(',')};//refresh?{refresh:true}:{};
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.baseUrl, params),
            success: function (data, status, jqxhr) {
                if (data.projects) {
                    self.loadProjects(data.projects);
                }
                //...
                if(self.batches().length>0){
                    self.loadBatch();
                }else{
                    self.batchLoading=false;
                }
            }
        });
    };

    /**
     * bound via the ko/binding-waypoints knockout binding
     * example:
     * <span data-bind="waypoints: $root.waypointHandler" >
     */
    self.waypointHandler=function(){
        "use strict";
        var projectName = jQuery(this.element).data('project');
        if(!self.projectForName(projectName).loaded()) {
            self.batchList.push(projectName);
        }

        this.destroy();
    };
    //initial setup
    self.beginLoad = function () {

        if (self.doRefresh()) {
            setTimeout(self.loadSummary, self.refreshDelay());
        }
    };
    self.loadProjectNames = function () {
        return jQuery.ajax({
            type: 'GET',
            contentType: 'json',
            headers: {'x-rundeck-ajax': 'true'},
            url: _genUrl(self.projectNamesUrl, {}),
            success: function (data, status, jqxhr) {
                self.projectNames(data.projectNames);
                self.projectNamesTotal(data.projectNames.length);
                self.loadedProjectNames(true);
            }
        });
    };
    self.init = function () {
        self.beginLoad();
        if (self.projectCount() != self.projectNamesTotal()) {
            self.loadProjectNames();
        }
    };
}
var _waypointBatchTimer;
function batchInitWaypoints(arr,handler,count){
    "use strict";
    var arr2=arr.splice(0,count);
    if(arr2.length>0) {
        jQuery(arr2).waypoint(handler, {context:'#main-panel',offset: '100%'});
        if (arr.length > 0) {
            _waypointBatchTimer=setTimeout(function(){batchInitWaypoints(arr, handler,count);}, 1500);
        }
    }
}
function initWaypoints(homedata,reset){
    "use strict";
    if(reset){
        if(_waypointBatchTimer){
            clearTimeout(_waypointBatchTimer);
            _waypointBatchTimer=null;
        }
        Waypoint.destroyAll();
    }

    batchInitWaypoints(jQuery('.project_list_item[data-project]'),homedata.waypointHandler,50);
}

/**
 * START page init
 */
var homedata;
function init() {
    // ko.options.deferUpdates = true;
    var pageparams = loadJsonData('homeDataPagingParams') || {};
    var projectNamesData = loadJsonData('projectNamesData');
    if (projectNamesData.projectNames == null) {
        projectNamesData.projectNames = [];
    }
    var statsdata = loadJsonData('statsData') || {};
    homedata = new HomeData(jQuery.extend({
        baseUrl: appLinks.menuHomeAjax,
        summaryUrl: appLinks.menuHomeSummaryAjax,
        projectNamesUrl: appLinks.menuProjectNamesAjax,
        projectNames: projectNamesData.projectNames.sort(),
        projectNamesTotal: projectNamesData.projectNamesTotal || 0
    },statsdata));
    homedata.loadedProjectNames(projectNamesData.projectNames.length == projectNamesData.projectNamesTotal);
    ko.applyBindings(homedata);

    homedata.pagingMax(pageparams.pagingInitialMax || 15);
    homedata.pagingRepeatMax(pageparams.pagingRepeatMax || 50);
    homedata.doRefresh(pageparams.summaryRefresh != null ? pageparams.summaryRefresh : true);
    homedata.refreshDelay(pageparams.refreshDelay || 60000);
    homedata.doPaging(pageparams.doPaging != null ? pageparams.doPaging : true);
    homedata.pagingDelay(pageparams.pagingDelay || 2000);
    homedata.searchedProjects.subscribe(function(val){
        "use strict";
        //when search results change, refresh waypoints
        ko.tasks.schedule(function(){initWaypoints(homedata,true);});
    });
    if(homedata.loadedProjectNames()){
        //load waypoints manually
        initWaypoints(homedata);
    }
    homedata.loaded.subscribe(Waypoint.refreshAll);
    homedata.projects.subscribe(Waypoint.refreshAll);
    homedata.init();
}
jQuery(init);
<|endoftext|>


<commit_before>/*
 * Copyright 2016 SimplifyOps, Inc. (http://simplifyops.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//= require momentutil
//= require knockout.min
//= require knockout-mapping
//= require knockout-foreachprop
//= require nodeFiltersKO
//= require executionOptions
//= require jobFiltersKO
//= require knockout-onenter
//= require knockout-node-filter-link
//= require menu/job-remote-options
//= require menu/joboptions
//= require ko/binding-popover
//= require ko/binding-datetimepicker
//= require ko/handler-bootstrapPopover
//= require ko/handler-bootstrapTooltip
//= require ko/handler-messageTemplate
//= require ko/binding-css2
//= require scheduledExecution/jobRunFormOptionsKO
//= require koBind
//= require ko/binding-url-path-param

/*
 Manifest for "menu/jobs.gsp" page
 */
//TODO: refactor menu/jobs.gsp to move javascript here
/**
 * Possible actions for bulk edit jobs, to present in modal dialog
 * @constructor
 */
function BulkEditor(data){
    var self=this;
    self.messages=data.messages||{};
    self.DISABLE_SCHEDULE = 'disable_schedule';
    self.ENABLE_SCHEDULE = 'enable_schedule';
    self.ENABLE_EXECUTION= 'enable_execution';
    self.DISABLE_EXECUTION= 'disable_execution';
    self.DELETE= 'delete';
    self.action=ko.observable(null);
    self.enabled=ko.observable(false);
    self.beginEdit=function(){
        self.expandAllComponents();
        self.enabled(true);
    };
    self.cancelEdit=function(){
        self.enabled(false);
        self.selectNone();
    };
    self.disableSchedule=function(){

        self.action(self.DISABLE_SCHEDULE);
    };
    self.isDisableSchedule=ko.pureComputed(function(){
        return self.action()===self.DISABLE_SCHEDULE;
    });
    self.enableSchedule=function(){
        self.action(self.ENABLE_SCHEDULE);
    };
    self.isEnableSchedule=ko.pureComputed(function(){
        return self.action()===self.ENABLE_SCHEDULE;
    });
    self.enableExecution=function(){
        self.action(self.ENABLE_EXECUTION);
    };
    self.isEnableExecution=ko.pureComputed(function(){
        return self.action()===self.ENABLE_EXECUTION;
    });
    self.disableExecution=function(){
        self.action(self.DISABLE_EXECUTION);
    };
    self.isDisableExecution=ko.pureComputed(function(){
        return self.action()===self.DISABLE_EXECUTION;
    });
    self.actionDelete=function(){
        self.action(self.DELETE);
    };
    self.isDelete=ko.pureComputed(function(){
        return self.action()===self.DELETE;
    });
    self.cancel=function(){
        self.action(null);
    };

    self.setCheckboxValues=function(ids){
        //check only the checkbox with this job id by passing an array
        jQuery('.jobbulkeditfield :input[name=ids]').val(ids);
    };
    self.checkboxesForGroup=function(group){
        return jQuery('.jobbulkeditfield input[type=checkbox][data-job-group="'+group+'"]');
    };
    self.allCheckboxes=function(group){
        return jQuery('.jobbulkeditfield input[type=checkbox]');
    };
    self.jobGroupSelectAll=function(e){
        var jgroup=jQuery(e).data('job-group');
        if(jgroup){
            self.checkboxesForGroup(jgroup).prop('checked', true);
        }
    };

    self.jobGroupSelectNone=function(e){
        var jgroup=jQuery(e).data('job-group');
        if(jgroup){
            self.checkboxesForGroup(jgroup).prop('checked', false);
        }
    };
    self.expandAllComponents=function(){
        jQuery('.topgroup .expandComponent').show();
        jQuery('#job_group_tree .expandComponent .expandComponentControl [data-expanding]').each(function(i,e){
            if(jQuery(e).data('expanderOpenClass')){
                jQuery(e).addClass(jQuery(e).data('expanderOpenClass'))
            }
            if(jQuery(e).data('expanderCloseClass')){
                jQuery(e).removeClass(jQuery(e).data('expanderCloseClass'))
            }
        });
        jQuery('#job_group_tree .expandComponent .expandComponentHolder').addClass('expanded');
    };
    self.collapseAllComponents=function(){
        jQuery('.topgroup .expandComponent').hide();
        jQuery('#job_group_tree .expandComponent .expandComponentControl [data-expanding]').each(function(i,e){
            if(jQuery(e).data('expanderOpenClass')){
                jQuery(e).removeClass(jQuery(e).data('expanderOpenClass'))
            }
            if(jQuery(e).data('expanderCloseClass')){
                jQuery(e).addClass(jQuery(e).data('expanderCloseClass'))
            }
        });
        jQuery('#job_group_tree .expandComponent .expandComponentHolder').removeClass('expanded');
    };
    self.selectAll=function(){
        self.expandAllComponents();
        self.allCheckboxes().prop('checked', true);
    };
    self.selectNone=function(){
        self.expandAllComponents();
        self.allCheckboxes().prop('checked', false);
    };
    self.toggleModal=function(){
        jQuery('#bulk_del_confirm').modal('toggle');
    };
    self.activateActionForJob=function(action,jobid){
        self.setCheckboxValues([jobid]);
        self.beginEdit();
        self.action(action);
        self.toggleModal();
    };

    self.scmExportEnabled = ko.observable(false);
    self.scmImportEnabled = ko.observable(false);
    self.scmStatus = ko.observable(null);
    self.scmImportJobStatus = ko.observable(null);
    self.scmExportStatus = ko.observable(null);
    self.scmImportStatus = ko.observable(null);
    self.scmExportActions = ko.observable(null);
    self.scmImportActions = ko.observable(null);
    self.scmExportRenamed = ko.observable(null);
    self.scmDone = ko.observable(null);
    self.isExportEnabled=ko.pureComputed(function(){
        return self.scmExportEnabled();
    });

    self.jobSynchState = function(jobid){
        var exportStatus = null;
        var importStatus = null;
        if(self.scmStatus() && self.scmStatus()[jobid]){
            exportStatus = self.scmStatus()[jobid].synchState;
        }
        if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){
            importStatus = self.scmImportJobStatus()[jobid].synchState;
        }
        if(!exportStatus || exportStatus == "CLEAN"){
            return importStatus;
        }else{
            return exportStatus
        }
    };

    self.displayBadge = function(jobid){
        var displayExport = false;
        var displayImport = false;
        if(self.scmExportEnabled() || self.scmImportEnabled()){
            if(self.scmStatus() && self.scmStatus()[jobid]){
                displayExport = self.scmStatus()[jobid].synchState != "CLEAN";
            }
            if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){
                displayImport = self.scmImportJobStatus()[jobid].synchState != "CLEAN";
            }
        }
        return (displayExport || displayImport);
    };

    self.jobText = function(jobid){
        var exportStatus = null;
        var importStatus = null;
        var text = null;
        if(self.scmStatus() && self.scmStatus()[jobid]){
            exportStatus = self.scmStatus()[jobid].synchState;
            switch(exportStatus) {
                case "EXPORT_NEEDED":
                    text = self.messages['scm.export.status.EXPORT_NEEDED.description'];
                    break;
                case "CREATE_NEEDED":
                    text = self.messages['scm.export.status.CREATE_NEEDED.description'];
                    break;
                case "CLEAN":
                    text = self.messages['scm.export.status.CLEAN.description'];
                    break;
                case "LOADING":
                    text = self.messages['scm.export.status.LOADING.description'];
                    break;
                default:
                    text = exportStatus;
            }
        }
        if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){
            if(text){
                text +=', ';
            }else{
                text = '';
            }
            importStatus = self.scmImportJobStatus()[jobid].synchState;
            switch(importStatus) {
                case "IMPORT_NEEDED":
                    text += self.messages['scm.import.status.IMPORT_NEEDED.description'];
                    break;
                case "DELETE_NEEDED":
                    text += self.messages['scm.import.status.DELETE_NEEDED.description'];
                    break;
                case "CLEAN":
                    text += self.messages['scm.import.status.CLEAN.description'];
                    break;
                case "REFRESH_NEEDED":
                    text += self.messages['scm.import.status.REFRESH_NEEDED.description'];
                    break;
                case "UNKNOWN":
                    text += self.messages['scm.import.status.UNKNOWN.description'];
                    break;
                case "LOADING":
                    text = self.messages['scm.import.status.LOADING.description'];
                    break;
                default:
                    text += importStatus;
            }

        }
        return text;
    };

    self.jobClass = function(jobid){
        switch(self.jobSynchState(jobid)) {
            case "EXPORT_NEEDED":
                return "text-info";
            case "CREATE_NEEDED":
                return "text-success";
            case "UNKNOWN":
                return "text-primary";
            case "IMPORT_NEEDED":
                return "text-warning";
            case "REFRESH_NEEDED":
                return "text-warning";
            case "DELETED":
                return "text-danger";
            case "CLEAN":
                return "text-primary";
            case "LOADING":
                return "text-danger";

        }
        return 'text-primary';
    };

    self.jobIcon = function(jobid){
        switch(self.jobSynchState(jobid)) {
            case "EXPORT_NEEDED":
                return "glyphicon-exclamation-sign";
            case "CREATE_NEEDED":
                return "glyphicon-exclamation-sign";
            case "UNKNOWN":
                return "glyphicon-question-sign";
            case "IMPORT_NEEDED":
                return "glyphicon-exclamation-sign";
            case "REFRESH_NEEDED":
                return "glyphicon-exclamation-sign";
            case "DELETED":
                return "glyphicon-minus-sign";
            case "CLEAN":
                return "glyphicon-ok";
            case "LOADING":
                return "glyphicon-refresh";

        }
        return 'glyphicon-plus';
    };

    self.exportMessage = function(){
        if(self.scmExportStatus()){
            return self.scmExportStatus().message;
        }
        return null;
    };
    self.importMessage = function(){
        if(self.scmImportStatus()){
            return self.scmImportStatus().message;
        }
        return null;
    };

    self.exportState = function(){
        if(self.scmExportStatus()){
            return self.scmExportStatus().state;
        }
        return null;
    };
    self.importState = function(){
        if(self.scmImportStatus()){
            return self.scmImportStatus().state;
        }
        return null;
    };

    self.jobCommit = function(jobid){
        return self.scmExportEnabled();
    };

    self.defaultExportText = function(){
        if(self.exportState()) {
            var text = null;
            switch(self.exportState()) {
                case "EXPORT_NEEDED":
                    text = self.messages['scm.export.status.EXPORT_NEEDED.display.text'];
                    break;
                case "CREATE_NEEDED":
                    text = self.messages['scm.export.status.CREATE_NEEDED.display.text'];
                    break;
                case "REFRESH_NEEDED":
                    text = self.messages['scm.export.status.REFRESH_NEEDED.display.text'];
                    break;
                case "DELETED":
                    text = self.messages['scm.export.status.DELETED.display.text'];
                    break;
                case "CLEAN":
                    text = self.messages['scm.export.status.CLEAN.display.text'];
                    break;
                case "LOADING":
                    text = self.messages['scm.export.status.LOADING.display.text'];
                    break;
            }
            if(!text){
                text = self.exportState();
            }
            return text;
        }
        return null;
    };

    self.defaultImportText = function(){
        if(self.importState()) {
            var text = null;
            switch(self.importState()) {
                case "IMPORT_NEEDED":
                    text = self.messages['scm.import.status.IMPORT_NEEDED.display.text'];
                    break;
                case "REFRESH_NEEDED":
                    text = self.messages['scm.import.status.REFRESH_NEEDED.display.text'];
                    break;
                case "UNKNOWN":
                    text = self.messages['scm.import.status.UNKNOWN.display.text'];
                    break;
                case "CLEAN":
                    text = self.messages['scm.import.status.CLEAN.display.text'];
                    break;
                case "LOADING":
                    text = self.messages['scm.import.status.LOADING.display.text'];
                    break;
            }
            if(!text){
                text = self.importState();
            }
            return text;
        }
        return null;
    };

    self.defaultDisplayText = function(){
        if(self.exportState()!=null && self.exportState() != 'CLEAN'){
            return self.defaultExportText();
        }else{
            return self.defaultImportText();
        }
    };

    self.displayExport = function(){
        return (self.exportState() && self.exportState() != 'CLEAN');
    };

    self.displayImport = function(){
        return (self.importState() && self.importState() != 'CLEAN');
    };

    self.displaySCMMEssage = function(){
        return (self.displayExport() || self.displayImport());
    };

    self.isLoadingSCMActions = function(){
        return (!self.scmDone());
    }
}

<commit_msg> - fix jobs.js code error<commit_after>/*
 * Copyright 2016 SimplifyOps, Inc. (http://simplifyops.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//= require momentutil
//= require knockout.min
//= require knockout-mapping
//= require knockout-foreachprop
//= require nodeFiltersKO
//= require executionOptions
//= require jobFiltersKO
//= require knockout-onenter
//= require knockout-node-filter-link
//= require menu/job-remote-options
//= require menu/joboptions
//= require ko/binding-popover
//= require ko/binding-datetimepicker
//= require ko/handler-bootstrapPopover
//= require ko/handler-bootstrapTooltip
//= require ko/handler-messageTemplate
//= require ko/binding-css2
//= require scheduledExecution/jobRunFormOptionsKO
//= require koBind
//= require ko/binding-url-path-param

/*
 Manifest for "menu/jobs.gsp" page
 */
//TODO: refactor menu/jobs.gsp to move javascript here
/**
 * Possible actions for bulk edit jobs, to present in modal dialog
 * @constructor
 */
function BulkEditor(data){
    var self=this;
    self.messages=data.messages||{};
    self.DISABLE_SCHEDULE = 'disable_schedule';
    self.ENABLE_SCHEDULE = 'enable_schedule';
    self.ENABLE_EXECUTION= 'enable_execution';
    self.DISABLE_EXECUTION= 'disable_execution';
    self.DELETE= 'delete';
    self.action=ko.observable(null);
    self.enabled=ko.observable(false);
    self.beginEdit=function(){
        self.expandAllComponents();
        self.enabled(true);
    };
    self.cancelEdit=function(){
        self.enabled(false);
        self.selectNone();
    };
    self.disableSchedule=function(){

        self.action(self.DISABLE_SCHEDULE);
    };
    self.isDisableSchedule=ko.pureComputed(function(){
        return self.action()===self.DISABLE_SCHEDULE;
    });
    self.enableSchedule=function(){
        self.action(self.ENABLE_SCHEDULE);
    };
    self.isEnableSchedule=ko.pureComputed(function(){
        return self.action()===self.ENABLE_SCHEDULE;
    });
    self.enableExecution=function(){
        self.action(self.ENABLE_EXECUTION);
    };
    self.isEnableExecution=ko.pureComputed(function(){
        return self.action()===self.ENABLE_EXECUTION;
    });
    self.disableExecution=function(){
        self.action(self.DISABLE_EXECUTION);
    };
    self.isDisableExecution=ko.pureComputed(function(){
        return self.action()===self.DISABLE_EXECUTION;
    });
    self.actionDelete=function(){
        self.action(self.DELETE);
    };
    self.isDelete=ko.pureComputed(function(){
        return self.action()===self.DELETE;
    });
    self.cancel=function(){
        self.action(null);
    };

    self.setCheckboxValues=function(ids){
        //check only the checkbox with this job id by passing an array
        jQuery('.jobbulkeditfield :input[name=ids]').val(ids);
    };
    self.checkboxesForGroup=function(group){
        return jQuery('.jobbulkeditfield input[type=checkbox][data-job-group="'+group+'"]');
    };
    self.allCheckboxes=function(group){
        return jQuery('.jobbulkeditfield input[type=checkbox]');
    };
    self.jobGroupSelectAll=function(e){
        var jgroup=jQuery(e).data('job-group');
        if(jgroup){
            self.checkboxesForGroup(jgroup).prop('checked', true);
        }
    };

    self.jobGroupSelectNone=function(e){
        var jgroup=jQuery(e).data('job-group');
        if(jgroup){
            self.checkboxesForGroup(jgroup).prop('checked', false);
        }
    };
    self.expandAllComponents=function(){
        jQuery('.topgroup .expandComponent').show();
        jQuery('#job_group_tree .expandComponent .expandComponentControl [data-expanding]').each(function(i,e){
            if(jQuery(e).data('expanderOpenClass')){
                jQuery(e).addClass(jQuery(e).data('expanderOpenClass'))
            }
            if(jQuery(e).data('expanderCloseClass')){
                jQuery(e).removeClass(jQuery(e).data('expanderCloseClass'))
            }
        });
        jQuery('#job_group_tree .expandComponent .expandComponentHolder').addClass('expanded');
    };
    self.collapseAllComponents=function(){
        jQuery('.topgroup .expandComponent').hide();
        jQuery('#job_group_tree .expandComponent .expandComponentControl [data-expanding]').each(function(i,e){
            if(jQuery(e).data('expanderOpenClass')){
                jQuery(e).removeClass(jQuery(e).data('expanderOpenClass'))
            }
            if(jQuery(e).data('expanderCloseClass')){
                jQuery(e).addClass(jQuery(e).data('expanderCloseClass'))
            }
        });
        jQuery('#job_group_tree .expandComponent .expandComponentHolder').removeClass('expanded');
    };
    self.selectAll=function(){
        self.expandAllComponents();
        self.allCheckboxes().prop('checked', true);
    };
    self.selectNone=function(){
        self.expandAllComponents();
        self.allCheckboxes().prop('checked', false);
    };
    self.toggleModal=function(){
        jQuery('#bulk_del_confirm').modal('toggle');
    };
    self.activateActionForJob=function(action,jobid){
        self.setCheckboxValues([jobid]);
        self.beginEdit();
        self.action(action);
        self.toggleModal();
    };

    self.scmExportEnabled = ko.observable(false);
    self.scmImportEnabled = ko.observable(false);
    self.scmStatus = ko.observable(null);
    self.scmImportJobStatus = ko.observable(null);
    self.scmExportStatus = ko.observable(null);
    self.scmImportStatus = ko.observable(null);
    self.scmExportActions = ko.observable(null);
    self.scmImportActions = ko.observable(null);
    self.scmExportRenamed = ko.observable(null);
    self.scmDone = ko.observable(null);
    self.isExportEnabled=ko.pureComputed(function(){
        return self.scmExportEnabled();
    });

    self.jobSynchState = function(jobid){
        var exportStatus = null;
        var importStatus = null;
        if(self.scmStatus() && self.scmStatus()[jobid]){
            exportStatus = self.scmStatus()[jobid].synchState;
        }
        if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){
            importStatus = self.scmImportJobStatus()[jobid].synchState;
        }
        if(!exportStatus || exportStatus == "CLEAN"){
            return importStatus;
        }else{
            return exportStatus
        }
    };

    self.displayBadge = function(jobid){
        var displayExport = false;
        var displayImport = false;
        if(self.scmExportEnabled() || self.scmImportEnabled()){
            if(self.scmStatus() && self.scmStatus()[jobid]){
                displayExport = self.scmStatus()[jobid].synchState != "CLEAN";
            }
            if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){
                displayImport = self.scmImportJobStatus()[jobid].synchState != "CLEAN";
            }
        }
        return (displayExport || displayImport);
    };

    self.jobText = function(jobid){
        var exportStatus = null;
        var importStatus = null;
        var text = null;
        if(self.scmStatus() && self.scmStatus()[jobid]){
            exportStatus = self.scmStatus()[jobid].synchState;
            switch(exportStatus) {
                case "EXPORT_NEEDED":
                    text = self.messages['scm.export.status.EXPORT_NEEDED.description'];
                    break;
                case "CREATE_NEEDED":
                    text = self.messages['scm.export.status.CREATE_NEEDED.description'];
                    break;
                case "CLEAN":
                    text = self.messages['scm.export.status.CLEAN.description'];
                    break;
                case "LOADING":
                    text = self.messages['scm.export.status.LOADING.description'];
                    break;
                default:
                    text = exportStatus;
            }
        }
        if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){
            if(text){
                text +=', ';
            }else{
                text = '';
            }
            importStatus = self.scmImportJobStatus()[jobid].synchState;
            switch(importStatus) {
                case "IMPORT_NEEDED":
                    text += self.messages['scm.import.status.IMPORT_NEEDED.description'];
                    break;
                case "DELETE_NEEDED":
                    text += self.messages['scm.import.status.DELETE_NEEDED.description'];
                    break;
                case "CLEAN":
                    text += self.messages['scm.import.status.CLEAN.description'];
                    break;
                case "REFRESH_NEEDED":
                    text += self.messages['scm.import.status.REFRESH_NEEDED.description'];
                    break;
                case "UNKNOWN":
                    text += self.messages['scm.import.status.UNKNOWN.description'];
                    break;
                case "LOADING":
                    text = self.messages['scm.import.status.LOADING.description'];
                    break;
                default:
                    text += importStatus;
            }

        }
        return text;
    };

    self.jobClass = function(jobid){
        switch(self.jobSynchState(jobid)) {
            case "EXPORT_NEEDED":
                return "text-info";
            case "CREATE_NEEDED":
                return "text-success";
            case "UNKNOWN":
                return "text-primary";
            case "IMPORT_NEEDED":
            case "REFRESH_NEEDED":
            case "LOADING":
                return "text-warning";
            case "DELETED":
                return "text-danger";
            case "CLEAN":
                return "text-primary";

        }
        return 'text-primary';
    };

    self.jobIcon = function(jobid){
        switch(self.jobSynchState(jobid)) {
            case "EXPORT_NEEDED":
            case "CREATE_NEEDED":
                return "glyphicon-exclamation-sign";
            case "UNKNOWN":
                return "glyphicon-question-sign";
            case "IMPORT_NEEDED":
            case "REFRESH_NEEDED":
                return "glyphicon-exclamation-sign";
            case "DELETED":
                return "glyphicon-minus-sign";
            case "CLEAN":
                return "glyphicon-ok";
            case "LOADING":
                return "glyphicon-refresh";

        }
        return 'glyphicon-plus';
    };

    self.exportMessage = function(){
        if(self.scmExportStatus()){
            return self.scmExportStatus().message;
        }
        return null;
    };
    self.importMessage = function(){
        if(self.scmImportStatus()){
            return self.scmImportStatus().message;
        }
        return null;
    };

    self.exportState = function(){
        if(self.scmExportStatus()){
            return self.scmExportStatus().state;
        }
        return null;
    };
    self.importState = function(){
        if(self.scmImportStatus()){
            return self.scmImportStatus().state;
        }
        return null;
    };

    self.jobCommit = function(jobid){
        return self.scmExportEnabled();
    };

    self.defaultExportText = function(){
        if(self.exportState()) {
            var text = null;
            switch(self.exportState()) {
                case "EXPORT_NEEDED":
                    text = self.messages['scm.export.status.EXPORT_NEEDED.display.text'];
                    break;
                case "CREATE_NEEDED":
                    text = self.messages['scm.export.status.CREATE_NEEDED.display.text'];
                    break;
                case "REFRESH_NEEDED":
                    text = self.messages['scm.export.status.REFRESH_NEEDED.display.text'];
                    break;
                case "DELETED":
                    text = self.messages['scm.export.status.DELETED.display.text'];
                    break;
                case "CLEAN":
                    text = self.messages['scm.export.status.CLEAN.display.text'];
                    break;
                case "LOADING":
                    text = self.messages['scm.export.status.LOADING.display.text'];
                    break;
            }
            if(!text){
                text = self.exportState();
            }
            return text;
        }
        return null;
    };

    self.defaultImportText = function(){
        if(self.importState()) {
            var text = null;
            switch(self.importState()) {
                case "IMPORT_NEEDED":
                    text = self.messages['scm.import.status.IMPORT_NEEDED.display.text'];
                    break;
                case "REFRESH_NEEDED":
                    text = self.messages['scm.import.status.REFRESH_NEEDED.display.text'];
                    break;
                case "UNKNOWN":
                    text = self.messages['scm.import.status.UNKNOWN.display.text'];
                    break;
                case "CLEAN":
                    text = self.messages['scm.import.status.CLEAN.display.text'];
                    break;
                case "LOADING":
                    text = self.messages['scm.import.status.LOADING.display.text'];
                    break;
            }
            if(!text){
                text = self.importState();
            }
            return text;
        }
        return null;
    };

    self.defaultDisplayText = function(){
        if(self.exportState()!=null && self.exportState() != 'CLEAN'){
            return self.defaultExportText();
        }else{
            return self.defaultImportText();
        }
    };

    self.displayExport = function(){
        return (self.exportState() && self.exportState() != 'CLEAN');
    };

    self.displayImport = function(){
        return (self.importState() && self.importState() != 'CLEAN');
    };

    self.displaySCMMEssage = function(){
        return (self.displayExport() || self.displayImport());
    };

    self.isLoadingSCMActions = function(){
        return (!self.scmDone());
    }
}

<|endoftext|>


<commit_before>// Object.assign polyfill
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign !== 'function') {
  Object.assign = function (target) {
    'use strict'
    if (target == null) {
      throw new TypeError('Cannot convert undefined or null to object')
    }

    target = Object(target)
    for (var index = 1; index < arguments.length; index++) {
      var source = arguments[index]
      if (source != null) {
        for (var key in source) {
          if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key]
          }
        }
      }
    }
    return target
  }
}

// Detect CSS Animation End Support
// https://github.com/limonte/sweetalert2/blob/99bd539f85e15ac170f69d35001d12e092ef0054/src/utils/dom.js#L194
var animationEndEvent = (function () {
  var el = document.createElement('div')
  var eventNames = {
    'WebkitAnimation': 'webkitAnimationEnd',
    'MozAnimation': 'animationend',
    'OAnimation': 'oanimationend',
    'msAnimation': 'MSAnimationEnd',
    'animation': 'animationend'
  }
  for (var i in eventNames) {
    if (el.style[i] !== undefined) {
      return eventNames[i]
    }
  }
  return false
})()

// vex base CSS classes
var baseClassNames = {
  vex: 'vex',
  content: 'vex-content',
  overlay: 'vex-overlay',
  close: 'vex-close',
  closing: 'vex-closing',
  open: 'vex-open'
}

// String to DOM function
var domify = require('domify')

var vexes = {}
var globalId = 1

var vex = {
  open: function (opts) {
    // vex object
    var vexInstance = {}

    // Set id
    vexInstance.id = globalId++

    // Store internally
    vexes[vexInstance.id] = vexInstance

    // Set state
    vexInstance.isOpen = true

    // Function to handle escape keypress
    var escHandler = function (e) {
      if (e.keyCode === 27) {
        vexInstance.close()
      }
    }

    // Close function on the vex object
    vexInstance.close = function () {
      // Check state
      if (!this.isOpen) {
        return true
      }

      var options = this.options

      var beforeClose = function () {
        if (options.beforeClose) {
          return options.beforeClose.call(this)
        }
        return true
      }.bind(this)

      var close = function () {
        if (!this.rootEl.parentNode) {
          return
        }
        // Run once
        this.rootEl.removeEventListener(animationEndEvent, close)
        // Remove the dialog from the DOM
        this.rootEl.parentNode.removeChild(this.rootEl)
        // Remove styling from the body during the next tick
        setTimeout(function () {
          document.body.classList.remove(baseClassNames.open)
        }, 0)
        // Call after close callback
        if (options.afterClose) {
          options.afterClose.call(this)
        }
      }.bind(this)

      if (beforeClose() === false) {
        return false
      }

      // Update state
      this.isOpen = false

      // Detect animation support
      var style = window.getComputedStyle(this.contentEl)
      function hasAnimationPre (prefix) {
        return style.getPropertyValue(prefix + 'animation-name') !== 'none' && style.getPropertyValue(prefix + 'animation-duration') !== '0s'
      }
      var hasAnimation = hasAnimationPre('') || hasAnimationPre('-webkit-') || hasAnimationPre('-moz-') || hasAnimationPre('-o-')

      // Close the vex
      if (animationEndEvent && hasAnimation) {
        this.rootEl.addEventListener(animationEndEvent, close)
        this.rootEl.classList.add(baseClassNames.closing)
      } else {
        close()
      }

      // Cleanup global handler for ESC
      window.removeEventListener('keyup', escHandler)

      return true
    }

    // TODO ESC key closes all vex dialogs
    // Register global handler for ESC
    window.addEventListener('keyup', escHandler)

    // Allow strings as content
    if (typeof opts === 'string') {
      opts = {
        content: opts
      }
    }
    var options = vexInstance.options = Object.assign({}, vex.defaultOptions, opts)

    // vex
    var rootEl = vexInstance.rootEl = document.createElement('div')
    rootEl.classList = baseClassNames.vex
    if (options.className) {
      rootEl.classList.add(options.className)
    }

    // Overlay
    var overlayEl = vexInstance.overlayEl = document.createElement('div')
    overlayEl.classList = baseClassNames.overlay
    if (options.overlayClassName) {
      overlayEl.classList.add(options.overlayClassName)
    }
    if (options.overlayClosesOnClick) {
      overlayEl.addEventListener('click', function (e) {
        if (e.target === overlayEl) {
          vexInstance.close()
        }
      })
    }
    rootEl.appendChild(overlayEl)

    // Content
    var contentEl = vexInstance.contentEl = document.createElement('div')
    contentEl.classList = baseClassNames.content
    if (options.contentClassName) {
      contentEl.classList.add(options.contentClassName)
    }
    contentEl.appendChild(options.content instanceof window.Node ? options.content : domify(options.content))
    rootEl.appendChild(contentEl)

    // Close button
    if (options.showCloseButton) {
      var closeEl = vexInstance.closeEl = document.createElement('div')
      closeEl.classList = baseClassNames.close
      if (options.closeClassName) {
        closeEl.classList.add(options.closeClassName)
      }
      closeEl.addEventListener('click', vexInstance.close.bind(vexInstance))
      contentEl.appendChild(closeEl)
    }

    // Inject DOM
    document.querySelector(options.appendLocation).appendChild(rootEl)

    // Call after open callback
    if (options.afterOpen) {
      options.afterOpen.call(vexInstance)
    }

    // Apply styling to the body during the next tick
    setTimeout(function () {
      document.body.classList.add(baseClassNames.open)
    }, 0)

    return vexInstance
  },

  close: function (vexOrId) {
    var id
    if (vexOrId.id) {
      id = vexOrId.id
    } else if (typeof vexOrId === 'string') {
      id = vexOrId
    } else {
      throw new TypeError('close requires a vex object or id string')
    }
    return vexes[id].close()
  },

  closeAll: function () {
    for (var id in vexes) {
      this.close(id)
    }
    return true
  },

  getAll: function () {
    return vexes
  },

  getById: function (id) {
    return vexes[id]
  }
}

vex.defaultOptions = {
  content: '',
  showCloseButton: true,
  escapeButtonCloses: true,
  overlayClosesOnClick: true,
  appendLocation: 'body',
  className: '',
  overlayClassName: '',
  contentClassName: '',
  closeClassName: ''
}

// TODO Loading symbols?

vex.registerPlugin = function (plugin, name) {
  var pluginName = name || plugin.pluginName || plugin.name
  if (vex[pluginName]) {
    throw new Error('Plugin ' + name + ' is already registered.')
  }
  vex[pluginName] = plugin(vex)
  for (var prop in plugin) {
    if (plugin.hasOwnProperty(prop) && prop !== 'pluginName' && prop !== 'name') {
      vex[pluginName][prop] = plugin[prop]
    }
  }
}

module.exports = vex
<commit_msg>More comments!<commit_after>// Object.assign polyfill
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign !== 'function') {
  Object.assign = function (target) {
    'use strict'
    if (target == null) {
      throw new TypeError('Cannot convert undefined or null to object')
    }

    target = Object(target)
    for (var index = 1; index < arguments.length; index++) {
      var source = arguments[index]
      if (source != null) {
        for (var key in source) {
          if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key]
          }
        }
      }
    }
    return target
  }
}

// Detect CSS Animation End Support
// https://github.com/limonte/sweetalert2/blob/99bd539f85e15ac170f69d35001d12e092ef0054/src/utils/dom.js#L194
var animationEndEvent = (function () {
  var el = document.createElement('div')
  var eventNames = {
    'WebkitAnimation': 'webkitAnimationEnd',
    'MozAnimation': 'animationend',
    'OAnimation': 'oanimationend',
    'msAnimation': 'MSAnimationEnd',
    'animation': 'animationend'
  }
  for (var i in eventNames) {
    if (el.style[i] !== undefined) {
      return eventNames[i]
    }
  }
  return false
})()

// vex base CSS classes
var baseClassNames = {
  vex: 'vex',
  content: 'vex-content',
  overlay: 'vex-overlay',
  close: 'vex-close',
  closing: 'vex-closing',
  open: 'vex-open'
}

// String to DOM function
var domify = require('domify')

// Private lookup table of all open vex objects, keyed by id
var vexes = {}
var globalId = 1

// vex itself is an object that exposes a simple API to open and close vex objects in various ways
var vex = {
  open: function (opts) {
    // the dialog instance
    var vexInstance = {}

    // Set id
    vexInstance.id = globalId++

    // Store internally
    vexes[vexInstance.id] = vexInstance

    // Set state
    vexInstance.isOpen = true

    // Function to handle escape keypress
    var escHandler = function (e) {
      if (e.keyCode === 27) {
        vexInstance.close()
      }
    }

    // Close function on the vex instance
    vexInstance.close = function () {
      // Check state
      if (!this.isOpen) {
        return true
      }

      var options = this.options

      var beforeClose = function () {
        if (options.beforeClose) {
          return options.beforeClose.call(this)
        }
        return true
      }.bind(this)

      var close = function () {
        if (!this.rootEl.parentNode) {
          return
        }
        // Run once
        this.rootEl.removeEventListener(animationEndEvent, close)
        // Remove the dialog from the DOM
        this.rootEl.parentNode.removeChild(this.rootEl)
        // Remove styling from the body during the next tick
        setTimeout(function () {
          document.body.classList.remove(baseClassNames.open)
        }, 0)
        // Call after close callback
        if (options.afterClose) {
          options.afterClose.call(this)
        }
      }.bind(this)

      // If any user-defined validation or anything fails, abort the close
      if (beforeClose() === false) {
        return false
      }

      // Update state
      this.isOpen = false

      // Detect if the content el has any CSS animations defined
      var style = window.getComputedStyle(this.contentEl)
      function hasAnimationPre (prefix) {
        return style.getPropertyValue(prefix + 'animation-name') !== 'none' && style.getPropertyValue(prefix + 'animation-duration') !== '0s'
      }
      var hasAnimation = hasAnimationPre('') || hasAnimationPre('-webkit-') || hasAnimationPre('-moz-') || hasAnimationPre('-o-')

      // Close the vex
      if (animationEndEvent && hasAnimation) {
        // Setup the end event listener, to remove the el from the DOM
        this.rootEl.addEventListener(animationEndEvent, close)
        // Add the closing class to the dialog, showing the close animation
        this.rootEl.classList.add(baseClassNames.closing)
      } else {
        close()
      }

      // Cleanup global handler for ESC
      window.removeEventListener('keyup', escHandler)

      return true
    }

    // TODO ESC key closes all vex dialogs
    // Register global handler for ESC
    window.addEventListener('keyup', escHandler)

    // Allow strings as content
    if (typeof opts === 'string') {
      opts = {
        content: opts
      }
    }
    var options = vexInstance.options = Object.assign({}, vex.defaultOptions, opts)

    // vex root
    var rootEl = vexInstance.rootEl = document.createElement('div')
    rootEl.classList = baseClassNames.vex
    if (options.className) {
      rootEl.classList.add(options.className)
    }

    // Overlay
    var overlayEl = vexInstance.overlayEl = document.createElement('div')
    overlayEl.classList = baseClassNames.overlay
    if (options.overlayClassName) {
      overlayEl.classList.add(options.overlayClassName)
    }
    if (options.overlayClosesOnClick) {
      overlayEl.addEventListener('click', function (e) {
        if (e.target === overlayEl) {
          vexInstance.close()
        }
      })
    }
    rootEl.appendChild(overlayEl)

    // Content
    var contentEl = vexInstance.contentEl = document.createElement('div')
    contentEl.classList = baseClassNames.content
    if (options.contentClassName) {
      contentEl.classList.add(options.contentClassName)
    }
    contentEl.appendChild(options.content instanceof window.Node ? options.content : domify(options.content))
    rootEl.appendChild(contentEl)

    // Close button
    if (options.showCloseButton) {
      var closeEl = vexInstance.closeEl = document.createElement('div')
      closeEl.classList = baseClassNames.close
      if (options.closeClassName) {
        closeEl.classList.add(options.closeClassName)
      }
      closeEl.addEventListener('click', vexInstance.close.bind(vexInstance))
      contentEl.appendChild(closeEl)
    }

    // Add to DOM
    document.querySelector(options.appendLocation).appendChild(rootEl)

    // Call after open callback
    if (options.afterOpen) {
      options.afterOpen.call(vexInstance)
    }

    // Apply styling to the body during the next tick
    setTimeout(function () {
      document.body.classList.add(baseClassNames.open)
    }, 0)

    return vexInstance
  },

  // A top-level vex.close function to close dialogs by reference or id
  close: function (vexOrId) {
    var id
    if (vexOrId.id) {
      id = vexOrId.id
    } else if (typeof vexOrId === 'string') {
      id = vexOrId
    } else {
      throw new TypeError('close requires a vex object or id string')
    }
    return vexes[id].close()
  },

  // Close every vex!
  closeAll: function () {
    for (var id in vexes) {
      this.close(id)
    }
    return true
  },

  // A getter for the internal lookup table
  getAll: function () {
    return vexes
  },

  // A getter for the internal lookup table
  getById: function (id) {
    return vexes[id]
  }
}

vex.defaultOptions = {
  content: '',
  showCloseButton: true,
  escapeButtonCloses: true,
  overlayClosesOnClick: true,
  appendLocation: 'body',
  className: '',
  overlayClassName: '',
  contentClassName: '',
  closeClassName: ''
}

// TODO Loading symbols?

// Plugin system!
vex.registerPlugin = function (plugin, name) {
  var pluginName = name || plugin.pluginName || plugin.name
  if (vex[pluginName]) {
    throw new Error('Plugin ' + name + ' is already registered.')
  }
  vex[pluginName] = plugin(vex)
  for (var prop in plugin) {
    if (plugin.hasOwnProperty(prop) && prop !== 'pluginName' && prop !== 'name') {
      vex[pluginName][prop] = plugin[prop]
    }
  }
}

module.exports = vex
<|endoftext|>