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

/**
 * Copyright (c) 2014 "Fronteer LTD"
 * Grasshopper Event Engine
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var _ = require('lodash');
var fs = require('fs');
var yargs = require('yargs');

var AdminsDAO = require('gh-admins/lib/internal/dao');
var AppsAPI = require('gh-apps');
var Context = require('gh-context').Context;
var EventsAPI = require('gh-events');
var GrassHopper = require('gh-core/lib/api');
var log = require('gh-core/lib/logger').logger('scripts/orgunit-import');
var OrgUnitAPI = require('gh-orgunit');
var SeriesAPI = require('gh-series');

var config = require('../../../config');

/*
 * This script allows you to import a tree of courses, subjects,
 * parts, modules, series and events. The tree should be formatted
 * in the following manner:
 *
 * ```json
 * {
    "name": "Timetable",
    "type": "root",
    "nodes": {
        "5": {
            "id": "5",
            "name": "Natural Sciences Tripos",
            "type": "course",
            "nodes": {
                "117": {
                    "id": "117",
                    "name": "Biology of Cells",
                    "type": "subject",
                    "nodes": {
                        "106-31": {
                            "id": "106-31",
                            "name": "Part IA",
                            "type": "part",
                            "nodes": {
                                "487": {
                                    "id": "487",
                                    "name": "Practicals",
                                    "type": "module"
                                },
                                "488": {
                                    "id": "488",
                                    "name": "Lectures",
                                    "type": "module",
                                    "nodes": {
                                        "5875": {
                                            "id": "5875",
                                            "name": "Practicals - Monday Group",
                                            "type": "serie",
                                            "nodes": {
                                                "49794": {
                                                    "id": "49794",
                                                    "name": "PCR",
                                                    "type": "event",
                                                    "event-type": "practical",
                                                    "start": "2015-02-23T11:00:00+00:00",
                                                    "end": "2015-02-23T17:00:00+00:00"
                                                },
    ...

 * ```
 *
 * This currently works by spinning up an application container, but
 * will eventually be migrated to use the REST apis
 */

var argv = yargs
    .usage('Import an organizational unit tree.\nUsage: $0')
    .example('$0 --file tree.json --app 19', 'Import the structure in tree.json for application 19')
    .demand('f')
    .alias('f', 'file')
    .describe('f', 'The JSON file that contains the tree')
    .demand('a')
    .alias('a', 'app')
    .describe('a', 'The id of the application for which the tree should be imported')

    .argv;

// Initialize the app server
GrassHopper.init(config, function(err) {
    if (err) {
        log().error({'err': err}, 'Failed to spin up the application container');
        process.exit(1);
    }

    // Get a global administrator
    AdminsDAO.getGlobalAdminByUsername('administrator', function(err, globalAdmin) {
        if (err) {
            log().error({'err': err}, 'Failed to get the global administrator');
            process.exit(1);
        }

        // Get the app
        var ctx = new Context(null, globalAdmin);
        AppsAPI.getApp(ctx, argv.app, function(err, app) {
            if (err) {
                log().error({'err': err}, 'Failed to get the provided app');
                process.exit(1);
            }

            ctx = new Context(app, globalAdmin);

            log().debug({'file': argv.file}, 'Reading file');
            fs.readFile(argv.file, function(err, tree) {
                if (err) {
                    log().error({'err': err, 'file': argv.file}, 'Failed to read file');
                    process.exit(1);
                }

                // Parse the tree
                log().debug('Parsing tree');
                tree = JSON.parse(tree);

                // Persist it
                log().info('Starting to persist the organizational tree, this is going to take a while');
                var courses = _.values(tree.nodes);
                createNodes(ctx, courses, null, function() {

                    // All done, simply exit
                    log().info('The organizational tree has been succesfully imported');
                    process.exit(0);
                });
            });
        });
    });
});

/**
 * Recursively create the organizational units for a set of nodes.
 *
 * @param  {Node[]}             nodes               A set of nodes to create
 * @param  {OrgUnit|Serie}      [parent]            The parent under which the nodes should be created
 * @param  {Function}           callback            Standard callback function
 */
var createNodes = function(ctx, nodes, parent, callback) {
    if (_.isEmpty(nodes)) {
        return callback();
    }

    // Create the node
    var node = nodes.pop();
    createNode(ctx, node, parent, function(createdItem) {
        // Create the child nodes, if any
        var childNodes = _.values(node.nodes);
        createNodes(ctx, childNodes, createdItem, function() {

            // All child nodes have been created, proceed
            // to the next sibling node, if any
            return createNodes(ctx, nodes, parent, callback);
        });
    });
};

/**
 * Create an organizational unit
 *
 * @param  {Node}               node            The node to create
 * @param  {OrgUnit|Serie}      [parent]        The parent under which the node should be created
 * @param  {Function}           callback        Standard callback function
 */
var createNode = function(ctx, node, parent, callback) {
    if (node.type === 'course' || node.type === 'subject' || node.type === 'part' || node.type === 'module') {
        createOrgUnit(ctx, node, parent, callback);
    } else if (node.type === 'serie') {
        createSerie(ctx, node, parent, callback);
    } else if (node.type === 'event') {
        createEvent(ctx, node, parent, callback);
    }
};

/**
 * Create an organisational unit
 *
 * @param  {Context}    ctx             Standard context object containing the current user and the current application
 * @param  {Node}       node            The node to create
 * @param  {OrgUnit}    parent          The parent under which the organisational unit should be created
 * @param  {Function}   callback        Standard callback function
 */
var createOrgUnit = function(ctx, node, parent, callback) {
    var parentId = null;
    if (parent) {
        parentId = parent.id;
    }

    // Re-use the group id of the part if we're creating a module
    var groupId = null;
    if (node.type === 'module') {
        groupId = parent.GroupId;
    }
    OrgUnitAPI.createOrgUnit(ctx, argv.app, node.name.substring(0, 255), node.type, null, groupId, parentId, function(err, orgunit) {
        if (err) {
            console.log(err);
            console.log("DisplayName: '%s'", node.name);
            console.log("type: '%s'", node.type);
            log().error({'err': err}, 'Failed to create orgunit');
            process.exit(1);
        }

        return callback(orgunit);
    });
};

/**
 * Create a serie
 *
 * @param  {Context}    ctx             Standard context object containing the current user and the current application
 * @param  {Node}       node            The node to create
 * @param  {OrgUnit     parent          The organisational unit under which the serie should be created
 * @param  {Function}   callback        Standard callback function
 */
var createSerie = function(ctx, node, parent, callback) {
    SeriesAPI.createSerie(ctx, argv.app, node.name.substring(0, 255), null, parent.GroupId, function(err, serie) {
        if (err) {
            console.log(err);
            console.log("DisplayName: '%s'", node.name);
            log().error({'err': err}, 'Failed to create serie');
            process.exit(1);
        }

        parent.addSeries(serie).complete(function(err) {
            if (err) {
                console.log(err);
                console.log("DisplayName: '%s'", node.name);
                log().error({'err': err}, 'Failed to add serie to orgunit');
                process.exit(1);
            }

            return callback(serie);
        });
    });
};

/**
 * Create an event
 *
 * @param  {Context}    ctx             Standard context object containing the current user and the current application
 * @param  {Node}       node            The node to create
 * @param  {Serie}      parent          The serie under which the event should be created
 * @param  {Function}   callback        Standard callback function
 */
var createEvent = function(ctx, node, parent, callback) {
    // TT's data isn't always correct
    var start = node.start;
    var end = node.end;
    if (start > end) {
        start = node.end;
        end = node.start;
        log().warn({'node': node}, 'Impossible start/end dates');
    }
    var opts = {
        'group': parent.GroupId
    };
    EventsAPI.createEvent(ctx, argv.app, node.name.substring(0, 255), start, end, opts, function(err, event) {
        if (err) {
            console.log(err);
            console.log("DisplayName: '%s'", node.name);
            log().error({'err': err}, 'Failed to create event');
            process.exit(1);
        }

        parent.addEvents(event).complete(function(err) {
            if (err) {
                console.log(err);
                console.log("DisplayName: '%s'", node.name);
                log().error({'err': err}, 'Failed to add event to serie');
                process.exit(1);
            }

            return callback(event);
        });
    });
};
<commit_msg>Fixed import script<commit_after>#!/usr/bin/env node

