<commit_before>/**
 * Attach Request event
 * @module tracker/events/attach-request
 */
const debug = require('debug')('bhit:tracker');
const moment = require('moment-timezone');
const WError = require('verror').WError;

/**
 * Attach Request event class
 */
class AttachRequest {
    /**
     * Create service
     * @param {App} app                                 The application
     * @param {object} config                           Configuration
     * @param {Logger} logger                           Logger service
     * @param {UserRepository} userRepo                 User repository
     * @param {DaemonRepository} daemonRepo             Daemon repository
     * @param {PathRepository} pathRepo                 Path repository
     * @param {ConnectionRepository} connectionRepo     Connection repository
     */
    constructor(app, config, logger, userRepo, daemonRepo, pathRepo, connectionRepo) {
        this._app = app;
        this._config = config;
        this._logger = logger;
        this._userRepo = userRepo;
        this._daemonRepo = daemonRepo;
        this._pathRepo = pathRepo;
        this._connectionRepo = connectionRepo;
    }

    /**
     * Service name is 'modules.tracker.events.attachRequest'
     * @type {string}
     */
    static get provides() {
        return 'modules.tracker.events.attachRequest';
    }

    /**
     * Dependencies as constructor arguments
     * @type {string[]}
     */
    static get requires() {
        return [
            'app',
            'config',
            'logger',
            'repositories.user',
            'repositories.daemon',
            'repositories.path',
            'repositories.connection'
        ];
    }

    /**
     * Event handler
     * @param {string} id           ID of the client
     * @param {object} message      The message
     */
    handle(id, message) {
        let client = this.tracker.clients.get(id);
        if (!client)
            return;

        debug(`Got ATTACH REQUEST from ${client.socket.remoteAddress}:${client.socket.remotePort}`);
        return Promise.resolve()
            .then(() => {
                if (!client.daemonId)
                    return [];

                return this._daemonRepo.find(client.daemonId);
            })
            .then(daemons => {
                let daemon = daemons.length && daemons[0];
                if (!daemon)
                    return null;
                if (!message.attachRequest.daemonName)
                    return daemon;

                return this._daemonRepo.findByUserAndName(daemon.userId, message.attachRequest.daemonName)
                    .then(daemons => {
                        return daemons.length && daemons[0];
                    });
            })
            .then(daemon => {
                if (!daemon) {
                    let response = this.tracker.AttachResponse.create({
                        response: this.tracker.AttachResponse.Result.REJECTED,
                    });
                    let reply = this.tracker.ServerMessage.create({
                        type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                        messageId: message.messageId,
                        attachResponse: response,
                    });
                    let data = this.tracker.ServerMessage.encode(reply).finish();
                    debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                    return this.tracker.send(id, data);
                }

                return Promise.all([
                        this._pathRepo.findByToken(message.attachRequest.token),
                        this._connectionRepo.findByToken(message.attachRequest.token)
                    ])
                    .then(([ paths, connections ]) => {
                        let path = paths.length && paths[0];
                        let connection = connections.length && connections[0];
                        let userId;

                        let actingAs;
                        if (path) {
                            actingAs = 'client';
                            userId = path.userId;
                        } else if (connection) {
                            actingAs = 'server';
                            userId = connection.userId;
                        } else {
                            let response = this.tracker.AttachResponse.create({
                                response: this.tracker.AttachResponse.Result.REJECTED,
                            });
                            let reply = this.tracker.ServerMessage.create({
                                type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                                messageId: message.messageId,
                                attachResponse: response,
                            });
                            let data = this.tracker.ServerMessage.encode(reply).finish();
                            debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                            return this.tracker.send(id, data);
                        }

                        let loadConnection = (path, fullPath) => {
                            return this._connectionRepo.findByPath(path)
                                .then(connections => {
                                    let connection = connections.length && connections[0];
                                    if (connection && path.path == fullPath)
                                        return [ connection, path ];

                                    return this._pathRepo.findByParent(path)
                                        .then(paths => {
                                            let promises = [];
                                            for (let subPath of paths)
                                                promises.push(loadConnection(subPath, fullPath));

                                            return Promise.all(promises)
                                                .then(loaded => {
                                                    for (let subResult of loaded) {
                                                        if (subResult)
                                                            return subResult;
                                                    }

                                                    return null;
                                                });
                                        })
                                });
                        };

                        return Promise.resolve()
                            .then(() => {
                                if (actingAs == 'server') {
                                    return this._pathRepo.find(connection.pathId)
                                        .then(paths => {
                                            let path = paths.length && paths[0];
                                            if (path && path.path == message.attachRequest.path)
                                                return [ connection, path ];

                                            return null;
                                        });
                                }

                                return loadConnection(path, message.attachRequest.path);
                            })
                            .then(result => {
                                if (!result) {
                                    let response = this.tracker.AttachResponse.create({
                                        response: this.tracker.AttachResponse.Result.REJECTED,
                                    });
                                    let reply = this.tracker.ServerMessage.create({
                                        type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                                        messageId: message.messageId,
                                        attachResponse: response,
                                    });
                                    let data = this.tracker.ServerMessage.encode(reply).finish();
                                    debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                                    return this.tracker.send(id, data);
                                }

                                let connection = result && result[0];
                                let path = result && result[1];

                                return this._daemonRepo.connect(daemon, connection, actingAs)
                                    .then(count => {
                                        let serverConnections = [], clientConnections = [];

                                        return Promise.resolve()
                                            .then(() => {
                                                if (count === 0)
                                                    return this.tracker.AttachResponse.Result.ALREADY_CONNECTED;

                                                if (message.attachRequest.daemonName)
                                                    return this.tracker.AttachResponse.Result.ACCEPTED;

                                                return this._userRepo.find(userId)
                                                    .then(users => {
                                                        let user = users.length && users[0];
                                                        if (!user)
                                                            return this.tracker.AttachResponse.Result.ACCEPTED;

                                                        if (actingAs == 'server') {
                                                            return this._daemonRepo.findByConnection(connection)
                                                                .then(clientDaemons => {
                                                                    let clients = [];
                                                                    let clientPromises = [];
                                                                    for (let clientDaemon of clientDaemons) {
                                                                        if (clientDaemon.actingAs != 'client')
                                                                            continue;

                                                                        clientPromises.push(
                                                                            this._userRepo.find(clientDaemon.userId)
                                                                                .then(clientUsers => {
                                                                                let clientUser = clientUsers.length && clientUsers[0];
                                                                                if (!clientUser)
                                                                                return;

                                                                                clients.push(clientUser.email + '?' + clientDaemon.name);
                                                                                })
                                                                        );
                                                                    }

                                                                    return Promise.all(clientPromises)
                                                                        .then(() => {
                                                                            serverConnections.push(this.tracker.ServerConnection.create({
                                                                                name: user.email + path.path,
                                                                                connectAddress: connection.connectAddress,
                                                                                connectPort: connection.connectPort,
                                                                                encrypted: connection.encrypted,
                                                                                fixed: connection.fixed,
                                                                                clients: clients,
                                                                            }));

                                                                            return this.tracker.AttachResponse.Result.ACCEPTED;
                                                                        });
                                                                });
                                                        } else {
                                                            return this._daemonRepo.findServerByConnection(connection)
                                                                .then(serverDaemons => {
                                                                    let serverDaemon = serverDaemons.length && serverDaemons[0];

                                                                    return Promise.resolve()
                                                                        .then(() => {
                                                                            if (!serverDaemon)
                                                                                return [];

                                                                            return this._userRepo.find(serverDaemon.userId);
                                                                        })
                                                                        .then(serverUsers => {
                                                                            let serverUser = serverUsers.length && serverUsers[0];

                                                                            clientConnections.push(this.tracker.ClientConnection.create({
                                                                                name: user.email + path.path,
                                                                                listenAddress: connection.listenAddress,
                                                                                listenPort: connection.listenPort,
                                                                                encrypted: connection.encrypted,
                                                                                fixed: connection.fixed,
                                                                                server: (serverDaemon && serverUser) ? serverUser.email + '?' + serverDaemon.name : '',
                                                                            }));

                                                                            return this.tracker.AttachResponse.Result.ACCEPTED;
                                                                        });
                                                                });
                                                        }
                                                    });
                                            })
                                            .then(value => {
                                                let list = this.tracker.ConnectionsList.create({
                                                    serverConnections: serverConnections,
                                                    clientConnections: clientConnections,
                                                });
                                                let response = this.tracker.AttachResponse.create({
                                                    response: value,
                                                    updates: list,
                                                });
                                                let reply = this.tracker.ServerMessage.create({
                                                    type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                                                    messageId: message.messageId,
                                                    attachResponse: response,
                                                });
                                                let data = this.tracker.ServerMessage.encode(reply).finish();
                                                debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                                                this.tracker.send(id, data);
                                            });
                                    });
                            });
                    });
            })
            .catch(error => {
                this._logger.error(new WError(error, 'AttachRequest.handle()'));
            });
    }

    /**
     * Retrieve server
     * @return {Tracker}
     */
    get tracker() {
        if (this._tracker)
            return this._tracker;
        this._tracker = this._app.get('servers').get('tracker');
        return this._tracker;
    }
}

module.exports = AttachRequest;<commit_msg>More path type responses in attach<commit_after>/**
 * Attach Request event
 * @module tracker/events/attach-request
 */
const debug = require('debug')('bhit:tracker');
const moment = require('moment-timezone');
const WError = require('verror').WError;

/**
 * Attach Request event class
 */
