<commit_before>/*global $, EzWebExt, InterfaceFactory, StyledElements, Element, ValidationErrorManager, Wirecloud */

(function () {

    "use strict";

    /**
     * Form
     */
    var Form = function Form(fields, options) {
        var div, legend, requiredMark, buttonArea, defaultOptions;

        defaultOptions = {
            'readOnly': false,
            'buttonArea': null,
            'acceptButton': true,
            'cancelButton': true,
            'useHtmlForm': true,
            'legend': 'auto',
            'edition': false,
            'factory': Wirecloud.form.WirecloudInterfaceFactory
        };
        if (options && options.readOnly) {
            defaultOptions.acceptButton = false;
            defaultOptions.cancelButton = false;
        }
        options = EzWebExt.merge(defaultOptions, options);

        StyledElements.StyledElement.call(this, ['submit', 'cancel']);

        this.readOnly = options.readOnly;
        this.fields = {};
        this.fieldInterfaces = {};
        this.edition = options.edition;
        this.factory = options.factory;

        // Build GUI
        div = document.createElement('div');
        if (options.useHtmlForm) {
            this.wrapperElement = document.createElement('form');
            this.wrapperElement.addEventListener('submit', function (e) {
                e.preventDefault();
            }, true);
            this.wrapperElement.appendChild(div);
        } else {
            this.wrapperElement = div;
        }
        div.appendChild(this.pBuildFieldTable(fields));
        this.wrapperElement.className = "styled_form";

        // Legend
        if (options.legend === true || (!this.readOnly && options.legend !== false)) {
            legend = document.createElement('div');
            legend.className = "legend";
            requiredMark = document.createElement('span');
            requiredMark.appendChild(document.createTextNode('*'));
            requiredMark.className = 'required_mark';
            legend.appendChild(requiredMark);
            legend.appendChild(document.createTextNode('required field'));
            div.appendChild(legend);
        }

        // Mark our message div as an error msg
        this.msgElement = document.createElement('div');
        this.msgElement.className = 'msg error';
        div.appendChild(this.msgElement);
        this.pSetMsgs([]);

        if (options.buttonArea != null) {
            buttonArea = options.buttonArea;
        } else {
            buttonArea = document.createElement('div');
            buttonArea.className = 'buttons';
            div.appendChild(buttonArea);
        }

        // Accept button
        this.pAcceptHandler = EzWebExt.bind(this.pAcceptHandler, this);
        this.acceptButton = null;
        if (options.acceptButton instanceof StyledElements.StyledButton) {
            this.acceptButton = options.acceptButton;
        } else if (options.acceptButton === true) {
            this.acceptButton = new StyledElements.StyledButton({
                'usedInForm': true,
                'class': 'btn-primary',
                'text': 'Accept'
            });
        }
        if (this.acceptButton !== null) {
            this.acceptButton.addEventListener("click", this.pAcceptHandler);
            this.acceptButton.insertInto(buttonArea);
        }

        // Cancel button
        this.pCancelHandler = EzWebExt.bind(this.pCancelHandler, this);
        this.cancelButton = null;
        if (options.cancelButton instanceof StyledElements.StyledButton) {
            this.cancelButton = options.cancelButton;
        } else if (options.cancelButton === true) {
            this.cancelButton = new StyledElements.StyledButton({
                usedInForm: true,
                text: 'Cancel'
            });
        }
        if (this.cancelButton !== null) {
            this.cancelButton.addEventListener("click", this.pCancelHandler);
            this.cancelButton.insertInto(buttonArea);
        }
    };
    Form.prototype = new StyledElements.StyledElement();

    Form.prototype.pSetMsgs = function (msgs) {
        var i, wrapper;

        this.msgElement.innerHTML = '';

        if (msgs.length > 0) {
            for (i = 0; i < msgs.length; i += 1) {
                wrapper = document.createElement('p');
                EzWebExt.setTextContent(wrapper, msgs[i]);
                this.msgElement.appendChild(wrapper);
            }
            this.msgElement.style.display = '';
        } else {
            this.msgElement.style.display = 'none';
        }
    };

    Form.prototype.pBuildFieldGroups = function (fields) {
        var notebook, i, field, tab, tmp_field, tmp_input;

        notebook = new StyledElements.StyledNotebook();

        for (i = 0; i < fields.length; i += 1) {
            field = fields[i];
            tab = notebook.createTab({name: field.shortTitle, closable: false});
            if (field.nested === true) {
                tmp_field = {
                    'name': field.name,
                    'type': 'fieldset',
                    'fields': field.fields
                };
                tmp_input = this.factory.createInterface(field.name, tmp_field);

                this.fieldInterfaces[field.name] = tmp_input;
                this.fields[field.name] = tmp_field;
                tab.appendChild(tmp_input);
            } else {
                tab.appendChild(this.pBuildFieldTable(field.fields));
            }
        }

        return notebook.wrapperElement;
    };

    Form.prototype.pBuildFieldTable = function (fields) {
        var table, tbody, fieldId, field, row, cell;

        // TODO
        if (fields[0] && fields[0].type === 'group') {
            return this.pBuildFieldGroups(fields);
        }

        table = document.createElement('table');
        table.setAttribute('cellspacing', '0');
        table.setAttribute('cellpadding', '0');
        tbody = document.createElement('tbody'); // IE6 and IE7 needs a tbody to display dynamic tables
        table.appendChild(tbody);

        for (fieldId in fields) {
            if (fields.hasOwnProperty(fieldId)) {
                field = fields[fieldId];
                if ('name' in field) {
                    fieldId = field.name;
                }

                row = tbody.insertRow(-1);

                switch (field.type) {
                case 'columnLayout':
                    cell = row.insertCell(-1);
                    cell.setAttribute('colspan', 2);
                    this.pInsertColumnLayout(field, cell);
                    break;
                case 'lineLayout':
                    cell = row.insertCell(-1);
                    cell.setAttribute('colspan', 2);
                    this.pInsertLineLayout(field, cell);
                    break;
                case 'hidden':
                    row.className = "hidden";
                    this.pInsertField(fieldId, field, row);
                    break;
                default:
                    this.pInsertField(fieldId, field, row);
                }
            }
        }

        return table;
    };

    Form.prototype.pInsertColumnLayout = function (desc, wrapper) {
        var table, tbody, row, cell, i;

        table = document.createElement('table');
        table.setAttribute('cellspacing', '0');
        table.setAttribute('cellpadding', '0');
        tbody = document.createElement('tbody'); // IE6 and IE7 needs a tbody to display dynamic tables
        table.appendChild(tbody);
        row = tbody.insertRow(-1);

        for (i = 0; i < desc.columns.length; i += 1) {
            cell = row.insertCell(-1);
            cell.appendChild(this.pBuildFieldTable(desc.columns[i]));
        }
        wrapper.appendChild(table);
    };

    Form.prototype.pInsertLineLayout = function (desc, wrapper) {
        var field, fieldId, inputInterface, wrapperElement;

        for (fieldId in desc.fields) {
            if (desc.fields.hasOwnProperty(fieldId)) {
                field = desc.fields[fieldId];

                inputInterface = this.factory.createInterface(fieldId, field);
                inputInterface.insertInto(wrapper);
                // TODO
                wrapperElement = null;
                if (inputInterface.wrapperElement && inputInterface.wrapperElement.wrapperElement) {
                    wrapperElement = inputInterface.wrapperElement.wrapperElement;
                } else if (inputInterface.inputElement && inputInterface.inputElement.wrapperElement) {
                    wrapperElement = inputInterface.inputElement.wrapperElement;
                }
                if (wrapperElement) {
                    wrapperElement.style.display = 'inline-block';
                    wrapperElement.style.verticalAlign = 'middle';
                }

                this.fieldInterfaces[fieldId] = inputInterface;

                this.fields[fieldId] = field;
            }
        }
    };

    /**
     * @private
     */
    Form.prototype.pInsertField = function (fieldId, field, row) {
        var separator, hr, labelRow, labelCell, label, requiredMark, inputCell, inputInterface;

        if (field.type === 'separator') {
            separator = row.insertCell(-1);
            separator.setAttribute('colspan', '2');
            hr = document.createElement('hr');
            separator.appendChild(hr);
            return;
        }

        if (field.type === 'label') {
            labelRow = row.insertCell(-1);
            Element.extend(labelRow);
            labelRow.addClassName('label');
            if (field.url) {
                label = document.createElement('a');
                label.setAttribute("href", field.url);
                label.setAttribute("target", "_blank");
            } else {
                label = document.createElement('label');
            }
            label.appendChild(document.createTextNode(field.label));
            labelRow.appendChild(label);
            return;
        }

        // Label Cell
        labelCell = row.insertCell(-1);
        EzWebExt.addClassName(labelCell, 'label');

        label = document.createElement('label');
        EzWebExt.setTextContent(label, field.label);
        labelCell.appendChild(label);
        if (field.description != null) {
            label.setAttribute('title', field.description);
        }

        if (field.required && !this.readOnly) {
            requiredMark = document.createElement('span');
            requiredMark.appendChild(document.createTextNode('*'));
            requiredMark.className = 'required_mark';
            labelCell.appendChild(requiredMark);
        }

        // Input Cell
        inputCell = document.createElement('td');
        row.appendChild(inputCell);

        inputInterface = this.factory.createInterface(fieldId, field);
        inputInterface.insertInto(inputCell);
        if (this.readOnly || inputInterface._readOnly) {
            inputInterface.setDisabled(true);
        }

        this.fieldInterfaces[fieldId] = inputInterface;

        this.fields[fieldId] = field;
    };

    /**
     * Does extra checks for testing field validity. This method must be overwriten
     * by child classes for providing these extra checks.
     *
     * @param {Hash} fields Hash with the current fields
     */
    Form.prototype.extraValidation = function (fields) {
        //Parent implementation, allways true if no redefined by child class!
        return [];
    };

    Form.prototype.getData = function () {
        var value, data, fieldId, field;

        data = {};
        for (fieldId in this.fieldInterfaces) {
            if (this.fieldInterfaces.hasOwnProperty(fieldId)) {
                field = this.fieldInterfaces[fieldId];
                value = field.getValue();

                if (this.edition || field.required || value !== "") {
                    data[fieldId] = value;
                }
            }
        }
        return data;
    };

    Form.prototype.setData = function (data) {
        var field, fieldId;

        if (typeof data !== 'object' && typeof data !== 'undefined') {
            throw new TypeError();
        }

        if (data == null) {
            data = {};
        }

        for (fieldId in this.fieldInterfaces) {
            if (this.fieldInterfaces.hasOwnProperty(fieldId)) {
                field = this.fieldInterfaces[fieldId];
                field._setValue(data[fieldId]);
            }
        }
    };

    Form.prototype.is_valid = function () {
        // Validate input fields
        var fieldId, extraErrorMsgs, errorMsgs,
            validationManager = new ValidationErrorManager();
        for (fieldId in this.fieldInterfaces) {
            if (this.fieldInterfaces.hasOwnProperty(fieldId)) {
                validationManager.validate(this.fieldInterfaces[fieldId]);
            }
        }

        // Extra validations
        extraErrorMsgs = this.extraValidation(this.fields);

        // Build Error Message
        errorMsgs = validationManager.toHTML();

        if (extraErrorMsgs !== null) {
            errorMsgs = errorMsgs.concat(extraErrorMsgs);
        }

        // Show error message if needed
        this.pSetMsgs(errorMsgs);
        return errorMsgs.length === 0;
    };

    /**
     * @private
     */
    Form.prototype.pAcceptHandler = function (e) {
        if (this.is_valid()) {
            var data = this.getData();
            this.events.submit.dispatch(this, data);
        }
    };

    /**
     * @private
     */
    Form.prototype.pCancelHandler = function (e) {
        this.events.cancel.dispatch(this);
    };

    Form.prototype.reset = function () {
        var fieldId, field;
        for (fieldId in this.fields) {
            if (this.fields.hasOwnProperty(fieldId)) {
                field = this.fieldInterfaces[fieldId];
                field.reset();
            }
        }
        this.pSetMsgs([]);
    };

    Form.prototype.normalSubmit = function (method, url, options) {
        options = options ? options : {};

        this.wrapperElement.method = method;
        this.wrapperElement.action = url;

        if (options.enctype) {
            this.wrapperElement.setAttribute('enctype', options.enctype);
        } else {
            this.wrapperElement.removeAttribute('enctype');
        }

        if (options.target) {
            this.wrapperElement.setAttribute('target', options.target);
        } else {
            this.wrapperElement.removeAttribute('target');
        }

        this.wrapperElement.submit();
    };

    Form.prototype.destroy = function () {
        this.pAcceptHandler = null;
        this.pCancelHandler = null;
    };

    window.Form = Form;
})();
<commit_msg>Add translation support to Form.js<commit_after>/*global $, EzWebExt, gettext, InterfaceFactory, StyledElements, Element, ValidationErrorManager, Wirecloud */

