<commit_before>/*
 * Copyright (c) 2014 Jesse van den Kieboom. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following disclaimer
 *      in the documentation and/or other materials provided with the
 *      distribution.
 *    * Neither the name of Google Inc. nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

var Material = require('./material');
var math = require('../math/math');

/**
 * Basic model. A model useful high-level representation
 * of a transform, geometry and material which can be rendered.
 * Models can be organized hierarchically (see add, remove).
 *
 * @param ctx the context.
 * @param name the name of the model.
 * @param options options.
 * @constructor
 */
function Model(ctx, name, options) {
    /** The name. */
    this.name = name;

    var mat;

    if (options && options.material) {
        mat = options.material;
    } else {
        mat = new Material();
    }

    /** The material (see Material). */
    this.material = mat;

    /**
     * The parent (or null). Do not set this directly,
     * use add/remove instead.
     */
    this.parent = null;

    /**
     * The children. Do not set this directly, use add/remove instead.
     */
    this.children = [];

    /** The transform. */
    this.transform = math.transform.create();

    /** The full transform (i.e. to world coordinates). This will
     * be computed and cached as needed when rendering.
     */
    this.fullTransform = (function() {
        return this.transform;
    }).bind(this);

    /** The geometry to render. This is usually a RenderGroup or
      * RenderGroups, but may be anything with a .renderParts()
      * function, returning an array of elements containing:
      * 1) a .geometry field containing a Geometry.
      * 2) a .render(ctx) function.
      */
    this.renderer = null;
}

/**
 * Render the model in the given context. Rendering will use the current view
 * set in the context.
 *
 * @param ctx the context.
 */
Model.prototype.render = function(ctx, options) {
    if (this.material.visible === Material.INVISIBLE) {
        return;
    }

    var view = ctx.view();

    var fullTransform = this.fullTransform();

    for (var i = 0; i < this.children.length; i++) {
        this.children[i].render(ctx, options);
    }

    if (this.material.visible === Material.ONLY_CHILDREN || this.renderer === null) {
        return;
    }

    var uniforms = {
        model: math.mat4.fromTransform(math.mat4.create(), fullTransform),
        view: null,
        modelView: null,
        projection: null,
        modelViewProjection: null
    };

    if (view) {
        uniforms.view = math.mat4.fromTransform(math.mat4.create(), view.originTransform());
        uniforms.modelView = math.mat4.mul(math.mat4.create(), uniforms.view, uniforms.model);
        uniforms.projection = view.projection();
        uniforms.modelViewProjection = math.mat4.mul(math.mat4.create(), uniforms.projection, uniforms.modelView);
    } else {
        uniforms.view = math.mat4.create();
        uniforms.modelView = uniforms.model;
        uniforms.projection = math.mat4.create();
        uniforms.modelViewProjection = uniforms.model;
    }

    if (options && options.uniforms) {
        for (var k in options.uniforms) {
            if (options.uniforms.hasOwnProperty(k)) {
                uniforms[k] = options.uniforms[k];
            }
        }
    }

    var p = ctx.findProgram(this.material.program);
    var parts = this.renderer.renderParts();

    var prevGeometry = null;

    for (var i = 0; i < parts.length; i++) {
        var part = parts[i];
        var geometry = part.geometry;
        var needsRebind = false;

        if (p !== null) {
            // Reconcile geometry attributes with program attributes
            for (var attrname in geometry.attributes) {
                var attr = geometry.attributes[attrname];

                if (!(attrname in p.attributes) || p.attributes[attrname] !== attr.id) {
                    needsRebind = true;
                    break;
                }
            }

            if (needsRebind) {
                var gl = ctx.gl;

                p.attributes = {};
                p.uniforms = {};

                for (var attrname in geometry.attributes) {
                    var attr = geometry.attributes[attrname];
                    gl.bindAttribLocation(p.program, attr.id, attrname);

                    p.attributes[attrname] = attr.id;
                }

                gl.linkProgram(p.program);
            }
        }

        if (geometry !== prevGeometry) {
            geometry.bind(ctx);
            prevGeometry = geometry;
        }

        if (needsRebind || i === 0) {
            this.material.bind(ctx, uniforms);
        }

        part.render(ctx);
    }

    if (prevGeometry !== null) {
        prevGeometry.unbind(ctx);
    }
}

/**
 * Remove a child model.
 *
 * @param child the model to remove.
 */
Model.prototype.remove = function(child) {
    if (child.parent === this) {
        child.parent = null;

        child.fullTransform = (function() {
            return this.transform;
        }).bind(child);
    }

    var i = this.children.indexOf(child);

    if (i !== -1) {
        this.children.splice(i, 1);
    }
}

/**
 * Add a child model.
 *
 * @param child the model to add.
 */
Model.prototype.add = function(child) {
    if (child.parent === this) {
        return;
    }

    if (child.parent !== null) {
        child.parent.remove(child);
    }

    child.parent = this;
    this.children.push(child);

    child.fullTransform = math.transform.track(math.transform.create(), this, 'fullTransform', function(out, tr) {
        return child.transform.preMul(tr());
    });
}

module.exports = Model;

var objloader = require('./objloader');
Model.load = objloader.load;

// vi:ts=4:et
<commit_msg>Partially fix tracking of top-parent transform<commit_after>/*
 * Copyright (c) 2014 Jesse van den Kieboom. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following disclaimer
 *      in the documentation and/or other materials provided with the
 *      distribution.
 *    * Neither the name of Google Inc. nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

var Material = require('./material');
var math = require('../math/math');

/**
 * Basic model. A model useful high-level representation
 * of a transform, geometry and material which can be rendered.
 * Models can be organized hierarchically (see add, remove).
 *
 * @param ctx the context.
 * @param name the name of the model.
 * @param options options.
 * @constructor
 */
function Model(ctx, name, options) {
    /** The name. */
    this.name = name;

    var mat;

    if (options && options.material) {
        mat = options.material;
    } else {
        mat = new Material();
    }

    /** The material (see Material). */
    this.material = mat;

    /**
     * The parent (or null). Do not set this directly,
     * use add/remove instead.
     */
    this.parent = null;

    /**
     * The children. Do not set this directly, use add/remove instead.
     */
    this.children = [];

    /** The transform. */
    this.transform = math.transform.create();

    /** The full transform (i.e. to world coordinates). This will
     * be computed and cached as needed when rendering.
     */
    this.fullTransform = math.transform.track(math.transform.create(), this, 'transform', function(out, tr) {
        return math.transform.copy(out, tr);
    });

    /** The geometry to render. This is usually a RenderGroup or
      * RenderGroups, but may be anything with a .renderParts()
      * function, returning an array of elements containing:
      * 1) a .geometry field containing a Geometry.
      * 2) a .render(ctx) function.
      */
    this.renderer = null;
}

/**
 * Render the model in the given context. Rendering will use the current view
 * set in the context.
 *
 * @param ctx the context.
 */
Model.prototype.render = function(ctx, options) {
    if (this.material.visible === Material.INVISIBLE) {
        return;
    }

    var view = ctx.view();

    var fullTransform = this.fullTransform();

    for (var i = 0; i < this.children.length; i++) {
        this.children[i].render(ctx, options);
    }

    if (this.material.visible === Material.ONLY_CHILDREN || this.renderer === null) {
        return;
    }

    var uniforms = {
        model: math.mat4.fromTransform(math.mat4.create(), fullTransform),
        view: null,
        modelView: null,
        projection: null,
        modelViewProjection: null
    };

    if (view) {
        uniforms.view = math.mat4.fromTransform(math.mat4.create(), view.originTransform());
        uniforms.modelView = math.mat4.mul(math.mat4.create(), uniforms.view, uniforms.model);
        uniforms.projection = view.projection();
        uniforms.modelViewProjection = math.mat4.mul(math.mat4.create(), uniforms.projection, uniforms.modelView);
    } else {
        uniforms.view = math.mat4.create();
        uniforms.modelView = uniforms.model;
        uniforms.projection = math.mat4.create();
        uniforms.modelViewProjection = uniforms.model;
    }

    if (options && options.uniforms) {
        for (var k in options.uniforms) {
            if (options.uniforms.hasOwnProperty(k)) {
                uniforms[k] = options.uniforms[k];
            }
        }
    }

    var p = ctx.findProgram(this.material.program);
    var parts = this.renderer.renderParts();

    var prevGeometry = null;

    for (var i = 0; i < parts.length; i++) {
        var part = parts[i];
        var geometry = part.geometry;
        var needsRebind = false;

        if (p !== null) {
            // Reconcile geometry attributes with program attributes
            for (var attrname in geometry.attributes) {
                var attr = geometry.attributes[attrname];

                if (!(attrname in p.attributes) || p.attributes[attrname] !== attr.id) {
                    needsRebind = true;
                    break;
                }
            }

            if (needsRebind) {
                var gl = ctx.gl;

                p.attributes = {};
                p.uniforms = {};

                for (var attrname in geometry.attributes) {
                    var attr = geometry.attributes[attrname];
                    gl.bindAttribLocation(p.program, attr.id, attrname);

                    p.attributes[attrname] = attr.id;
                }

                gl.linkProgram(p.program);
            }
        }

        if (geometry !== prevGeometry) {
            geometry.bind(ctx);
            prevGeometry = geometry;
        }

        if (needsRebind || i === 0) {
            this.material.bind(ctx, uniforms);
        }

        part.render(ctx);
    }

    if (prevGeometry !== null) {
        prevGeometry.unbind(ctx);
    }
}

/**
 * Remove a child model.
 *
 * @param child the model to remove.
 */
Model.prototype.remove = function(child) {
    if (child.parent === this) {
        child.parent = null;

        child.fullTransform = (function() {
            return this.transform;
        }).bind(child);
    }

    var i = this.children.indexOf(child);

    if (i !== -1) {
        this.children.splice(i, 1);
    }
}

/**
 * Add a child model.
 *
 * @param child the model to add.
 */
Model.prototype.add = function(child) {
    if (child.parent === this) {
        return;
    }

    if (child.parent !== null) {
        child.parent.remove(child);
    }

    child.parent = this;
    this.children.push(child);

    child.fullTransform = math.transform.track(math.transform.create(), this, 'fullTransform', function(out, tr) {
        return child.transform.preMul(tr());
    });
}

module.exports = Model;

var objloader = require('./objloader');
Model.load = objloader.load;

// vi:ts=4:et
<|endoftext|>


<commit_before>var list_images = {}

var
    $ = function (id) {
        return document.getElementById(id);
    },
    container = $('example1'),
    exampleConsole = $('example1console'),
    autosave = $('autosave'),
    load = $('load'),
    save = $('save'),
    reload = $('reload'),
    autosaveNotification,
    hot,
    number,
    selectedColumn,
    colorData = [],
    colors = ['#d53e4f', '#3288bd', '#66c265', '#4d4d4d'];

while (color = colors.shift()) {
    colorData.push([
        [color]
    ]);
}