/**
 * Copyright (c) 2014 "Fronteer LTD"
 * Grasshopper Event Engine
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var _ = require('lodash');
var fs = require('fs');
var yargs = require('yargs');

var AdminsDAO = require('gh-admins/lib/internal/dao');
var AppsAPI = require('gh-apps');
var Context = require('gh-context').Context;
var EventsAPI = require('gh-events');
var GrassHopper = require('gh-core/lib/api');
var log = require('gh-core/lib/logger').logger('scripts/orgunit-import');
var OrgUnitAPI = require('gh-orgunit');
var SeriesAPI = require('gh-series');

var config = require('../../../config');

/*
 * This script allows you to import a tree of courses, subjects,
 * parts, modules, series and events. The tree should be formatted
 * in the following manner:
 *
 * ```json
 * {
    "name": "Timetable",
    "type": "root",
    "nodes": {
        "5": {
            "id": "5",
            "name": "Natural Sciences Tripos",
            "type": "course",
            "nodes": {
                "117": {
                    "id": "117",
                    "name": "Biology of Cells",
                    "type": "subject",
                    "nodes": {
                        "106-31": {
                            "id": "106-31",
                            "name": "Part IA",
                            "type": "part",
                            "nodes": {
                                "487": {
                                    "id": "487",
                                    "name": "Practicals",
                                    "type": "module"
                                },
                                "488": {
                                    "id": "488",
                                    "name": "Lectures",
                                    "type": "module",
                                    "nodes": {
                                        "5875": {
                                            "id": "5875",
                                            "name": "Practicals - Monday Group",
                                            "type": "serie",
                                            "nodes": {
                                                "49794": {
                                                    "id": "49794",
                                                    "name": "PCR",
                                                    "type": "event",
                                                    "event-type": "practical",
                                                    "start": "2015-02-23T11:00:00+00:00",
                                                    "end": "2015-02-23T17:00:00+00:00"
                                                },
    ...

 * ```
 *
 * This currently works by spinning up an application container, but
 * will eventually be migrated to use the REST apis
 */

var argv = yargs
    .usage('Import an organizational unit tree.\nUsage: $0')
    .example('$0 --file tree.json --app 19', 'Import the structure in tree.json for application 19')
    .demand('f')
    .alias('f', 'file')
    .describe('f', 'The JSON file that contains the tree')
    .demand('a')
    .alias('a', 'app')
    .describe('a', 'The id of the application for which the tree should be imported')

    .argv;

// Initialize the app server
GrassHopper.init(config, function(err) {
    if (err) {
        log().error({'err': err}, 'Failed to spin up the application container');
        process.exit(1);
    }

    // Get a global administrator
    AdminsDAO.getGlobalAdminByUsername('administrator', function(err, globalAdmin) {
        if (err) {
            log().error({'err': err}, 'Failed to get the global administrator');
            process.exit(1);
        }

        // Get the app
        var ctx = new Context(null, globalAdmin);
        AppsAPI.getApp(ctx, argv.app, function(err, app) {
            if (err) {
                log().error({'err': err}, 'Failed to get the provided app');
                process.exit(1);
            }

            ctx = new Context(app, globalAdmin);

            log().debug({'file': argv.file}, 'Reading file');
            fs.readFile(argv.file, function(err, tree) {
                if (err) {
                    log().error({'err': err, 'file': argv.file}, 'Failed to read file');
                    process.exit(1);
                }

                // Parse the tree
                log().debug('Parsing tree');
                tree = JSON.parse(tree);

                // Persist it
                log().info('Starting to persist the organizational tree, this is going to take a while');
                var courses = _.values(tree.nodes);
                createNodes(ctx, courses, null, function() {

                    // All done, simply exit
                    log().info('The organizational tree has been succesfully imported');
                    process.exit(0);
                });
            });
        });
    });
});

/**
 * Recursively create the organizational units for a set of nodes.
 *
 * @param  {Node[]}             nodes               A set of nodes to create
 * @param  {OrgUnit|Serie}      [parent]            The parent under which the nodes should be created
 * @param  {Function}           callback            Standard callback function
 */
var createNodes = function(ctx, nodes, parent, callback) {
    if (_.isEmpty(nodes)) {
        return callback();
    }

    // Create the node
    var node = nodes.pop();
    createNode(ctx, node, parent, function(createdItem) {
        // Create the child nodes, if any
        var childNodes = _.values(node.nodes);
        createNodes(ctx, childNodes, createdItem, function() {

            // All child nodes have been created, proceed
            // to the next sibling node, if any
            return createNodes(ctx, nodes, parent, callback);
        });
    });
};

/**
 * Create an organizational unit
 *
 * @param  {Node}               node            The node to create
 * @param  {OrgUnit|Serie}      [parent]        The parent under which the node should be created
 * @param  {Function}           callback        Standard callback function
 */
var createNode = function(ctx, node, parent, callback) {
    if (node.type === 'course' || node.type === 'subject' || node.type === 'part' || node.type === 'module') {
        createOrgUnit(ctx, node, parent, callback);
    } else if (node.type === 'serie') {
        createSerie(ctx, node, parent, callback);
    } else if (node.type === 'event') {
        createEvent(ctx, node, parent, callback);
    }
};

/**
 * Create an organisational unit
 *
 * @param  {Context}    ctx             Standard context object containing the current user and the current application
 * @param  {Node}       node            The node to create
 * @param  {OrgUnit}    parent          The parent under which the organisational unit should be created
 * @param  {Function}   callback        Standard callback function
 */
var createOrgUnit = function(ctx, node, parent, callback) {
    var parentId = null;
    if (parent) {
        parentId = parent.id;
    }

    // Re-use the group id of the part if we're creating a module
    var groupId = null;
    if (node.type === 'module') {
        groupId = parent.GroupId;
    }
    OrgUnitAPI.createOrgUnit(ctx, argv.app, node.name.substring(0, 255), node.type, null, groupId, parentId, function(err, orgunit) {
        if (err) {
            console.log(err);
            console.log("DisplayName: '%s'", node.name);
            console.log("type: '%s'", node.type);
            log().error({'err': err}, 'Failed to create orgunit');
            process.exit(1);
        }

        return callback(orgunit);
    });
};

/**
 * Create a serie
 *
 * @param  {Context}    ctx             Standard context object containing the current user and the current application
 * @param  {Node}       node            The node to create
 * @param  {OrgUnit     parent          The organisational unit under which the serie should be created
 * @param  {Function}   callback        Standard callback function
 */
var createSerie = function(ctx, node, parent, callback) {
    SeriesAPI.createSerie(ctx, argv.app, node.name.substring(0, 255), null, parent.GroupId, function(err, serie) {
        if (err) {
            console.log(err);
            console.log("DisplayName: '%s'", node.name);
            log().error({'err': err}, 'Failed to create serie');
            process.exit(1);
        }

        parent.addSeries(serie).complete(function(err) {
            if (err) {
                console.log(err);
                console.log("DisplayName: '%s'", node.name);
                log().error({'err': err}, 'Failed to add serie to orgunit');
                process.exit(1);
            }

            return callback(serie);
        });
    });
};

/**
 * Create an event
 *
 * @param  {Context}    ctx             Standard context object containing the current user and the current application
 * @param  {Node}       node            The node to create
 * @param  {Serie}      parent          The serie under which the event should be created
 * @param  {Function}   callback        Standard callback function
 */
var createEvent = function(ctx, node, parent, callback) {
    // TT's data isn't always correct
    var start = node.start;
    var end = node.end;
    if (start > end) {
        start = node.end;
        end = node.start;
        log().warn({'node': node}, 'Impossible start/end dates');
    }
    var opts = {
        'group': parent.GroupId,
        'series': [parent.id]
    };
    EventsAPI.createEvent(ctx, argv.app, node.name.substring(0, 255), start, end, opts, function(err, event) {
        if (err) {
            console.log(err);
            console.log("DisplayName: '%s'", node.name);
            log().error({'err': err}, 'Failed to create event');
            process.exit(1);
        }

        return callback(event);
    });
};
<|endoftext|>