(function () {

    "use strict";

    /**
     * Form
     */
    var Form = function Form(fields, options) {
        var div, legend, requiredMark, buttonArea, defaultOptions;

        defaultOptions = {
            'readOnly': false,
            'buttonArea': null,
            'acceptButton': true,
            'cancelButton': true,
            'useHtmlForm': true,
            'legend': 'auto',
            'edition': false,
            'factory': Wirecloud.form.WirecloudInterfaceFactory
        };
        if (options && options.readOnly) {
            defaultOptions.acceptButton = false;
            defaultOptions.cancelButton = false;
        }
        options = EzWebExt.merge(defaultOptions, options);

        StyledElements.StyledElement.call(this, ['submit', 'cancel']);

        this.readOnly = options.readOnly;
        this.fields = {};
        this.fieldInterfaces = {};
        this.edition = options.edition;
        this.factory = options.factory;

        // Build GUI
        div = document.createElement('div');
        if (options.useHtmlForm) {
            this.wrapperElement = document.createElement('form');
            this.wrapperElement.addEventListener('submit', function (e) {
                e.preventDefault();
            }, true);
            this.wrapperElement.appendChild(div);
        } else {
            this.wrapperElement = div;
        }
        div.appendChild(this.pBuildFieldTable(fields));
        this.wrapperElement.className = "styled_form";

        // Legend
        if (options.legend === true || (!this.readOnly && options.legend !== false)) {
            legend = document.createElement('div');
            legend.className = "legend";
            requiredMark = document.createElement('span');
            requiredMark.appendChild(document.createTextNode('*'));
            requiredMark.className = 'required_mark';
            legend.appendChild(requiredMark);
            legend.appendChild(document.createTextNode('required field'));
            div.appendChild(legend);
        }

        // Mark our message div as an error msg
        this.msgElement = document.createElement('div');
        this.msgElement.className = 'msg error';
        div.appendChild(this.msgElement);
        this.pSetMsgs([]);

        if (options.buttonArea != null) {
            buttonArea = options.buttonArea;
        } else {
            buttonArea = document.createElement('div');
            buttonArea.className = 'buttons';
            div.appendChild(buttonArea);
        }

        // Accept button
        this.pAcceptHandler = EzWebExt.bind(this.pAcceptHandler, this);
        this.acceptButton = null;
        if (options.acceptButton instanceof StyledElements.StyledButton) {
            this.acceptButton = options.acceptButton;
        } else if (options.acceptButton === true) {
            this.acceptButton = new StyledElements.StyledButton({
                'usedInForm': true,
                'class': 'btn-primary',
                'text': gettext('Accept')
            });
        }
        if (this.acceptButton !== null) {
            this.acceptButton.addEventListener("click", this.pAcceptHandler);
            this.acceptButton.insertInto(buttonArea);
        }

        // Cancel button
        this.pCancelHandler = EzWebExt.bind(this.pCancelHandler, this);
        this.cancelButton = null;
        if (options.cancelButton instanceof StyledElements.StyledButton) {
            this.cancelButton = options.cancelButton;
        } else if (options.cancelButton === true) {
            this.cancelButton = new StyledElements.StyledButton({
                usedInForm: true,
                text: gettext('Cancel')
            });
        }
        if (this.cancelButton !== null) {
            this.cancelButton.addEventListener("click", this.pCancelHandler);
            this.cancelButton.insertInto(buttonArea);
        }
    };
    Form.prototype = new StyledElements.StyledElement();

    Form.prototype.pSetMsgs = function (msgs) {
        var i, wrapper;

        this.msgElement.innerHTML = '';

        if (msgs.length > 0) {
            for (i = 0; i < msgs.length; i += 1) {
                wrapper = document.createElement('p');
                EzWebExt.setTextContent(wrapper, msgs[i]);
                this.msgElement.appendChild(wrapper);
            }
            this.msgElement.style.display = '';
        } else {
            this.msgElement.style.display = 'none';
        }
    };

    Form.prototype.pBuildFieldGroups = function (fields) {
        var notebook, i, field, tab, tmp_field, tmp_input;

        notebook = new StyledElements.StyledNotebook();

        for (i = 0; i < fields.length; i += 1) {
            field = fields[i];
            tab = notebook.createTab({name: field.shortTitle, closable: false});
            if (field.nested === true) {
                tmp_field = {
                    'name': field.name,
                    'type': 'fieldset',
                    'fields': field.fields
                };
                tmp_input = this.factory.createInterface(field.name, tmp_field);

                this.fieldInterfaces[field.name] = tmp_input;
                this.fields[field.name] = tmp_field;
                tab.appendChild(tmp_input);
            } else {
                tab.appendChild(this.pBuildFieldTable(field.fields));
            }
        }

        return notebook.wrapperElement;
    };

    Form.prototype.pBuildFieldTable = function (fields) {
        var table, tbody, fieldId, field, row, cell;

        // TODO
        if (fields[0] && fields[0].type === 'group') {
            return this.pBuildFieldGroups(fields);
        }

        table = document.createElement('table');
        table.setAttribute('cellspacing', '0');
        table.setAttribute('cellpadding', '0');
        tbody = document.createElement('tbody'); // IE6 and IE7 needs a tbody to display dynamic tables
        table.appendChild(tbody);

        for (fieldId in fields) {
            if (fields.hasOwnProperty(fieldId)) {
                field = fields[fieldId];
                if ('name' in field) {
                    fieldId = field.name;
                }

                row = tbody.insertRow(-1);

                switch (field.type) {
                case 'columnLayout':
                    cell = row.insertCell(-1);
                    cell.setAttribute('colspan', 2);
                    this.pInsertColumnLayout(field, cell);
                    break;
                case 'lineLayout':
                    cell = row.insertCell(-1);
                    cell.setAttribute('colspan', 2);
                    this.pInsertLineLayout(field, cell);
                    break;
                case 'hidden':
                    row.className = "hidden";
                    this.pInsertField(fieldId, field, row);
                    break;
                default:
                    this.pInsertField(fieldId, field, row);
                }
            }
        }

        return table;
    };

    Form.prototype.pInsertColumnLayout = function (desc, wrapper) {
        var table, tbody, row, cell, i;

        table = document.createElement('table');
        table.setAttribute('cellspacing', '0');
        table.setAttribute('cellpadding', '0');
        tbody = document.createElement('tbody'); // IE6 and IE7 needs a tbody to display dynamic tables
        table.appendChild(tbody);
        row = tbody.insertRow(-1);

        for (i = 0; i < desc.columns.length; i += 1) {
            cell = row.insertCell(-1);
            cell.appendChild(this.pBuildFieldTable(desc.columns[i]));
        }
        wrapper.appendChild(table);
    };

    Form.prototype.pInsertLineLayout = function (desc, wrapper) {
        var field, fieldId, inputInterface, wrapperElement;

        for (fieldId in desc.fields) {
            if (desc.fields.hasOwnProperty(fieldId)) {
                field = desc.fields[fieldId];

                inputInterface = this.factory.createInterface(fieldId, field);
                inputInterface.insertInto(wrapper);
                // TODO
                wrapperElement = null;
                if (inputInterface.wrapperElement && inputInterface.wrapperElement.wrapperElement) {
                    wrapperElement = inputInterface.wrapperElement.wrapperElement;
                } else if (inputInterface.inputElement && inputInterface.inputElement.wrapperElement) {
                    wrapperElement = inputInterface.inputElement.wrapperElement;
                }
                if (wrapperElement) {
                    wrapperElement.style.display = 'inline-block';
                    wrapperElement.style.verticalAlign = 'middle';
                }

                this.fieldInterfaces[fieldId] = inputInterface;

                this.fields[fieldId] = field;
            }
        }
    };

    /**
     * @private
     */
    Form.prototype.pInsertField = function (fieldId, field, row) {
        var separator, hr, labelRow, labelCell, label, requiredMark, inputCell, inputInterface;

        if (field.type === 'separator') {
            separator = row.insertCell(-1);
            separator.setAttribute('colspan', '2');
            hr = document.createElement('hr');
            separator.appendChild(hr);
            return;
        }

        if (field.type === 'label') {
            labelRow = row.insertCell(-1);
            Element.extend(labelRow);
            labelRow.addClassName('label');
            if (field.url) {
                label = document.createElement('a');
                label.setAttribute("href", field.url);
                label.setAttribute("target", "_blank");
            } else {
                label = document.createElement('label');
            }
            label.appendChild(document.createTextNode(field.label));
            labelRow.appendChild(label);
            return;
        }

        // Label Cell
        labelCell = row.insertCell(-1);
        EzWebExt.addClassName(labelCell, 'label');

        label = document.createElement('label');
        EzWebExt.setTextContent(label, field.label);
        labelCell.appendChild(label);
        if (field.description != null) {
            label.setAttribute('title', field.description);
        }

        if (field.required && !this.readOnly) {
            requiredMark = document.createElement('span');
            requiredMark.appendChild(document.createTextNode('*'));
            requiredMark.className = 'required_mark';
            labelCell.appendChild(requiredMark);
        }

        // Input Cell
        inputCell = document.createElement('td');
        row.appendChild(inputCell);

        inputInterface = this.factory.createInterface(fieldId, field);
        inputInterface.insertInto(inputCell);
        if (this.readOnly || inputInterface._readOnly) {
            inputInterface.setDisabled(true);
        }

        this.fieldInterfaces[fieldId] = inputInterface;

        this.fields[fieldId] = field;
    };

    /**
     * Does extra checks for testing field validity. This method must be overwriten
     * by child classes for providing these extra checks.
     *
     * @param {Hash} fields Hash with the current fields
     */
    Form.prototype.extraValidation = function (fields) {
        //Parent implementation, allways true if no redefined by child class!
        return [];
    };

    Form.prototype.getData = function () {
        var value, data, fieldId, field;

        data = {};
        for (fieldId in this.fieldInterfaces) {
            if (this.fieldInterfaces.hasOwnProperty(fieldId)) {
                field = this.fieldInterfaces[fieldId];
                value = field.getValue();

                if (this.edition || field.required || value !== "") {
                    data[fieldId] = value;
                }
            }
        }
        return data;
    };

    Form.prototype.setData = function (data) {
        var field, fieldId;

        if (typeof data !== 'object' && typeof data !== 'undefined') {
            throw new TypeError();
        }

        if (data == null) {
            data = {};
        }

        for (fieldId in this.fieldInterfaces) {
            if (this.fieldInterfaces.hasOwnProperty(fieldId)) {
                field = this.fieldInterfaces[fieldId];
                field._setValue(data[fieldId]);
            }
        }
    };

    Form.prototype.is_valid = function () {
        // Validate input fields
        var fieldId, extraErrorMsgs, errorMsgs,
            validationManager = new ValidationErrorManager();
        for (fieldId in this.fieldInterfaces) {
            if (this.fieldInterfaces.hasOwnProperty(fieldId)) {
                validationManager.validate(this.fieldInterfaces[fieldId]);
            }
        }

        // Extra validations
        extraErrorMsgs = this.extraValidation(this.fields);

        // Build Error Message
        errorMsgs = validationManager.toHTML();

        if (extraErrorMsgs !== null) {
            errorMsgs = errorMsgs.concat(extraErrorMsgs);
        }

        // Show error message if needed
        this.pSetMsgs(errorMsgs);
        return errorMsgs.length === 0;
    };

    /**
     * @private
     */
    Form.prototype.pAcceptHandler = function (e) {
        if (this.is_valid()) {
            var data = this.getData();
            this.events.submit.dispatch(this, data);
        }
    };

    /**
     * @private
     */
    Form.prototype.pCancelHandler = function (e) {
        this.events.cancel.dispatch(this);
    };

    Form.prototype.reset = function () {
        var fieldId, field;
        for (fieldId in this.fields) {
            if (this.fields.hasOwnProperty(fieldId)) {
                field = this.fieldInterfaces[fieldId];
                field.reset();
            }
        }
        this.pSetMsgs([]);
    };

    Form.prototype.normalSubmit = function (method, url, options) {
        options = options ? options : {};

        this.wrapperElement.method = method;
        this.wrapperElement.action = url;

        if (options.enctype) {
            this.wrapperElement.setAttribute('enctype', options.enctype);
        } else {
            this.wrapperElement.removeAttribute('enctype');
        }

        if (options.target) {
            this.wrapperElement.setAttribute('target', options.target);
        } else {
            this.wrapperElement.removeAttribute('target');
        }

        this.wrapperElement.submit();
    };

    Form.prototype.destroy = function () {
        this.pAcceptHandler = null;
        this.pCancelHandler = null;
    };

    window.Form = Form;
})();
<|endoftext|>