hot = new Handsontable(container, {
    startRows: 1,
    dataSchema:
    {
        id: 1,
        name: null,
        className: null,
        shape: null,
        text: null,
        image: null,
        image2: null,
        loaded: "true",
        style: {
            lineWidth: "10",
            radius: null,
            lineColor: null
        }
    },
    columns: [
        { data: "id" },
        { data: "name" },
        {
            data: "className",
            type: 'dropdown',
            source: ['personas', 'bienes', 'empresas', 'vehiculos', 'conectores', 'cuentasbancarias']
        },
        {
            data: "image",
            renderer: coverRenderer,
            type: 'dropdown',
            source: ['http://s.hswstatic.com/gif/buying-house1.jpg', 'https://d2x3bkdslnxkuj.cloudfront.net/1028152_300.jpg', 'https://i.cbc.ca/1.2115364.1382070777!/httpImage/image.jpg_gen/derivatives/original_300/morton.jpg', 'http://img1.zergnet.com/1391764_300.jpg']
        },
        {
            data: "image2",
            renderer: coverRenderer,
            type: 'dropdown',
            source: ['http://s.hswstatic.com/gif/buying-house1.jpg', 'https://d2x3bkdslnxkuj.cloudfront.net/1028152_300.jpg', 'https://i.cbc.ca/1.2115364.1382070777!/httpImage/image.jpg_gen/derivatives/original_300/morton.jpg', 'http://img1.zergnet.com/1391764_300.jpg']
        },
        { data: "text" }, {
            data: "style.radius",
            type: 'dropdown',
            source: ['60', '100', '150']
        }, {
            data: "style.lineColor",
            type: 'handsontable',
            renderer: colorRenderer,
            allowInvalid: false,
            handsontable: {
                data: colorData,
                autoColumnSize: true,
                columns: [{ renderer: colorDropdownRenderer }]

            }
        },
        {
            data: "shape",
            renderer: hiddenText
            // type: 'dropdown',
            // source: ['circle', 'square', 'triangle']
        },
        {
            data: "loaded",
            renderer: hiddenText
        },
        {
            data: "style.lineWidth",
            // type: 'dropdown',
            // source: ['5', '10', '15']
        }
    ],
    currentRowClassName: 'currentRow',
    rowHeaders: true,
    rowHeights: 55,
    colHeaders: ["ID", "Nombre", "Tipo de nodo", "Icono", "Foto", "Descripción", "Tamaño", "Color del borde", "Figura", "Cargado", "Longitud de línea"],
    colWidths: [1, 100, 100, 100, 100, 300, 100, 100, 1, 1, 1],
    stretchH: 'all',
    persistentState: true,
    contextMenu: true,
    afterChange: function (change, source) {
        if (source === 'loadData') {
            return; //don't save this change
        }
        if (!autosave.checked) {
            return;
        }
        clearTimeout(autosaveNotification);
        ajax('json/save.json', 'GET', JSON.stringify({ data: change }), function (data) {
            exampleConsole.innerText = 'Autosaved (' + change.length + ' ' + 'cell' + (change.length > 1 ? 's' : '') + ')';
            autosaveNotification = setTimeout(function () {
                exampleConsole.innerText = 'Changes will be autosaved';
            }, 1000);
        });
    },
    afterCreateRow: function (index) {
        updateIDs(hot)
    },
    afterRemoveRow: function (index) {
        updateIDs(hot)
    },
});

hot.addHook('afterChange', function () {
    if (hot.getSelected() != undefined) {
        var row = hot.getSelected()[0]
        var column = hot.getSelected()[1]
        if (column == 2) {
            var classNameValue = hot.getDataAtCell(row, column)
            if (classNameValue === "empresas" || classNameValue === "bienes" || classNameValue === "cuentasbancarias") {
                //hot.getSourceData()[row].image = "/images/android-desktop.png"
                hot.getSourceData()[row].shape = "square"
            } else if (classNameValue === "conectores" || classNameValue === "personas") {
                hot.getSourceData()[row].shape = "circle"
            } else if (classNameValue === "vehiculos") {
                hot.getSourceData()[row].shape = "triangle"
            }
        }
    }

}
)

hot.updateSettings({
    contextMenu: {
        callback: function (key, options) {
            if (key === 'edit') {
                number = (hot.getSelected()[0]);
                var dialogScrollable = new mdc.dialog.MDCDialog(document.querySelector('#mdc-dialog-with-list'));
                dialogScrollable.show();
                selectedColumn = (hot.getSelected()[1]);
                list_images = {}
                //var image = new Image()

                $('#accept').on('click', function () {
                    if (currentImage != undefined) {

                        document.getElementById("crop").src = currentImage
                        var testImage = new Image()
                        var canvas = document.getElementById("canvas2");
                        //console.log(testImage.src)
                        canvas.width = 100;
                        canvas.height = 100;
                        var x = 0;
                        var y = 0;
                        var imgWidth = 100;
                        var imgHeight = 100;

                        var ctx = canvas.getContext("2d");
                        testImage.onload = function () {
                            ctx.drawImage(testImage, x, y, imgWidth, imgHeight);
                        }
                        testImage.src = currentImage
                        testImage.style.display = 'none';
                        // ctx.fillStyle = "red";
                        // ctx.fillRect(x, y, imgWidth, imgHeight);

                        var imageX = ctx.getImageData(x, y, imgWidth, imgHeight);
                        console.log(imageX)
                        var data = imageX.data,
                            length = data.length;
                        for (var i = 0; i < length; i += 4) {
                            imageX.data[i+1] = 255 - imageX.data[i];     // red
                            //imageX.data[i + 1] = 255 - imageX.data[i + 1]; // green
                            //imageX.data[i + 2] = 255 - imageX.data[i + 2]; // blue
                        }
                        imageX.data = data;
                        ctx.putImageData(imageX, 0, 0);
                        testImage.src = canvas.toDataURL();
                        console.log(testImage.src)

                        list_images[number] = currentImage
                        for (var n in list_images) {
                            if (selectedColumn == 3) {
                                hot.getSourceData()[n].image = list_images[n];
                            } else if (selectedColumn == 4)
                                hot.getSourceData()[n].image2 = list_images[n];
                        }
                    }
                    hot.loadData(hot.getSourceData())
                    //$('#mdc-dialog-with-list').trigger("reset")
                })
                // $('#cancel').on('click', function(){
                //     dialogScrollable.close()

                // })

            }
        },
        items: {
            'row_above': {
                name: function () {
                    return "keyboard_arrow_up Insertar fila encima";
                }
            }, 'row_below': {
                name: function () {
                    return "keyboard_arrow_down Insertar fila debajo";
                }
            }, 'remove_row': {
                name: function () {
                    return "delete Eliminar fila";
                }
            },
            "hsep1": "---------",
            "edit": {
                name: function () {
                    return "photo_library Editar foto";
                },
                disabled: function () {
                    return !(((hot.getSelected()[1] === 3) || (hot.getSelected()[1] === 4)))
                }
            }
        }
    }
})

Handsontable.dom.addEvent(autosave, 'click', function () {
    if (autosave.checked) {
        exampleConsole.innerText = 'Changes will be autosaved';
    }
    else {
        exampleConsole.innerText = 'Changes will not be autosaved';
    }
});

<commit_msg>machete<commit_after>var list_images = {}

var
    $ = function (id) {
        return document.getElementById(id);
    },
    container = $('example1'),
    exampleConsole = $('example1console'),
    autosave = $('autosave'),
    load = $('load'),
    save = $('save'),
    reload = $('reload'),
    autosaveNotification,
    hot,
    number,
    selectedColumn,
    colorData = [],
    colors = ['#d53e4f', '#3288bd', '#66c265', '#4d4d4d'];

while (color = colors.shift()) {
    colorData.push([
        [color]
    ]);
}

hot = new Handsontable(container, {
    startRows: 1,
    dataSchema:
    {
        id: 1,
        name: null,
        className: null,
        shape: null,
        text: null,
        image: null,
        image2: null,
        loaded: "true",
        style: {
            lineWidth: "10",
            radius: null,
            lineColor: null
        }
    },
    columns: [
        { data: "id" },
        { data: "name" },
        {
            data: "className",
            type: 'dropdown',
            source: ['personas', 'bienes', 'empresas', 'vehiculos', 'conectores', 'cuentasbancarias']
        },
        {
            data: "image",
            renderer: coverRenderer,
            type: 'dropdown',
            source: ['http://s.hswstatic.com/gif/buying-house1.jpg', 'https://d2x3bkdslnxkuj.cloudfront.net/1028152_300.jpg', 'https://i.cbc.ca/1.2115364.1382070777!/httpImage/image.jpg_gen/derivatives/original_300/morton.jpg', 'http://img1.zergnet.com/1391764_300.jpg']
        },
        {
            data: "image2",
            renderer: coverRenderer,
            type: 'dropdown',
            source: ['http://s.hswstatic.com/gif/buying-house1.jpg', 'https://d2x3bkdslnxkuj.cloudfront.net/1028152_300.jpg', 'https://i.cbc.ca/1.2115364.1382070777!/httpImage/image.jpg_gen/derivatives/original_300/morton.jpg', 'http://img1.zergnet.com/1391764_300.jpg']
        },
        { data: "text" }, {
            data: "style.radius",
            type: 'dropdown',
            source: ['60', '100', '150']
        }, {
            data: "style.lineColor",
            type: 'handsontable',
            renderer: colorRenderer,
            allowInvalid: false,
            handsontable: {
                data: colorData,
                autoColumnSize: true,
                columns: [{ renderer: colorDropdownRenderer }]

            }
        },
        {
            data: "shape",
            renderer: hiddenText
            // type: 'dropdown',
            // source: ['circle', 'square', 'triangle']
        },
        {
            data: "loaded",
            renderer: hiddenText
        },
        {
            data: "style.lineWidth",
            // type: 'dropdown',
            // source: ['5', '10', '15']
        }
    ],
    currentRowClassName: 'currentRow',
    rowHeaders: true,
    rowHeights: 55,
    colHeaders: ["ID", "Nombre", "Tipo de nodo", "Icono", "Foto", "Descripción", "Tamaño", "Color del borde", "Figura", "Cargado", "Longitud de línea"],
    colWidths: [1, 100, 100, 100, 100, 300, 100, 100, 1, 1, 1],
    stretchH: 'all',
    persistentState: true,
    contextMenu: true,
    afterChange: function (change, source) {
        if (source === 'loadData') {
            return; //don't save this change
        }
        if (!autosave.checked) {
            return;
        }
        clearTimeout(autosaveNotification);
        ajax('json/save.json', 'GET', JSON.stringify({ data: change }), function (data) {
            exampleConsole.innerText = 'Autosaved (' + change.length + ' ' + 'cell' + (change.length > 1 ? 's' : '') + ')';
            autosaveNotification = setTimeout(function () {
                exampleConsole.innerText = 'Changes will be autosaved';
            }, 1000);
        });
    },
    afterCreateRow: function (index) {
        updateIDs(hot)
    },
    afterRemoveRow: function (index) {
        updateIDs(hot)
    },
});