<commit_before>/* This file is part of Indico.
 * Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

(function($) {
    'use strict';

    $.widget('indico.ajaxqbubble', {
        options: {
            qBubbleOptions: {
                position: {
                    effect: false
                },
                content: {
                    text: $('<span>', {'text': $T.gettext('Loading...')})
                }
            },
            url: null,
            method: 'GET',
            cache: false,
            success: null,
            onClose: null // callback to invoke after closing the qtip by submitting the inner form. the argument
                          // is null if closed manually, otherwise the JSON returned by the server.
        },

        _create: function() {
            var self = this;
            var qBubbleOptions = _.pick(self.options, 'qBubbleOptions').qBubbleOptions;
            var ajaxOptions = _.omit(self.options, 'qBubbleOptions');
            var returnData = null;

            self.element.qbubble($.extend(true, {}, qBubbleOptions, {
                events: {
                    show: function(evt, api) {
                        $.ajax($.extend(true, {}, ajaxOptions, {
                            complete: IndicoUI.Dialogs.Util.progress(),
                            error: handleAjaxError,
                            success: function(data, _, xhr) {
                                if ($.isFunction(ajaxOptions.success)) {
                                    ajaxOptions.success.call(self.element, data);
                                }

                                var loadedURL = xhr.getResponseHeader('X-Indico-URL');
                                if (loadedURL) {
                                    // in case of a redirect we need to update the url used to submit the ajaxified
                                    // form. otherwise url normalization might fail during the POST requests.
                                    // we also remove the _=\d+ cache buster since it's only relevant for the GET
                                    // request and added there automatically
                                    loadedURL = loadedURL.replace(/&_=\d+/, '').replace(/\?_=\d+$/, '').replace(/\?_=\d+&/, '?');
                                }

                                function updateContent(data) {
                                    if (data) {
                                        api.set('content.text', ajaxifyForm($(data.html).find('form').addBack('form')));
                                        if (data.js) {
                                            $('body').append(data.js);
                                        }
                                    }
                                }

                                function ajaxifyForm($form) {
                                    initForms($form);
                                    var killProgress;
                                    return $form.ajaxForm({
                                        url: $form.attr('action') || loadedURL,
                                        method: 'POST',
                                        error: handleAjaxError,
                                        beforeSubmit: function() {
                                            killProgress = IndicoUI.Dialogs.Util.progress();
                                        },
                                        complete: function() {
                                            killProgress();
                                        },
                                        success: function(data) {
                                            if (data.success) {
                                                self.element.next('.label').text(data.new_value);
                                                returnData = data;
                                                api.hide(true);
                                            } else {
                                                updateContent(data);
                                                showFormErrors($('#qtip-' + api.id + '-content'));
                                            }
                                        }
                                    });
                                }

                                updateContent(data);
                            }
                        }));
                    },
                    hide: function(evt) {
                        var originalEvent = evt.originalEvent;

                        self.options.onClose(returnData);
                        returnData = null;

                        // in order not to hide the qBubble when selecting a date
                        if ((originalEvent && $(originalEvent.target).closest('#ui-datepicker-div').length)) {
                            return false;
                        }

                        return true;
                    },
                    hidden: function(evt, api) {
                        api.get('content.text').remove();
                    }
                }
            }));
        }
    });
})(jQuery);
<commit_msg>Don't try to call undefined ajaxqbubble onClose<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

(function($) {
    'use strict';

    $.widget('indico.ajaxqbubble', {
        options: {
            qBubbleOptions: {
                position: {
                    effect: false
                },
                content: {
                    text: $('<span>', {'text': $T.gettext('Loading...')})
                }
            },
            url: null,
            method: 'GET',
            cache: false,
            success: null,
            onClose: null // callback to invoke after closing the qtip by submitting the inner form. the argument
                          // is null if closed manually, otherwise the JSON returned by the server.
        },

        _create: function() {
            var self = this;
            var qBubbleOptions = _.pick(self.options, 'qBubbleOptions').qBubbleOptions;
            var ajaxOptions = _.omit(self.options, 'qBubbleOptions');
            var returnData = null;

            self.element.qbubble($.extend(true, {}, qBubbleOptions, {
                events: {
                    show: function(evt, api) {
                        $.ajax($.extend(true, {}, ajaxOptions, {
                            complete: IndicoUI.Dialogs.Util.progress(),
                            error: handleAjaxError,
                            success: function(data, _, xhr) {
                                if ($.isFunction(ajaxOptions.success)) {
                                    ajaxOptions.success.call(self.element, data);
                                }

                                var loadedURL = xhr.getResponseHeader('X-Indico-URL');
                                if (loadedURL) {
                                    // in case of a redirect we need to update the url used to submit the ajaxified
                                    // form. otherwise url normalization might fail during the POST requests.
                                    // we also remove the _=\d+ cache buster since it's only relevant for the GET
                                    // request and added there automatically
                                    loadedURL = loadedURL.replace(/&_=\d+/, '').replace(/\?_=\d+$/, '').replace(/\?_=\d+&/, '?');
                                }

                                function updateContent(data) {
                                    if (data) {
                                        api.set('content.text', ajaxifyForm($(data.html).find('form').addBack('form')));
                                        if (data.js) {
                                            $('body').append(data.js);
                                        }
                                    }
                                }

                                function ajaxifyForm($form) {
                                    initForms($form);
                                    var killProgress;
                                    return $form.ajaxForm({
                                        url: $form.attr('action') || loadedURL,
                                        method: 'POST',
                                        error: handleAjaxError,
                                        beforeSubmit: function() {
                                            killProgress = IndicoUI.Dialogs.Util.progress();
                                        },
                                        complete: function() {
                                            killProgress();
                                        },
                                        success: function(data) {
                                            if (data.success) {
                                                self.element.next('.label').text(data.new_value);
                                                returnData = data;
                                                api.hide(true);
                                            } else {
                                                updateContent(data);
                                                showFormErrors($('#qtip-' + api.id + '-content'));
                                            }
                                        }
                                    });
                                }

                                updateContent(data);
                            }
                        }));
                    },
                    hide: function(evt) {
                        var originalEvent = evt.originalEvent;

                        if (self.options.onClose) {
                            self.options.onClose(returnData);
                        }
                        returnData = null;

                        // in order not to hide the qBubble when selecting a date
                        if ((originalEvent && $(originalEvent.target).closest('#ui-datepicker-div').length)) {
                            return false;
                        }

                        return true;
                    },
                    hidden: function(evt, api) {
                        api.get('content.text').remove();
                    }
                }
            }));
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>/* This file is part of Indico.
 * Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

(function(global) {
    'use strict';

    $(document).ready(function() {
        setupActionLinks();
        setupConfirmPopup();
        setupSelectAllNone();
    });

    function setupSelectAllNone() {
        $('body').on('click', '[data-select-all]', function() {
            var selector = $(this).data('select-all');
            $(selector).filter(':not(:checked)').prop('checked', true).trigger('change');
        });

        $('body').on('click', '[data-select-none]', function() {
            var selector = $(this).data('select-none');
            $(selector).filter(':checked').prop('checked', false).trigger('change');
        });
    }

    function setupConfirmPopup() {
        $('body').on('click', '[data-confirm]:not(button[data-href]):not(input:button[data-href]):not(a[data-method][data-href])', function() {
            var $this = $(this);
            confirmPrompt($(this).data('confirm'), $(this).data('title')).then(function() {
                if ($this.is('form')) {
                    $this.submit();
                } else {
                    window.location = $this.attr('href');
                }
            });
            return false;
        });
    }

    function setupActionLinks() {
        $('body').on('click', 'button[data-method][data-href], input:button[data-method][data-href], a[data-method][data-href]', function(e) {
            e.preventDefault();
            var $this = $(this);
            var url = $this.data('href');
            var method = $this.data('method').toUpperCase();
            var params = $this.data('params') || {};
            var paramsSelector = $this.data('params-selector');
            var update = $this.data('update');
            var dialog = $this.data('ajax-dialog') !== undefined;
            if (!$.isPlainObject(params)) {
                throw new Error('Invalid params. Must be valid JSON if set.');
            }

            if (paramsSelector) {
                var fieldParams = {};
                $(paramsSelector).each(function() {
                    if (!(this.name in fieldParams)) {
                        fieldParams[this.name] = [];
                    }
                    fieldParams[this.name].push($(this).val());
                });
                params = $.extend({}, fieldParams, params);
            }

            function execute() {
                var evt = $.Event('indico:confirmed');
                $this.trigger(evt);

                // Handle custom code
                if (evt.isDefaultPrevented()) {
                    return;
                }

                // Handle AJAX dialog
                if (dialog) {
                    ajaxDialog({
                        trigger: $this,
                        url: url,
                        title: $this.data('title'),
                        onClose: function(data) {
                            handleFlashes(data, true, $this);
                            if (data && update) {
                                $(update).html(data.html);
                            }
                        }
                    });
                    return;
                }

                // Handle html update
                if (update) {
                    $.ajax({
                        method: method,
                        url: url,
                        data: params,
                        error: handleAjaxError,
                        complete: IndicoUI.Dialogs.Util.progress(),
                        success: function(data) {
                            handleFlashes(data, true, $this);
                            $(update).html(data.html);
                        }
                    });
                    return;
                }

                // Handle normal GET/POST
                if (method === 'GET') {
                    location.href = build_url(url, params);
                } else if (method === 'POST') {
                    var form = $('<form>', {
                        action: url,
                        method: method
                    });
                    form.append($('<input>', {type: 'hidden', name: 'csrf_token', value: $('#csrf-token').attr('content')}));
                    $.each(params, function(key, value) {
                        form.append($('<input>', {type: 'hidden', name: key, value: value}));
                    });
                    form.appendTo('body').submit();
                }
            }

            var promptMsg = $this.data('confirm');
            var confirmed;
            if (!promptMsg) {
                confirmed = $.Deferred().resolve();
            } else {
                confirmed = confirmPrompt(promptMsg, $(this).data('title') || $T('Confirm action'));
            }
            confirmed.then(execute);
        });
    }
})(window);
<commit_msg>Fix closing declarative ajax dialogs<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

(function(global) {
    'use strict';

    $(document).ready(function() {
        setupActionLinks();
        setupConfirmPopup();
        setupSelectAllNone();
    });

    function setupSelectAllNone() {
        $('body').on('click', '[data-select-all]', function() {
            var selector = $(this).data('select-all');
            $(selector).filter(':not(:checked)').prop('checked', true).trigger('change');
        });

        $('body').on('click', '[data-select-none]', function() {
            var selector = $(this).data('select-none');
            $(selector).filter(':checked').prop('checked', false).trigger('change');
        });
    }

    function setupConfirmPopup() {
        $('body').on('click', '[data-confirm]:not(button[data-href]):not(input:button[data-href]):not(a[data-method][data-href])', function() {
            var $this = $(this);
            confirmPrompt($(this).data('confirm'), $(this).data('title')).then(function() {
                if ($this.is('form')) {
                    $this.submit();
                } else {
                    window.location = $this.attr('href');
                }
            });
            return false;
        });
    }

    function setupActionLinks() {
        $('body').on('click', 'button[data-method][data-href], input:button[data-method][data-href], a[data-method][data-href]', function(e) {
            e.preventDefault();
            var $this = $(this);
            var url = $this.data('href');
            var method = $this.data('method').toUpperCase();
            var params = $this.data('params') || {};
            var paramsSelector = $this.data('params-selector');
            var update = $this.data('update');
            var dialog = $this.data('ajax-dialog') !== undefined;
            if (!$.isPlainObject(params)) {
                throw new Error('Invalid params. Must be valid JSON if set.');
            }

            if (paramsSelector) {
                var fieldParams = {};
                $(paramsSelector).each(function() {
                    if (!(this.name in fieldParams)) {
                        fieldParams[this.name] = [];
                    }
                    fieldParams[this.name].push($(this).val());
                });
                params = $.extend({}, fieldParams, params);
            }

            function execute() {
                var evt = $.Event('indico:confirmed');
                $this.trigger(evt);

                // Handle custom code
                if (evt.isDefaultPrevented()) {
                    return;
                }

                // Handle AJAX dialog
                if (dialog) {
                    ajaxDialog({
                        trigger: $this,
                        url: url,
                        title: $this.data('title'),
                        onClose: function(data) {
                            if (data) {
                                handleFlashes(data, true, $this);
                                if (update) {
                                    $(update).html(data.html);
                                }
                            }
                        }
                    });
                    return;
                }

                // Handle html update
                if (update) {
                    $.ajax({
                        method: method,
                        url: url,
                        data: params,
                        error: handleAjaxError,
                        complete: IndicoUI.Dialogs.Util.progress(),
                        success: function(data) {
                            handleFlashes(data, true, $this);
                            $(update).html(data.html);
                        }
                    });
                    return;
                }

                // Handle normal GET/POST
                if (method === 'GET') {
                    location.href = build_url(url, params);
                } else if (method === 'POST') {
                    var form = $('<form>', {
                        action: url,
                        method: method
                    });
                    form.append($('<input>', {type: 'hidden', name: 'csrf_token', value: $('#csrf-token').attr('content')}));
                    $.each(params, function(key, value) {
                        form.append($('<input>', {type: 'hidden', name: key, value: value}));
                    });
                    form.appendTo('body').submit();
                }
            }

            var promptMsg = $this.data('confirm');
            var confirmed;
            if (!promptMsg) {
                confirmed = $.Deferred().resolve();
            } else {
                confirmed = confirmPrompt(promptMsg, $(this).data('title') || $T('Confirm action'));
            }
            confirmed.then(execute);
        });
    }
})(window);
<|endoftext|>


<commit_before>/*jshint strict: false */