<commit_before>define([
    'q',
    'knockout',
    'util/galaxy',
    'util/form',
    'store/Stacks',
    'store/StackHosts',
    'store/StackSecurityGroups',
    'store/StackActions',
    'store/Profiles',
    'store/InstanceSizes',
    'store/Blueprints',
    'store/BlueprintHosts',
    'store/BlueprintComponents',
    'api/api'
],
function (Q, ko, $galaxy, formutils, StackStore, StackHostStore, StackSecurityGroupStore, StackActionStore, ProfileStore, InstanceSizeStore, BlueprintStore, BlueprintHostStore, BlueprintComponentStore, API) {
    var vm = function () {
        var self = this;

        /*
         *  ==================================================================================
         *   V I E W   V A R I A B L E S
         *  ==================================================================================
        */
        self.selectedBlueprint = ko.observable(null);
        self.blueprintHostDefinitions = ko.observable(null);
        self.selectedStack = ko.observable(null);
        self.stackTitle = ko.observable();
        self.blueprintTitle = ko.observable();
        self.blueprintProperties = ko.observable();
        self.stackPropertiesStringified = ko.observable();
        self.editMode = ko.observable('create');

        self.historicalLogText = ko.observable();
        self.launchLogText = ko.observable();
        self.orchestrationLogText = ko.observable();
        self.orchestrationErrorLogText = ko.observable();
        self.provisioningLogText = ko.observable();
        self.provisioningErrorLogText = ko.observable();
        self.historicalLogs = ko.observableArray([]);

        self.StackStore = StackStore;
        self.StackHostStore = StackHostStore;
        self.StackSecurityGroupStore = StackSecurityGroupStore;
        self.StackActionStore = StackActionStore;
        self.ProfileStore = ProfileStore;
        self.InstanceSizeStore = InstanceSizeStore;
        self.BlueprintHostStore = BlueprintHostStore;
        self.BlueprintComponentStore = BlueprintComponentStore;
        self.BlueprintStore = BlueprintStore;
        self.$galaxy = $galaxy;

        /*
         *  ==================================================================================
         *   R E G I S T R A T I O N   S E C T I O N
         *  ==================================================================================
        */
        self.id = 'stack.logs';
        self.templatePath = 'stack.logs.html';
        self.domBindingId = '#stack-logs';

        try {
            $galaxy.join(self);
        } catch (ex) {
            console.log(ex);
        }

        /*
         *  ==================================================================================
         *   E V E N T   S U B S C R I P T I O N S
         *  ==================================================================================
         */
        $galaxy.network.subscribe(self.id + '.docked', function (data) {
            BlueprintStore.populate().then(function () {
                return StackStore.populate();
            }).then(function () {
                self.init(data);
            });
        });

        /*
         *  ==================================================================================
         *   V I E W   M E T H O D S
         *  ==================================================================================
         */

        self.init = function (data) {
            var blueprint = null;
            var stack = null;
            var stackHosts = [];

            // Automatically select the first tab in the view so that if the user had
            // clicked on the logs or orchestraton tab previously, it doesn't end up
            // showing a blank view
            $('#stack-tabs a[id="logs"]').tab('show');

            self.stackPropertiesStringified('');

            if (data.hasOwnProperty('stack')) {
                self.editMode('update');

                stack = StackStore.collection().filter(function (s) {
                    return s.id === parseInt(data.stack, 10);
                })[0];

                self.stackTitle(stack.title);

                API.Stacks.getLogs(stack).then(function (logs) {
                    self.logObject = logs;
                    self.logObject.historical.forEach(function(logrecord) {
                        urlarr = logrecord.split('/');
                        self.historicalLogs.push({
                            name: urlarr[urlarr.length-1],
                            url: logrecord
                        });
                    });
                    self.getLogs();
                }).catch(function(error) {
                    console.error(error);
                }).done();

            } else {
                $galaxy.transport('stack.list');
            }

            self.selectedStack(stack);
        };

        self.goToTab = function (obj, evt) {
            var tab=evt.target.id;
            $galaxy.transport({
                location: 'stack.'+tab,
                payload: {
                    stack: self.selectedStack().id
                }
            });
        };

        self.getStatusType = function(status) {
            switch(status) {
                case 'waiting':
                    return 'info';
                case 'running':
                    return 'warning';
                case 'finished':
                    return 'success';
                default:
                    return 'default';
            }
	    };

        self.getLogs = function () {
            // Query param ?tail=20&head=20

            var promises = [];
            var historical = [];

            self.logObject.historical.forEach(function (logrecord) {
                promises[promises.length] = API.Stacks.getLog(logrecord).then(function (log) {
                    historical[historical.length] = log;
                });
            });

            Q.all(promises).then(function () {
                $('#historical_logs').text(historical.join(''));
            }).catch(function (error) {
                console.log('error', error.toString());
            }).done();

            API.Stacks.getLog(self.logObject.latest.launch).then(function (log) {
                $('#launch_logs').text(log);
            }).catch(function (error) {
                $('#launch_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest.orchestration).then(function (log) {
                $('#orchestration_logs').text(log);
            }).catch(function (error) {
                $('#orchestration_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest["orchestration-error"]).then(function (log) {
                $('#orchestration_error_logs').text(log);
            }).catch(function (error) {
                $('#orchestration_error_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest.provisioning).then(function (log) {
                $('#provisioning_logs').text(log);
            }).catch(function (error) {
                $('#provisioning_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest["provisioning-error"]).then(function (log) {
                $('#provisioning_error_logs').text(log);
            }).catch(function (error) {
                $('#provisioning_error_logs').text(error);
            });
        };

    };
    return new vm();
});
<commit_msg>No duplication of logs<commit_after>define([
    'q',
    'knockout',
    'util/galaxy',
    'util/form',
    'store/Stacks',
    'store/StackHosts',
    'store/StackSecurityGroups',
    'store/StackActions',
    'store/Profiles',
    'store/InstanceSizes',
    'store/Blueprints',
    'store/BlueprintHosts',
    'store/BlueprintComponents',
    'api/api'
],
function (Q, ko, $galaxy, formutils, StackStore, StackHostStore, StackSecurityGroupStore, StackActionStore, ProfileStore, InstanceSizeStore, BlueprintStore, BlueprintHostStore, BlueprintComponentStore, API) {
    var vm = function () {
        var self = this;

        /*
         *  ==================================================================================
         *   V I E W   V A R I A B L E S
         *  ==================================================================================
        */
        self.selectedBlueprint = ko.observable(null);
        self.blueprintHostDefinitions = ko.observable(null);
        self.selectedStack = ko.observable(null);
        self.stackTitle = ko.observable();
        self.blueprintTitle = ko.observable();
        self.blueprintProperties = ko.observable();
        self.stackPropertiesStringified = ko.observable();
        self.editMode = ko.observable('create');

        self.historicalLogText = ko.observable();
        self.launchLogText = ko.observable();
        self.orchestrationLogText = ko.observable();
        self.orchestrationErrorLogText = ko.observable();
        self.provisioningLogText = ko.observable();
        self.provisioningErrorLogText = ko.observable();
        self.historicalLogs = ko.observableArray([]);

        self.StackStore = StackStore;
        self.StackHostStore = StackHostStore;
        self.StackSecurityGroupStore = StackSecurityGroupStore;
        self.StackActionStore = StackActionStore;
        self.ProfileStore = ProfileStore;
        self.InstanceSizeStore = InstanceSizeStore;
        self.BlueprintHostStore = BlueprintHostStore;
        self.BlueprintComponentStore = BlueprintComponentStore;
        self.BlueprintStore = BlueprintStore;
        self.$galaxy = $galaxy;

        /*
         *  ==================================================================================
         *   R E G I S T R A T I O N   S E C T I O N
         *  ==================================================================================
        */
        self.id = 'stack.logs';
        self.templatePath = 'stack.logs.html';
        self.domBindingId = '#stack-logs';

        try {
            $galaxy.join(self);
        } catch (ex) {
            console.log(ex);
        }

        /*
         *  ==================================================================================
         *   E V E N T   S U B S C R I P T I O N S
         *  ==================================================================================
         */
        $galaxy.network.subscribe(self.id + '.docked', function (data) {
            BlueprintStore.populate().then(function () {
                return StackStore.populate();
            }).then(function () {
                self.init(data);
            });
        });

        /*
         *  ==================================================================================
         *   V I E W   M E T H O D S
         *  ==================================================================================
         */

        self.init = function (data) {
            var blueprint = null;
            var stack = null;
            var stackHosts = [];

            // Automatically select the first tab in the view so that if the user had
            // clicked on the logs or orchestraton tab previously, it doesn't end up
            // showing a blank view
            $('#stack-tabs a[id="logs"]').tab('show');

            self.stackPropertiesStringified('');

            if (data.hasOwnProperty('stack')) {
                self.editMode('update');

                stack = StackStore.collection().filter(function (s) {
                    return s.id === parseInt(data.stack, 10);
                })[0];

                self.stackTitle(stack.title);

                API.Stacks.getLogs(stack).then(function (logs) {
                    self.logObject = logs;
                    self.historicalLogs.removeAll();
                    self.logObject.historical.forEach(function(logrecord) {
                        urlarr = logrecord.split('/');
                        self.historicalLogs.push({
                            name: urlarr[urlarr.length-1],
                            url: logrecord
                        });
                    });
                    self.getLogs();
                }).catch(function(error) {
                    console.error(error);
                }).done();

            } else {
                $galaxy.transport('stack.list');
            }

            self.selectedStack(stack);
        };

        self.goToTab = function (obj, evt) {
            var tab=evt.target.id;
            $galaxy.transport({
                location: 'stack.'+tab,
                payload: {
                    stack: self.selectedStack().id
                }
            });
        };

        self.getStatusType = function(status) {
            switch(status) {
                case 'waiting':
                    return 'info';
                case 'running':
                    return 'warning';
                case 'finished':
                    return 'success';
                default:
                    return 'default';
            }
	    };

        self.getLogs = function () {
            // Query param ?tail=20&head=20

            var promises = [];
            var historical = [];

            self.logObject.historical.forEach(function (logrecord) {
                promises[promises.length] = API.Stacks.getLog(logrecord).then(function (log) {
                    historical[historical.length] = log;
                });
            });

            Q.all(promises).then(function () {
                $('#historical_logs').text(historical.join(''));
            }).catch(function (error) {
                console.log('error', error.toString());
            }).done();

            API.Stacks.getLog(self.logObject.latest.launch).then(function (log) {
                $('#launch_logs').text(log);
            }).catch(function (error) {
                $('#launch_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest.orchestration).then(function (log) {
                $('#orchestration_logs').text(log);
            }).catch(function (error) {
                $('#orchestration_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest["orchestration-error"]).then(function (log) {
                $('#orchestration_error_logs').text(log);
            }).catch(function (error) {
                $('#orchestration_error_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest.provisioning).then(function (log) {
                $('#provisioning_logs').text(log);
            }).catch(function (error) {
                $('#provisioning_logs').text(error);
            });

            API.Stacks.getLog(self.logObject.latest["provisioning-error"]).then(function (log) {
                $('#provisioning_error_logs').text(log);
            }).catch(function (error) {
                $('#provisioning_error_logs').text(error);
            });
        };

    };
    return new vm();
});
<|endoftext|>


<commit_before>var fs         = require('fs')
  , util       = require('util')
  , exec       = require('child_process').exec
  , underscore = require('underscore')

var messageGenerator = exports

messageGenerator.template = function(packageName, messages, callback) {
  var packageData = {
    packageName: packageName
  , templatedMessages: []
  }

  fs.readFile(__dirname + '/message_template.js', 'utf8', function(error, template) {
    if (error) {
      callback(error)
    }
    else {
      for (var i = 0; i < messages.length; i++) {
        var messageData = messages[i]
        var output      = underscore.template(template, messageData)
        packageData.templatedMessages.push(output)
      }

      fs.readFile(__dirname + '/package_template.js', 'utf8', function(error, template) {
        if (error) {
          callback(error)
        }
        else {
          var output = underscore.template(template, packageData)
          callback(error, output)
        }
      })
    }
  })
}

messageGenerator.createFromPackage = function(packageName, callback) {
  var that = this

  var messages = []
  var createFromMessageTypes = function(messageTypes) {
    for (var i = 0; i < messageTypes.length; i++) {
      var messageType = messageTypes[i]
      that.createFromMessageType(messageType, function(error, message) {
        if (error) {
          callback(error)
        }
        else {
          messages.push(message)
          if (messages.length === messageTypes.length) {
            callback(error, messages)
          }
        }
      })
    }
  }

  getAllMessageTypes(packageName, function(error, messageTypes) {
    if (error) {
      callback(error)
    }
    else {
      createFromMessageTypes(messageTypes)
    }
  })
}

messageGenerator.createFromMessageType = function(messageType, callback) {
  var that = this

  getMessageDefinition(messageType, function(error, definition) {
    that.createFromDefinition(definition, function(error, message) {

      var messageTypeComponents = messageType.split('/')
      message.packageName       = messageTypeComponents[0]
      message.messageName       = messageTypeComponents[1]
      message.attributes.type   = messageType

      getMessageMd5Sum(messageType, function(error, md5sum) {
        if (error) {
          callback(error)
        }
        else {
          message.attributes.md5sum = md5sum
          callback(error, message)
        }
      })
    })
  })
}

messageGenerator.createFromDefinition = function(definition, callback) {
  var message = {
    attributes: {
      fieldOrder: []
    , fieldTypes: {}
    }
  }

  // Reads message definition line by line, adding property to object
  var lines = definition.split('\n')
  for (var i = 0; i < lines.length; i++) {
    // Line format:
    // type name
    // or
    // type name=value
    var line            = lines[i].trim()
      , lineComponents  = line.split('=', 2)
      , fieldComponents = lineComponents[0].split(' ', 2)
      , fieldType       = fieldComponents[0]
      , fieldName       = fieldComponents[1]
      , fieldValue      = null

    // A constant value was specified for this field
    if (lineComponents.length > 1) {

      // Converts from String to type specified by message
      fieldValue = lineComponents[1].trim()
      if (fieldType.indexOf('int') >= 0) {
        fieldValue = parseInt(fieldValue)
      }
      else if (fieldType.indexOf('float') >= 0) {
        fieldValue = parseFloat(fieldValue)
      }
      else if (fieldType === 'bool') {
        if (fieldValue === '1') {
          fieldValue = true
        }
        else {
          fieldValue = false
        }
      }
    }

    message.attributes[fieldName] = fieldValue
    message.attributes.fieldTypes[fieldName] = fieldType
    message.attributes.fieldOrder.push(fieldName)
  }

  callback(null, message)
}

function getAllMessageTypes(packageName, callback) {
  var packageCommand = 'rosmsg package ' + packageName
  var child = exec(packageCommand, function (error, stdout, stderr) {
    if (error) {
      callback(error)
    }
    else {
      var cleanedOutput = cleanText(stdout)
        , messageTypes  = cleanedOutput.split('\n')
      callback(error, messageTypes)
    }
  })
}

function getMessageDefinition(messageType, callback) {
  var showMessageCommand = 'rosmsg show ' + messageType
  var child = exec(showMessageCommand, function (error, stdout, stderr) {
    var cleanedOutput = cleanText(stdout)
    callback(error, cleanedOutput)
  })
}

function getMessageMd5Sum(messageType, callback) {
  var md5SumCommand = 'rosmsg md5 ' + messageType
  var child = exec(md5SumCommand, function (error, stdout, stderr) {
    var cleanedOutput = cleanText(stdout)
    callback(error, cleanedOutput)
  })
}

function cleanText(text) {
  // Removes empty lines
  var validLines = []
  var lines = text.split('\n')
  for (var i = 0; i < lines.length; i++) {
    var line = lines[i].trim()
    if (line.length > 0) {
      validLines.push(line)
    }
  }
  var cleanedText = validLines.join('\n')

  return cleanedText
}

<commit_msg>Handles empty message definitions (like std_msgs/Empty)<commit_after>var fs         = require('fs')
  , util       = require('util')
  , exec       = require('child_process').exec
  , underscore = require('underscore')

var messageGenerator = exports

messageGenerator.template = function(packageName, messages, callback) {
  var packageData = {
    packageName: packageName
  , templatedMessages: []
  }

  fs.readFile(__dirname + '/message_template.js', 'utf8', function(error, template) {
    if (error) {
      callback(error)
    }
    else {
      for (var i = 0; i < messages.length; i++) {
        var messageData = messages[i]
        var output      = underscore.template(template, messageData)
        packageData.templatedMessages.push(output)
      }

      fs.readFile(__dirname + '/package_template.js', 'utf8', function(error, template) {
        if (error) {
          callback(error)
        }
        else {
          var output = underscore.template(template, packageData)
          callback(error, output)
        }
      })
    }
  })
}

messageGenerator.createFromPackage = function(packageName, callback) {
  var that = this

  var messages = []
  var createFromMessageTypes = function(messageTypes) {
    for (var i = 0; i < messageTypes.length; i++) {
      var messageType = messageTypes[i]
      that.createFromMessageType(messageType, function(error, message) {
        if (error) {
          callback(error)
        }
        else {
          messages.push(message)
          if (messages.length === messageTypes.length) {
            callback(error, messages)
          }
        }
      })
    }
  }

  getAllMessageTypes(packageName, function(error, messageTypes) {
    if (error) {
      callback(error)
    }
    else {
      createFromMessageTypes(messageTypes)
    }
  })
}

messageGenerator.createFromMessageType = function(messageType, callback) {
  var that = this

  getMessageDefinition(messageType, function(error, definition) {
    that.createFromDefinition(definition, function(error, message) {

      var messageTypeComponents = messageType.split('/')
      message.packageName       = messageTypeComponents[0]
      message.messageName       = messageTypeComponents[1]
      message.attributes.type   = messageType

      getMessageMd5Sum(messageType, function(error, md5sum) {
        if (error) {
          callback(error)
        }
        else {
          message.attributes.md5sum = md5sum
          callback(error, message)
        }
      })
    })
  })
}

messageGenerator.createFromDefinition = function(definition, callback) {
  var message = {
    attributes: {
      fieldOrder: []
    , fieldTypes: {}
    }
  }

  // Reads message definition line by line, adding property to object
  var lines = definition.split('\n')
  for (var i = 0; i < lines.length; i++) {
    // Line format:
    // type name
    // or
    // type name=value
    var line            = lines[i].trim()
      , lineComponents  = line.split('=', 2)
      , fieldComponents = lineComponents[0].split(' ', 2)
      , fieldType       = fieldComponents[0]
      , fieldName       = fieldComponents[1]
      , fieldValue      = null

    if (fieldName !== undefined) {
      // A constant value was specified for this field
      if (lineComponents.length > 1) {

        // Converts from String to type specified by message
        fieldValue = lineComponents[1].trim()
        if (fieldType.indexOf('int') >= 0) {
          fieldValue = parseInt(fieldValue)
        }
        else if (fieldType.indexOf('float') >= 0) {
          fieldValue = parseFloat(fieldValue)
        }
        else if (fieldType === 'bool') {
          if (fieldValue === '1') {
            fieldValue = true
          }
          else {
            fieldValue = false
          }
        }
      }

      message.attributes[fieldName] = fieldValue
      message.attributes.fieldTypes[fieldName] = fieldType
      message.attributes.fieldOrder.push(fieldName)
    }
  }

  callback(null, message)
}

function getAllMessageTypes(packageName, callback) {
  var packageCommand = 'rosmsg package ' + packageName
  var child = exec(packageCommand, function (error, stdout, stderr) {
    if (error) {
      callback(error)
    }
    else {
      var cleanedOutput = cleanText(stdout)
        , messageTypes  = cleanedOutput.split('\n')
      callback(error, messageTypes)
    }
  })
}

function getMessageDefinition(messageType, callback) {
  var showMessageCommand = 'rosmsg show ' + messageType
  var child = exec(showMessageCommand, function (error, stdout, stderr) {
    var cleanedOutput = cleanText(stdout)
    callback(error, cleanedOutput)
  })
}

function getMessageMd5Sum(messageType, callback) {
  var md5SumCommand = 'rosmsg md5 ' + messageType
  var child = exec(md5SumCommand, function (error, stdout, stderr) {
    var cleanedOutput = cleanText(stdout)
    callback(error, cleanedOutput)
  })
}

function cleanText(text) {
  // Removes empty lines
  var validLines = []
  var lines = text.split('\n')
  for (var i = 0; i < lines.length; i++) {
    var line = lines[i].trim()
    if (line.length > 0) {
      validLines.push(line)
    }
  }
  var cleanedText = validLines.join('\n')

  return cleanedText
}

<|endoftext|>


<commit_before>var methods = {};

methods.setRelated = function(relationName, value) {};

methods.getRelated = function(relationName) {
  var doc = this;
  var Class = doc.constructor;

  // If there is already a reference to the relation object(s) stored in the
  // "_references" object then we can take it without looking in collection.
  if (_.has(this._references, relationName)) {
    return this._references[relationName];
  }

  // Look for the relation definition.
  var relation = Class.getRelation(relationName);
  if (!relation) {
    return;
  }

  // Get a collection defined in the relation.
  var ForeignClass = Astro.classes[relation.class];
  var ForeignCollection = ForeignClass.getCollection();

  // Prepare selector to select only these documents that much the relation.
  var selector = {};
  selector[relation.foreign] = this.get(relation.local);

  // Get a related object.
  var related;
  if (relation.type === 'one') {
    related = ForeignCollection.findOne(selector);
  } else if (relation.type === 'many') {
    related = ForeignCollection.find(selector);
  }

  // Assing the related object to the "_references" object for further use.
  return this._references[relationName] = related;
};

_.extend(Astro.BaseClass.prototype, methods);
<commit_msg>Use the "Astro.getClass" method<commit_after>var methods = {};

methods.setRelated = function(relationName, value) {};

methods.getRelated = function(relationName) {
  var doc = this;
  var Class = doc.constructor;

  // If there is already a reference to the relation object(s) stored in the
  // "_references" object then we can take it without looking in collection.
  if (_.has(this._references, relationName)) {
    return this._references[relationName];
  }

  // Look for the relation definition.
  var relation = Class.getRelation(relationName);
  if (!relation) {
    return;
  }

  // Get a collection defined in the relation.
  var ForeignClass = Astro.getClass(relation.class);
  var ForeignCollection = ForeignClass.getCollection();

  // Prepare selector to select only these documents that much the relation.
  var selector = {};
  selector[relation.foreign] = this.get(relation.local);

  // Get a related object.
  var related;
  if (relation.type === 'one') {
    related = ForeignCollection.findOne(selector);
  } else if (relation.type === 'many') {
    related = ForeignCollection.find(selector);
  }

  // Assing the related object to the "_references" object for further use.
  return this._references[relationName] = related;
};

_.extend(Astro.BaseClass.prototype, methods);
<|endoftext|>


<commit_before>/**
 * node-archiver
 *
 * Copyright (c) 2012-2014 Chris Talkington, contributors.
 * Licensed under the MIT license.
 * https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT
 */
var fs = require('fs');
var inherits = require('util').inherits;
var Transform = require('readable-stream').Transform;

var async = require('async');

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

var Archiver = module.exports = function(options) {
  options = this.options = util.defaults(options, {
    highWaterMark: 1024 * 1024
  });

  Transform.call(this, options);

  this._entries = [];
  this._module = false;
  this._pointer = 0;

  this._queue = async.queue(this._onQueueTask.bind(this), 1);
  this._queue.drain = this._onQueueDrain.bind(this);

  this._state = {
    finalize: false,
    finalized: false,
    modulePiped: false
  };
};

inherits(Archiver, Transform);

Archiver.prototype._append = function(filepath, data) {
  data = data || {};

  if (!data.name) {
    data.name = filepath;
  }

  data.sourcePath = filepath;

  this._queue.push({
    data: data,
    source: false,
    deferredStat: true,
    filepath: filepath
  });
};

Archiver.prototype._moduleAppend = function(source, data, callback) {
  this._module.append(source, data, callback);
};

Archiver.prototype._moduleFinalize = function() {
  this._state.finalized = true;

  if (typeof this._module.finalize === 'function') {
    this._module.finalize();
  } else if (typeof this._module.end === 'function') {
    this._module.end();
  } else {
    this.emit('error', new Error('format module missing finalize and end method'));
  }
};

Archiver.prototype._moduleSupports = function(key) {
  this._module.supports = util.defaults(this._module.supports, {
    directory: false
  });

  return this._module.supports[key];
};

Archiver.prototype._normalizeEntryData = function(data, stats) {
  stats = stats || false;
  data = util.defaults(data, {
    type: 'file',
    name: null,
    date: null,
    mode: null,
    sourcePath: null
  });

  var isDir = data.type === 'directory';

  if (data.name) {
    data.name = util.sanitizePath(data.name);

    if (data.name.slice(-1) === '/') {
      isDir = true;
      data.type = 'directory';
    } else if (isDir) {
      data.name += '/';
    }
  }

  if (typeof data.mode === 'number') {
    data.mode &= 0777;
  } else if (stats) {
    data.mode = stats.mode & 0777;
  } else {
    data.mode = isDir ? 0755 : 0644;
  }

  if (stats && data.date === null) {
    data.date = stats.mtime;
  }

  data.date = util.dateify(data.date);

  data._stats = stats;

  return data;
};

Archiver.prototype._onModuleError = function(err) {
  this.emit('error', err);
};

Archiver.prototype._onQueueDrain = function() {
  if (this._state.finalize && !this._state.finalized && this._queue.idle()) {
    this._moduleFinalize();
  }
};

Archiver.prototype._onQueueTask = function(task, callback) {
  var afterAppend = function(err, entry) {
    if (err) {
      this.emit('error', err);
      callback();
      return;
    }

    entry = entry || task.data;

    this.emit('entry', entry);
    this._entries.push(entry);

    callback();
  }.bind(this);

  var afterStat = function(err, stats) {
    if (err) {
      this.emit('error', err);
      callback();
      return;
    }

    task = this._updateQueueTaskWithStats(task, task.filepath, stats);
    this._moduleAppend(task.source, task.data, afterAppend);
  }.bind(this);

  if (task.deferredStat) {
    fs.stat(task.filepath, afterStat);
  } else {
    this._moduleAppend(task.source, task.data, afterAppend);
  }
};

Archiver.prototype._updateQueueTaskWithStats = function(task, filepath, stats) {
  if (stats.isFile()) {
    task.data.type = 'file';
    task.data.sourceType = 'stream';
    task.source = util.lazyReadStream(filepath);
  } else if (stats.isDirectory() && this._moduleSupports('directory')) {
    task.data.name = util.trailingSlashIt(task.data.name);
    task.data.type = 'directory';
    task.data.sourcePath = util.trailingSlashIt(filepath);
    task.data.sourceType = 'buffer';
    task.source = new Buffer(0);
  } else {
    this.emit('error', new Error('unsupported filepath: ' + filepath));
  }

  task.data = this._normalizeEntryData(task.data, stats);
  return task;
};

Archiver.prototype._pipeModuleOutput = function() {
  this._module.on('error', this._onModuleError.bind(this));
  this._module.pipe(this);

  this._state.modulePiped = true;
};

Archiver.prototype._processFile = function(source, data, callback) {
  this.emit('error', new Error('method not implemented'));
};

Archiver.prototype._transform = function(chunk, encoding, callback) {
  if (chunk) {
    this._pointer += chunk.length;
  }

  callback(null, chunk);
};

Archiver.prototype.append = function(source, data) {
  if (this._state.finalize) {
    this.emit('error', new Error('unable to append after calling finalize.'));
    return this;
  }

  data = this._normalizeEntryData(data);

  if (typeof data.name !== 'string' || data.name.length === 0) {
    this.emit('error', new Error('entry name must be a non-empty string value'));
    return this;
  }

  if (data.type === 'directory' && !this._moduleSupports('directory')) {
    this.emit('error', new Error('entries of "' + data.type + '" type not currently supported by this module'));
    return;
  }

  source = util.normalizeInputSource(source);

  if (Buffer.isBuffer(source)) {
    data.sourceType = 'buffer';
  } else if (util.isStream(source)) {
    data.sourceType = 'stream';
  } else {
    this.emit('error', new Error('input source must be valid Stream or Buffer instance'));
    return this;
  }

  this._queue.push({
    data: data,
    source: source
  });

  return this;
};

Archiver.prototype.bulk = function(mappings) {
  if (this._state.finalize) {
    this.emit('error', new Error('unable to append after calling finalize.'));
    return this;
  }

  if (!Array.isArray(mappings)) {
    mappings = [mappings];
  }

  var self = this;
  var files = util.file.normalizeFilesArray(mappings);

  files.forEach(function(file){
    var isExpandedPair = file.orig.expand || false;
    var fileData = file.data || {};

    file.src.forEach(function(filepath) {
      var data = util._.extend({}, fileData);
      var name = isExpandedPair ? file.dest : util.unixifyPath(file.dest || '', filepath);

      if (name === '.') {
        return;
      }

      data.name = name;
      self._append(filepath, data);
    });
  });

  return this;
};

Archiver.prototype.file = function(filepath, data) {
  if (this._state.finalize) {
    this.emit('error', new Error('unable to append after calling finalize.'));
    return this;
  }

  if (typeof filepath !== 'string' || filepath.length === 0) {
    this.emit('error', new Error('filepath must be a non-empty string value'));
    return this;
  }

  this._append(filepath, data);

  return this;
};

Archiver.prototype.finalize = function() {
  this._state.finalize = true;

  if (this._queue.idle()) {
    this._moduleFinalize();
  }

  return this;
};

Archiver.prototype.setModule = function(module) {
  if (this._state.modulePiped) {
    this.emit('error', new Error('format module already set'));
    return;
  }

  this._module = module;
  this._pipeModuleOutput();
};

Archiver.prototype.pointer = function() {
  return this._pointer;
};<commit_msg>core: minor optimizations.<commit_after>/**
 * node-archiver
 *
 * Copyright (c) 2012-2014 Chris Talkington, contributors.
 * Licensed under the MIT license.
 * https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT
 */
var fs = require('fs');
var inherits = require('util').inherits;
var Transform = require('readable-stream').Transform;

var async = require('async');

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

var Archiver = module.exports = function(options) {
  options = this.options = util.defaults(options, {
    highWaterMark: 1024 * 1024
  });

  Transform.call(this, options);

  this._entries = [];
  this._module = false;
  this._pointer = 0;

  this._queue = async.queue(this._onQueueTask.bind(this), 1);
  this._queue.drain = this._onQueueDrain.bind(this);

  this._state = {
    finalize: false,
    finalized: false,
    modulePiped: false
  };
};

inherits(Archiver, Transform);

Archiver.prototype._append = function(filepath, data) {
  data = data || {};

  if (!data.name) {
    data.name = filepath;
  }

  data.sourcePath = filepath;

  this._queue.push({
    data: data,
    source: false,
    deferredStat: true,
    filepath: filepath
  });
};

Archiver.prototype._moduleAppend = function(source, data, callback) {
  this._module.append(source, data, callback);
};

Archiver.prototype._moduleFinalize = function() {
  this._state.finalized = true;

  if (typeof this._module.finalize === 'function') {
    this._module.finalize();
  } else if (typeof this._module.end === 'function') {
    this._module.end();
  } else {
    this.emit('error', new Error('format module missing finalize and end method'));
  }
};

Archiver.prototype._moduleSupports = function(key) {
  this._module.supports = util.defaults(this._module.supports, {
    directory: false
  });

  return this._module.supports[key];
};

Archiver.prototype._normalizeEntryData = function(data, stats) {
  stats = stats || false;
  data = util.defaults(data, {
    type: 'file',
    name: null,
    date: null,
    mode: null,
    sourcePath: null
  });

  var isDir = data.type === 'directory';

  if (data.name) {
    data.name = util.sanitizePath(data.name);

    if (data.name.slice(-1) === '/') {
      isDir = true;
      data.type = 'directory';
    } else if (isDir) {
      data.name += '/';
    }
  }

  if (typeof data.mode === 'number') {
    data.mode &= 0777;
  } else if (stats) {
    data.mode = stats.mode & 0777;
  } else {
    data.mode = isDir ? 0755 : 0644;
  }

  if (stats && data.date === null) {
    data.date = stats.mtime;
  }

  data.date = util.dateify(data.date);

  data._stats = stats;

  return data;
};

Archiver.prototype._onModuleError = function(err) {
  this.emit('error', err);
};

Archiver.prototype._onQueueDrain = function() {
  if (this._state.finalize && !this._state.finalized && this._queue.idle()) {
    this._moduleFinalize();
  }
};

Archiver.prototype._onQueueTask = function(task, callback) {
  var afterAppend = function(err, entry) {
    if (err) {
      this.emit('error', err);
      callback();
      return;
    }

    entry = entry || task.data;

    this.emit('entry', entry);
    this._entries.push(entry);

    callback();
  }.bind(this);

  var afterStat = function(err, stats) {
    if (err) {
      this.emit('error', err);
      callback();
      return;
    }

    task = this._updateQueueTaskWithStats(task, stats);
    this._moduleAppend(task.source, task.data, afterAppend);
  }.bind(this);

  if (task.deferredStat) {
    fs.stat(task.filepath, afterStat);
  } else {
    this._moduleAppend(task.source, task.data, afterAppend);
  }
};

Archiver.prototype._updateQueueTaskWithStats = function(task, stats) {
  if (stats.isFile()) {
    task.data.type = 'file';
    task.data.sourceType = 'stream';
    task.source = util.lazyReadStream(task.filepath);
  } else if (stats.isDirectory() && this._moduleSupports('directory')) {
    task.data.name = util.trailingSlashIt(task.data.name);
    task.data.type = 'directory';
    task.data.sourcePath = util.trailingSlashIt(task.filepath);
    task.data.sourceType = 'buffer';
    task.source = new Buffer(0);
  } else {
    this.emit('error', new Error('unsupported filepath: ' + task.filepath));
  }

  task.data = this._normalizeEntryData(task.data, stats);
  return task;
};

Archiver.prototype._pipeModuleOutput = function() {
  this._module.on('error', this._onModuleError.bind(this));
  this._module.pipe(this);

  this._state.modulePiped = true;
};

Archiver.prototype._processFile = function(source, data, callback) {
  this.emit('error', new Error('method not implemented'));
};

Archiver.prototype._transform = function(chunk, encoding, callback) {
  if (chunk) {
    this._pointer += chunk.length;
  }

  callback(null, chunk);
};

Archiver.prototype.append = function(source, data) {
  if (this._state.finalize) {
    this.emit('error', new Error('unable to append after calling finalize.'));
    return this;
  }

  data = this._normalizeEntryData(data);

  if (typeof data.name !== 'string' || data.name.length === 0) {
    this.emit('error', new Error('entry name must be a non-empty string value'));
    return this;
  }

  if (data.type === 'directory' && !this._moduleSupports('directory')) {
    this.emit('error', new Error('entries of "' + data.type + '" type not currently supported by this module'));
    return;
  }

  source = util.normalizeInputSource(source);

  if (Buffer.isBuffer(source)) {
    data.sourceType = 'buffer';
  } else if (util.isStream(source)) {
    data.sourceType = 'stream';
  } else {
    this.emit('error', new Error('input source must be valid Stream or Buffer instance'));
    return this;
  }

  this._queue.push({
    data: data,
    source: source
  });

  return this;
};

Archiver.prototype.bulk = function(mappings) {
  if (this._state.finalize) {
    this.emit('error', new Error('unable to append after calling finalize.'));
    return this;
  }

  if (!Array.isArray(mappings)) {
    mappings = [mappings];
  }

  var self = this;
  var files = util.file.normalizeFilesArray(mappings);

  files.forEach(function(file){
    var isExpandedPair = file.orig.expand || false;
    var fileData = file.data || {};

    file.src.forEach(function(filepath) {
      var data = util._.extend({}, fileData);
      var name = isExpandedPair ? file.dest : util.unixifyPath(file.dest || '', filepath);

      if (name === '.') {
        return;
      }

      data.name = name;
      self._append(filepath, data);
    });
  });

  return this;
};

Archiver.prototype.file = function(filepath, data) {
  if (this._state.finalize) {
    this.emit('error', new Error('unable to append after calling finalize.'));
    return this;
  }

  if (typeof filepath !== 'string' || filepath.length === 0) {
    this.emit('error', new Error('filepath must be a non-empty string value'));
    return this;
  }

  this._append(filepath, data);

  return this;
};

Archiver.prototype.finalize = function() {
  this._state.finalize = true;

  if (this._queue.idle()) {
    this._moduleFinalize();
  }

  return this;
};

Archiver.prototype.setModule = function(module) {
  if (this._state.modulePiped) {
    this.emit('error', new Error('format module already set'));
    return;
  }

  this._module = module;
  this._pipeModuleOutput();
};

Archiver.prototype.pointer = function() {
  return this._pointer;
};<|endoftext|>


<commit_before>const UploadIPFS = require('./upload.js');
const utils = require('../../utils/utils.js');
const fs = require('../../core/fs.js');
const IpfsApi = require('ipfs-api');
// TODO: not great, breaks module isolation
const StorageProcessesLauncher = require('../storage/storageProcessesLauncher');

class IPFS {

  constructor(embark, options) {
    const self = this;
    this.logger = embark.logger;
    this.events = embark.events;
    this.buildDir = options.buildDir;
    this.storageConfig = embark.config.storageConfig;
    this.namesystemConfig = embark.config.namesystemConfig;
    this.embark = embark;

    this.webServerConfig = embark.config.webServerConfig;
    this.blockchainConfig = embark.config.blockchainConfig;

    if (this.isIpfsStorageEnabledInTheConfig()) {
      this.downloadIpfsApi();
      this.setServiceCheck();
      this.addStorageProviderToEmbarkJS();
      this.addObjectToConsole();
      this.registerUploadCommand();

      this._checkService((err) => {
        if (!err) {
          return;
        }
        self.logger.info("IPFS node not found, attempting to start own node");
        this.listenToCommands();
        this.registerConsoleCommands();
        self.startProcess(() => {});
      });
    }
  }

  downloadIpfsApi() {
    const self = this;

    self.events.request("version:get:ipfs-api", function(ipfsApiVersion) {
      let currentIpfsApiVersion = require('../../../package.json').dependencies["ipfs-api"];
      if (ipfsApiVersion !== currentIpfsApiVersion) {
        self.events.request("version:getPackageLocation", "ipfs-api", ipfsApiVersion, function(err, location) {
          self.embark.registerImportFile("ipfs-api", fs.dappPath(location));
        });
      }
    });
  }

  setServiceCheck() {
    let self = this;

    self.events.on('check:backOnline:IPFS', function () {
      self.logger.info(__('IPFS node detected') + '..');
    });

    self.events.on('check:wentOffline:IPFS', function () {
      self.logger.info(__('IPFS node is offline') + '..');
    });

    self.events.request("services:register", 'IPFS', function (cb) {
      self._checkService((err, body) => {
        if (err) {
          self.logger.trace("IPFS unavailable");
          return cb({name: "IPFS ", status: 'off'});
        }
        if (body.Version) {
          self.logger.trace("IPFS available");
          return cb({name: ("IPFS " + body.Version), status: 'on'});
        }
        self.logger.trace("IPFS available");
        return cb({name: "IPFS ", status: 'on'});
      });
    });
  }

  _getNodeUrl() {
    if (this.storageConfig.upload.provider === 'ipfs') {
      return utils.buildUrlFromConfig(this.storageConfig.upload) + '/api/v0/version';
    }

    for (let connection of this.storageConfig.dappConnection) {
      if (connection.provider === 'ipfs') {
        return utils.buildUrlFromConfig(connection) + '/api/v0/version';
      }
    }
  }

  _checkService(cb) {
    let url = this._getNodeUrl();
    utils.getJson(url, cb);
  }

  addStorageProviderToEmbarkJS() {
    let code = "";
    code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
    code += "\nEmbarkJS.Storage.registerProvider('ipfs', __embarkIPFS);";

    this.embark.addCodeToEmbarkJS(code);
  }

  addObjectToConsole() {
    let ipfs = IpfsApi(this.host, this.port);
    this.events.emit("runcode:register", "ipfs", ipfs);
  }

  startProcess(callback) {
    let self = this;
    const storageProcessesLauncher = new StorageProcessesLauncher({
      logger: self.logger,
      events: self.events,
      storageConfig: self.storageConfig,
      webServerConfig: self.webServerConfig,
      blockchainConfig: self.blockchainConfig,
      corsParts: self.embark.config.corsParts
    });
    self.logger.trace(`Storage module: Launching ipfs process...`);
    return storageProcessesLauncher.launchProcess('ipfs', callback);
  }

  registerUploadCommand() {
    const self = this;
    this.embark.registerUploadCommand('ipfs', (cb) => {
      let upload_ipfs = new UploadIPFS({
        buildDir: self.buildDir || 'dist/',
        storageConfig: self.storageConfig,
        configIpfsBin: self.storageConfig.ipfs_bin || "ipfs",
        env: this.embark.env
      });

      upload_ipfs.deploy(cb);
    });
  }

  listenToCommands() {
    this.events.setCommandHandler('logs:ipfs:turnOn',  (cb) => {
      this.events.emit('logs:storage:enable');
      return cb(null, 'Enabling IPFS logs');
    });

    this.events.setCommandHandler('logs:ipfs:turnOff',  (cb) => {
      this.events.emit('logs:storage:disable');
      return cb(null, 'Disabling IPFS logs');
    });
  }

  registerConsoleCommands() {
    const self = this;
    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log ipfs on',
        process: (cb) => self.events.request('logs:ipfs:turnOn', cb)
      };
    });

    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log ipfs off',
        process: (cb) => self.events.request('logs:ipfs:turnOff', cb)
      };
    });
  }

  isIpfsStorageEnabledInTheConfig() {
    let {enabled, available_providers, dappConnection} = this.storageConfig;
    return enabled && (available_providers.indexOf('ipfs') > 0 || dappConnection.find(c => c.provider === 'ipfs'));
  }
}

module.exports = IPFS;
<commit_msg>Add ipns resolve<commit_after>const UploadIPFS = require('./upload.js');
const utils = require('../../utils/utils.js');
const fs = require('../../core/fs.js');
const IpfsApi = require('ipfs-api');
// TODO: not great, breaks module isolation
const StorageProcessesLauncher = require('../storage/storageProcessesLauncher');

class IPFS {

  constructor(embark, options) {
    const self = this;
    this.logger = embark.logger;
    this.events = embark.events;
    this.buildDir = options.buildDir;
    this.storageConfig = embark.config.storageConfig;
    this.namesystemConfig = embark.config.namesystemConfig;
    this.embark = embark;

    this.webServerConfig = embark.config.webServerConfig;
    this.blockchainConfig = embark.config.blockchainConfig;

    if (this.isIpfsStorageEnabledInTheConfig()) {
      this.downloadIpfsApi();
      this.setServiceCheck();
      this.addStorageProviderToEmbarkJS();
      this.addObjectToConsole();
      this.registerUploadCommand();

      this._checkService((err) => {
        if (!err) {
          return;
        }
        self.logger.info("IPFS node not found, attempting to start own node");
        this.listenToCommands();
        this.registerConsoleCommands();
        self.startProcess(() => {});
      });
    }
  }

  downloadIpfsApi() {
    const self = this;

    self.events.request("version:get:ipfs-api", function(ipfsApiVersion) {
      let currentIpfsApiVersion = require('../../../package.json').dependencies["ipfs-api"];
      if (ipfsApiVersion !== currentIpfsApiVersion) {
        self.events.request("version:getPackageLocation", "ipfs-api", ipfsApiVersion, function(err, location) {
          self.embark.registerImportFile("ipfs-api", fs.dappPath(location));
        });
      }
    });
  }

  setServiceCheck() {
    let self = this;

    self.events.on('check:backOnline:IPFS', function () {
      self.logger.info(__('IPFS node detected') + '..');
    });

    self.events.on('check:wentOffline:IPFS', function () {
      self.logger.info(__('IPFS node is offline') + '..');
    });

    self.events.request("services:register", 'IPFS', function (cb) {
      self._checkService((err, body) => {
        if (err) {
          self.logger.trace("IPFS unavailable");
          return cb({name: "IPFS ", status: 'off'});
        }
        if (body.Version) {
          self.logger.trace("IPFS available");
          return cb({name: ("IPFS " + body.Version), status: 'on'});
        }
        self.logger.trace("IPFS available");
        return cb({name: "IPFS ", status: 'on'});
      });
    });
  }

  _getNodeUrl() {
    if (this.storageConfig.upload.provider === 'ipfs') {
      return utils.buildUrlFromConfig(this.storageConfig.upload) + '/api/v0/version';
    }

    for (let connection of this.storageConfig.dappConnection) {
      if (connection.provider === 'ipfs') {
        return utils.buildUrlFromConfig(connection) + '/api/v0/version';
      }
    }
  }

  _checkService(cb) {
    let url = this._getNodeUrl();
    utils.getJson(url, cb);
  }

  addStorageProviderToEmbarkJS() {
    let code = "";
    code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
    code += "\nEmbarkJS.Storage.registerProvider('ipfs', __embarkIPFS);";
    code += "\nEmbarkJS.Names.registerProvider('ipns', __embarkIPFS);";

    this.embark.addCodeToEmbarkJS(code);
  }

  addObjectToConsole() {
    let ipfs = IpfsApi(this.host, this.port);
    this.events.emit("runcode:register", "ipfs", ipfs);
  }

  startProcess(callback) {
    let self = this;
    const storageProcessesLauncher = new StorageProcessesLauncher({
      logger: self.logger,
      events: self.events,
      storageConfig: self.storageConfig,
      webServerConfig: self.webServerConfig,
      blockchainConfig: self.blockchainConfig,
      corsParts: self.embark.config.corsParts
    });
    self.logger.trace(`Storage module: Launching ipfs process...`);
    return storageProcessesLauncher.launchProcess('ipfs', callback);
  }

  registerUploadCommand() {
    const self = this;
    this.embark.registerUploadCommand('ipfs', (cb) => {
      let upload_ipfs = new UploadIPFS({
        buildDir: self.buildDir || 'dist/',
        storageConfig: self.storageConfig,
        configIpfsBin: self.storageConfig.ipfs_bin || "ipfs",
        env: this.embark.env
      });

      upload_ipfs.deploy(cb);
    });
  }

  listenToCommands() {
    this.events.setCommandHandler('logs:ipfs:turnOn',  (cb) => {
      this.events.emit('logs:storage:enable');
      return cb(null, 'Enabling IPFS logs');
    });

    this.events.setCommandHandler('logs:ipfs:turnOff',  (cb) => {
      this.events.emit('logs:storage:disable');
      return cb(null, 'Disabling IPFS logs');
    });
  }

  registerConsoleCommands() {
    const self = this;
    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log ipfs on',
        process: (cb) => self.events.request('logs:ipfs:turnOn', cb)
      };
    });

    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log ipfs off',
        process: (cb) => self.events.request('logs:ipfs:turnOff', cb)
      };
    });
  }

  isIpfsStorageEnabledInTheConfig() {
    let {enabled, available_providers, dappConnection} = this.storageConfig;
    return enabled && (available_providers.indexOf('ipfs') > 0 || dappConnection.find(c => c.provider === 'ipfs'));
  }
}

module.exports = IPFS;
<|endoftext|>