hot.addHook('afterChange', function () {
    if (hot.getSelected() != undefined) {
        var row = hot.getSelected()[0]
        var column = hot.getSelected()[1]
        if (column == 2) {
            var classNameValue = hot.getDataAtCell(row, column)
            if (classNameValue === "empresas" || classNameValue === "bienes" || classNameValue === "cuentasbancarias") {
                //hot.getSourceData()[row].image = "/images/android-desktop.png"
                hot.getSourceData()[row].shape = "square"
            } else if (classNameValue === "conectores" || classNameValue === "personas") {
                hot.getSourceData()[row].shape = "circle"
            } else if (classNameValue === "vehiculos") {
                hot.getSourceData()[row].shape = "triangle"
            }
        }
    }

}
)

hot.updateSettings({
    contextMenu: {
        callback: function (key, options) {
            if (key === 'edit') {
                number = (hot.getSelected()[0]);
                var dialogScrollable = new mdc.dialog.MDCDialog(document.querySelector('#mdc-dialog-with-list'));
                dialogScrollable.show();
                selectedColumn = (hot.getSelected()[1]);
                list_images = {}
                //var image = new Image()

                $('#accept').on('click', function () {
                    if (currentImage != undefined) {

                        document.getElementById("crop").src = currentImage
                        var testImage = new Image()
                        var canvas = document.getElementById("canvas2");
                        //console.log(testImage.src)
                        canvas.width = 100;
                        canvas.height = 100;
                        var x = 0;
                        var y = 0;
                        var imgWidth = 100;
                        var imgHeight = 100;
                        var auxiliarImage
                        var ctx = canvas.getContext("2d");
                        testImage.onload = function () {
                            //ctx.save();
                            ctx.beginPath();
                            ctx.arc(50, 50, imgHeight * 0.5, 0, Math.PI*2, true);
                            ctx.closePath();
                            ctx.clip();

                            ctx.drawImage(testImage, x, y, imgWidth, imgHeight);

                            ctx.beginPath();
                            ctx.arc(50, 50, imgHeight * 0.5, 0, Math.PI*2, true);
                            ctx.clip();
                            ctx.closePath();
                            //ctx.save()
                            //auxiliarImage = canvas.toDataURL()
                            list_images[number] = canvas.toDataURL()
                            //console.log("Imagen" + list_images[number])
                            for (var n in list_images) {
                            if (selectedColumn == 3) {
                                hot.getSourceData()[n].image = list_images[n];
                            } else if (selectedColumn == 4)
                                hot.getSourceData()[n].image2 = list_images[n];
                        }
                            //ctx.restore();
                            // ctx.drawImage(testImage, x, y, imgWidth, imgHeight);
                        }
                        //ctx.fill()
                        testImage.src = currentImage
                         hot.loadData(hot.getSourceData())

                        // testImage.style.display = 'none';
                        // ctx.fillStyle = "red";
                        // ctx.fillRect(x, y, imgWidth, imgHeight);
                        /*
                        var imageX = ctx.getImageData(x, y, imgWidth, imgHeight);
                        console.log(imageX)
                        var data = imageX.data,
                            length = data.length;
                        for (var i = 0; i < length; i += 4) {
                            imageX.data[i+1] = 255 - imageX.data[i];     // red
                            //imageX.data[i + 1] = 255 - imageX.data[i + 1]; // green
                            //imageX.data[i + 2] = 255 - imageX.data[i + 2]; // blue
                        }
                        imageX.data = data;
                        ctx.putImageData(imageX, 0, 0);
                        testImage.src = canvas.toDataURL();
                        console.log(testImage.src)
                        */

                    }

                    //$('#mdc-dialog-with-list').trigger("reset")
                })
                // $('#cancel').on('click', function(){
                //     dialogScrollable.close()

                // })

            }
        },
        items: {
            'row_above': {
                name: function () {
                    return "keyboard_arrow_up Insertar fila encima";
                }
            }, 'row_below': {
                name: function () {
                    return "keyboard_arrow_down Insertar fila debajo";
                }
            }, 'remove_row': {
                name: function () {
                    return "delete Eliminar fila";
                }
            },
            "hsep1": "---------",
            "edit": {
                name: function () {
                    return "photo_library Editar foto";
                },
                disabled: function () {
                    return !(((hot.getSelected()[1] === 3) || (hot.getSelected()[1] === 4)))
                }
            }
        }
    }
})

Handsontable.dom.addEvent(autosave, 'click', function () {
    if (autosave.checked) {
        exampleConsole.innerText = 'Changes will be autosaved';
    }
    else {
        exampleConsole.innerText = 'Changes will not be autosaved';
    }
});

<|endoftext|>


<commit_before>define([
	'random',
	'app/objects/Platform',
	'app/objects/Garbage',
	'app/objects/CurveRoadSection',
	'noisejs/perlin'
], function(
	random,
	Platform,
	Garbage,
	CurveRoadSection
){
	var fn = function(world, levelSeed) {

		var rand = new random();

		// GOOD level coeficients examples
		levelSeed = 0; // base constructor

		rand.seed(levelSeed);
		noise.seed(levelSeed);

		var length = 1;

		var x = 1;
		var y = 18;
		var ydelta = 0;
		var w = 0;
		var l = 0;
		var prevx = 0;
		var prevy = 0;
		var mx = 0;
		var my = 0;
		var mw = 0;
		var dx = 0;
		var dy = 0;
		var angle = 0;

		// draw road
		this.cr = new CurveRoadSection(world);
		var end = {};

		this.backLimit = 10;
		this.frontLimit = 3;
		this.trackIndex = 0;

		this.firstNode = null; // start of linked list  [first -> next -> next -> last]
		this.lastNode = null; // end of linked list

		for (var i = 0; i <= length; i++) {

			// shift to next position
			end = this.buildFrom(x, y);

			if (this.firstNode === null) {
				this.firstNode = end.startNode;
				this.lastNode = end.lastNode;
			} else {
				this.lastNode.next = end.startNode
				this.lastNode = end.lastNode;
			}

			x = this.lastNode.x;
			y = this.lastNode.y;
		}
	}

	fn.prototype.buildFrom = function(prevx, prevy) {
		// initialize next value from noise generation
		this.trackIndex++;
		ydelta = noise.simplex2(this.trackIndex, 0); // 1D noise

		y = 17 + ydelta * 10;
		x = prevx + 20; //Math.abs(ydelta * 10);

		dx = x - prevx;
		dy = y - prevy;

		return this.cr.buildCurve(prevx, prevy, dx, dy);
	}

	fn.prototype.update = function(offsetX) {
		// remove extra nodes from the end
		var backCut = offsetX - this.backLimit;
		var nextNode = null;
		while (this.firstNode.x < backCut) {
			nextNode = this.firstNode.next;
			this.firstNode.remove();
			this.firstNode = nextNode;
		}

		// add extra nodes to the front
		var frontCut = offsetX + this.frontLimit;
		var curve = null;
		while (this.lastNode.x < frontCut) {
			curve = this.buildFrom(this.lastNode.x, this.lastNode.y);
			this.lastNode.next = curve.startNode;
			this.lastNode = curve.lastNode;
		}
	}

	function avg(a, b) {
		return (a + b) / 2;
	}

	return fn;

});<commit_msg>minor code cleanup<commit_after>define([
	'random',
	'app/objects/Platform',
	'app/objects/Garbage',
	'app/objects/CurveRoadSection',
	'noisejs/perlin'
], function(
	random,
	Platform,
	Garbage,
	CurveRoadSection
){
	var fn = function(world, levelSeed) {

		var rand = new random();

		var levelSeed = 0; // base constructor
		var length = 1;

		this.backLimit = 10;
		this.frontLimit = 3;
		this.trackIndex = 0;

		this.firstNode = null; // start of linked list  [first -> next -> next -> last]
		this.lastNode = null; // end of linked list

		var end = {};
		rand.seed(levelSeed);
		noise.seed(levelSeed);

		// draw road helper that builds curves from blocks
		this.cr = new CurveRoadSection(world);
		var x = 1;
		var y = 18;
		for (var i = 0; i <= length; i++) {

			// build blocks chain
			end = this.buildFrom(x, y);

			// blocks are chained into linked list
			if (this.firstNode === null) {
				this.firstNode = end.startNode;
				this.lastNode = end.lastNode;
			} else {
				this.lastNode.next = end.startNode
				this.lastNode = end.lastNode;
			}

			x = this.lastNode.x;
			y = this.lastNode.y;
		}
	}

	fn.prototype.buildFrom = function(prevx, prevy) {
		// initialize next value from noise generation
		this.trackIndex++;
		ydelta = noise.simplex2(this.trackIndex, 0); // 1D noise

		y = 17 + ydelta * 10;
		x = prevx + 20; //Math.abs(ydelta * 10);

		dx = x - prevx;
		dy = y - prevy;

		return this.cr.buildCurve(prevx, prevy, dx, dy);
	}

	fn.prototype.update = function(offsetX) {
		// remove extra nodes from the end
		var backCut = offsetX - this.backLimit;
		var nextNode = null;
		while (this.firstNode.x < backCut) {
			nextNode = this.firstNode.next;
			this.firstNode.remove();
			this.firstNode = nextNode;
		}

		// add extra nodes to the front
		var frontCut = offsetX + this.frontLimit;
		var curve = null;
		while (this.lastNode.x < frontCut) {
			curve = this.buildFrom(this.lastNode.x, this.lastNode.y);
			this.lastNode.next = curve.startNode;
			this.lastNode = curve.lastNode;
		}
	}

	return fn;

});<|endoftext|>


<commit_before>/* changeElementType: this function changes element types. e.g.
 to
 */
(function($) {
    $.fn.changeElementType = function(newType) {
        var attrs = {};
        if (!(this[0] && this[0].attributes))
            return;

        $.each(this[0].attributes, function(idx, attr) {
            attrs[attr.nodeName] = attr.nodeValue;
        });
        this.replaceWith(function() {
            return $("<" + newType + "/>", attrs).append($(this).contents());
        });
    }
})(jQuery);