////////////////////////////////////////////////////////////////////////////////
/// @brief global configurations
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var db = require("org/arangodb").db;
var internal = require("internal");

// -----------------------------------------------------------------------------
// --SECTION--                               module "org/arangodb/configuration"
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief the configuration collection
////////////////////////////////////////////////////////////////////////////////

var configuration = db._collection("_configuration");

if (configuration === null) {
  configuration = db._create("_configuration", { isSystem: true, waitForSync: true });
}

// -----------------------------------------------------------------------------
// --SECTION--                                                  public variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief the notification configuration
////////////////////////////////////////////////////////////////////////////////

exports.notifications = {};

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the versions notification configuration
////////////////////////////////////////////////////////////////////////////////

exports.notifications.versions = function () {
  var n = "notifications";
  var v = "versions";
  var d;

  try {
    d = configuration.document(n);
  }
  catch (err) {
    try {
      d = configuration.save({ _key: n });
    }
    catch (err2) {
      d = {};
    }
  }

  d = d._shallowCopy;

  if (! d.hasOwnProperty(v)) {
    d.versions = {};
  }

  if (! internal.frontendVersionCheck) {
    d.enableVersionNotification = false;
  }

  return d.versions;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief sets the versions notification collections
////////////////////////////////////////////////////////////////////////////////

exports.notifications.setVersions = function (data) {
  var n = "notifications";
  var d;

  try {
    d = configuration.document(n);
  }
  catch (err) {
    d = configuration.save({ _key: n });
  }

  d = d._shallowCopy;
  d.versions = data;

  configuration.replace(n, d);
};

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<commit_msg>Create _configuration collection only at startup and no longer on the fly.<commit_after>/*jshint strict: false */

////////////////////////////////////////////////////////////////////////////////
/// @brief global configurations
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var db = require("org/arangodb").db;
var internal = require("internal");

// -----------------------------------------------------------------------------
// --SECTION--                               module "org/arangodb/configuration"
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief the configuration collection
////////////////////////////////////////////////////////////////////////////////

function getConfigurationCollection () {
  var configuration = db._collection("_configuration");

  if (configuration === null) {
    throw new Error("_configuration collection not (yet) available");
  }
  return configuration;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                  public variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief the notification configuration
////////////////////////////////////////////////////////////////////////////////

exports.notifications = {};

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief returns the versions notification configuration
////////////////////////////////////////////////////////////////////////////////

exports.notifications.versions = function () {
  var n = "notifications";
  var v = "versions";
  var d;
  var configuration = getConfigurationCollection();

  try {
    d = configuration.document(n);
  }
  catch (err) {
    try {
      d = configuration.save({ _key: n });
    }
    catch (err2) {
      d = {};
    }
  }

  d = d._shallowCopy;

  if (! d.hasOwnProperty(v)) {
    d.versions = {};
  }

  if (! internal.frontendVersionCheck) {
    d.enableVersionNotification = false;
  }

  return d.versions;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief sets the versions notification collections
////////////////////////////////////////////////////////////////////////////////

exports.notifications.setVersions = function (data) {
  var n = "notifications";
  var d;
  var configuration = getConfigurationCollection();

  try {
    d = configuration.document(n);
  }
  catch (err) {
    d = configuration.save({ _key: n });
  }

  d = d._shallowCopy;
  d.versions = data;

  configuration.replace(n, d);
};

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<|endoftext|>


<commit_before>/**
 * @module ol/events/condition
 */
import MapBrowserEventType from '../MapBrowserEventType.js';
import {FALSE, TRUE} from '../functions.js';
import {MAC, WEBKIT} from '../has.js';
import {assert} from '../asserts.js';

/**
 * A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
 * `{boolean}`. If the condition is met, true should be returned.
 *
 * @typedef {function(this: ?, import("../MapBrowserEvent.js").default): boolean} Condition
 */

/**
 * Creates a condition function that passes when all provided conditions pass.
 * @param {...Condition} var_args Conditions to check.
 * @return {Condition} Condition function.
 */
export function all(var_args) {
  const conditions = arguments;
  /**
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @return {boolean} All conditions passed.
   */
  return function (event) {
    let pass = true;
    for (let i = 0, ii = conditions.length; i < ii; ++i) {
      pass = pass && conditions[i](event);
      if (!pass) {
        break;
      }
    }
    return pass;
  };
}

/**
 * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when
 * additionally the shift-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the alt key is pressed.
 * @api
 */
export const altKeyOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    !originalEvent.shiftKey
  );
};

/**
 * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise
 * (e.g. when additionally the platform-modifier-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the alt and shift keys are pressed.
 * @api
 */
export const altShiftKeysOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    originalEvent.shiftKey
  );
};