class AttachRequest {
    /**
     * Create service
     * @param {App} app                                 The application
     * @param {object} config                           Configuration
     * @param {Logger} logger                           Logger service
     * @param {UserRepository} userRepo                 User repository
     * @param {DaemonRepository} daemonRepo             Daemon repository
     * @param {PathRepository} pathRepo                 Path repository
     * @param {ConnectionRepository} connectionRepo     Connection repository
     */
    constructor(app, config, logger, userRepo, daemonRepo, pathRepo, connectionRepo) {
        this._app = app;
        this._config = config;
        this._logger = logger;
        this._userRepo = userRepo;
        this._daemonRepo = daemonRepo;
        this._pathRepo = pathRepo;
        this._connectionRepo = connectionRepo;
    }

    /**
     * Service name is 'modules.tracker.events.attachRequest'
     * @type {string}
     */
    static get provides() {
        return 'modules.tracker.events.attachRequest';
    }

    /**
     * Dependencies as constructor arguments
     * @type {string[]}
     */
    static get requires() {
        return [
            'app',
            'config',
            'logger',
            'repositories.user',
            'repositories.daemon',
            'repositories.path',
            'repositories.connection'
        ];
    }

    /**
     * Event handler
     * @param {string} id           ID of the client
     * @param {object} message      The message
     */
    handle(id, message) {
        let client = this.tracker.clients.get(id);
        if (!client)
            return;

        debug(`Got ATTACH REQUEST from ${client.socket.remoteAddress}:${client.socket.remotePort}`);
        return Promise.resolve()
            .then(() => {
                if (!client.daemonId)
                    return [];

                return this._daemonRepo.find(client.daemonId);
            })
            .then(daemons => {
                let daemon = daemons.length && daemons[0];
                if (!daemon)
                    return null;
                if (!message.attachRequest.daemonName)
                    return daemon;

                return this._daemonRepo.findByUserAndName(daemon.userId, message.attachRequest.daemonName)
                    .then(daemons => {
                        return daemons.length && daemons[0];
                    });
            })
            .then(daemon => {
                if (!daemon) {
                    let response = this.tracker.AttachResponse.create({
                        response: this.tracker.AttachResponse.Result.REJECTED,
                    });
                    let reply = this.tracker.ServerMessage.create({
                        type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                        messageId: message.messageId,
                        attachResponse: response,
                    });
                    let data = this.tracker.ServerMessage.encode(reply).finish();
                    debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                    return this.tracker.send(id, data);
                }
                if (!this.tracker.validatePath(message.attachRequest.path)) {
                    let response = this.tracker.AttachResponse.create({
                        response: this.tracker.AttachResponse.Result.INVALID_PATH,
                    });
                    let reply = this.tracker.ServerMessage.create({
                        type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                        messageId: message.messageId,
                        attachResponse: response,
                    });
                    let data = this.tracker.ServerMessage.encode(reply).finish();
                    debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                    return this.tracker.send(id, data);
                }

                return Promise.all([
                        this._pathRepo.findByToken(message.attachRequest.token),
                        this._connectionRepo.findByToken(message.attachRequest.token)
                    ])
                    .then(([ paths, connections ]) => {
                        let path = paths.length && paths[0];
                        let connection = connections.length && connections[0];
                        let userId;

                        let actingAs;
                        if (path) {
                            actingAs = 'client';
                            userId = path.userId;
                        } else if (connection) {
                            actingAs = 'server';
                            userId = connection.userId;
                        } else {
                            let response = this.tracker.AttachResponse.create({
                                response: this.tracker.AttachResponse.Result.PATH_NOT_FOUND,
                            });
                            let reply = this.tracker.ServerMessage.create({
                                type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                                messageId: message.messageId,
                                attachResponse: response,
                            });
                            let data = this.tracker.ServerMessage.encode(reply).finish();
                            debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                            return this.tracker.send(id, data);
                        }

                        let loadConnection = (path, fullPath) => {
                            return this._connectionRepo.findByPath(path)
                                .then(connections => {
                                    let connection = connections.length && connections[0];
                                    if (connection && path.path == fullPath)
                                        return [ connection, path ];

                                    return this._pathRepo.findByParent(path)
                                        .then(paths => {
                                            let promises = [];
                                            for (let subPath of paths)
                                                promises.push(loadConnection(subPath, fullPath));

                                            return Promise.all(promises)
                                                .then(loaded => {
                                                    for (let subResult of loaded) {
                                                        if (subResult)
                                                            return subResult;
                                                    }

                                                    return null;
                                                });
                                        })
                                });
                        };

                        return Promise.resolve()
                            .then(() => {
                                if (actingAs == 'server') {
                                    return this._pathRepo.find(connection.pathId)
                                        .then(paths => {
                                            let path = paths.length && paths[0];
                                            if (path && path.path == message.attachRequest.path)
                                                return [ connection, path ];

                                            return null;
                                        });
                                }

                                return loadConnection(path, message.attachRequest.path);
                            })
                            .then(result => {
                                if (!result) {
                                    let response = this.tracker.AttachResponse.create({
                                        response: this.tracker.AttachResponse.Result.PATH_NOT_FOUND,
                                    });
                                    let reply = this.tracker.ServerMessage.create({
                                        type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                                        messageId: message.messageId,
                                        attachResponse: response,
                                    });
                                    let data = this.tracker.ServerMessage.encode(reply).finish();
                                    debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                                    return this.tracker.send(id, data);
                                }

                                let connection = result && result[0];
                                let path = result && result[1];

                                return this._daemonRepo.connect(daemon, connection, actingAs)
                                    .then(count => {
                                        let serverConnections = [], clientConnections = [];

                                        return Promise.resolve()
                                            .then(() => {
                                                if (count === 0)
                                                    return this.tracker.AttachResponse.Result.ALREADY_CONNECTED;

                                                if (message.attachRequest.daemonName)
                                                    return this.tracker.AttachResponse.Result.ACCEPTED;

                                                return this._userRepo.find(userId)
                                                    .then(users => {
                                                        let user = users.length && users[0];
                                                        if (!user)
                                                            return this.tracker.AttachResponse.Result.ACCEPTED;

                                                        if (actingAs == 'server') {
                                                            return this._daemonRepo.findByConnection(connection)
                                                                .then(clientDaemons => {
                                                                    let clients = [];
                                                                    let clientPromises = [];
                                                                    for (let clientDaemon of clientDaemons) {
                                                                        if (clientDaemon.actingAs != 'client')
                                                                            continue;

                                                                        clientPromises.push(
                                                                            this._userRepo.find(clientDaemon.userId)
                                                                                .then(clientUsers => {
                                                                                let clientUser = clientUsers.length && clientUsers[0];
                                                                                if (!clientUser)
                                                                                return;

                                                                                clients.push(clientUser.email + '?' + clientDaemon.name);
                                                                                })
                                                                        );
                                                                    }

                                                                    return Promise.all(clientPromises)
                                                                        .then(() => {
                                                                            serverConnections.push(this.tracker.ServerConnection.create({
                                                                                name: user.email + path.path,
                                                                                connectAddress: connection.connectAddress,
                                                                                connectPort: connection.connectPort,
                                                                                encrypted: connection.encrypted,
                                                                                fixed: connection.fixed,
                                                                                clients: clients,
                                                                            }));

                                                                            return this.tracker.AttachResponse.Result.ACCEPTED;
                                                                        });
                                                                });
                                                        } else {
                                                            return this._daemonRepo.findServerByConnection(connection)
                                                                .then(serverDaemons => {
                                                                    let serverDaemon = serverDaemons.length && serverDaemons[0];

                                                                    return Promise.resolve()
                                                                        .then(() => {
                                                                            if (!serverDaemon)
                                                                                return [];

                                                                            return this._userRepo.find(serverDaemon.userId);
                                                                        })
                                                                        .then(serverUsers => {
                                                                            let serverUser = serverUsers.length && serverUsers[0];

                                                                            clientConnections.push(this.tracker.ClientConnection.create({
                                                                                name: user.email + path.path,
                                                                                listenAddress: connection.listenAddress,
                                                                                listenPort: connection.listenPort,
                                                                                encrypted: connection.encrypted,
                                                                                fixed: connection.fixed,
                                                                                server: (serverDaemon && serverUser) ? serverUser.email + '?' + serverDaemon.name : '',
                                                                            }));

                                                                            return this.tracker.AttachResponse.Result.ACCEPTED;
                                                                        });
                                                                });
                                                        }
                                                    });
                                            })
                                            .then(value => {
                                                let list = this.tracker.ConnectionsList.create({
                                                    serverConnections: serverConnections,
                                                    clientConnections: clientConnections,
                                                });
                                                let response = this.tracker.AttachResponse.create({
                                                    response: value,
                                                    updates: list,
                                                });
                                                let reply = this.tracker.ServerMessage.create({
                                                    type: this.tracker.ServerMessage.Type.ATTACH_RESPONSE,
                                                    messageId: message.messageId,
                                                    attachResponse: response,
                                                });
                                                let data = this.tracker.ServerMessage.encode(reply).finish();
                                                debug(`Sending ATTACH RESPONSE to ${client.socket.remoteAddress}:${client.socket.remotePort}`);
                                                this.tracker.send(id, data);
                                            });
                                    });
                            });
                    });
            })
            .catch(error => {
                this._logger.error(new WError(error, 'AttachRequest.handle()'));
            });
    }

    /**
     * Retrieve server
     * @return {Tracker}
     */
    get tracker() {
        if (this._tracker)
            return this._tracker;
        this._tracker = this._app.get('servers').get('tracker');
        return this._tracker;
    }
}