/* Batch Downloader START */
$(document).ready(function() {
  $('#batchDownloadLink').closest('li').addClass('dropdown');
  $('#batchDownloadLink').addClass('dropdown-toggle').removeClass('pwg-state-default pwg-button').attr('data-toggle', 'dropdown').attr('href', '#');
  $('#batchDownloadLink .pwg-button-text').after('');
  $('#batchDownloadBox').changeElementType('ul');
  $('#batchDownloadBox a').wrap('

');
  $('#batchDownloadBox').attr('role', 'menu').attr('style', '');
  $('#batchDownloadBox .switchBoxTitle').changeElementType('li');
  $('#batchDownloadBox .switchBoxTitle').addClass('dropdown-header').removeClass('switchBoxTitle');
  $('#batchDownloadBox br').remove();
  $('#batchDownloadBox').addClass('dropdown-menu').removeClass('switchBox');
});
$(window).load(function() {
  $('#batchDownloadLink').off().on('click', function() { $('#downloadSizeLink').dropdown() });
});
/* Batch Downloader END */

/* Download by Size START */
$(document).ready(function() {
  var liDownloadSizeLink = $('#downloadSizeLink').closest('li');
  $('#downloadSizeBox').appendTo(liDownloadSizeLink);
  $(liDownloadSizeLink).addClass('dropdown');
  $('#downloadSizeLink').addClass('dropdown-toggle').removeClass('pwg-state-default pwg-button').attr('data-toggle', 'dropdown');
  $('#downloadSizeLink .pwg-button-text').after('');
  $('#downloadSizeBox').changeElementType('ul');
  $('#downloadSizeBox a').wrap('

');
  $('#downloadSizeBox').attr('role', 'menu').attr('style', '');
  $('#downloadSizeBox .switchBoxTitle').changeElementType('li');
  $('#downloadSizeBox .switchBoxTitle').addClass('dropdown-header').removeClass('switchBoxTitle');
  $('#downloadSizeBox br').remove();
  $('#downloadSizeBox').addClass('dropdown-menu').removeClass('switchBox');
});

$(window).load(function() {
  $('#downloadSizeBox').off('mouseleave click');
  $('#downloadSizeLink').off().on('click', function() { $('#downloadSizeLink').dropdown() });
});
/* Download by Size END */
<commit_msg>more fixes for batchdownloader plugin<commit_after>/* changeElementType: this function changes element types. e.g.
 to
 */
(function($) {
    $.fn.changeElementType = function(newType) {
        var attrs = {};
        if (!(this[0] && this[0].attributes))
            return;

        $.each(this[0].attributes, function(idx, attr) {
            attrs[attr.nodeName] = attr.nodeValue;
        });
        this.replaceWith(function() {
            return $("<" + newType + "/>", attrs).append($(this).contents());
        });
    }
})(jQuery);

/* Batch Downloader START */
$(document).ready(function() {
  $('#batchDownloadLink').closest('li').addClass('dropdown');
  $('#batchDownloadLink').addClass('dropdown-toggle').removeClass('pwg-state-default pwg-button').attr('data-toggle', 'dropdown').attr('href', '#');
  $('#batchDownloadLink .pwg-button-text').after('');
  $('#batchDownloadBox').changeElementType('ul');
  $('#batchDownloadBox a').wrap('

');
  $('#batchDownloadBox').attr('role', 'menu').attr('style', '');
  $('#batchDownloadBox .switchBoxTitle').changeElementType('li');
  $('#batchDownloadBox .switchBoxTitle').addClass('dropdown-header').removeClass('switchBoxTitle');
  $('#batchDownloadBox br').remove();
  $('#batchDownloadBox').addClass('dropdown-menu').removeClass('switchBox');
  $('.navbar-main dt:contains("Downloads")').next('dd').appendTo($('.navbar-main dt:contains("Downloads")'));
  $('.navbar-main dt:contains("Downloads")').wrap('

');
  $('.navbar-main dt:contains("Downloads")').closest('li').addClass('dropdown').attr('id', 'bd_downloads');
  $('.navbar-main dt:contains("Downloads")').changeElementType('a');
  $('#bd_downloads>a').addClass('dropdown-toggle').attr('data-toggle', 'dropdown').append('');
  $('#bd_downloads dd ul').appendTo('#bd_downloads');
  $('#bd_downloads dd').remove();
  $('#bd_downloads ul').addClass('dropdown-menu');
  $('#bd_downloads ul').find('span').each(function() { $(this).appendTo($(this).prev('a')); });
});
$(window).load(function() {
  $('#batchDownloadLink').off().on('click', function() { $('#downloadSizeLink').dropdown() });
});
/* Batch Downloader END */

/* Download by Size START */
$(document).ready(function() {
  var liDownloadSizeLink = $('#downloadSizeLink').closest('li');
  $('#downloadSizeBox').appendTo(liDownloadSizeLink);
  $(liDownloadSizeLink).addClass('dropdown');
  $('#downloadSizeLink').addClass('dropdown-toggle').removeClass('pwg-state-default pwg-button').attr('data-toggle', 'dropdown');
  $('#downloadSizeLink .pwg-button-text').after('');
  $('#downloadSizeBox').changeElementType('ul');
  $('#downloadSizeBox a').wrap('

');
  $('#downloadSizeBox').attr('role', 'menu').attr('style', '');
  $('#downloadSizeBox .switchBoxTitle').changeElementType('li');
  $('#downloadSizeBox .switchBoxTitle').addClass('dropdown-header').removeClass('switchBoxTitle');
  $('#downloadSizeBox br').remove();
  $('#downloadSizeBox').addClass('dropdown-menu').removeClass('switchBox');
});

$(window).load(function() {
  $('#downloadSizeBox').off('mouseleave click');
  $('#downloadSizeLink').off().on('click', function() { $('#downloadSizeLink').dropdown() });
});
/* Download by Size END */
<|endoftext|>


<commit_before>var _QACALLBACK_;
$(document).ready(
	function() {
		function parse(v) {
			var t = v.replace(/(“|”)/ig, '"');
			return JSON.parse(t);
		}
		var v = $('.qaletplugin'), r={}, f=[];
		for (var i = 0; i < v.length; i++) {
			var o = parse($(v[i]).attr('data'));
			if (o.module) {
				r[o.module] = true;
				o.id = o.module + '_plugin_' + i;
				f[f.length] = o;
				 $(v[i]).html('

');
			}
		}

		_QACALLBACK_ = function() {
			for (var i=0; i<f.length; i++) {
				_QALET_[f[i].module](f[i]);
				$(v[i]).fadeIn( "slow");
			}
		};
		_QACALLBACK_();
		$('<link>').appendTo('head').attr({ type: 'text/css', rel: 'stylesheet', href: '//qalet.com/css/bootstrap.min.css' });
		$('<link>').appendTo('head').attr({ type: 'text/css', rel: 'stylesheet', href: '//docviewer.qalet.com/package/docviewer_wp.min.css' });
	//	$.getScript('http://docviewer.qalet.com/package/qalet_plugin_plus.jsx?plus='+Object.keys(r).join(',') + '&callback=_QACALLBACK_');
	}
);
<commit_msg>Update qalet_plugin.js<commit_after>var _CALLBACK_;
$(document).ready(
	function() {
		function parse(v) {
			var t = v.replace(/(“|”)/ig, '"');
			return JSON.parse(t);
		}
		var v = $('.qaletplugin'), r={}, f=[];
		for (var i = 0; i < v.length; i++) {
			var o = parse($(v[i]).attr('data'));
			if (o.module) {
				r[o.module] = true;
				o.id = o.module + '_plugin_' + i;
				f[f.length] = o;
				 $(v[i]).html('

');
			}
		}

		_CALLBACK_ = function() {
			for (var i=0; i<f.length; i++) {
				_QALET_[f[i].module](f[i]);
				$(v[i]).fadeIn( "slow");
			}
		};

		$('<link>').appendTo('head').attr({ type: 'text/css', rel: 'stylesheet', href: '//qalet.com/css/bootstrap.min.css' });
		$('<link>').appendTo('head').attr({ type: 'text/css', rel: 'stylesheet', href: '//docviewer.qalet.com/package/docviewer_wp.min.css' });
	//	$.getScript('http://docviewer.qalet.com/package/qalet_plugin_plus.jsx?plus='+Object.keys(r).join(',') + '&callback=_QACALLBACK_');
	}
);
<|endoftext|>


<commit_before>/**
 * QuickBlox VideoChat WebRTC library
 * version 0.1.0
 *
 * Author: Igor Khomenko (igor@quickblox.com)
 *
 */

/*
  Public methods:
    - call(userID)
    - accept(userID)
    - reject(userID)
    - stop(userID)

  Public callbacks:
    - onCall(fromUserID, sessionDescription)
    - onAccept(fromUserID, sessionDescription)
    - onReject(fromUserID)
    - onStop(fromUserID, reason)
    - onCandidate(fromUserID, candidate)
 */

var SDP_CONSTRAINTS = {
	'mandatory': {
		'OfferToReceiveAudio': true,
		'OfferToReceiveVideo': true
	}
};

var QBVideoChatState = {
	INACTIVE: 'inactive',
	ESTABLISHING: 'establishing',
	ACTIVE: 'active'
};

function QBVideoChat(constraints, localStreamElement, remoteStreamElement, signalingService, sessionID) {
 	var self = this;

	this.sessionID = sessionID || new Date().getTime();
	traceVC("sessionID = " + this.sessionID);

	this.candidatesQueue = [];
	this.remoteSessionDescription = null;
	this.state = QBVideoChatState.INACTIVE;

	this.localStreamElement = localStreamElement;
	this.remoteStreamElement = remoteStreamElement;
	this.constraints = constraints;

	this.signalingService = signalingService;
	this.signalingService.onCandidateCallback = this.addCandidate;
	this.signalingService.addOnAcceptCallback(this.onAcceptSignalingCallback);

	// Signalling callbacks
	this.addCandidate = function(data) {
		traceVC("Added remote candidate");
		var jsonCandidate, candidate;

		jsonCandidate = self.signalingService.xmppTextToDictionary(data);
		candidate = new RTCIceCandidate(jsonCandidate);

		self.pc.addIceCandidate(candidate);
	};

	this.onAcceptSignalingCallback = function(sessionDescription) {
		console.log('true');
		self.setRemoteDescription(sessionDescription, "answer"); //TODO: refactor this (hide)
	};

	// MediaStream getUserMedia
	this.getUserMedia = function() {
		traceVC("getUserMedia...");

		getUserMedia(this.constraints, successCallback, errorCallback);

		function successCallback(localMediaStream) {
			traceVC("getUserMedia success");
			self.localStream = localMediaStream;
			console.log(localMediaStream);
			attachMediaStream(self.localStreamElement, localMediaStream);
			self.createRTCPeerConnection();
			self.onGetUserMediaSuccess();
		}

		function errorCallback(error) {
			traceVC("getUserMedia error: ", error);
			self.onGetUserMediaSuccess();
		}
	};

	this.onGetUserMediaSuccess = null;
	this.onGetUserMediaError = null;

	// RTCPeerConnection creation
	this.createRTCPeerConnection = function() {
		traceVC("RTCPeerConnection...");
		try {
			this.pc = new RTCPeerConnection(ICE_SERVERS);
			this.pc.onicecandidate = this.onIceCandidateCallback;
			this.pc.onaddstream = this.onRemoteStreamAddedCallback;
			this.pc.onremovestream = this.onRemoteStreamRemovedCallback;

			this.pc.addStream(this.localStream);

			traceVC('RTCPeerConnnection created');
			//console.log(this.pc);
		} catch (e) {
			traceVC('RTCPeerConnection failed: ' + e.message);
		}
	};

	// onIceCandidate callback
	this.onIceCandidateCallback = function(event) {
		//traceVC('iceGatheringState: ' + event.target.iceGatheringState);
		var iceData, iceDataAsmessage, candidate = event.candidate;

		if (candidate) {
			iceData = {
				sdpMLineIndex: candidate.sdpMLineIndex,
				candidate: candidate.candidate,
				sdpMid: candidate.sdpMid
			};

			iceDataAsmessage = self.signalingService.xmppDictionaryToText(iceData);

			if (self.state == QBVideoChatState.INACTIVE) {
				// save to queue
				self.candidatesQueue.push(iceDataAsmessage);
			} else {
				// Send ICE candidate to opponent
				self.signalingService.sendCandidate(self.opponentID, iceDataAsmessage, self.sessionID);
			}
		}
	};

	// onRemoteStreamAdded callback
	this.onRemoteStreamAddedCallback = function(event) {
		traceVC('Remote stream added...');

		console.log(event);
		self.remoteStream = event.stream;
		attachMediaStream(self.remoteStreamElement, event.stream);
	};

	// onRemoteStreamRemoved callback
	this.onRemoteStreamRemovedCallback = function(event) {
		traceVC('Remote stream removed...');
	};

	// set Local description
	this.onGetSessionDescriptionSuccessCallback = function(sessionDescription) {
		traceVC('LocalDescription...');

		self.pc.setLocalDescription(sessionDescription,

                                function onSuccess() {
                                  traceVC('LocalDescription success');
                                  self.localSessionDescription = sessionDescription;

                                  // ICE gathering starts work here
                                  if (sessionDescription.type === 'offer')
                                    self.sendCallRequest();
                                  else if (sessionDescription.type === 'answer')
                                    self.sendAceptRequest();
                                },

                                function onError(error) {
                                  traceVC('LocalDescription error: ' + error);
                                }
		);
	};

	this.onCreateOfferFailureCallback = function(event) {
		traceVC('createOffer() error: ', event);
	};

	// set Remote description
	this.setRemoteDescription = function(descriptionSDP, descriptionType) {
		traceVC('RemoteDescription...');
		var sessionDescription, candidate;

		sessionDescription = new RTCSessionDescription({sdp: descriptionSDP, type: descriptionType});

		this.pc.setRemoteDescription(sessionDescription,

                                 function onSuccess() {
                                   traceVC("RemoteDescription success");

                                   if (sessionDescription.type === 'offer')
                                     self.pc.createAnswer(self.onGetSessionDescriptionSuccessCallback, self.onCreateAnswerFailureCallback, SDP_CONSTRAINTS);
                                 },

                                 function onError(error) {
                                   traceVC('RemoteDescription error: ' + error);
                                 }
		);

		// send candidates
		for (var i = 0; i < this.candidatesQueue.length; i++) {
			candidate = this.candidatesQueue.pop();
			self.signalingService.sendCandidate(self.opponentID, candidate, self.sessionID);
		}
	};

	this.onCreateAnswerFailureCallback = function(event) {
		traceVC('createAnswer() error: ', event);
	};

	this.sendCallRequest = function() {
		// Send only string representation of sdp
		// http://www.w3.org/TR/webrtc/#rtcsessiondescription-class

		self.signalingService.call(self.opponentID, self.localSessionDescription.sdp, self.sessionID);
	};

	this.sendAceptRequest = function() {
		// Send only string representation of sdp
		// http://www.w3.org/TR/webrtc/#rtcsessiondescription-class

		self.signalingService.accept(self.opponentID, self.localSessionDescription.sdp, self.sessionID);
	};

	// Cleanup
	this.hangup = function() {
		traceVC("Closed RTC");
		self.pc.close();
		self.pc = null;
	};
}

// Call to user
QBVideoChat.prototype.call = function(userID) {
	if (this.localSessionDescription) return;

	this.opponentID = userID;
	this.pc.createOffer(this.onGetSessionDescriptionSuccessCallback, this.onCreateOfferFailureCallback);
};

// Accept call from user
QBVideoChat.prototype.accept = function(userID) {
	this.opponentID = userID;
	this.state = QBVideoChatState.ESTABLISHING;

	// set remote description here
	this.setRemoteDescription(this.remoteSessionDescription, "offer");
};

// Reject call from user
QBVideoChat.prototype.reject = function(userID) {
	traceVC("reject");
	this.signalingService.reject(userID, this.sessionID);

	this.state = QBVideoChatState.INACTIVE;
};

// Stap call with user
QBVideoChat.prototype.stop = function(userID) {
	traceVC("stop");
	this.signalingService.stops(userID, "manual", this.sessionID);

	this.state = QBVideoChatState.INACTIVE;
};

function traceVC(text) {
	console.log("[qb_videochat]: " + text);
}<commit_msg>test commit<commit_after>/**
 * QuickBlox VideoChat WebRTC library
 * version 0.1.0
 *
 * Author: Igor Khomenko (igor@quickblox.com)
 *
 */

/*
  Public methods:
    - call(userID)
    - accept(userID)
    - reject(userID)
    - stop(userID)

  Public callbacks:
    - onCall(fromUserID, sessionDescription)
    - onAccept(fromUserID, sessionDescription)
    - onReject(fromUserID)
    - onStop(fromUserID, reason)
    - onCandidate(fromUserID, candidate)
 */

var SDP_CONSTRAINTS = {
	'mandatory': {
		'OfferToReceiveAudio': true,
		'OfferToReceiveVideo': true
	}
};

var QBVideoChatState = {
	INACTIVE: 'inactive',
	ESTABLISHING: 'establishing',
	ACTIVE: 'active'
};

function QBVideoChat(constraints, localStreamElement, remoteStreamElement, signalingService, sessionID) {
 	var self = this;

	this.sessionID = sessionID || new Date().getTime();
	traceVC("sessionID = " + this.sessionID);

	this.candidatesQueue = [];
	this.remoteSessionDescription = null;
	this.state = QBVideoChatState.INACTIVE;

	this.localStreamElement = localStreamElement;
	this.remoteStreamElement = remoteStreamElement;
	this.constraints = constraints;

	this.signalingService = signalingService;
	this.signalingService.onCandidateCallback = this.addCandidate;
	this.signalingService.addOnAcceptCallback(this.onAcceptSignalingCallback);

	// Signalling callbacks
	this.addCandidate = function(data) {
		traceVC("Added remote candidate");
		var jsonCandidate, candidate;

		jsonCandidate = self.signalingService.xmppTextToDictionary(data);
		candidate = new RTCIceCandidate(jsonCandidate);

		self.pc.addIceCandidate(candidate);
	};

	this.onAcceptSignalingCallback = function(sessionDescription) {
		console.log('true');
		self.setRemoteDescription(sessionDescription, "answer"); //TODO: refactor this (hide)
	};

	// MediaStream getUserMedia
	this.getUserMedia = function() {
		traceVC("getUserMedia...");

		getUserMedia(this.constraints, successCallback, errorCallback);

		function successCallback(localMediaStream) {
			traceVC("getUserMedia success");
			self.localStream = localMediaStream;
			console.log(localMediaStream);
			attachMediaStream(self.localStreamElement, localMediaStream);
			self.createRTCPeerConnection();
			self.onGetUserMediaSuccess();
		}

		function errorCallback(error) {
			traceVC("getUserMedia error: ", error);
			self.onGetUserMediaSuccess();
		}
	};

	this.onGetUserMediaSuccess = null;
	this.onGetUserMediaError = null;

	// RTCPeerConnection creation
	this.createRTCPeerConnection = function() {
		traceVC("RTCPeerConnection...");
		try {
			this.pc = new RTCPeerConnection(ICE_SERVERS);
			this.pc.onicecandidate = this.onIceCandidateCallback;
			this.pc.onaddstream = this.onRemoteStreamAddedCallback;
			this.pc.onremovestream = this.onRemoteStreamRemovedCallback;

			this.pc.addStream(this.localStream);

			traceVC('RTCPeerConnnection created');
			//console.log(this.pc);
		} catch (e) {
			traceVC('RTCPeerConnection failed: ' + e.message);
		}
	};

	// onIceCandidate callback
	this.onIceCandidateCallback = function(event) {
		//traceVC('iceGatheringState: ' + event.target.iceGatheringState);
		var iceData, iceDataAsmessage, candidate = event.candidate;

		if (candidate) {
			iceData = {
				sdpMLineIndex: candidate.sdpMLineIndex,
				candidate: candidate.candidate,
				sdpMid: candidate.sdpMid
			};

			iceDataAsmessage = self.signalingService.xmppDictionaryToText(iceData);

			if (self.state == QBVideoChatState.INACTIVE) {
				// save to queue
				self.candidatesQueue.push(iceDataAsmessage);
			} else {
				// Send ICE candidate to opponent
				self.signalingService.sendCandidate(self.opponentID, iceDataAsmessage, self.sessionID);
			}
		}
	};

	// onRemoteStreamAdded callback
	this.onRemoteStreamAddedCallback = function(event) {
		traceVC('Remote stream added...');

		console.log(event);
		self.remoteStream = event.stream;
		attachMediaStream(self.remoteStreamElement, event.stream);
	};

	// onRemoteStreamRemoved callback
	this.onRemoteStreamRemovedCallback = function(event) {
		traceVC('Remote stream removed...');
	};

	// set Local description
	this.onGetSessionDescriptionSuccessCallback = function(sessionDescription) {
		traceVC('LocalDescription...');

		self.pc.setLocalDescription(sessionDescription,

                                function onSuccess() {
                                  traceVC('LocalDescription success');
                                  self.localSessionDescription = sessionDescription;

                                  // ICE gathering starts work here
                                  if (sessionDescription.type === 'offer')
                                    self.sendCallRequest();
                                  else if (sessionDescription.type === 'answer')
                                    self.sendAceptRequest();
                                },

                                function onError(error) {
                                  traceVC('LocalDescription error: ' + error);
                                }
		);
	};

	this.onCreateOfferFailureCallback = function(event) {
		traceVC('createOffer() error: ', event);
	};

	// set Remote description
	this.setRemoteDescription = function(descriptionSDP, descriptionType) {
		traceVC('RemoteDescription...');
		var sessionDescription, candidate;

		this.state = QBVideoChatState.ESTABLISHING;
		sessionDescription = new RTCSessionDescription({sdp: descriptionSDP, type: descriptionType});

		this.pc.setRemoteDescription(sessionDescription,

                                 function onSuccess() {
                                   traceVC("RemoteDescription success");

                                   if (sessionDescription.type === 'offer')
                                     self.pc.createAnswer(self.onGetSessionDescriptionSuccessCallback, self.onCreateAnswerFailureCallback, SDP_CONSTRAINTS);
                                 },

                                 function onError(error) {
                                   traceVC('RemoteDescription error: ' + error);
                                 }
		);

		// send candidates
		for (var i = 0; i < this.candidatesQueue.length; i++) {
			candidate = this.candidatesQueue.pop();
			self.signalingService.sendCandidate(self.opponentID, candidate, self.sessionID);
		}
	};

	this.onCreateAnswerFailureCallback = function(event) {
		traceVC('createAnswer() error: ', event);
	};

	this.sendCallRequest = function() {
		// Send only string representation of sdp
		// http://www.w3.org/TR/webrtc/#rtcsessiondescription-class

		self.signalingService.call(self.opponentID, self.localSessionDescription.sdp, self.sessionID);
	};

	this.sendAceptRequest = function() {
		// Send only string representation of sdp
		// http://www.w3.org/TR/webrtc/#rtcsessiondescription-class

		self.signalingService.accept(self.opponentID, self.localSessionDescription.sdp, self.sessionID);
	};

	// Cleanup
	this.hangup = function() {
		traceVC("Closed RTC");
		self.pc.close();
		self.pc = null;
	};
}

// Call to user
QBVideoChat.prototype.call = function(userID) {
	if (this.localSessionDescription) return;

	this.opponentID = userID;
	this.pc.createOffer(this.onGetSessionDescriptionSuccessCallback, this.onCreateOfferFailureCallback);
};

// Accept call from user
QBVideoChat.prototype.accept = function(userID) {
	this.opponentID = userID;
	this.setRemoteDescription(this.remoteSessionDescription, "offer");
};

// Reject call from user
QBVideoChat.prototype.reject = function(userID) {
	traceVC("reject");
	this.signalingService.reject(userID, this.sessionID);

	this.state = QBVideoChatState.INACTIVE;
};

// Stap call with user
QBVideoChat.prototype.stop = function(userID) {
	traceVC("stop");
	this.signalingService.stops(userID, "manual", this.sessionID);

	this.state = QBVideoChatState.INACTIVE;
};

function traceVC(text) {
	console.log("[qb_videochat]: " + text);
}<|endoftext|>


<commit_before>//
// Please update "commments" to "submit point"
//

'use strict';

var assertionUrl = 'https://3pp.io:4343/persona';
var postPointUrl = 'https://3pp.io:4343/post/point';
var serviceListUrl = 'https://tosdr.org/index/services.json';

$(document).ready(function(){
	var loggedInUser = null;

	function logout(){
		loggedInUser = null;
		var response = $.post(assertionUrl + '/logout');
		response.always(showPersona);
	}

	function verify(assertion){
		var response = $.ajax(assertionUrl + '/verify', {data: {assertion: assertion}, type: 'POST', xhrFields: {withCredentials: true}});
		response.done(login);
		response.fail(function(){
			navigator.id.logout();
		});
	}

	function login(data){
		showSubmitForm(data.email);
	}

	navigator.id.watch({
		loggedInUser: loggedInUser,
		onlogin: verify,
		onlogout: logout
	});

	function showPersona(){
		$('#form').html('
To submit a point, please sign in — you can use an existing email address.

');
		$('.signinButton').click(function(){ navigator.id.request(); }).css('cursor', 'pointer');
	}

        // This is ugly, too much html here
        //
        //

	function showSubmitForm(email){
		$('#form').html('
Submitting as ' + email + ' (Not your email address?)
' +
                        '<form class="submitForm">' +
                            '<fieldset>' +
                                'Title<input type="text" id="titleField" name="title" required />' +
                                '<input type="radio" required name="point" id="pointBad" value="bad" />Bad<input type="radio" name="point" id="pointNeutral" value="neutral" />Neutral<input type="radio" name="point" id="pointGood" value="good" />Good' +
                                'Service(s)<input id="servicesField" name="services" required class="input-large" />' +
                                'Topic<input id="topicsField" name="topics" required class="input-large" />' +
                                'Can you summarise this clause?<textarea name="summary" id="summaryField" required class="input-xxlarge"></textarea>
<button class="btn btn-primary" id="postPoint">Send</button>' +
                            '</fieldset>' +
                        '</form>');

        var response = $.get(serviceListUrl, 'json');
        response.done(function(services){
            services = $.map(services, function(value, key){
                return key;
            });
            // Note: the width should be 'element', but for some reason it receives a different width than other input elements
            $('#servicesField').select2({tags: services, width: '220px', containerCss: {'border-radius': '4px'}});
        });

		$('.submitForm').submit(function(e){
			var response = $.ajax(postPointUrl, {data: {title: $('#titleField').val(), point: $('input[name=point]:checked', '.submitForm').val(), services: $('#servicesField').val(), summary: $('#summaryField').val()}, type: 'POST', xhrFields: {withCredentials: true}});
			response.done(showConfirmation);
			response.fail(showError);
			e.preventDefault();
		});
		$('.signoutButton').click(function(){ navigator.id.logout(); });
	}

	function showConfirmation(){
		$('#form').html('Your point has been submitted. Thank you! '
                   +'submit another one or '
                   +'see the list.');
	}

	function showError(){
		$('#form').prepend('
<button type="button" class="close" data-dismiss="alert">×</button>Something went wrong saving your point, did you fill in all the fields?
');
	}

	showPersona();
});
<commit_msg>separate fieldset<commit_after>//
// Please update "commments" to "submit point"
//

'use strict';

var assertionUrl = 'https://3pp.io:4343/persona';
var postPointUrl = 'https://3pp.io:4343/post/point';
var serviceListUrl = 'https://tosdr.org/index/services.json';

$(document).ready(function(){
	var loggedInUser = null;

	function logout(){
		loggedInUser = null;
		var response = $.post(assertionUrl + '/logout');
		response.always(showPersona);
	}

	function verify(assertion){
		var response = $.ajax(assertionUrl + '/verify', {data: {assertion: assertion}, type: 'POST', xhrFields: {withCredentials: true}});
		response.done(login);
		response.fail(function(){
			navigator.id.logout();
		});
	}

	function login(data){
		showSubmitForm(data.email);
	}

	navigator.id.watch({
		loggedInUser: loggedInUser,
		onlogin: verify,
		onlogout: logout
	});

	function showPersona(){
		$('#form').html('
To submit a point, please sign in — you can use an existing email address.

');
		$('.signinButton').click(function(){ navigator.id.request(); }).css('cursor', 'pointer');
	}

        // This is ugly, too much html here
        //
        //

	function showSubmitForm(email){
		$('#form').html('
Submitting as ' + email + ' (Not your email address?)
' +
                        '<form class="submitForm">' +
                            '<fieldset>' +
                                'Title<input type="text" id="titleField" name="title" required />' +
                                '<input type="radio" required name="point" id="pointBad" value="bad" />Bad<input type="radio" name="point" id="pointNeutral" value="neutral" />Neutral<input type="radio" name="point" id="pointGood" value="good" />Good' +
                                'Service(s)<input id="servicesField" name="services" required class="input-large" />' +
                                'Topic<input id="topicsField" name="topics" required class="input-large" />' +
                                'Can you summarise this clause?<textarea name="summary" id="summaryField" required class="input-xxlarge"></textarea>' +
                            '</fieldset>' +
                            '
' +
                                '<button class="btn btn-primary" id="postPoint">Send</button>' +
                            '
' +
                        '</form>');

        var response = $.get(serviceListUrl, 'json');
        response.done(function(services){
            services = $.map(services, function(value, key){
                return key;
            });
            // Note: the width should be 'element', but for some reason it receives a different width than other input elements
            $('#servicesField').select2({tags: services, width: '220px', containerCss: {'border-radius': '4px'}});
        });

		$('.submitForm').submit(function(e){
			var response = $.ajax(postPointUrl, {data: {title: $('#titleField').val(), point: $('input[name=point]:checked', '.submitForm').val(), services: $('#servicesField').val(), summary: $('#summaryField').val()}, type: 'POST', xhrFields: {withCredentials: true}});
			response.done(showConfirmation);
			response.fail(showError);
			e.preventDefault();
		});
		$('.signoutButton').click(function(){ navigator.id.logout(); });
	}

	function showConfirmation(){
		$('#form').html('Your point has been submitted. Thank you! '
                   +'submit another one or '
                   +'see the list.');
	}

	function showError(){
		$('#form').prepend('
<button type="button" class="close" data-dismiss="alert">×</button>Something went wrong saving your point, did you fill in all the fields?
');
	}

	showPersona();
});
<|endoftext|>


<commit_before>import expect from 'expect';
import { msToTime, leadingDigits } from './../../lib/utils/date';

describe('date utils', function () {
  describe('leadingDigits function', function () {
    it('should return any two-digit number as a string', function () {
      const result = leadingDigits(11);

      expect(result).toBeA('string');
      expect(result).toBe('11');
    });

    it('should add a leading 0 to any one-digit number', function () {
      const result = leadingDigits(1);

      expect(result).toBeA('string');
      expect(result).toBe('01');
    });

    it('should be able to pad milliseconds', function () {
      const result = leadingDigits(1, 3);

      expect(result).toBeA('string');
      expect(result).toBe('001');
    });
  });

  describe('timeToMs function', function () {
    it('should convert milliseconds to a Time object', function () {
      const time = {
        days: 1,
        hours: 2,
        minutes: 3,
        seconds: 4,
        milliseconds: 5,
      };

      const timeObj = msToTime(5 + (4 + (3 + (2 + (1 * 24)) * 60) * 60) * 1000);

      expect(timeObj.days).toBe(time.days);
      expect(timeObj.hours).toBe(time.hours);
      expect(timeObj.minutes).toBe(time.minutes);
      expect(timeObj.seconds).toBe(time.seconds);
      expect(timeObj.milliseconds).toBe(time.milliseconds);
    });
  });
});
<commit_msg>test correction<commit_after>import expect from 'expect';
import { msToTime, leadingDigits } from './../../lib/utils/date';

describe('date utils', function () {
  describe('leadingDigits function', function () {
    it('should return any two-digit number as a string', function () {
      const result = leadingDigits(11);

      expect(result).toBeA('string');
      expect(result).toBe('11');
    });

    it('should add a leading 0 to any one-digit number', function () {
      const result = leadingDigits(1);

      expect(result).toBeA('string');
      expect(result).toBe('01');
    });

    it('should be able to pad milliseconds', function () {
      const result = leadingDigits(1, 3);

      expect(result).toBeA('string');
      expect(result).toBe('001');
    });
  });

  describe('timeToMs function', function () {
    it('should convert milliseconds to a Time object', function () {
      const time = {
        days: 2,
        hours: 2,
        minutes: 3,
        seconds: 4,
        milliseconds: 5,
      };

      const timeObj = msToTime(5 + (4 + (3 + (2 + (2 * 24)) * 60) * 60) * 1000);

      expect(timeObj.days).toBe(time.days);
      expect(timeObj.hours).toBe(time.hours);
      expect(timeObj.minutes).toBe(time.minutes);
      expect(timeObj.seconds).toBe(time.seconds);
      expect(timeObj.milliseconds).toBe(time.milliseconds);
    });
  });
});
<|endoftext|>


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

/**
 * @fileoverview [MODULE: edit] The toolbar for editing commands.
 * @author kpy@google.com (Ka-Ping Yee)
 */
goog.provide('cm.ToolbarView');

goog.require('cm.MapModel');
goog.require('cm.css');
goog.require('cm.events');
goog.require('cm.ui');
goog.require('goog.dom');
goog.require('goog.format.JsonPrettyPrinter');
goog.require('goog.json');
goog.require('goog.net.XhrIo');
goog.require('goog.string');

/** @desc Label for a link that lets the user rearrange the layer
 *  order and hierarchy.
 */

/** @desc Link text to arrange the layers in the panel. */
var MSG_ARRANGE_LAYERS_LINK = goog.getMsg('Arrange');

/** @desc Link text to arrange the layers in the panel. */
var MSG_SHARE_EMAIL_LINK = goog.getMsg('Share with user');

/** @desc Link text to add a new layer to the map. */
var MSG_ADD_NEW_LAYERS = goog.getMsg('Add layers');

/** @desc Default title for an empty layer. */
var MSG_UNTITLED_LAYER = goog.getMsg('Untitled Layer');

/** @desc Link text to add a new folder to the map. */
var MSG_ADD_NEW_FOLDER = goog.getMsg('Add folder');

/** @desc Link text to return to map list. */
var MSG_BACK_TO_MAP_LIST = goog.getMsg('Back to map list');

/** @desc Default title for an empty folder. */
var MSG_UNTITLED_FOLDER = goog.getMsg('Untitled Folder');

/** @desc Warning message when discarding unsaved changes. */
var MSG_UNSAVED_CHANGES = goog.getMsg(
    'You have unsaved changes that will be lost if you leave' +
    ' the page without clicking the "Save" link.');

/**
 * A command toolbar.  For now, this is just a few links, but in future will
 * contain other editing/drawing functions.
 * @param {Element} parentElem The DOM element in which to render the toolbar.
 * @param {cm.MapModel} mapModel The map model.
 * @param {boolean} enableSave True to enable the "Save" function.
 * @param {boolean} devMode True to enable the "Show JSON" function.
 * @param {string} mapListUrl The URL endpoint for the user's map list.
 * @param {boolean} touch True if the map is being edited on a touch device.
 * @param {string=} opt_diffUrl URL used in devMode to diff the current
 *     maproot against the original maproot.
 * @constructor
 */
cm.ToolbarView = function(parentElem, mapModel, enableSave, devMode, mapListUrl,
    touch, opt_diffUrl) {
  // Initially, neither the undo nor the redo operation can be done.
  var undoLink = cm.ui.createLink('Undo');
  var redoLink = cm.ui.createLink('Redo');
  goog.dom.classes.add(undoLink, cm.css.DISABLED);
  goog.dom.classes.add(redoLink, cm.css.DISABLED);

  var undoLinkEventToken = cm.events.forward(undoLink, 'click',
      goog.global, cm.events.UNDO);
  var redoLinkEventToken = cm.events.forward(redoLink, 'click',
      goog.global, cm.events.REDO);

  cm.events.listen(goog.global, cm.events.UNDO_REDO_BUFFER_CHANGED,
    function(e) {
      goog.dom.classes.enable(undoLink, cm.css.DISABLED, !e.undo_possible);
      goog.dom.classes.enable(redoLink, cm.css.DISABLED, !e.redo_possible);
  }, this);

  var toolbarElem = cm.ui.create('div', {'class': cm.css.TOOLBAR});
  var backToMapsLink = cm.ui.createLink(MSG_BACK_TO_MAP_LIST, mapListUrl);
  cm.ui.append(toolbarElem, backToMapsLink, cm.ui.SEPARATOR_DOT,
               undoLink, cm.ui.SEPARATOR_DOT, redoLink, cm.ui.SEPARATOR_DOT);

  if (!touch) {
    var arrangeLink = cm.ui.createLink(MSG_ARRANGE_LAYERS_LINK);
    cm.ui.append(toolbarElem, arrangeLink, cm.ui.SEPARATOR_DOT);
    cm.events.forward(arrangeLink, 'click', goog.global, cm.events.ARRANGE);
  }

  var addNewLayerLink = cm.ui.createLink(MSG_ADD_NEW_LAYERS);
  cm.events.forward(addNewLayerLink, 'click', goog.global,
      cm.events.IMPORT);
  cm.ui.append(toolbarElem, addNewLayerLink, cm.ui.SEPARATOR_DOT);

  // TODO(joeysilva): Use INSPECT event to create new folders by using a type
  // FOLDER argument.
  var addNewFolderLink = cm.ui.createLink(MSG_ADD_NEW_FOLDER);
  cm.events.forward(
      addNewFolderLink, 'click', goog.global, cm.events.ADD_LAYERS, {
        layers: [{title: MSG_UNTITLED_FOLDER, type: cm.LayerModel.Type.FOLDER}]
      });
  cm.ui.append(toolbarElem, addNewFolderLink);

  if (enableSave) {
    var saveLink = cm.ui.createLink('Saved');
    cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, saveLink);

    // The "Save" link is initially disabled. Changing the model enables it.
    goog.dom.classes.add(saveLink, cm.css.DISABLED);
    cm.events.listen(goog.global, cm.events.MODEL_CHANGED, function() {
      cm.ui.setText(saveLink, 'Save');
      goog.dom.classes.remove(saveLink, cm.css.DISABLED, cm.css.ERROR);
    }, this);

    // Handle clicks on the "Save" link.
    cm.events.listen(saveLink, 'click', function() {
      if (!goog.dom.classes.has(saveLink, cm.css.DISABLED)) {
        cm.ui.setText(saveLink, 'Saving...');
        goog.dom.classes.remove(saveLink, cm.css.ERROR);
        goog.dom.classes.add(saveLink, cm.css.DISABLED);
        cm.events.emit(goog.global, cm.events.SAVE, {model: mapModel});
      }
    });

    // Handle completion of the Save operation.
    cm.events.listen(goog.global, cm.events.SAVE_DONE, function() {
      cm.ui.setText(saveLink, 'Saved');
    }, this);
    cm.events.listen(goog.global, cm.events.SAVE_FAILED, function() {
      // If the save fails, leave the link enabled so the user can click it
      // to try again.  Not the most elegant solution, but good enough for now.
      goog.dom.classes.remove(saveLink, cm.css.DISABLED);
      goog.dom.classes.add(saveLink, cm.css.ERROR);
      cm.ui.setText(saveLink, 'Save failed');
    }, this);

    // This way works for Chrome, Firefox.
    // cm.events.listen only works in Chrome.
    // In Chrome, this event will not get fired if you navigate to another page
    // within this app via the navigation bar.
    window.onbeforeunload = function() {
      if (!goog.dom.classes.has(saveLink, cm.css.DISABLED)) {
        return MSG_UNSAVED_CHANGES;
      }
    };

    var shareEmailLink = cm.ui.createLink(MSG_SHARE_EMAIL_LINK);
    cm.events.forward(shareEmailLink, 'click',
                      goog.global, cm.events.SHARE_EMAIL);
    cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, shareEmailLink);
  }

  if (devMode) {
    var diffJsonLink = cm.ui.createLink(opt_diffUrl ? 'Diff' : 'Show JSON');
    cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, diffJsonLink);
    cm.events.listen(diffJsonLink, 'click', goog.bind(
        this.handleDiffJsonClick_, this, mapModel, opt_diffUrl));
  }

  parentElem.appendChild(toolbarElem);
};

/**
 * Displays a popup showing diffs between the MapRoot JSON of the most recently
 * saved draft as well as any/all published versions of this map, against the
 * current, unsaved draft. Will simply show the current, unsaved draft if no
 * map ID is provided.
 * @param {cm.MapModel} mapModel The map model.
 * @param {string=} opt_diffUrl URL used to retrieve diffs between the current,
 *     currently saved, and published versions of this map.
 * @private
 */
cm.ToolbarView.prototype.handleDiffJsonClick_ =
    function(mapModel, opt_diffUrl) {
  var popup = cm.ui.create('div', {'class': [cm.css.POPUP, cm.css.DIFF]});
  cm.ui.createCloseButton(
      popup, function() { goog.dom.removeNode(popup); });
  cm.ui.showPopup(popup);

  // Define links and content element used by showJson and showDiff methods.
  var showJsonLink, showDiffLink;
  var contentElem = cm.ui.create('div');

  // Method to show JSON. Used by JSON link, and when diffs cannot be loaded.
  var showJson = function() {
    contentElem.innerHTML = goog.string.htmlEscape(
        new goog.format.JsonPrettyPrinter(
            new goog.format.JsonPrettyPrinter.TextDelimiters()).
            format(mapModel.toMapRoot())).
        replace(/ /g, ' ').replace(/\n/g, '
');

    showJsonLink && goog.style.setElementShown(showJsonLink, false);
    showDiffLink && goog.style.setElementShown(showDiffLink, true);
    cm.ui.showPopup(popup);
  };

  if (opt_diffUrl) {
    // Request diffs and show them.
    var loading = cm.ui.create('span', {}, 'Loading diff...');
    cm.ui.append(popup, loading);
    goog.net.XhrIo.send(opt_diffUrl, function(e) {
      cm.ui.remove(loading);
      if (e.target.isSuccess()) {
        // Stored diffs, along with method to show one based on the select
        // element's current selection. Used by select element, as well as
        // diff link.
        var htmlDiffs, diffSelectElem;
        var showDiff = function() {
          // TODO(joeysilva): Fix bug where line numbers are compacted.
          contentElem.innerHTML = htmlDiffs[diffSelectElem.selectedIndex];
          goog.style.setElementShown(showJsonLink, true);
          goog.style.setElementShown(showDiffLink, false);
          cm.ui.showPopup(popup);
        };

        cm.ui.append(popup,
            'Diff against: ', diffSelectElem = cm.ui.create('select', {},
                cm.ui.create('option', {}, 'Saved')),
            cm.ui.SEPARATOR_DASH,
            showJsonLink = cm.ui.createLink('Show JSON'),
            showDiffLink = cm.ui.createLink('Show diff'),
            cm.ui.create('br'), cm.ui.create('br'),
            contentElem);

        var response = e.target.getResponseJson();
        htmlDiffs = [response['saved_diff']];
        goog.array.forEach(response['catalog_diffs'], function(entry) {
          cm.ui.append(diffSelectElem,
              cm.ui.create('option', {}, entry['name']));
          htmlDiffs.push(entry['diff']);
        });

        cm.events.listen(diffSelectElem, 'change', showDiff);
        cm.events.listen(showDiffLink, 'click', showDiff);
        showDiff();
      } else {
        cm.ui.append(popup, 'Failed to load diff',
            cm.ui.SEPARATOR_DASH,
            showJsonLink = cm.ui.createLink('Show JSON'),
            cm.ui.create('br'), cm.ui.create('br'),
            contentElem);
      }
      cm.events.listen(showJsonLink, 'click', showJson);

    }, 'POST', 'new_json=' + encodeURIComponent(
        goog.json.serialize(mapModel.toMapRoot())));
  } else {
    // No map ID; just show the JSON.
    cm.ui.append(popup, contentElem);
    showJson();
  }
};
<commit_msg>Add help link to editor links. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=44869880<commit_after>// Copyright 2012 Google Inc.  All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distrib-
// uted under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
// OR CONDITIONS OF ANY KIND, either express or implied.  See the License for
// specific language governing permissions and limitations under the License.

/**
 * @fileoverview [MODULE: edit] The toolbar for editing commands.
 * @author kpy@google.com (Ka-Ping Yee)
 */
goog.provide('cm.ToolbarView');

goog.require('cm.MapModel');
goog.require('cm.css');
goog.require('cm.events');
goog.require('cm.ui');
goog.require('goog.dom');
goog.require('goog.format.JsonPrettyPrinter');
goog.require('goog.json');
goog.require('goog.net.XhrIo');
goog.require('goog.string');

/** @desc Label for a link that lets the user rearrange the layer
 *  order and hierarchy.
 */

/** @desc Link text to arrange the layers in the panel. */
var MSG_ARRANGE_LAYERS_LINK = goog.getMsg('Arrange');

/** @desc Link text to arrange the layers in the panel. */
var MSG_SHARE_EMAIL_LINK = goog.getMsg('Share with user');

/** @desc Link text to add a new layer to the map. */
var MSG_ADD_NEW_LAYERS = goog.getMsg('Add layers');

/** @desc Default title for an empty layer. */
var MSG_UNTITLED_LAYER = goog.getMsg('Untitled Layer');

/** @desc Link text to add a new folder to the map. */
var MSG_ADD_NEW_FOLDER = goog.getMsg('Add folder');

/** @desc Link text to return to map list. */
var MSG_BACK_TO_MAP_LIST = goog.getMsg('Back to map list');

/** @desc Link text to documentation on how to use the map editor. */
var MSG_HELP_LINK = goog.getMsg('Help');

/** @desc Default title for an empty folder. */
var MSG_UNTITLED_FOLDER = goog.getMsg('Untitled Folder');

/** @desc Warning message when discarding unsaved changes. */
var MSG_UNSAVED_CHANGES = goog.getMsg(
    'You have unsaved changes that will be lost if you leave' +
    ' the page without clicking the "Save" link.');

/* TODO(rew): This link needs to be updated when the draft document is
   finalized and published in its permanent location. */
/* URL to the help document for editing maps. */
var HELP_LINK_URL = 'https://docs.google.com/document/d/' +
    '1cp9hLYJzGZZtM6IyO2WqIUvolU1WyCadlI_pGGtBGDY/edit#';

/**
 * A command toolbar.  For now, this is just a few links, but in future will
 * contain other editing/drawing functions.
 * @param {Element} parentElem The DOM element in which to render the toolbar.
 * @param {cm.MapModel} mapModel The map model.
 * @param {boolean} enableSave True to enable the "Save" function.
 * @param {boolean} devMode True to enable the "Show JSON" function.
 * @param {string} mapListUrl The URL endpoint for the user's map list.
 * @param {boolean} touch True if the map is being edited on a touch device.
 * @param {string=} opt_diffUrl URL used in devMode to diff the current
 *     maproot against the original maproot.
 * @constructor
 */
cm.ToolbarView = function(parentElem, mapModel, enableSave, devMode, mapListUrl,
    touch, opt_diffUrl) {
  // Initially, neither the undo nor the redo operation can be done.
  var undoLink = cm.ui.createLink('Undo');
  var redoLink = cm.ui.createLink('Redo');
  goog.dom.classes.add(undoLink, cm.css.DISABLED);
  goog.dom.classes.add(redoLink, cm.css.DISABLED);

  var undoLinkEventToken = cm.events.forward(undoLink, 'click',
      goog.global, cm.events.UNDO);
  var redoLinkEventToken = cm.events.forward(redoLink, 'click',
      goog.global, cm.events.REDO);

  cm.events.listen(goog.global, cm.events.UNDO_REDO_BUFFER_CHANGED,
    function(e) {
      goog.dom.classes.enable(undoLink, cm.css.DISABLED, !e.undo_possible);
      goog.dom.classes.enable(redoLink, cm.css.DISABLED, !e.redo_possible);
  }, this);

  var toolbarElem = cm.ui.create('div', {'class': cm.css.TOOLBAR});
  var backToMapsLink = cm.ui.createLink(MSG_BACK_TO_MAP_LIST, mapListUrl);
  cm.ui.append(toolbarElem, backToMapsLink, cm.ui.SEPARATOR_DOT,
               undoLink, cm.ui.SEPARATOR_DOT, redoLink, cm.ui.SEPARATOR_DOT);

  if (!touch) {
    var arrangeLink = cm.ui.createLink(MSG_ARRANGE_LAYERS_LINK);
    cm.ui.append(toolbarElem, arrangeLink, cm.ui.SEPARATOR_DOT);
    cm.events.forward(arrangeLink, 'click', goog.global, cm.events.ARRANGE);
  }

  var addNewLayerLink = cm.ui.createLink(MSG_ADD_NEW_LAYERS);
  cm.events.forward(addNewLayerLink, 'click', goog.global,
      cm.events.IMPORT);
  cm.ui.append(toolbarElem, addNewLayerLink, cm.ui.SEPARATOR_DOT);

  // TODO(joeysilva): Use INSPECT event to create new folders by using a type
  // FOLDER argument.
  var addNewFolderLink = cm.ui.createLink(MSG_ADD_NEW_FOLDER);
  cm.events.forward(
      addNewFolderLink, 'click', goog.global, cm.events.ADD_LAYERS, {
        layers: [{title: MSG_UNTITLED_FOLDER, type: cm.LayerModel.Type.FOLDER}]
      });
  cm.ui.append(toolbarElem, addNewFolderLink);

  if (enableSave) {
    var saveLink = cm.ui.createLink('Saved');
    cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, saveLink);

    // The "Save" link is initially disabled. Changing the model enables it.
    goog.dom.classes.add(saveLink, cm.css.DISABLED);
    cm.events.listen(goog.global, cm.events.MODEL_CHANGED, function() {
      cm.ui.setText(saveLink, 'Save');
      goog.dom.classes.remove(saveLink, cm.css.DISABLED, cm.css.ERROR);
    }, this);

    // Handle clicks on the "Save" link.
    cm.events.listen(saveLink, 'click', function() {
      if (!goog.dom.classes.has(saveLink, cm.css.DISABLED)) {
        cm.ui.setText(saveLink, 'Saving...');
        goog.dom.classes.remove(saveLink, cm.css.ERROR);
        goog.dom.classes.add(saveLink, cm.css.DISABLED);
        cm.events.emit(goog.global, cm.events.SAVE, {model: mapModel});
      }
    });

    // Handle completion of the Save operation.
    cm.events.listen(goog.global, cm.events.SAVE_DONE, function() {
      cm.ui.setText(saveLink, 'Saved');
    }, this);
    cm.events.listen(goog.global, cm.events.SAVE_FAILED, function() {
      // If the save fails, leave the link enabled so the user can click it
      // to try again.  Not the most elegant solution, but good enough for now.
      goog.dom.classes.remove(saveLink, cm.css.DISABLED);
      goog.dom.classes.add(saveLink, cm.css.ERROR);
      cm.ui.setText(saveLink, 'Save failed');
    }, this);

    // This way works for Chrome, Firefox.
    // cm.events.listen only works in Chrome.
    // In Chrome, this event will not get fired if you navigate to another page
    // within this app via the navigation bar.
    window.onbeforeunload = function() {
      if (!goog.dom.classes.has(saveLink, cm.css.DISABLED)) {
        return MSG_UNSAVED_CHANGES;
      }
    };

    var shareEmailLink = cm.ui.createLink(MSG_SHARE_EMAIL_LINK);
    cm.events.forward(shareEmailLink, 'click',
                      goog.global, cm.events.SHARE_EMAIL);
    cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, shareEmailLink);
  }

  if (devMode) {
    var diffJsonLink = cm.ui.createLink(opt_diffUrl ? 'Diff' : 'Show JSON');
    cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, diffJsonLink);
    cm.events.listen(diffJsonLink, 'click', goog.bind(
        this.handleDiffJsonClick_, this, mapModel, opt_diffUrl));
  }

  var helpLink = cm.ui.createLink(MSG_HELP_LINK, HELP_LINK_URL, '_blank');
  cm.ui.append(toolbarElem, cm.ui.SEPARATOR_DOT, helpLink);
  parentElem.appendChild(toolbarElem);
};

/**
 * Displays a popup showing diffs between the MapRoot JSON of the most recently
 * saved draft as well as any/all published versions of this map, against the
 * current, unsaved draft. Will simply show the current, unsaved draft if no
 * map ID is provided.
 * @param {cm.MapModel} mapModel The map model.
 * @param {string=} opt_diffUrl URL used to retrieve diffs between the current,
 *     currently saved, and published versions of this map.
 * @private
 */
cm.ToolbarView.prototype.handleDiffJsonClick_ =
    function(mapModel, opt_diffUrl) {
  var popup = cm.ui.create('div', {'class': [cm.css.POPUP, cm.css.DIFF]});
  cm.ui.createCloseButton(
      popup, function() { goog.dom.removeNode(popup); });
  cm.ui.showPopup(popup);

  // Define links and content element used by showJson and showDiff methods.
  var showJsonLink, showDiffLink;
  var contentElem = cm.ui.create('div');

  // Method to show JSON. Used by JSON link, and when diffs cannot be loaded.
  var showJson = function() {
    contentElem.innerHTML = goog.string.htmlEscape(
        new goog.format.JsonPrettyPrinter(
            new goog.format.JsonPrettyPrinter.TextDelimiters()).
            format(mapModel.toMapRoot())).
        replace(/ /g, ' ').replace(/\n/g, '
');

    showJsonLink && goog.style.setElementShown(showJsonLink, false);
    showDiffLink && goog.style.setElementShown(showDiffLink, true);
    cm.ui.showPopup(popup);
  };

  if (opt_diffUrl) {
    // Request diffs and show them.
    var loading = cm.ui.create('span', {}, 'Loading diff...');
    cm.ui.append(popup, loading);
    goog.net.XhrIo.send(opt_diffUrl, function(e) {
      cm.ui.remove(loading);
      if (e.target.isSuccess()) {
        // Stored diffs, along with method to show one based on the select
        // element's current selection. Used by select element, as well as
        // diff link.
        var htmlDiffs, diffSelectElem;
        var showDiff = function() {
          // TODO(joeysilva): Fix bug where line numbers are compacted.
          contentElem.innerHTML = htmlDiffs[diffSelectElem.selectedIndex];
          goog.style.setElementShown(showJsonLink, true);
          goog.style.setElementShown(showDiffLink, false);
          cm.ui.showPopup(popup);
        };

        cm.ui.append(popup,
            'Diff against: ', diffSelectElem = cm.ui.create('select', {},
                cm.ui.create('option', {}, 'Saved')),
            cm.ui.SEPARATOR_DASH,
            showJsonLink = cm.ui.createLink('Show JSON'),
            showDiffLink = cm.ui.createLink('Show diff'),
            cm.ui.create('br'), cm.ui.create('br'),
            contentElem);

        var response = e.target.getResponseJson();
        htmlDiffs = [response['saved_diff']];
        goog.array.forEach(response['catalog_diffs'], function(entry) {
          cm.ui.append(diffSelectElem,
              cm.ui.create('option', {}, entry['name']));
          htmlDiffs.push(entry['diff']);
        });

        cm.events.listen(diffSelectElem, 'change', showDiff);
        cm.events.listen(showDiffLink, 'click', showDiff);
        showDiff();
      } else {
        cm.ui.append(popup, 'Failed to load diff',
            cm.ui.SEPARATOR_DASH,
            showJsonLink = cm.ui.createLink('Show JSON'),
            cm.ui.create('br'), cm.ui.create('br'),
            contentElem);
      }
      cm.events.listen(showJsonLink, 'click', showJson);

    }, 'POST', 'new_json=' + encodeURIComponent(
        goog.json.serialize(mapModel.toMapRoot())));
  } else {
    // No map ID; just show the JSON.
    cm.ui.append(popup, contentElem);
    showJson();
  }
};
<|endoftext|>