/**
 * Return `true` if the map has the focus. This condition requires a map target
 * element with a `tabindex` attribute, e.g. `<div id="map" tabindex="1">`.
 *
 * @param {import("../MapBrowserEvent.js").default} event Map browser event.
 * @return {boolean} The map has the focus.
 * @api
 */
export const focus = function (event) {
  const targetElement = event.map.getTargetElement();
  const activeElement = event.map.getOwnerDocument().activeElement;
  return targetElement.contains(activeElement);
};

/**
 * Return `true` if the map has the focus or no 'tabindex' attribute set.
 *
 * @param {import("../MapBrowserEvent.js").default} event Map browser event.
 * @return {boolean} The map container has the focus or no 'tabindex' attribute.
 */
export const focusWithTabindex = function (event) {
  return event.map.getTargetElement().hasAttribute('tabindex')
    ? focus(event)
    : true;
};

/**
 * Return always true.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True.
 * @api
 */
export const always = TRUE;

/**
 * Return `true` if the event is a `click` event, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event is a map `click` event.
 * @api
 */
export const click = function (mapBrowserEvent) {
  return mapBrowserEvent.type == MapBrowserEventType.CLICK;
};

/**
 * Return `true` if the event has an "action"-producing mouse button.
 *
 * By definition, this includes left-click on windows/linux, and left-click
 * without the ctrl key on Macs.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} The result.
 */
export const mouseActionButton = function (mapBrowserEvent) {
  const originalEvent = /** @type {MouseEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return originalEvent.button == 0 && !(WEBKIT && MAC && originalEvent.ctrlKey);
};

/**
 * Return always false.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} False.
 * @api
 */
export const never = FALSE;

/**
 * Return `true` if the browser event is a `pointermove` event, `false`
 * otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the browser event is a `pointermove` event.
 * @api
 */
export const pointerMove = function (mapBrowserEvent) {
  return mapBrowserEvent.type == 'pointermove';
};

/**
 * Return `true` if the event is a map `singleclick` event, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event is a map `singleclick` event.
 * @api
 */
export const singleClick = function (mapBrowserEvent) {
  return mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK;
};

/**
 * Return `true` if the event is a map `dblclick` event, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event is a map `dblclick` event.
 * @api
 */
export const doubleClick = function (mapBrowserEvent) {
  return mapBrowserEvent.type == MapBrowserEventType.DBLCLICK;
};

/**
 * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is
 * pressed.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True only if there no modifier keys are pressed.
 * @api
 */
export const noModifierKeys = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    !originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    !originalEvent.shiftKey
  );
};

/**
 * Return `true` if only the platform-modifier-key (the meta-key on Mac,
 * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally
 * the shift-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the platform modifier key is pressed.
 * @api
 */
export const platformModifierKeyOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    !originalEvent.altKey &&
    (MAC ? originalEvent.metaKey : originalEvent.ctrlKey) &&
    !originalEvent.shiftKey
  );
};

/**
 * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when
 * additionally the alt-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the shift key is pressed.
 * @api
 */
export const shiftKeyOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    !originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    originalEvent.shiftKey
  );
};

/**
 * Return `true` if the target element is not editable, i.e. not a `<input>`-,
 * `<select>`-, `<textarea>`-element or `contentEditable` -attribut at true, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True only if the target element is not editable.
 * @api
 */
export const targetNotEditable = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  const tagName = /** @type {Element} */ (originalEvent.target).tagName;
  return (
    tagName !== 'INPUT' &&
    tagName !== 'SELECT' &&
    tagName !== 'TEXTAREA' &&
    // `isContentEditable` is only available on `HTMLElement`, but it may also be a
    // different type like `SVGElement`.
    // @ts-ignore
    !originalEvent.target.isContentEditable
  );
};

/**
 * Return `true` if the event originates from a mouse device.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a mouse device.
 * @api
 */
export const mouseOnly = function (mapBrowserEvent) {
  const pointerEvent = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvent !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
  return pointerEvent.pointerType == 'mouse';
};

/**
 * Return `true` if the event originates from a touchable device.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a touchable device.
 * @api
 */
export const touchOnly = function (mapBrowserEvent) {
  const pointerEvt = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvt !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
  return pointerEvt.pointerType === 'touch';
};

/**
 * Return `true` if the event originates from a digital pen.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a digital pen.
 * @api
 */
export const penOnly = function (mapBrowserEvent) {
  const pointerEvt = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvt !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
  return pointerEvt.pointerType === 'pen';
};

/**
 * Return `true` if the event originates from a primary pointer in
 * contact with the surface or if the left mouse button is pressed.
 * See https://www.w3.org/TR/pointerevents/#button-states.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a primary pointer.
 * @api
 */
export const primaryAction = function (mapBrowserEvent) {
  const pointerEvent = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvent !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  return pointerEvent.isPrimary && pointerEvent.button === 0;
};
<commit_msg>Update condition.js<commit_after>/**
 * @module ol/events/condition
 */
import MapBrowserEventType from '../MapBrowserEventType.js';
import {FALSE, TRUE} from '../functions.js';
import {MAC, WEBKIT} from '../has.js';
import {assert} from '../asserts.js';

/**
 * A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
 * `{boolean}`. If the condition is met, true should be returned.
 *
 * @typedef {function(this: ?, import("../MapBrowserEvent.js").default): boolean} Condition
 */

/**
 * Creates a condition function that passes when all provided conditions pass.
 * @param {...Condition} var_args Conditions to check.
 * @return {Condition} Condition function.
 */
export function all(var_args) {
  const conditions = arguments;
  /**
   * @param {import("../MapBrowserEvent.js").default} event Event.
   * @return {boolean} All conditions passed.
   */
  return function (event) {
    let pass = true;
    for (let i = 0, ii = conditions.length; i < ii; ++i) {
      pass = pass && conditions[i](event);
      if (!pass) {
        break;
      }
    }
    return pass;
  };
}

/**
 * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when
 * additionally the shift-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the alt key is pressed.
 * @api
 */
export const altKeyOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    !originalEvent.shiftKey
  );
};

/**
 * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise
 * (e.g. when additionally the platform-modifier-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the alt and shift keys are pressed.
 * @api
 */
export const altShiftKeysOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    originalEvent.shiftKey
  );
};

/**
 * Return `true` if the map has the focus. This condition requires a map target
 * element with a `tabindex` attribute, e.g. `<div id="map" tabindex="1">`.
 *
 * @param {import("../MapBrowserEvent.js").default} event Map browser event.
 * @return {boolean} The map has the focus.
 * @api
 */
export const focus = function (event) {
  const targetElement = event.map.getTargetElement();
  const activeElement = event.map.getOwnerDocument().activeElement;
  return targetElement.contains(activeElement);
};

/**
 * Return `true` if the map has the focus or no 'tabindex' attribute set.
 *
 * @param {import("../MapBrowserEvent.js").default} event Map browser event.
 * @return {boolean} The map container has the focus or no 'tabindex' attribute.
 */
export const focusWithTabindex = function (event) {
  return event.map.getTargetElement().hasAttribute('tabindex')
    ? focus(event)
    : true;
};

/**
 * Return always true.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True.
 * @api
 */
export const always = TRUE;

/**
 * Return `true` if the event is a `click` event, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event is a map `click` event.
 * @api
 */
export const click = function (mapBrowserEvent) {
  return mapBrowserEvent.type == MapBrowserEventType.CLICK;
};

/**
 * Return `true` if the event has an "action"-producing mouse button.
 *
 * By definition, this includes left-click on windows/linux, and left-click
 * without the ctrl key on Macs.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} The result.
 */
export const mouseActionButton = function (mapBrowserEvent) {
  const originalEvent = /** @type {MouseEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return originalEvent.button == 0 && !(WEBKIT && MAC && originalEvent.ctrlKey);
};

/**
 * Return always false.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} False.
 * @api
 */
export const never = FALSE;

/**
 * Return `true` if the browser event is a `pointermove` event, `false`
 * otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the browser event is a `pointermove` event.
 * @api
 */
export const pointerMove = function (mapBrowserEvent) {
  return mapBrowserEvent.type == 'pointermove';
};

/**
 * Return `true` if the event is a map `singleclick` event, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event is a map `singleclick` event.
 * @api
 */
export const singleClick = function (mapBrowserEvent) {
  return mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK;
};

/**
 * Return `true` if the event is a map `dblclick` event, `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event is a map `dblclick` event.
 * @api
 */
export const doubleClick = function (mapBrowserEvent) {
  return mapBrowserEvent.type == MapBrowserEventType.DBLCLICK;
};

/**
 * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is
 * pressed.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True only if there no modifier keys are pressed.
 * @api
 */
export const noModifierKeys = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    !originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    !originalEvent.shiftKey
  );
};

/**
 * Return `true` if only the platform-modifier-key (the meta-key on Mac,
 * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally
 * the shift-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the platform modifier key is pressed.
 * @api
 */