module.exports = AttachRequest;<|endoftext|>


<commit_before>"use strict";

var $ = require('jquery'),
    Bacon = require('baconjs'),
    R = require('ramda'),
    _ = require('lodash'),
    format = require('util').format,
    M = require('treemap/BaconModels'),
    moment = require('moment'),
    getOptionAttr = M.getOptionAttr,
    getVal = M.getVal,
    DATETIME_FORMAT = require('treemap/fieldHelpers').DATETIME_FORMAT;

// Placed onto the jquery object
require('bootstrap-datepicker');

var nameTemplate = _.template('udf:<%= modelName %>:<%= udfFieldDefId %>.<%= fieldKey %>'),

    widgets = {
        modelName: {
            selector: '#udfc-search-model',
            reset: _.partial(resetSelectWidget, 'modelName', 'data-model'),
            stateModifiers: {
                modelName: getOptionAttr('data-model'),
                action: null
            }
        },
        type: {
            selector: '#udfc-search-type',
            reset: _.partial(resetType, 'type', 'data-type'),
            stateModifiers: {
                type: getOptionAttr('data-type'),
                udfFieldDefIds: getOptionAttr('data-udfd-ids'),
                actionFieldKey: getOptionAttr('data-action-field-key'),
                dateFieldKey: getOptionAttr('data-date-field-key'),
                action: null
            }
        },
        action: {
            selector: '#udfc-search-action',
            reset: resetAction,
            stateModifiers: {action: getVal}
        },
        dateMin: {
            selector: '#udfc-search-date-from',
            reset: _.partial(resetDateBox, 'dateMin'),
            stateModifiers: {dateMin: getVal}
        },
        dateMax: {
            selector: '#udfc-search-date-to',
            reset: _.partial(resetDateBox, 'dateMax'),
            stateModifiers: {dateMax: getVal }
        },
        extraClauses: {
            selector: '#udfc-extra-clauses',
            reset: resetExtraClauses
        }
    },
    emptyState = _.chain(widgets)
        .pluck('stateModifiers')
        .map(_.keys)
        .flatten()
        .uniq()
        .map(function (key) { return [key, null]; })
        .object()
        .value();

function makeNameAttribute (state, fieldKey) {
    var modelName = state.modelName,
        requiredFields = [modelName,
                          state.actionFieldKey,
                          state.dateFieldKey,
                          state.udfFieldDefIds],
        udfFieldDefId;

    if (_.any(requiredFields, R.or(_.isUndefined, _.isNull))) {
        return '';
    }

    udfFieldDefId = JSON.parse(state.udfFieldDefIds)[modelName];

    if (_.isUndefined(udfFieldDefId)) {
        return '';
    }

    return nameTemplate({modelName: modelName,
                      udfFieldDefId: udfFieldDefId,
                      fieldKey: fieldKey});
}

function resetSelectWidget(widgetName, optionKey, state) {
    var stateVal = state[widgetName],
        $option,
        val;

    if (!_.isNull(stateVal)) {
        $option = $(widgets[widgetName].selector)
            .find('option')
            .filter('[' + optionKey + '="' + stateVal + '"]');
        val = $option.val();
    } else {
        val = '';
    }
    $(widgets[widgetName].selector).val(val);
}

function resetType(widgetName, optionKey, state) {
    resetSelectWidget(widgetName, optionKey, state);
    var $el = $(widgets.type.selector),
        shouldEnable = !_.isNull(state.modelName);
    enableDropdown($el, shouldEnable);
}

function enableDropdown($el, shouldEnable) {
    $el.prop('disabled', shouldEnable ? false : 'disabled');
}

function resetAction(state) {
    var $el = $(widgets.action.selector),
        $currentOptions = $el.find('option').not('[data-class="udfc-placeholder"]'),
        $allOptions = $el.data('options'),
        shouldEnable = !_.isNull(state.modelName) && !_.isNull(state.type),
        modelSelector,
        typeSelector;

    // You can't hide <option> tags, so we need to stash them and add/remove
    // them as needed
    if (_.isUndefined($allOptions)) {
        $allOptions = $currentOptions.detach();
        $el.data('options', $allOptions);
    }

    $currentOptions.remove();
    if (shouldEnable) {
        modelSelector = format('[data-model="%s"]', state.modelName);
        typeSelector = format('[data-type="%s"]', state.type);

        // Add the relevant options to the select
        $allOptions
            .filter(modelSelector)
            .filter(typeSelector)
            .appendTo($el);
    }
    enableDropdown($el, shouldEnable);

    $el = $(widgets.action.selector);
    if (!_.isNull(state.action)) {
        $el.val(state.action);
    } else {
        $el.val('');
    }
    $el.attr('name', makeNameAttribute(state, state.actionFieldKey));
}

function resetDateBox(widgetName, state) {
    var name = makeNameAttribute(state, state.dateFieldKey),
        $widget = $(widgets[widgetName].selector),
        longDate = moment(state[widgetName], DATETIME_FORMAT),
        shortDate = moment(state[widgetName], 'MM/DD/YYYY'),
        val;

    if (!_.isNull(longDate) && longDate.isValid()) {
        val = longDate.format('MM/DD/YYYY');
    } else if (!_.isNull(shortDate) && shortDate.isValid()) {
        val = shortDate.format('MM/DD/YYYY');
    } else {
        val = '';
    }

    $widget.attr('name', name);
    $widget.val(val);
}

function resetExtraClauses(state) {
    var $els = $(widgets.extraClauses.selector).find('input'),
        name;

    $els.attr('name', '');

    if (_.isNull(state.type)) { return; }

    var $matches = $els.filter('[data-type="' + state.type  + '"]');
    _.each($matches, function (match) {
        var $match = $(match),
            field = $match.attr('data-field'),
            name = makeNameAttribute(state, field);
        $match.attr('name', name);
        // this is a concession. Why won't value stick?
        $match.val($match.attr('value'));
    });
}

function applyFilterObjectToDom(bus, filterObject) {
    var state = _.extend({}, emptyState),
        parsed = _.filter(_.map(filterObject.filter, function (v, k) {
            // parse each field name and update the filterObject to also
            // contain the parse results
            var fieldNameData = parseUdfCollectionFieldName(k);
            if (fieldNameData) {
                return _.extend({}, v, fieldNameData);
            } else {
                return null;
            }
        })),
        modelName = _.uniq(_.pluck(parsed, 'modelName'))[0],
        udfFieldDefId = _.uniq(_.pluck(parsed, 'fieldDefId'))[0],
        eligibleModelNames = _.map(
            $(widgets.modelName.selector)
                .find('option')
                .not('[data-class="udfc-placeholder"]'),
            function (option) {
                return $(option).attr('data-model');
            }),
        cleanModelName,
        action,
        date;

    // there's no data if there's no modelName / udfFieldDefId
    if (!_.isString(modelName) || !_.isString(udfFieldDefId)) { return; }

    // don't attempt to populate if invalid data provided
    cleanModelName = modelName.substring(4);
    if (!_.contains(eligibleModelNames, cleanModelName)) { return; }
    state.modelName = cleanModelName;

    var $typeEl = $(widgets.type.selector)
            .find('option[data-udfd-ids]')
            .filter(function (__, el) {
                var id = JSON.parse($(el).attr('data-udfd-ids'))[cleanModelName];
                return id == udfFieldDefId;
            });

    state.udfFieldDefIds = $typeEl.attr('data-udfd-ids');
    state.dateFieldKey = $typeEl.attr('data-date-field-key');
    state.actionFieldKey = $typeEl.attr('data-action-field-key');
    state.type = $typeEl.attr('data-type');

    // set the model name in the model selector and initialize fields
    state.action = _.where(parsed, {hStoreMember: state.actionFieldKey})[0].IS;

    date = _.where(parsed, {hStoreMember: state.dateFieldKey})[0];
    if (!_.isUndefined(date)) {
        state.dateMin = _.isString(date.MIN) ? date.MIN : null;
        state.dateMax = _.isString(date.MAX) ? date.MAX : null;
    }

    bus.push(state);
}

// exported for testing
exports._makeNameAttribute = makeNameAttribute;
exports._widgets = widgets;

exports.init = function (resetStream) {
    var resetStateStream = (resetStream || Bacon.never()).map(emptyState),
        externalChangeBus = new Bacon.Bus();

    var globalState = M.init({
            externalStreams: [externalChangeBus, resetStateStream],
            widgets: widgets,
            emptyState: emptyState
        });

    return {
        applyFilterObjectToDom: _.partial(applyFilterObjectToDom,
                                          externalChangeBus),
        _externalChangeBus: externalChangeBus        // for unit testing
    };
};

// Copied from OTM2-Tiler, documentation removed.
// TODO: factor this out into a common node module
function parseUdfCollectionFieldName (fieldName) {
    var tokens = fieldName.split(':'),
        fieldDefIdAndHStoreMember;

    if (tokens.length !== 3) {
        return null;
    }

    fieldDefIdAndHStoreMember = tokens[2].split('.');

    return {
        modelName: 'udf:' + tokens[1],
        fieldDefId: fieldDefIdAndHStoreMember[0],
        hStoreMember: fieldDefIdAndHStoreMember[1]
    };
}
<commit_msg>Conditionally disable collection UDF search dates<commit_after>"use strict";