export const platformModifierKeyOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    !originalEvent.altKey &&
    (MAC ? originalEvent.metaKey : originalEvent.ctrlKey) &&
    !originalEvent.shiftKey
  );
};

/**
 * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when
 * additionally the alt-key is pressed).
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if only the shift key is pressed.
 * @api
 */
export const shiftKeyOnly = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  return (
    !originalEvent.altKey &&
    !(originalEvent.metaKey || originalEvent.ctrlKey) &&
    originalEvent.shiftKey
  );
};

/**
 * Return `true` if the target element is not editable, i.e. not an `<input>`,
 * `<select>`, or `<textarea>` element and no `contenteditable` attribut. `false` otherwise.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True only if the target element is not editable.
 * @api
 */
export const targetNotEditable = function (mapBrowserEvent) {
  const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ (
    mapBrowserEvent.originalEvent
  );
  const tagName = /** @type {Element} */ (originalEvent.target).tagName;
  return (
    tagName !== 'INPUT' &&
    tagName !== 'SELECT' &&
    tagName !== 'TEXTAREA' &&
    // `isContentEditable` is only available on `HTMLElement`, but it may also be a
    // different type like `SVGElement`.
    // @ts-ignore
    !originalEvent.target.isContentEditable
  );
};

/**
 * Return `true` if the event originates from a mouse device.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a mouse device.
 * @api
 */
export const mouseOnly = function (mapBrowserEvent) {
  const pointerEvent = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvent !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
  return pointerEvent.pointerType == 'mouse';
};

/**
 * Return `true` if the event originates from a touchable device.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a touchable device.
 * @api
 */
export const touchOnly = function (mapBrowserEvent) {
  const pointerEvt = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvt !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
  return pointerEvt.pointerType === 'touch';
};

/**
 * Return `true` if the event originates from a digital pen.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a digital pen.
 * @api
 */
export const penOnly = function (mapBrowserEvent) {
  const pointerEvt = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvt !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
  return pointerEvt.pointerType === 'pen';
};

/**
 * Return `true` if the event originates from a primary pointer in
 * contact with the surface or if the left mouse button is pressed.
 * See https://www.w3.org/TR/pointerevents/#button-states.
 *
 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
 * @return {boolean} True if the event originates from a primary pointer.
 * @api
 */
export const primaryAction = function (mapBrowserEvent) {
  const pointerEvent = /** @type {import("../MapBrowserEvent").default} */ (
    mapBrowserEvent
  ).originalEvent;
  assert(pointerEvent !== undefined, 56); // mapBrowserEvent must originate from a pointer event
  return pointerEvent.isPrimary && pointerEvent.button === 0;
};
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var del = require('del');
var rename = require("gulp-rename");
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');

// var vendors = './scss/vendors/';

/** Build all **/
gulp.task('build:vendors', function (callback) {
  runSequence(
    'vendors:cleanCSS', 'compile-vendors-admin:sass', 'node-vendors:copyCSS', 'node-vendors:minifyCSS',
    'vendors:cleanJS', 'node-vendors:copyJS', 'node-vendors:minifyJS',
    'node-vendors:copyTinyMCE', 'node-vendors:copyDatetimePicker',
    'vendors:copyFonts',
    'clean:temp',
    callback
  );
});

gulp.task('clean:temp', function () {
  return del(gulp.paths.temp);
});

gulp.task('clean:min-min', function () {
  return del(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors + '*.min.min.js');
});

/** CSS **/
var vendorsCSS = [
  'node_modules/codemirror/lib/codemirror.css',
  'node_modules/datatables.net-bs4/css/dataTables.bootstrap4.css',
  'node_modules/datatables.net-buttons-bs4/css/buttons.bootstrap4.css',
  'node_modules/font-awesome/css/font-awesome.css',
  'node_modules/ladda/dist/ladda-themeless.min.css',
  'node_modules/quill/dist/quill.snow.css',
  'node_modules/simple-line-icons/css/simple-line-icons.css',
  'node_modules/spinkit/css/spinkit.css',
  'node_modules/fancybox/dist/css/jquery.fancybox.css',
  'node_modules/select2/dist/css/select2.css',
  'node_modules/blueimp-file-upload/css/jquery.fileupload.css'
];

gulp.task('node-vendors:copyCSS', function () {
  return gulp.src(vendorsCSS)
    .pipe(gulp.dest(gulp.paths.temp + gulp.paths.css + gulp.paths.vendors));
});

gulp.task('node-vendors:minifyCSS', function () {
  return gulp.src([
    gulp.paths.temp + gulp.paths.css + gulp.paths.vendors + '*.css',
    '!' + gulp.paths.temp + gulp.paths.css + gulp.paths.vendors + '*.min.css'
  ])
    .pipe(cssmin())
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors));
});

gulp.task('vendors:cleanCSS', function () {
  return del(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors);
});

gulp.task('compile-vendors-admin:sass', function () {
  return gulp.src('./assets/scss/admin/vendors/**/*.scss')
    .pipe(sass().on('error', sass.logError))
    .pipe(autoprefixer())
    .pipe(rename({ dirname: '' }))
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors))
    .pipe(cssmin())
    .pipe(rename({ suffix: '.min' }))
    .pipe(rename({ dirname: '' }))
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors));
});

/** JavaScript **/
var vendorsJS = [
  'node_modules/bootstrap/dist/js/bootstrap.min.js',
  //'node_modules/bootstrap-daterangepicker/daterangepicker.js',
  'node_modules/chart.js/dist/Chart.min.js',
  'node_modules/codemirror/lib/codemirror.js',
  'node_modules/codemirror/mode/markdown/markdown.js',
  'node_modules/codemirror/mode/xml/xml.js',
  'node_modules/datatables.net/js/jquery.dataTables.js',
  'node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js',
  'node_modules/datatables.net-buttons-bs4/js/buttons.bootstrap4.js',
  'node_modules/fullcalendar/dist/fullcalendar.min.js',
  'node_modules/fullcalendar/dist/gcal.min.js',
  'node_modules/gaugeJS/dist/gauge.min.js',
  'node_modules/ion-rangeslider/js/ion.rangeSlider.min.js',
  'node_modules/jquery/dist/jquery.min.js',
  'node_modules/jquery/dist/jquery.min.map',
  'node_modules/jquery-ui-dist/jquery-ui.min.js',
  'node_modules/jquery-validation/dist/jquery.validate.min.js',
  'node_modules/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.js',
  'node_modules/jquery.maskedinput/src/jquery.maskedinput.js',
  'node_modules/ladda/dist/ladda.min.js',
  'node_modules/ladda/dist/spin.min.js',
  'node_modules/moment/min/moment.min.js',
  'node_modules/quill/dist/quill.min.js',
  'node_modules/quill/dist/quill.min.js.map',
  'node_modules/pace-progress/pace.min.js',
  'node_modules/popper.js/dist/umd/popper.min.js',
  'node_modules/popper.js/dist/umd/popper.min.js.map',
  'node_modules/select2/dist/js/select2.min.js',
  'node_modules/toastr/toastr.js',
  'node_modules/fancybox/dist/js/jquery.fancybox.js',
  'node_modules/jquery.cookie/jquery.cookie.js',
  'node_modules/select2/js/select2.js',
  'node_modules/blueimp-file-upload/js/vendor/jquery.ui.widget.js',
  'node_modules/blueimp-file-upload/js/jquery.fileupload.js'
];

gulp.task('node-vendors:copyJS', function () {
  return gulp.src(vendorsJS)
    .pipe(gulp.dest(gulp.paths.temp + gulp.paths.js + gulp.paths.vendors));
});

gulp.task('node-vendors:minifyJS', function () {
  return gulp.src([
    gulp.paths.temp + gulp.paths.js + gulp.paths.vendors + '*.js'
  ])
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors))
    .pipe(uglify())
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

gulp.task('vendors:cleanJS', function () {
  return del(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors);
});

/** Fonts **/
var fonts = [
  'node_modules/font-awesome/fonts/**',
  'node_modules/simple-line-icons/fonts/**',
  'assets/fonts/blog.*'
];

gulp.task('vendors:copyFonts', function () {
  return gulp.src(fonts)
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.fonts));
});

/** TinyMCE **/
gulp.task('node-vendors:copyTinyMCE', function () {
  gulp.src([
    'node_modules/tinymce/tinymce.min.js',
    'node_modules/tinymce/plugins/**',
    'node_modules/tinymce/themes/modern/theme.min.js',
    'node_modules/tinymce/skins/lightgray/skin.min.css',
    'node_modules/tinymce/skins/lightgray/content.min.css',
    'node_modules/tinymce/skins/lightgray/fonts/tinymce.woff',
    'node_modules/tinymce/skins/lightgray/fonts/tinymce.ttf'
  ], { base: './node_modules' })
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

/** Datetime picker **/
gulp.task('node-vendors:copyDatetimePicker', function () {
  gulp.src([
    'node_modules/pc-bootstrap4-datetimepicker/build/js/bootstrap-datetimepicker.min.js',
    'node_modules/pc-bootstrap4-datetimepicker/build/css/bootstrap-datetimepicker.min.css'
  ], { base: './node_modules' })
    .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

<commit_msg>Added map copy when building scripts<commit_after>'use strict';

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var del = require('del');
var rename = require("gulp-rename");
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');

// var vendors = './scss/vendors/';

/** Build all **/
gulp.task('build:vendors', function (callback) {
    runSequence(
        'vendors:cleanCSS', 'compile-vendors-admin:sass', 'node-vendors:copyCSS', 'node-vendors:minifyCSS',
        'vendors:cleanJS', 'node-vendors:copyJS', 'node-vendors:copyMAP', 'node-vendors:minifyJS',
        'node-vendors:copyTinyMCE', 'node-vendors:copyDatetimePicker',
        'vendors:copyFonts',
        'clean:temp',
        callback
    );
});

gulp.task('clean:temp', function () {
    return del(gulp.paths.temp);
});

gulp.task('clean:min-min', function () {
    return del(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors + '*.min.min.js');
});

/** CSS **/
var vendorsCSS = [
    'node_modules/codemirror/lib/codemirror.css',
    'node_modules/datatables.net-bs4/css/dataTables.bootstrap4.css',
    'node_modules/datatables.net-buttons-bs4/css/buttons.bootstrap4.css',
    'node_modules/font-awesome/css/font-awesome.css',
    'node_modules/ladda/dist/ladda-themeless.min.css',
    'node_modules/quill/dist/quill.snow.css',
    'node_modules/simple-line-icons/css/simple-line-icons.css',
    'node_modules/spinkit/css/spinkit.css',
    'node_modules/fancybox/dist/css/jquery.fancybox.css',
    'node_modules/select2/dist/css/select2.css',
    'node_modules/blueimp-file-upload/css/jquery.fileupload.css'
];

gulp.task('node-vendors:copyCSS', function () {
    return gulp.src(vendorsCSS)
        .pipe(gulp.dest(gulp.paths.temp + gulp.paths.css + gulp.paths.vendors));
});

gulp.task('node-vendors:minifyCSS', function () {
    return gulp.src([
        gulp.paths.temp + gulp.paths.css + gulp.paths.vendors + '*.css',
        '!' + gulp.paths.temp + gulp.paths.css + gulp.paths.vendors + '*.min.css'
    ])
        .pipe(cssmin())
        .pipe(rename({ suffix: '.min' }))
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors));
});

gulp.task('vendors:cleanCSS', function () {
    return del(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors);
});

gulp.task('compile-vendors-admin:sass', function () {
    return gulp.src('./assets/scss/admin/vendors/**/*.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(autoprefixer())
        .pipe(rename({ dirname: '' }))
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors))
        .pipe(cssmin())
        .pipe(rename({ suffix: '.min' }))
        .pipe(rename({ dirname: '' }))
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.vendors));
});

/** JavaScript **/
var vendorsJS = [
    'node_modules/bootstrap/dist/js/bootstrap.min.js',
    'node_modules/bootstrap/dist/js/bootstrap.min.js.map',
    //'node_modules/bootstrap-daterangepicker/daterangepicker.js',
    'node_modules/chart.js/dist/Chart.min.js',
    'node_modules/codemirror/lib/codemirror.js',
    'node_modules/codemirror/mode/markdown/markdown.js',
    'node_modules/codemirror/mode/xml/xml.js',
    'node_modules/datatables.net/js/jquery.dataTables.js',
    'node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js',
    'node_modules/datatables.net-buttons-bs4/js/buttons.bootstrap4.js',
    'node_modules/fullcalendar/dist/fullcalendar.min.js',
    'node_modules/fullcalendar/dist/gcal.min.js',
    'node_modules/gaugeJS/dist/gauge.min.js',
    'node_modules/ion-rangeslider/js/ion.rangeSlider.min.js',
    'node_modules/jquery/dist/jquery.min.js',
    'node_modules/jquery/dist/jquery.min.map',
    'node_modules/jquery-ui-dist/jquery-ui.min.js',
    'node_modules/jquery-validation/dist/jquery.validate.min.js',
    'node_modules/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.js',
    'node_modules/jquery.maskedinput/src/jquery.maskedinput.js',
    'node_modules/ladda/dist/ladda.min.js',
    'node_modules/ladda/dist/spin.min.js',
    'node_modules/moment/min/moment.min.js',
    'node_modules/quill/dist/quill.min.js',
    'node_modules/quill/dist/quill.min.js.map',
    'node_modules/pace-progress/pace.min.js',
    'node_modules/popper.js/dist/umd/popper.min.js',
    'node_modules/popper.js/dist/umd/popper.min.js.map',
    'node_modules/select2/dist/js/select2.min.js',
    'node_modules/toastr/toastr.js',
    'node_modules/fancybox/dist/js/jquery.fancybox.js',
    'node_modules/jquery.cookie/jquery.cookie.js',
    'node_modules/select2/js/select2.js',
    'node_modules/blueimp-file-upload/js/vendor/jquery.ui.widget.js',
    'node_modules/blueimp-file-upload/js/jquery.fileupload.js'
];

gulp.task('node-vendors:copyJS', function () {
    return gulp.src(vendorsJS)
        .pipe(gulp.dest(gulp.paths.temp + gulp.paths.js + gulp.paths.vendors));
});

gulp.task('node-vendors:copyMAP', function () {
    return gulp.src([
        gulp.paths.temp + gulp.paths.js + gulp.paths.vendors + '*.map'
    ])
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

gulp.task('node-vendors:minifyJS', function () {
    return gulp.src([
        gulp.paths.temp + gulp.paths.js + gulp.paths.vendors + '*.js'
    ])
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors))
        .pipe(uglify())
        .pipe(rename({ suffix: '.min' }))
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

gulp.task('vendors:cleanJS', function () {
    return del(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors);
});

/** Fonts **/
var fonts = [
    'node_modules/font-awesome/fonts/**',
    'node_modules/simple-line-icons/fonts/**',
    'assets/fonts/blog.*'
];

gulp.task('vendors:copyFonts', function () {
    return gulp.src(fonts)
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.css + gulp.paths.fonts));
});