var $ = require('jquery'),
    Bacon = require('baconjs'),
    R = require('ramda'),
    _ = require('lodash'),
    format = require('util').format,
    M = require('treemap/BaconModels'),
    moment = require('moment'),
    getOptionAttr = M.getOptionAttr,
    getVal = M.getVal,
    DATETIME_FORMAT = require('treemap/fieldHelpers').DATETIME_FORMAT;

// Placed onto the jquery object
require('bootstrap-datepicker');

var nameTemplate = _.template('udf:<%= modelName %>:<%= udfFieldDefId %>.<%= fieldKey %>'),

    widgets = {
        modelName: {
            selector: '#udfc-search-model',
            reset: _.partial(resetSelectWidget, 'modelName', 'data-model'),
            stateModifiers: {
                modelName: getOptionAttr('data-model'),
                action: null
            }
        },
        type: {
            selector: '#udfc-search-type',
            reset: _.partial(resetType, 'type', 'data-type'),
            stateModifiers: {
                type: getOptionAttr('data-type'),
                udfFieldDefIds: getOptionAttr('data-udfd-ids'),
                actionFieldKey: getOptionAttr('data-action-field-key'),
                dateFieldKey: getOptionAttr('data-date-field-key'),
                action: null
            }
        },
        action: {
            selector: '#udfc-search-action',
            reset: resetAction,
            stateModifiers: {action: getVal}
        },
        dateMin: {
            selector: '#udfc-search-date-from',
            reset: _.partial(resetDateBox, 'dateMin'),
            stateModifiers: {dateMin: getVal}
        },
        dateMax: {
            selector: '#udfc-search-date-to',
            reset: _.partial(resetDateBox, 'dateMax'),
            stateModifiers: {dateMax: getVal }
        },
        extraClauses: {
            selector: '#udfc-extra-clauses',
            reset: resetExtraClauses
        }
    },
    emptyState = _.chain(widgets)
        .pluck('stateModifiers')
        .map(_.keys)
        .flatten()
        .uniq()
        .map(function (key) { return [key, null]; })
        .object()
        .value();

function makeNameAttribute (state, fieldKey) {
    var modelName = state.modelName,
        requiredFields = [modelName,
                          state.actionFieldKey,
                          state.dateFieldKey,
                          state.udfFieldDefIds],
        udfFieldDefId;

    if (_.any(requiredFields, R.or(_.isUndefined, _.isNull))) {
        return '';
    }

    udfFieldDefId = JSON.parse(state.udfFieldDefIds)[modelName];

    if (_.isUndefined(udfFieldDefId)) {
        return '';
    }

    return nameTemplate({modelName: modelName,
                      udfFieldDefId: udfFieldDefId,
                      fieldKey: fieldKey});
}

function resetSelectWidget(widgetName, optionKey, state) {
    var stateVal = state[widgetName],
        $option,
        val;

    if (!_.isNull(stateVal)) {
        $option = $(widgets[widgetName].selector)
            .find('option')
            .filter('[' + optionKey + '="' + stateVal + '"]');
        val = $option.val();
    } else {
        val = '';
    }
    $(widgets[widgetName].selector).val(val);
}

function resetType(widgetName, optionKey, state) {
    resetSelectWidget(widgetName, optionKey, state);
    var $el = $(widgets.type.selector),
        shouldEnable = !_.isNull(state.modelName);
    enableInput($el, shouldEnable);
}

function enableInput($el, shouldEnable) {
    $el.prop('disabled', shouldEnable ? false : 'disabled');
}

function resetAction(state) {
    var $el = $(widgets.action.selector),
        $currentOptions = $el.find('option').not('[data-class="udfc-placeholder"]'),
        $allOptions = $el.data('options'),
        shouldEnable = !_.isNull(state.modelName) && !_.isNull(state.type),
        modelSelector,
        typeSelector;

    // You can't hide <option> tags, so we need to stash them and add/remove
    // them as needed
    if (_.isUndefined($allOptions)) {
        $allOptions = $currentOptions.detach();
        $el.data('options', $allOptions);
    }

    $currentOptions.remove();
    if (shouldEnable) {
        modelSelector = format('[data-model="%s"]', state.modelName);
        typeSelector = format('[data-type="%s"]', state.type);

        // Add the relevant options to the select
        $allOptions
            .filter(modelSelector)
            .filter(typeSelector)
            .appendTo($el);
    }
    enableInput($el, shouldEnable);

    $el = $(widgets.action.selector);
    if (!_.isNull(state.action)) {
        $el.val(state.action);
    } else {
        $el.val('');
    }
    $el.attr('name', makeNameAttribute(state, state.actionFieldKey));
}

function resetDateBox(widgetName, state) {
    var name = makeNameAttribute(state, state.dateFieldKey),
        $widget = $(widgets[widgetName].selector),
        longDate = moment(state[widgetName], DATETIME_FORMAT),
        shortDate = moment(state[widgetName], 'MM/DD/YYYY'),
        shouldEnable = !_.isNull(state.modelName) && !_.isNull(state.type),
        val;

    if (shouldEnable) {
        if (!_.isNull(longDate) && longDate.isValid()) {
            val = longDate.format('MM/DD/YYYY');
        } else if (!_.isNull(shortDate) && shortDate.isValid()) {
            val = shortDate.format('MM/DD/YYYY');
        } else {
            val = '';
        }
    }
    enableInput($widget, shouldEnable);

    $widget.attr('name', name);
    $widget.val(val);
}

function resetExtraClauses(state) {
    var $els = $(widgets.extraClauses.selector).find('input'),
        name;

    $els.attr('name', '');

    if (_.isNull(state.type)) { return; }

    var $matches = $els.filter('[data-type="' + state.type  + '"]');
    _.each($matches, function (match) {
        var $match = $(match),
            field = $match.attr('data-field'),
            name = makeNameAttribute(state, field);
        $match.attr('name', name);
        // this is a concession. Why won't value stick?
        $match.val($match.attr('value'));
    });
}

function applyFilterObjectToDom(bus, filterObject) {
    var state = _.extend({}, emptyState),
        parsed = _.filter(_.map(filterObject.filter, function (v, k) {
            // parse each field name and update the filterObject to also
            // contain the parse results
            var fieldNameData = parseUdfCollectionFieldName(k);
            if (fieldNameData) {
                return _.extend({}, v, fieldNameData);
            } else {
                return null;
            }
        })),
        modelName = _.uniq(_.pluck(parsed, 'modelName'))[0],
        udfFieldDefId = _.uniq(_.pluck(parsed, 'fieldDefId'))[0],
        eligibleModelNames = _.map(
            $(widgets.modelName.selector)
                .find('option')
                .not('[data-class="udfc-placeholder"]'),
            function (option) {
                return $(option).attr('data-model');
            }),
        cleanModelName,
        action,
        date;

    // there's no data if there's no modelName / udfFieldDefId
    if (!_.isString(modelName) || !_.isString(udfFieldDefId)) { return; }

    // don't attempt to populate if invalid data provided
    cleanModelName = modelName.substring(4);
    if (!_.contains(eligibleModelNames, cleanModelName)) { return; }
    state.modelName = cleanModelName;

    var $typeEl = $(widgets.type.selector)
            .find('option[data-udfd-ids]')
            .filter(function (__, el) {
                var id = JSON.parse($(el).attr('data-udfd-ids'))[cleanModelName];
                return id == udfFieldDefId;
            });

    state.udfFieldDefIds = $typeEl.attr('data-udfd-ids');
    state.dateFieldKey = $typeEl.attr('data-date-field-key');
    state.actionFieldKey = $typeEl.attr('data-action-field-key');
    state.type = $typeEl.attr('data-type');

    // set the model name in the model selector and initialize fields
    state.action = _.where(parsed, {hStoreMember: state.actionFieldKey})[0].IS;

    date = _.where(parsed, {hStoreMember: state.dateFieldKey})[0];
    if (!_.isUndefined(date)) {
        state.dateMin = _.isString(date.MIN) ? date.MIN : null;
        state.dateMax = _.isString(date.MAX) ? date.MAX : null;
    }

    bus.push(state);
}

// exported for testing
exports._makeNameAttribute = makeNameAttribute;
exports._widgets = widgets;

exports.init = function (resetStream) {
    var resetStateStream = (resetStream || Bacon.never()).map(emptyState),
        externalChangeBus = new Bacon.Bus();

    var globalState = M.init({
            externalStreams: [externalChangeBus, resetStateStream],
            widgets: widgets,
            emptyState: emptyState
        });

    return {
        applyFilterObjectToDom: _.partial(applyFilterObjectToDom,
                                          externalChangeBus),
        _externalChangeBus: externalChangeBus        // for unit testing
    };
};

// Copied from OTM2-Tiler, documentation removed.
// TODO: factor this out into a common node module
function parseUdfCollectionFieldName (fieldName) {
    var tokens = fieldName.split(':'),
        fieldDefIdAndHStoreMember;

    if (tokens.length !== 3) {
        return null;
    }

    fieldDefIdAndHStoreMember = tokens[2].split('.');

    return {
        modelName: 'udf:' + tokens[1],
        fieldDefId: fieldDefIdAndHStoreMember[0],
        hStoreMember: fieldDefIdAndHStoreMember[1]
    };
}
<|endoftext|>


<commit_before>const fetchWithNetworkError = require('@uppy/utils/lib/fetchWithNetworkError')
const NetworkError = require('@uppy/utils/lib/NetworkError')