/** TinyMCE **/
gulp.task('node-vendors:copyTinyMCE', function () {
    gulp.src([
        'node_modules/tinymce/tinymce.min.js',
        'node_modules/tinymce/plugins/**',
        'node_modules/tinymce/themes/modern/theme.min.js',
        'node_modules/tinymce/skins/lightgray/skin.min.css',
        'node_modules/tinymce/skins/lightgray/content.min.css',
        'node_modules/tinymce/skins/lightgray/fonts/tinymce.woff',
        'node_modules/tinymce/skins/lightgray/fonts/tinymce.ttf'
    ], { base: './node_modules' })
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

/** Datetime picker **/
gulp.task('node-vendors:copyDatetimePicker', function () {
    gulp.src([
        'node_modules/pc-bootstrap4-datetimepicker/build/js/bootstrap-datetimepicker.min.js',
        'node_modules/pc-bootstrap4-datetimepicker/build/css/bootstrap-datetimepicker.min.css'
    ], { base: './node_modules' })
        .pipe(gulp.dest(gulp.paths.webroot + gulp.paths.js + gulp.paths.vendors));
});

<|endoftext|>


<commit_before>var LATIN_MAP = {
    'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
    'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
    'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
    'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U',
    'Ý': 'Y', 'Þ': 'TH', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä':
    'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',
    'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó':
    'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u',
    'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
}
var LATIN_SYMBOLS_MAP = {
    '©':'(c)'
}
var GREEK_MAP = {
    'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8',
    'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p',
    'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w',
    'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s',
    'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i',
    'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8',
    'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P',
    'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W',
    'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I',
    'Ϋ':'Y'
}
var TURKISH_MAP = {
    'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U',
    'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G'
}
var RUSSIAN_MAP = {
    'а':'a', 'б':'b', 'в':'v', 'г':'g', 'д':'d', 'е':'e', 'ё':'yo', 'ж':'zh',
    'з':'z', 'и':'i', 'й':'j', 'к':'k', 'л':'l', 'м':'m', 'н':'n', 'о':'o',
    'п':'p', 'р':'r', 'с':'s', 'т':'t', 'у':'u', 'ф':'f', 'х':'h', 'ц':'c',
    'ч':'ch', 'ш':'sh', 'щ':'sh', 'ъ':'', 'ы':'y', 'ь':'', 'э':'e', 'ю':'yu',
    'я':'ya',
    'А':'A', 'Б':'B', 'В':'V', 'Г':'G', 'Д':'D', 'Е':'E', 'Ё':'Yo', 'Ж':'Zh',
    'З':'Z', 'И':'I', 'Й':'J', 'К':'K', 'Л':'L', 'М':'M', 'Н':'N', 'О':'O',
    'П':'P', 'Р':'R', 'С':'S', 'Т':'T', 'У':'U', 'Ф':'F', 'Х':'H', 'Ц':'C',
    'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu',
    'Я':'Ya'
}

var ALL_DOWNCODE_MAPS=new Array()
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP

var Downcoder = new Object();
Downcoder.Initialize = function()
{
    if (Downcoder.map) // already made
        return ;
    Downcoder.map ={}
    Downcoder.chars = '' ;
    for(var i in ALL_DOWNCODE_MAPS)
    {
        var lookup = ALL_DOWNCODE_MAPS[i]
        for (var c in lookup)
        {
            Downcoder.map[c] = lookup[c] ;
            Downcoder.chars += c ;
        }
     }
    Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ;
}

downcode= function( slug )
{
    Downcoder.Initialize() ;
    var downcoded =""
    var pieces = slug.match(Downcoder.regex);
    if(pieces)
    {
        for (var i = 0 ; i < pieces.length ; i++)
        {
            if (pieces[i].length == 1)
            {
                var mapped = Downcoder.map[pieces[i]] ;
                if (mapped != null)
                {
                    downcoded+=mapped;
                    continue ;
                }
            }
            downcoded+=pieces[i];
        }
    }
    else
    {
        downcoded = slug;
    }
    return downcoded;
}

function URLify(s, num_chars) {
    // changes, e.g., "Petty theft" to "petty_theft"
    // remove all these words from the string before urlifying
    s = downcode(s);
    removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
                  "is", "in", "into", "like", "of", "off", "on", "onto", "per",
                  "since", "than", "the", "this", "that", "to", "up", "via",
                  "with"];
    r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
    s = s.replace(r, '');
    // if downcode doesn't hit, the char will be stripped here
    s = s.replace(/[^-\w\s]/g, '');  // remove unneeded chars
    s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
    s = s.replace(/[-\s]+/g, '-');   // convert spaces to hyphens
    s = s.toLowerCase();             // convert to lowercase
    return s.substring(0, num_chars);// trim to first num_chars chars
}

<commit_msg>urlify from django trunk<commit_after>var LATIN_MAP = {
    'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
    'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
    'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
    'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U',
    'Ý': 'Y', 'Þ': 'TH', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä':
    'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',
    'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó':
    'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u',
    'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
}
var LATIN_SYMBOLS_MAP = {
    '©':'(c)'
}
var GREEK_MAP = {
    'α':'a', 'β':'b', 'γ':'g', 'δ':'d', 'ε':'e', 'ζ':'z', 'η':'h', 'θ':'8',
    'ι':'i', 'κ':'k', 'λ':'l', 'μ':'m', 'ν':'n', 'ξ':'3', 'ο':'o', 'π':'p',
    'ρ':'r', 'σ':'s', 'τ':'t', 'υ':'y', 'φ':'f', 'χ':'x', 'ψ':'ps', 'ω':'w',
    'ά':'a', 'έ':'e', 'ί':'i', 'ό':'o', 'ύ':'y', 'ή':'h', 'ώ':'w', 'ς':'s',
    'ϊ':'i', 'ΰ':'y', 'ϋ':'y', 'ΐ':'i',
    'Α':'A', 'Β':'B', 'Γ':'G', 'Δ':'D', 'Ε':'E', 'Ζ':'Z', 'Η':'H', 'Θ':'8',
    'Ι':'I', 'Κ':'K', 'Λ':'L', 'Μ':'M', 'Ν':'N', 'Ξ':'3', 'Ο':'O', 'Π':'P',
    'Ρ':'R', 'Σ':'S', 'Τ':'T', 'Υ':'Y', 'Φ':'F', 'Χ':'X', 'Ψ':'PS', 'Ω':'W',
    'Ά':'A', 'Έ':'E', 'Ί':'I', 'Ό':'O', 'Ύ':'Y', 'Ή':'H', 'Ώ':'W', 'Ϊ':'I',
    'Ϋ':'Y'
}
var TURKISH_MAP = {
    'ş':'s', 'Ş':'S', 'ı':'i', 'İ':'I', 'ç':'c', 'Ç':'C', 'ü':'u', 'Ü':'U',
    'ö':'o', 'Ö':'O', 'ğ':'g', 'Ğ':'G'
}
var RUSSIAN_MAP = {
    'а':'a', 'б':'b', 'в':'v', 'г':'g', 'д':'d', 'е':'e', 'ё':'yo', 'ж':'zh',
    'з':'z', 'и':'i', 'й':'j', 'к':'k', 'л':'l', 'м':'m', 'н':'n', 'о':'o',
    'п':'p', 'р':'r', 'с':'s', 'т':'t', 'у':'u', 'ф':'f', 'х':'h', 'ц':'c',
    'ч':'ch', 'ш':'sh', 'щ':'sh', 'ъ':'', 'ы':'y', 'ь':'', 'э':'e', 'ю':'yu',
    'я':'ya',
    'А':'A', 'Б':'B', 'В':'V', 'Г':'G', 'Д':'D', 'Е':'E', 'Ё':'Yo', 'Ж':'Zh',
    'З':'Z', 'И':'I', 'Й':'J', 'К':'K', 'Л':'L', 'М':'M', 'Н':'N', 'О':'O',
    'П':'P', 'Р':'R', 'С':'S', 'Т':'T', 'У':'U', 'Ф':'F', 'Х':'H', 'Ц':'C',
    'Ч':'Ch', 'Ш':'Sh', 'Щ':'Sh', 'Ъ':'', 'Ы':'Y', 'Ь':'', 'Э':'E', 'Ю':'Yu',
    'Я':'Ya'
}
var CZECH_MAP = {
    'č':'c', 'ď':'d', 'ě':'e', 'ň': 'n', 'ř':'r', 'š':'s', 'ť':'t', 'ů':'u',
    'ž':'z'
}

var ALL_DOWNCODE_MAPS=new Array()
ALL_DOWNCODE_MAPS[0]=LATIN_MAP
ALL_DOWNCODE_MAPS[1]=LATIN_SYMBOLS_MAP
ALL_DOWNCODE_MAPS[2]=GREEK_MAP
ALL_DOWNCODE_MAPS[3]=TURKISH_MAP
ALL_DOWNCODE_MAPS[4]=RUSSIAN_MAP
ALL_DOWNCODE_MAPS[5]=CZECH_MAP

var Downcoder = new Object();
Downcoder.Initialize = function()
{
    if (Downcoder.map) // already made
        return ;
    Downcoder.map ={}
    Downcoder.chars = '' ;
    for(var i in ALL_DOWNCODE_MAPS)
    {
        var lookup = ALL_DOWNCODE_MAPS[i]
        for (var c in lookup)
        {
            Downcoder.map[c] = lookup[c] ;
            Downcoder.chars += c ;
        }
     }
    Downcoder.regex = new RegExp('[' + Downcoder.chars + ']|[^' + Downcoder.chars + ']+','g') ;
}

downcode= function( slug )
{
    Downcoder.Initialize() ;
    var downcoded =""
    var pieces = slug.match(Downcoder.regex);
    if(pieces)
    {
        for (var i = 0 ; i < pieces.length ; i++)
        {
            if (pieces[i].length == 1)
            {
                var mapped = Downcoder.map[pieces[i]] ;
                if (mapped != null)
                {
                    downcoded+=mapped;
                    continue ;
                }
            }
            downcoded+=pieces[i];
        }
    }
    else
    {
        downcoded = slug;
    }
    return downcoded;
}

function URLify(s, num_chars) {
    // changes, e.g., "Petty theft" to "petty_theft"
    // remove all these words from the string before urlifying
    s = downcode(s);
    removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
                  "is", "in", "into", "like", "of", "off", "on", "onto", "per",
                  "since", "than", "the", "this", "that", "to", "up", "via",
                  "with"];
    r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
    s = s.replace(r, '');
    // if downcode doesn't hit, the char will be stripped here
    s = s.replace(/[^-\w\s]/g, '');  // remove unneeded chars
    s = s.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces
    s = s.replace(/[-\s]+/g, '-');   // convert spaces to hyphens
    s = s.toLowerCase();             // convert to lowercase
    return s.substring(0, num_chars);// trim to first num_chars chars
}

<|endoftext|>