function fetchJSON (...args) {
  return fetchWithNetworkError(...args).then(response => {
    if (response.status === 429) {
      // If the server asks the client to rate limit, reschedule the request 2s later.
      // TODO: there are several instances of rate limiting accross the code base, having one global one could be useful.
      return new Promise((resolve, reject) => {
        setTimeout(() => fetchJSON(...args).then(resolve, reject), 2_000)
      })
    }

    if (!response.ok) {
      return Promise.reject(new NetworkError(response.statusText))
    }

    return response.json()
  })
}

/**
 * A Barebones HTTP API client for Transloadit.
 */
module.exports = class Client {
  #headers = {}

  constructor (opts = {}) {
    this.opts = opts

    if (this.opts.client != null) {
      this.#headers['Transloadit-Client'] = this.opts.client
    }
  }

  /**
   * Create a new assembly.
   *
   * @param {object} options
   * @param {string|object} options.params
   * @param {object} options.fields
   * @param {string} options.signature
   * @param {number} options.expectedFiles
   */
  createAssembly ({
    params,
    fields,
    signature,
    expectedFiles,
  }) {
    const data = new FormData()
    data.append('params', typeof params === 'string'
      ? params
      : JSON.stringify(params))
    if (signature) {
      data.append('signature', signature)
    }

    Object.keys(fields).forEach((key) => {
      data.append(key, fields[key])
    })
    data.append('num_expected_upload_files', expectedFiles)

    const url = new URL('/assemblies', `${this.opts.service}`).href
    return fetchJSON(url, {
      method: 'post',
      headers: this.#headers,
      body: data,
    })
      .then((assembly) => {
        if (assembly.error) {
          const error = new Error(assembly.error)
          error.details = assembly.message
          error.assembly = assembly
          if (assembly.assembly_id) {
            error.details += ` Assembly ID: ${assembly.assembly_id}`
          }
          throw error
        }

        return assembly
      })
      .catch((err) => this.#reportError(err, { url, type: 'API_ERROR' }))
  }

  /**
   * Reserve resources for a file in an Assembly. Then addFile can be used later.
   *
   * @param {object} assembly
   * @param {UppyFile} file
   */
  reserveFile (assembly, file) {
    const size = encodeURIComponent(file.size)
    const url = `${assembly.assembly_ssl_url}/reserve_file?size=${size}`
    return fetchJSON(url, { method: 'post', headers: this.#headers })
      .catch((err) => this.#reportError(err, { assembly, file, url, type: 'API_ERROR' }))
  }

  /**
   * Import a remote file to an Assembly.
   *
   * @param {object} assembly
   * @param {UppyFile} file
   */
  addFile (assembly, file) {
    if (!file.uploadURL) {
      return Promise.reject(new Error('File does not have an `uploadURL`.'))
    }
    const size = encodeURIComponent(file.size)
    const uploadUrl = encodeURIComponent(file.uploadURL)
    const filename = encodeURIComponent(file.name)
    const fieldname = 'file'

    const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${uploadUrl}`
    const url = `${assembly.assembly_ssl_url}/add_file?${qs}`
    return fetchJSON(url, { method: 'post', headers: this.#headers })
      .catch((err) => this.#reportError(err, { assembly, file, url, type: 'API_ERROR' }))
  }

  /**
   * Cancel a running Assembly.
   *
   * @param {object} assembly
   */
  cancelAssembly (assembly) {
    const url = assembly.assembly_ssl_url
    return fetchJSON(url, { method: 'delete', headers: this.#headers })
      .catch((err) => this.#reportError(err, { url, type: 'API_ERROR' }))
  }

  /**
   * Get the current status for an assembly.
   *
   * @param {string} url The status endpoint of the assembly.
   */
  getAssemblyStatus (url) {
    return fetchJSON(url, { headers: this.#headers })
      .catch((err) => this.#reportError(err, { url, type: 'STATUS_ERROR' }))
  }

  submitError (err, { endpoint, instance, assembly } = {}) {
    const message = err.details
      ? `${err.message} (${err.details})`
      : err.message

    return fetchJSON('https://transloaditstatus.com/client_error', {
      method: 'post',
      body: JSON.stringify({
        endpoint,
        instance,
        assembly_id: assembly,
        agent: typeof navigator !== 'undefined' ? navigator.userAgent : '',
        client: this.opts.client,
        error: message,
      }),
    })
  }

  #reportError = (err, params) => {
    if (this.opts.errorReporting === false) {
      throw err
    }

    const opts = {
      type: params.type,
    }
    if (params.assembly) {
      opts.assembly = params.assembly.assembly_id
      opts.instance = params.assembly.instance
    }
    if (params.url) {
      opts.endpoint = params.url
    }

    this.submitError(err, opts).catch(() => {
      // not much we can do then is there
    })

    throw err
  }
}
<commit_msg>@uppy/transloadit: improve fetch error handling (#3637)<commit_after>const fetchWithNetworkError = require('@uppy/utils/lib/fetchWithNetworkError')

const ASSEMBLIES_ENDPOINT = '/assemblies'

function fetchJSON (...args) {
  return fetchWithNetworkError(...args).then(response => {
    if (response.status === 429) {
      // If the server asks the client to rate limit, reschedule the request 2s later.
      // TODO: there are several instances of rate limiting accross the code base, having one global one could be useful.
      return new Promise((resolve, reject) => {
        setTimeout(() => fetchJSON(...args).then(resolve, reject), 2_000)
      })
    }

    if (!response.ok) {
      const serverError = new Error(response.statusText)
      serverError.statusCode = response.status

      if (!`${args[0]}`.endsWith(ASSEMBLIES_ENDPOINT)) return Promise.reject(serverError)

      // Failed assembly requests should return a more detailed error in JSON.
      return response.json().then(assembly => {
        if (!assembly.error) throw serverError

        const error = new Error(assembly.error)
        error.details = assembly.message
        error.assembly = assembly
        if (assembly.assembly_id) {
          error.details += ` Assembly ID: ${assembly.assembly_id}`
        }
        throw error
      }, err => {
        // eslint-disable-next-line no-param-reassign
        err.cause = serverError
        throw err
      })
    }

    return response.json()
  })
}

/**
 * A Barebones HTTP API client for Transloadit.
 */
module.exports = class Client {
  #headers = {}

  constructor (opts = {}) {
    this.opts = opts

    if (this.opts.client != null) {
      this.#headers['Transloadit-Client'] = this.opts.client
    }
  }

  /**
   * Create a new assembly.
   *
   * @param {object} options
   * @param {string|object} options.params
   * @param {object} options.fields
   * @param {string} options.signature
   * @param {number} options.expectedFiles
   */
  createAssembly ({
    params,
    fields,
    signature,
    expectedFiles,
  }) {
    const data = new FormData()
    data.append('params', typeof params === 'string'
      ? params
      : JSON.stringify(params))
    if (signature) {
      data.append('signature', signature)
    }

    Object.keys(fields).forEach((key) => {
      data.append(key, fields[key])
    })
    data.append('num_expected_upload_files', expectedFiles)

    const url = new URL(ASSEMBLIES_ENDPOINT, `${this.opts.service}`).href
    return fetchJSON(url, {
      method: 'post',
      headers: this.#headers,
      body: data,
    })
      .catch((err) => this.#reportError(err, { url, type: 'API_ERROR' }))
  }

  /**
   * Reserve resources for a file in an Assembly. Then addFile can be used later.
   *
   * @param {object} assembly
   * @param {UppyFile} file
   */
  reserveFile (assembly, file) {
    const size = encodeURIComponent(file.size)
    const url = `${assembly.assembly_ssl_url}/reserve_file?size=${size}`
    return fetchJSON(url, { method: 'post', headers: this.#headers })
      .catch((err) => this.#reportError(err, { assembly, file, url, type: 'API_ERROR' }))
  }

  /**
   * Import a remote file to an Assembly.
   *
   * @param {object} assembly
   * @param {UppyFile} file
   */
  addFile (assembly, file) {
    if (!file.uploadURL) {
      return Promise.reject(new Error('File does not have an `uploadURL`.'))
    }
    const size = encodeURIComponent(file.size)
    const uploadUrl = encodeURIComponent(file.uploadURL)
    const filename = encodeURIComponent(file.name)
    const fieldname = 'file'

    const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${uploadUrl}`
    const url = `${assembly.assembly_ssl_url}/add_file?${qs}`
    return fetchJSON(url, { method: 'post', headers: this.#headers })
      .catch((err) => this.#reportError(err, { assembly, file, url, type: 'API_ERROR' }))
  }

  /**
   * Cancel a running Assembly.
   *
   * @param {object} assembly
   */
  cancelAssembly (assembly) {
    const url = assembly.assembly_ssl_url
    return fetchJSON(url, { method: 'delete', headers: this.#headers })
      .catch((err) => this.#reportError(err, { url, type: 'API_ERROR' }))
  }

  /**
   * Get the current status for an assembly.
   *
   * @param {string} url The status endpoint of the assembly.
   */
  getAssemblyStatus (url) {
    return fetchJSON(url, { headers: this.#headers })
      .catch((err) => this.#reportError(err, { url, type: 'STATUS_ERROR' }))
  }

  submitError (err, { endpoint, instance, assembly } = {}) {
    const message = err.details
      ? `${err.message} (${err.details})`
      : err.message

    return fetchJSON('https://transloaditstatus.com/client_error', {
      method: 'post',
      body: JSON.stringify({
        endpoint,
        instance,
        assembly_id: assembly,
        agent: typeof navigator !== 'undefined' ? navigator.userAgent : '',
        client: this.opts.client,
        error: message,
      }),
    })
  }

  #reportError = (err, params) => {
    if (this.opts.errorReporting === false) {
      throw err
    }

    const opts = {
      type: params.type,
    }
    if (params.assembly) {
      opts.assembly = params.assembly.assembly_id
      opts.instance = params.assembly.instance
    }
    if (params.url) {
      opts.endpoint = params.url
    }

    this.submitError(err, opts).catch(() => {
      // not much we can do then is there
    })

    throw err
  }
}
<|endoftext|>


<commit_before>/* @flow weak */
const handler = require(`serve-handler`)
const openurl = require(`opn`)
const http = require(`http`)
const signalExit = require(`signal-exit`)

module.exports = program => {
  let { port, open } = program
  port = typeof port === `string` ? parseInt(port, 10) : port

  let server = http.createServer((request, response) =>
    handler(request, response, {
      public: `public`,
    })
  )

  server.listen(port, () => {
    let openUrlString = `http://localhost:` + port
    if (open) {
      let openUrlString = `http://localhost:` + port
      openurl(openUrlString)
    }
  })

  signalExit((code, signal) => {
    server.close()
  })
}
<commit_msg>Revert "Remove console.log"<commit_after>/* @flow weak */
const handler = require(`serve-handler`)
const openurl = require(`opn`)
const http = require(`http`)
const signalExit = require(`signal-exit`)

module.exports = program => {
  let { port, open } = program
  port = typeof port === `string` ? parseInt(port, 10) : port

  let server = http.createServer((request, response) =>
    handler(request, response, {
      public: `public`,
    })
  )

  server.listen(port, () => {
    let openUrlString = `http://localhost:` + port
    console.log(`gatsby serve running at:`, openUrlString)
    if (open) {
      let openUrlString = `http://localhost:` + port
      console.log(`Opening browser...`)
      openurl(openUrlString)
    }
  })

  signalExit((code, signal) => {
    server.close()
  })
}
<|endoftext|>


<commit_before>/*
 @author Zakai Hamilton
 @component CoreModule
 */

screens.core.module = function CoreModule(me, { core, db, storage, cmd }) {
    me.init = function () {
        core.property.link("core.http.receive", "core.module.receive", true);
        me.autoprefixer = require("autoprefixer");
        me.postcss = require("postcss");
        me.mime = require("mime");
        me.cache = {};
    };
    me.path_file_to_component = function (filePath) {
        filePath = filePath.substring(filePath.lastIndexOf("/") + 1);
        if (filePath.indexOf("_") === -1) {
            return "";
        }
        var component_path = filePath.replace(/_/g, ".").replace(".js", "");
        return component_path;
    };
    me.loadTextFile = async function (filePath, optional) {
        try {
            var data = await core.file.readFile(filePath, "utf8", optional);
        }
        catch (err) {
            var error = "Cannot load text file: " + filePath + " err: " + err;
            me.log_error(error);
            throw error;
        }
        return data;
    };
    me.loadBinaryFile = async function (filePath) {
        var data = await core.file.readFile(filePath);
        return data;
    };
    me.handleStylesheet = async function (filePath, params) {
        if (filePath.startsWith("/")) {
            filePath = filePath.substring(1);
        }
        if (filePath === "screens.css") {
            return await core.pack.collect("packages/code", "browser", ["platform"], ["css"], false, "utf8");
        }
        var data = await me.loadTextFile(filePath, params.optional);
        if (!data && params.optional) {
            data = "";
        }
        var result = await me.postcss([me.autoprefixer]).process(data, {
            from: undefined
        });
        result.warnings().forEach(function (warn) {
            me.log_warn(warn.toString());
        });
        data = await core.pack.minify(filePath, result.css);
        return data;
    };
    me.handleCode = async function (filePath, params, info) {
        if (filePath.startsWith("/")) {
            filePath = filePath.substring(1);
        }
        if (filePath.startsWith("platform/")) {
            let platform = filePath.split("/").pop().split(".")[0];
            const folderExclude = ["platform"];
            if (platform !== "browser") {
                folderExclude.push("react");
                folderExclude.push("app");
            }
            let code = await core.pack.collect("packages/code", platform, folderExclude, ["js", "json", "html"], true, "utf8", "react");
            return code;
        }
        if (filePath.startsWith("res/")) {
            let type = filePath.split("/").pop().split(".")[0];
            let icons = await core.pack.collect("packages/res/" + type, null, null, ["png", "svg"], false, null, "ui", "image");
            return icons;
        }
        var component_path = core.module.path_file_to_component(filePath);
        var target_platform = null;
        if (component_path) {
            try {
                var component = screens.browse(component_path);
                if (component) {
                    target_platform = component.require;
                }
            }
            catch (err) {
                return;
            }
        }
        var components = [component_path];
        var source_platform = info.query["platform"];
        if (target_platform && target_platform !== source_platform) {
            filePath = "packages/code/remote.js";
            components = me.components.map(function (component_name) {
                if (!(component_name.includes(component_path))) {
                    return null;
                }
                return component_name;
            });
            components = components.filter(Boolean);
        }
        var data = await me.loadTextFile(filePath);
        var vars = {
            "target_platform": target_platform || "",
            "source_platform": source_platform || ""
        };
        var originalData = data;
        for (var componentIndex = 0; componentIndex < components.length; componentIndex++) {
            vars.component = components[componentIndex];
            /* Apply variables */
            if (data) {
                for (var key in vars) {
                    data = data.split("__" + key + "__").join(vars[key]);
                }
            }
            if (componentIndex < components.length - 1) {
                data += originalData;
            }
        }
        data = core.pack.minify(filePath, data);
        return data;
    };
    me.handleMultiFiles = async function (filePath, params, info) {
        var files = filePath.split(",");
        var file = files[0];
        var folder = core.path.folderPath(file);
        var name = core.path.fileName(file);
        if (name.includes("*")) {
            var items = await core.file.readDir(folder);
            files = items.map((filePath) => {
                return folder + "/" + filePath;
            });
            files = files.filter((filePath) => {
                return filePath.endsWith(params.extension);
            });
        }
        else if (files.length > 1) {
            files = files.slice(1).map((filePath) => {
                return folder + "/" + filePath;
            });
            files.unshift(file);
        }
        var data = "";
        for (var fileItem of files) {
            data += await params.method(fileItem, params, info);
        }
        return data;
    };
    me.buildHtml = async function (html, params, info) {
        var ignoreNextLine = false;
        var lines = html.split("\n");
        try {
            lines = lines.map(async (line) => {
                if (ignoreNextLine) {
                    ignoreNextLine = false;
                    return "";
                }
                /* Check if to inject file */
                var result = line.match(/\s<script\ssrc="([^"]*)"><\/script>/);
                if (result && result.length > 1) {
                    var filePath = core.string.trimEnd(result[1], "?");
                    if (filePath.startsWith("http")) {
                        return line;
                    }
                    let codeParams = Object.assign({}, params, { method: me.handleCode, extension: ".js" });
                    let codeContent = await core.module.handleMultiFiles(filePath, codeParams, info);
                    line = "<script id=\"" + filePath + "\">\n" + codeContent + "\n</" + "script>\n";
                    return line;
                }
                result = line.match(/\s<link\srel="stylesheet"\shref="([^"]*)">/);
                if (result && result.length > 1) {
                    ignoreNextLine = true;
                    let filePath = core.string.trimEnd(result[1], "?");
                    if (filePath.startsWith("http")) {
                        return line;
                    }
                    let styleParams = Object.assign({}, params, { method: me.handleStylesheet, extension: ".css" });
                    let styleContent = await core.module.handleMultiFiles(filePath, styleParams, info);
                    line = "<style id=\"" + filePath + "\">\n" + styleContent + "\n</style>\n";
                    return line;
                }
                return line;
            });
            lines = await Promise.all(lines);
            html = lines.join("\n");
        }
        catch (err) {
            me.log_error("Cannot parse html: " + err);
        }
        return html;
    };
    me.handleFile = async function (filePath, params, info) {
        if (filePath.endsWith(".js")) {
            params = Object.assign({}, params);
            params.method = me.handleCode;
            params.extension = ".js";
            info["content-type"] = "application/javascript";
            info.body = await core.module.handleMultiFiles(filePath, params, info);
        } else if (filePath.endsWith(".css")) {
            params = Object.assign({}, params);
            params.method = me.handleStylesheet;
            params.extension = ".css";
            info["content-type"] = "text/css";
            info.body = await core.module.handleMultiFiles(filePath, params, info);
        } else if (filePath.endsWith(".html")) {
            info["content-type"] = "text/html";
            var useCache = core.util.isSecure();
            var data = null;
            if (useCache) {
                data = me.cache[filePath];
            }
            if (!data) {
                me.log("building html, useCache: " + useCache + " filePath: " + filePath);
                data = await me.loadTextFile(filePath);
                data = data.replace(/__react__/g, core.util.isSecure() ? "production.min" : "development");
                data = await me.buildHtml(data, params, info);
                if (useCache) {
                    me.cache[filePath] = data;
                }
            }
            var startupArgs = info.query["args"];
            if (!startupArgs) {
                startupArgs = "";
            }
            data = data.replace(/__startup_app__/g, "'" + params.startupApp + "'");
            data = data.replace(/__startup_args__/g, "'" + startupArgs + "'");
            info.body = data;
        } else if (filePath.endsWith(".png")) {
            info["content-type"] = "image/png";
            info.body = await me.loadBinaryFile(filePath);
        } else if (filePath.endsWith(".svg")) {
            info["content-type"] = "image/svg+xml";
            info.body = await me.loadBinaryFile(filePath);
        } else if (filePath.endsWith(".json")) {
            info["content-type"] = "application/json";
            info.body = await me.loadTextFile(filePath);
        } else if (filePath.endsWith(".txt")) {
            info["content-type"] = "text/plain";
            info.body = await me.loadTextFile(filePath);
        } else if (filePath.endsWith(".m4a")) {
            let mimeType = "audio/mp4";
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        } else if (filePath.endsWith(".mp4")) {
            let mimeType = "video/mp4";
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        } else if (filePath.endsWith(".mp3")) {
            let mimeType = "audio/mpeg";
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        } else {
            var extension = core.path.extension(filePath);
            let mimeType = me.mime.getType(extension);
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        }
    };
    me.handleMeta = function (info) {
        info["content-type"] = "text/html";
        var metaTags = "";
        for (var key in info.query) {
            if (key === "redirect") {
                metaTags += "<meta http-equiv=\"refresh\" content=\"0; URL=" + info.query[key] + "\"></meta>";
            }
            else {
                if (key.startsWith("og:")) {
                    metaTags += "<meta property=\"" + key + "\" content=\"" + info.query[key] + "\"></meta>";
                }
                else {
                    metaTags += "<meta name=\"" + key + "\" content=\"" + info.query[key] + "\"></meta>";
                }
            }
        }
        var html = "<!DOCTYPE html>\
        <html>\
        <head>" + metaTags + "\
        </head>\
        <body></body>\
        </html>";
        info.body = html;
    };
    me.emptyCache = function () {
        me.cache = {};
    };
    me.receive = async function (info) {
        const rejectPrefixes = [
            "commands",
            "ext",
            "lib",
            "solr",
            "mouse",
            "layer",
            "vendor",
            "cgi-bin",
            "mode",
            "behaviour",
            "locale",
            "keyboard",
            "worker"];
        const customPrefixes = ["custom", "api", "interface"];
        if (me.platform === "server") {
            if (info.method === "GET") {
                var params = {};
                if (info.url == "/meta") {
                    me.handleMeta(info);
                    return;
                }
                if (customPrefixes.find(prefix => info.url.startsWith("/" + prefix + "/"))) {
                    return;
                }
                if (rejectPrefixes.find(prefix => info.url.startsWith("/" + prefix + "/"))) {
                    info.custom = true;
                    info.response.writeHead(403);
                    info.response.end();
                    return;
                }
                if (info.url.startsWith("/reset")) {
                    db.events.msg.send(me.id + ".emptyCache");
                    storage.fs.delete("server/metadata");
                    info.body = "Emptying cache";
                    return;
                }
                if (info.url.startsWith("/upgrade")) {
                    db.events.msg.send(me.id + ".emptyCache");
                    cmd.update.cmd(null, "reload");
                    info.body = "Upgrading...";
                    return;
                }
                if (info.url.startsWith("/reload")) {
                    db.events.msg.send("core.server.run", "pm2 reload all");
                    info.body = "Reload complete";
                    return;
                }
                if (info.url.startsWith("/") && !info.url.includes(".")) {
                    params.startupApp = info.url.substring(1);
                    info.url = "/main.html";
                }
                var filePath = info.url.substring(1);
                await me.handleFile(filePath, params, info);
            }
        }
    };
    return "server";
};
<commit_msg>bug fix<commit_after>/*
 @author Zakai Hamilton
 @component CoreModule
 */

screens.core.module = function CoreModule(me, { core, db, storage, cmd }) {
    me.init = function () {
        core.property.link("core.http.receive", "core.module.receive", true);
        me.autoprefixer = require("autoprefixer");
        me.postcss = require("postcss");
        me.mime = require("mime");
        me.cache = {};
    };
    me.path_file_to_component = function (filePath) {
        filePath = filePath.substring(filePath.lastIndexOf("/") + 1);
        if (filePath.indexOf("_") === -1) {
            return "";
        }
        var component_path = filePath.replace(/_/g, ".").replace(".js", "");
        return component_path;
    };
    me.loadTextFile = async function (filePath, optional) {
        try {
            var data = await core.file.readFile(filePath, "utf8", optional);
        }
        catch (err) {
            var error = "Cannot load text file: " + filePath + " err: " + err;
            me.log_error(error);
            throw error;
        }
        return data;
    };
    me.loadBinaryFile = async function (filePath) {
        var data = await core.file.readFile(filePath);
        return data;
    };
    me.handleStylesheet = async function (filePath, params) {
        if (filePath.startsWith("/")) {
            filePath = filePath.substring(1);
        }
        if (filePath === "screens.css") {
            return await core.pack.collect("packages/code", "browser", ["platform"], ["css"], false, "utf8");
        }
        var data = await me.loadTextFile(filePath, params.optional);
        if (!data && params.optional) {
            data = "";
        }
        var result = await me.postcss([me.autoprefixer]).process(data, {
            from: undefined
        });
        result.warnings().forEach(function (warn) {
            me.log_warn(warn.toString());
        });
        data = await core.pack.minify(filePath, result.css);
        return data;
    };
    me.handleCode = async function (filePath, params, info) {
        if (filePath.startsWith("/")) {
            filePath = filePath.substring(1);
        }
        if (filePath.startsWith("platform/")) {
            let platform = filePath.split("/").pop().split(".")[0];
            const folderExclude = ["platform"];
            if (platform !== "browser") {
                folderExclude.push("react");
                folderExclude.push("app");
            }
            let code = await core.pack.collect("packages/code", platform, folderExclude, ["js", "json", "html"], true, "utf8", "react");
            return code;
        }
        if (filePath.startsWith("res/")) {
            let type = filePath.split("/").pop().split(".")[0];
            let icons = await core.pack.collect("packages/res/" + type, null, null, ["png", "svg"], false, null, "ui", "image");
            return icons;
        }
        var component_path = core.module.path_file_to_component(filePath);
        var target_platform = null;
        if (component_path) {
            try {
                var component = screens.browse(component_path);
                if (component) {
                    target_platform = component.require;
                }
            }
            catch (err) {
                return;
            }
        }
        var components = [component_path];
        var source_platform = info.query["platform"];
        if (target_platform && target_platform !== source_platform) {
            filePath = "packages/code/remote.js";
            components = me.components.map(function (component_name) {
                if (!(component_name.includes(component_path))) {
                    return null;
                }
                return component_name;
            });
            components = components.filter(Boolean);
        }
        var data = await me.loadTextFile(filePath);
        var vars = {
            "target_platform": target_platform || "",
            "source_platform": source_platform || ""
        };
        var originalData = data;
        for (var componentIndex = 0; componentIndex < components.length; componentIndex++) {
            vars.component = components[componentIndex];
            /* Apply variables */
            if (data) {
                for (var key in vars) {
                    data = data.split("__" + key + "__").join(vars[key]);
                }
            }
            if (componentIndex < components.length - 1) {
                data += originalData;
            }
        }
        data = core.pack.minify(filePath, data);
        return data;
    };
    me.handleMultiFiles = async function (filePath, params, info) {
        var files = filePath.split(",");
        var file = files[0];
        var folder = core.path.folderPath(file);
        var name = core.path.fileName(file);
        if (name.includes("*")) {
            var items = await core.file.readDir(folder);
            files = items.map((filePath) => {
                return folder + "/" + filePath;
            });
            files = files.filter((filePath) => {
                return filePath.endsWith(params.extension);
            });
        }
        else if (files.length > 1) {
            files = files.slice(1).map((filePath) => {
                return folder + "/" + filePath;
            });
            files.unshift(file);
        }
        var data = "";
        for (var fileItem of files) {
            data += await params.method(fileItem, params, info);
        }
        return data;
    };
    me.buildHtml = async function (html, params, info) {
        var ignoreNextLine = false;
        var lines = html.split("\n");
        try {
            lines = lines.map(async (line) => {
                if (ignoreNextLine) {
                    ignoreNextLine = false;
                    return "";
                }
                /* Check if to inject file */
                var result = line.match(/\s<script\ssrc="([^"]*)"><\/script>/);
                if (result && result.length > 1) {
                    var filePath = core.string.trimEnd(result[1], "?");
                    if (filePath.startsWith("http")) {
                        return line;
                    }
                    let codeParams = Object.assign({}, params, { method: me.handleCode, extension: ".js" });
                    let codeContent = await core.module.handleMultiFiles(filePath, codeParams, info);
                    line = "<script id=\"" + filePath + "\">\n" + codeContent + "\n</" + "script>\n";
                    return line;
                }
                result = line.match(/\s<link\srel="stylesheet"\shref="([^"]*)">/);
                if (result && result.length > 1) {
                    ignoreNextLine = true;
                    let filePath = core.string.trimEnd(result[1], "?");
                    if (filePath.startsWith("http")) {
                        return line;
                    }
                    let styleParams = Object.assign({}, params, { method: me.handleStylesheet, extension: ".css" });
                    let styleContent = await core.module.handleMultiFiles(filePath, styleParams, info);
                    line = "<style id=\"" + filePath + "\">\n" + styleContent + "\n</style>\n";
                    return line;
                }
                return line;
            });
            lines = await Promise.all(lines);
            html = lines.join("\n");
        }
        catch (err) {
            me.log_error("Cannot parse html: " + err);
        }
        return html;
    };
    me.handleFile = async function (filePath, params, info) {
        if (filePath.endsWith(".js")) {
            params = Object.assign({}, params);
            params.method = me.handleCode;
            params.extension = ".js";
            info["content-type"] = "application/javascript";
            info.body = await core.module.handleMultiFiles(filePath, params, info);
        } else if (filePath.endsWith(".css")) {
            params = Object.assign({}, params);
            params.method = me.handleStylesheet;
            params.extension = ".css";
            info["content-type"] = "text/css";
            info.body = await core.module.handleMultiFiles(filePath, params, info);
        } else if (filePath.endsWith(".html")) {
            info["content-type"] = "text/html";
            var useCache = core.util.isSecure();
            var data = null;
            if (useCache) {
                data = me.cache[filePath];
            }
            if (!data) {
                me.log("building html, useCache: " + useCache + " filePath: " + filePath);
                data = await me.loadTextFile(filePath);
                data = data.replace(/__react__/g, core.util.isSecure() ? "production.min" : "development");
                data = await me.buildHtml(data, params, info);
                if (useCache) {
                    me.cache[filePath] = data;
                }
            }
            var startupArgs = info.query["args"];
            if (!startupArgs) {
                startupArgs = "";
            }
            data = data.replace(/__startup_app__/g, "'" + params.startupApp + "'");
            data = data.replace(/__startup_args__/g, "'" + startupArgs + "'");
            info.body = data;
        } else if (filePath.endsWith(".png")) {
            info["content-type"] = "image/png";
            info.body = await me.loadBinaryFile(filePath);
        } else if (filePath.endsWith(".svg")) {
            info["content-type"] = "image/svg+xml";
            info.body = await me.loadBinaryFile(filePath);
        } else if (filePath.endsWith(".json")) {
            info["content-type"] = "application/json";
            info.body = await me.loadTextFile(filePath);
        } else if (filePath.endsWith(".txt")) {
            info["content-type"] = "text/plain";
            info.body = await me.loadTextFile(filePath);
        } else if (filePath.endsWith(".m4a")) {
            let mimeType = "audio/mp4";
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        } else if (filePath.endsWith(".mp4")) {
            let mimeType = "video/mp4";
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        } else if (filePath.endsWith(".mp3")) {
            let mimeType = "audio/mpeg";
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        } else {
            var extension = core.path.extension(filePath);
            let mimeType = me.mime.getType(extension);
            info.custom = true;
            core.stream.serve(info.headers, info.response, filePath, mimeType);
        }
    };
    me.handleMeta = function (info) {
        info["content-type"] = "text/html";
        var metaTags = "";
        for (var key in info.query) {
            if (key === "redirect") {
                metaTags += "<meta http-equiv=\"refresh\" content=\"0; URL=" + info.query[key] + "\"></meta>";
            }
            else {
                if (key.startsWith("og:")) {
                    metaTags += "<meta property=\"" + key + "\" content=\"" + info.query[key] + "\"></meta>";
                }
                else {
                    metaTags += "<meta name=\"" + key + "\" content=\"" + info.query[key] + "\"></meta>";
                }
            }
        }
        var html = "<!DOCTYPE html>\
        <html>\
        <head>" + metaTags + "\
        </head>\
        <body></body>\
        </html>";
        info.body = html;
    };
    me.emptyCache = function () {
        me.cache = {};
    };
    me.receive = async function (info) {
        const rejectPrefixes = [
            "commands",
            "ext",
            "lib",
            "solr",
            "mouse",
            "layer",
            "vendor",
            "cgi-bin",
            "mode",
            "behaviour",
            "locale",
            "keyboard",
            "worker"];
        const customPrefixes = ["custom", "api", "interface"];
        if (me.platform === "server") {
            if (info.method === "GET") {
                var params = {};
                if (info.url == "/meta") {
                    me.handleMeta(info);
                    return;
                }
                if (customPrefixes.find(prefix => info.url.startsWith("/" + prefix + "/"))) {
                    return;
                }
                if (rejectPrefixes.find(prefix => info.url.startsWith("/" + prefix + "/"))) {
                    info.custom = true;
                    info.response.writeHead(403);
                    info.response.end();
                    return;
                }
                if (info.url.startsWith("/reset")) {
                    db.events.msg.send(me.id + ".emptyCache");
                    db.events.msg.send("storage.fs.delete", "server/metadata");
                    info.body = "Emptying cache";
                    return;
                }
                if (info.url.startsWith("/upgrade")) {
                    db.events.msg.send(me.id + ".emptyCache");
                    cmd.update.cmd(null, "reload");
                    info.body = "Upgrading...";
                    return;
                }
                if (info.url.startsWith("/reload")) {
                    db.events.msg.send("core.server.run", "pm2 reload all");
                    info.body = "Reload complete";
                    return;
                }
                if (info.url.startsWith("/") && !info.url.includes(".")) {
                    params.startupApp = info.url.substring(1);
                    info.url = "/main.html";
                }
                var filePath = info.url.substring(1);
                await me.handleFile(filePath, params, info);
            }
        }
    };
    return "server";
};
<|endoftext|>


<commit_before><commit_msg>We now have region select<commit_after><|endoftext|>


<commit_before><commit_msg>Fix the loc info for lines with comments.<commit_after><|endoftext|>


<commit_before><commit_msg>Get rid of Geotrek notion<commit_after><|endoftext|>


<commit_before>
var generateMouvementsFacture = function (element, regexp_replace, callback)
{
    if ($(element).length) {

        var uuid = UUID.generate();
        var bloc_html = $($(element).attr('data-template')).html().replace(regexp_replace, "nouveau_" + uuid);

        var inputsToGetValues = $(element).children('div').last().find('input');

        var selectsToGetValues = $(element).children('div').last().find('select, input[type="hidden"]');

        var bloc = $(element).children('div').last().after(bloc_html);

        $(element).children('div').last().find('input').each(function () {
            var name = $(this).attr('name');
            var value = "";
            if ((name != undefined) && (name.contains(uuid))) {
                var nameReduct = name.substring(name.lastIndexOf("["));
                inputsToGetValues.each(function () {
                    var inputName = $(this).attr('name');
                    if ((inputName != undefined) && (inputName.contains(nameReduct))) {
                        if (nameReduct != "[identifiant]" && nameReduct != "[quantite]") {
                            value = $(this).val();
                        }
                    }
                });
            }
            $(this).val(value);
        });

        $(element).children('div').last().find('select').each(function () {
            var valueSelected = selectsToGetValues.val();
            $(this).val(valueSelected);
        });

        $(element).children('div').find('input').each(function () {
            var name = $(this).attr('name');
            if (name != undefined) {
                if ($(this).val() && name.substring(name.lastIndexOf("[")) == "[identifiant]") {
                    var new_value = $(this).val();
                    $(this).val(new_value + "," + $(this).parent().find('.select2-container').find('.select2-chosen').text());
                }
            }
        });

        if (callback) {
            callback(bloc);
            initCollectionDeleteMouvementsFactureTemplate();
            $(document).initAdvancedElements();
            initCollectionMouvementsFactureTemplate(element, regexp_replace, callback);
        }
        return false;
    }
}

var isConformForNewLine = function (element) {
    var result = true;
    $(element).children('div').last().find('input').each(function () {
        if ($(this).attr('name') != undefined)
        {
            if (($(this).val() == null) || ($(this).val() == "")) {
                if ($(this).attr('name').indexOf('libelle') <= -1) {
                    result = false;
                }
            }
        }
    });
    $(element).children('div').last().find('select').each(function () {
        if (($(this).attr('name') != undefined) && (($(this).val() == null) || ($(this).val() == ""))) {
            result = false;
        }
    });
    return result;
}

var initCollectionMouvementsFactureTemplate = function (element, regexp_replace, callback)
{
    var lastRowInputs = $(element).children('div').last().find('input');
    var lastRowSelects = $(element).children('div').last().find('input');

    $(lastRowInputs).change(function () {
        var addNewLine = isConformForNewLine(element);

        if (addNewLine) {
            generateMouvementsFacture(element, regexp_replace, callback);
        }

    });

    $(lastRowSelects).change(function () {
        var addNewLine = isConformForNewLine(element);

        if (addNewLine) {
            generateMouvementsFacture(element, regexp_replace, callback);
        }

    });

}

var initCollectionDeleteMouvementsFactureTemplate = function ()
{
    $('.mouvements_facture_delete_row .btn_supprimer_ligne_template').on('click', function ()
    {
        var element = $(this).parent().parent().parent().parent();
        if (element.parent().children('.mvt_ligne').size() > 1) {
            $(element).remove();

        }
        return false;
    });
}

var initMouvementsFacture = function () {
    generateMouvementsFacture('#mouvementsfacture_list', /var---nbItem---/g, function (bloc) {
    });
    initCollectionMouvementsFactureTemplate('#mouvementsfacture_list', /var---nbItem---/g, function (bloc) {
    });
    initCollectionDeleteMouvementsFactureTemplate();

}

$(document).ready(function ()
{
    initMouvementsFacture();
    $('.btn-suppr-ligne').click(function () {
        $(this).parents('.row').remove();
    });
});
<commit_msg>refacto js facturation libre<commit_after>var initCollectionDeleteMouvementsFactureTemplate = function ()
{
    $('.mouvements_facture_delete_row .btn_supprimer_ligne_template').click(function ()
    {
        var element = $(this).parent().parent().parent().parent();
        if (element.parent().children('.mvt_ligne').size() > 1) {
            $(element).remove();

        }
        return false;
    });
}

$(document).ready(function ()
{
    initCollectionDeleteMouvementsFactureTemplate();
    $('.btn-suppr-ligne').click(function () {
        $(this).parents('.row').remove();
    });
});
<|endoftext|>


<commit_before><commit_msg>修复移动端提示框位置不正确的问题<commit_after><|endoftext|>