<commit_before>/**
 * Created by tomk on 9/27/14.
 */

var PB_PIXEL_WIDTH_BAR = 6;
var PB_PIXEL_WIDTH_SPACING = 1;
var PB_PIXEL_HEIGHT = 100;
var PB_PIXEL_HEIGHT_SPACING = 3;
var PB_PIXEL_HEIGHT_NODENAME = 10;

function saturate0(value) {
    if (value < 0) {
        return 0;
    }

    return value;
}

function PerfbarCore(coreIdx) {
    this.pbFirstUpdate = true;
    this.pbCoreIdx = coreIdx;
    this.pbUserTicks = 0;
    this.pbSystemTicks = 0;
    this.pbOtherTicks = 0;
    this.pbIdleTicks = 0;
    this.pbUserHeight = 0;
    this.pbSystemHeight = 0;
    this.pbOtherHeight = 0;
    this.pbX = this.pbCoreIdx * (PB_PIXEL_WIDTH_BAR + PB_PIXEL_WIDTH_SPACING);

    this.fill = function (ctx, fillStyle, x, y, x_width, y_height) {
        // console.log("fillRect:", fillStyle, x, y, x_width, y_height);
        ctx.fillStyle = fillStyle;
        ctx.fillRect(x, y, x_width, y_height);
    };

    this.initializeTicks = function (userTicks, systemTicks, otherTicks, idleTicks) {
        this.pbUserTicks = userTicks;
        this.pbSystemTicks = systemTicks;
        this.pbOtherTicks = otherTicks;
        this.pbIdleTicks = idleTicks;
    };

    this.updateTicks = function (ctx, userTicks, systemTicks, otherTicks, idleTicks) {
        // console.log("updateTics:", this.pbCoreIdx);

        var deltaUserTicks   = saturate0(userTicks - this.pbUserTicks);
        var deltaSystemTicks = saturate0(systemTicks - this.pbSystemTicks);
        var deltaOtherTicks  = saturate0(otherTicks - this.pbOtherTicks);
        var deltaIdleTicks   = saturate0(idleTicks - this.pbIdleTicks);
        var deltaTotalTicks  = deltaUserTicks + deltaSystemTicks + deltaOtherTicks + deltaIdleTicks;

        var userTicksPct;
        var systemTicksPct;
        var otherTicksPct;
        if (deltaTotalTicks > 0) {
            userTicksPct     = (deltaUserTicks / deltaTotalTicks);
            systemTicksPct   = (deltaSystemTicks / deltaTotalTicks);
            otherTicksPct    = (deltaOtherTicks / deltaTotalTicks);
        }
        else {
            userTicksPct     = 0;
            systemTicksPct   = 0;
            otherTicksPct    = 0;
        }

        var perfectUserHeight     = PB_PIXEL_HEIGHT * userTicksPct;
        var perfectSystemHeight   = PB_PIXEL_HEIGHT * systemTicksPct;
        var perfectOtherHeight    = PB_PIXEL_HEIGHT * otherTicksPct;

        // Blend previous and current height values to get some optical smoothing for the eye.
        // Take three parts old data and two parts new data.
        var blendedUserHeight;
        var blendedSystemHeight;
        var blendedOtherHeight;
        if (this.pbFirstUpdate) {
            // Don't blend, since there is nothing to smooth out.
            blendedUserHeight     = perfectUserHeight;
            blendedSystemHeight   = perfectSystemHeight;
            blendedOtherHeight    = perfectOtherHeight;
        }
        else {
            blendedUserHeight     = (3*this.pbUserHeight   + 2*perfectUserHeight)   / 5;
            blendedSystemHeight   = (3*this.pbSystemHeight + 2*perfectSystemHeight) / 5;
            blendedOtherHeight    = (3*this.pbOtherHeight  + 2*perfectOtherHeight)  / 5;
        }
        var blendedIdleHeight     = saturate0(PB_PIXEL_HEIGHT - (blendedUserHeight + blendedSystemHeight + blendedOtherHeight));

        var x = this.pbX;
        var x_width = PB_PIXEL_WIDTH_BAR;
        var y;
        var y_height;

        // user (green)
        y = blendedIdleHeight + blendedOtherHeight + blendedSystemHeight;
        y_height = blendedUserHeight;
        this.fill(ctx, "#00FF00", x, y, x_width, y_height);

        // system (red)
        y = blendedIdleHeight + blendedOtherHeight;
        y_height = blendedSystemHeight;
        this.fill(ctx, "#FF0000", x, y, x_width, y_height);

        // other (white)
        y = blendedIdleHeight;
        y_height = blendedOtherHeight;
        this.fill(ctx, "#FFFFFF", x, y, x_width, y_height);

        // idle (blue)
        y = 0;
        y_height = blendedIdleHeight;
        this.fill(ctx, "#0000FF", x, y, x_width, y_height);

        this.pbUserTicks = userTicks;
        this.pbSystemTicks = systemTicks;
        this.pbOtherTicks = otherTicks;
        this.pbIdleTicks = idleTicks;

        this.pbUserHeight = blendedUserHeight;
        this.pbSystemHeight = blendedSystemHeight;
        this.pbOtherHeight = blendedOtherHeight;

        this.pbFirstUpdate = false;
    };
}

function Perfbar(nodeName, nodeIdx, numCores) {
    this.pbFirstUpdate = true;
    this.pbCtx = null;
    this.pbNodeName = nodeName;
    this.pbNodeIdx = nodeIdx;
    this.pbNumCores = numCores;
    this.pbCores = new Array(numCores);

    console.log("instantiating:", this.pbNodeName, this.pbNodeIdx);

    for (var i = 0; i < numCores; i++) {
        this.pbCores[i] = new PerfbarCore (i);
    }

    this.docWriteCanvas = function() {
        var width = (numCores * PB_PIXEL_WIDTH_BAR) + ((numCores - 1) * PB_PIXEL_WIDTH_SPACING);

        var s = "<canvas id=\"" +
            nodeName + "" +
            "\" width=\"" +
            width +
            "\" height=\"" +
            (PB_PIXEL_HEIGHT + PB_PIXEL_HEIGHT_SPACING + PB_PIXEL_HEIGHT_NODENAME) +
            "\" style=\"background-color: white;\"></canvas>\n";
            console.log("docWriteCanvas: ", s);
        document.write(s);
    };

    this.docGetElement = function() {
        // console.log("docGetElement called");
        var c = document.getElementById(this.pbNodeName);
        this.pbCtx = c.getContext("2d");
        this.pbCtx.fontStyle = "10px sans-serif";
    };

    this.initializeTicks = function(cpuTicks) {
        if (cpuTicks.length != this.pbNumCores) {
            // This is really bad.
            console.log("ERROR: ", cpuTicks.length, "!=", this.pbNumCores);
        }

        for (var i = 0; i < this.pbNumCores; i++) {
            this.pbCores[i].initializeTicks(cpuTicks[i][0], cpuTicks[i][1], cpuTicks[i][2], cpuTicks[i][3]);
        }
    };

    this.updateTicks = function(cpuTicks) {
        if (this.pbFirstUpdate) {
            console.log("calling fillText");
            this.pbCtx.fillStyle = "black";
            this.pbCtx.fillText(
                this.pbNodeName,
                0,
                PB_PIXEL_HEIGHT + PB_PIXEL_HEIGHT_SPACING + PB_PIXEL_HEIGHT_NODENAME);
            this.pbFirstUpdate = false;
        }

        if (cpuTicks.length != this.pbNumCores) {
            // This is really bad.
            console.log("ERROR: ", cpuTicks.length, "!=", this.pbNumCores);
        }

        for (var i = 0; i < this.pbNumCores; i++) {
            this.pbCores[i].updateTicks(this.pbCtx, cpuTicks[i][0], cpuTicks[i][1], cpuTicks[i][2], cpuTicks[i][3]);
        }
    };
}

var perfbars = null;
var timeouts = null;
var timeoutDelayMillis = 200;
var cloud_size = -1;
var acknowledged_cloud_size = 0;

initializeCloud();

function initializeCloud() {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            console.log(xmlhttp.responseText);
            var obj = JSON.parse(xmlhttp.responseText);
            cloud_size = obj.cloud_size;
            console.log("cloud size is " + cloud_size);
            perfbars = new Array(cloud_size);
            for (var i = 0; i < cloud_size; i = i + 1) {
                initializeNode(i);
            }
            timeouts = new Array(cloud_size);
        }
    };
    xmlhttp.open("GET","/2/Cloud.json",true);
    xmlhttp.send();
}

function initializeNode(nodeIdx) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            var nodeName = "node " + nodeIdx;

            console.log("initializeNode ", nodeIdx, "response: ", xmlhttp.responseText);
            var obj = JSON.parse(xmlhttp.responseText);
            var cpuTicks = obj.cpuTicks;
            if (cpuTicks.length == 0) {
                console.log("ticks array has length " + cpuTicks.length);
                return;
            }

            var numCpus = cpuTicks.length;
            var pb = new Perfbar(nodeName, nodeIdx, numCpus);
            perfbars[nodeIdx] = pb;
            pb.initializeTicks(cpuTicks);

            // Only emit the doc elements once all nodes have checked in.
            // This way they are laid out synchronously and in order.
            acknowledged_cloud_size = acknowledged_cloud_size + 1;
            if (acknowledged_cloud_size == cloud_size) {
                for (var i = 0; i < cloud_size; i++) {
                    var pb2 = perfbars[i];
                    pb2.docWriteCanvas();
                    pb2.docGetElement();

                    timeouts[i] = setTimeout(function(idx) {
                        repaintAndArmTimeout(idx);
                    }, timeoutDelayMillis, i);
                }
            }
        }
    };
    xmlhttp.open("GET","/2/WaterMeterCpuTicks.json?node_idx=" + nodeIdx,true);
    xmlhttp.send();
}

function repaintAndArmTimeout(nodeIdx) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            console.log("repaintAndArmTimeout", nodeIdx, "response: ", xmlhttp.responseText);
            var obj = JSON.parse(xmlhttp.responseText);
            var cpuTicks = obj.cpuTicks;
            perfbars[nodeIdx].updateTicks(cpuTicks);

            timeouts[nodeIdx] = setTimeout(function(idx) {
                repaintAndArmTimeout(idx);
            }, timeoutDelayMillis, nodeIdx);
        }
    };
    xmlhttp.open("GET", "/2/WaterMeterCpuTicks.json?node_idx=" + nodeIdx, true);
    xmlhttp.send();
}
<commit_msg>Tweak white bar color to be not quite white.<commit_after>/**
 * Created by tomk on 9/27/14.
 */

var PB_PIXEL_WIDTH_BAR = 6;
var PB_PIXEL_WIDTH_SPACING = 1;
var PB_PIXEL_HEIGHT = 100;
var PB_PIXEL_HEIGHT_SPACING = 3;
var PB_PIXEL_HEIGHT_NODENAME = 10;

function saturate0(value) {
    if (value < 0) {
        return 0;
    }

    return value;
}

function PerfbarCore(coreIdx) {
    this.pbFirstUpdate = true;
    this.pbCoreIdx = coreIdx;
    this.pbUserTicks = 0;
    this.pbSystemTicks = 0;
    this.pbOtherTicks = 0;
    this.pbIdleTicks = 0;
    this.pbUserHeight = 0;
    this.pbSystemHeight = 0;
    this.pbOtherHeight = 0;
    this.pbX = this.pbCoreIdx * (PB_PIXEL_WIDTH_BAR + PB_PIXEL_WIDTH_SPACING);

    this.fill = function (ctx, fillStyle, x, y, x_width, y_height) {
        // console.log("fillRect:", fillStyle, x, y, x_width, y_height);
        ctx.fillStyle = fillStyle;
        ctx.fillRect(x, y, x_width, y_height);
    };

    this.initializeTicks = function (userTicks, systemTicks, otherTicks, idleTicks) {
        this.pbUserTicks = userTicks;
        this.pbSystemTicks = systemTicks;
        this.pbOtherTicks = otherTicks;
        this.pbIdleTicks = idleTicks;
    };

    this.updateTicks = function (ctx, userTicks, systemTicks, otherTicks, idleTicks) {
        // console.log("updateTics:", this.pbCoreIdx);

        var deltaUserTicks   = saturate0(userTicks - this.pbUserTicks);
        var deltaSystemTicks = saturate0(systemTicks - this.pbSystemTicks);
        var deltaOtherTicks  = saturate0(otherTicks - this.pbOtherTicks);
        var deltaIdleTicks   = saturate0(idleTicks - this.pbIdleTicks);
        var deltaTotalTicks  = deltaUserTicks + deltaSystemTicks + deltaOtherTicks + deltaIdleTicks;

        var userTicksPct;
        var systemTicksPct;
        var otherTicksPct;
        if (deltaTotalTicks > 0) {
            userTicksPct     = (deltaUserTicks / deltaTotalTicks);
            systemTicksPct   = (deltaSystemTicks / deltaTotalTicks);
            otherTicksPct    = (deltaOtherTicks / deltaTotalTicks);
        }
        else {
            userTicksPct     = 0;
            systemTicksPct   = 0;
            otherTicksPct    = 0;
        }

        var perfectUserHeight     = PB_PIXEL_HEIGHT * userTicksPct;
        var perfectSystemHeight   = PB_PIXEL_HEIGHT * systemTicksPct;
        var perfectOtherHeight    = PB_PIXEL_HEIGHT * otherTicksPct;

        // Blend previous and current height values to get some optical smoothing for the eye.
        // Take three parts old data and two parts new data.
        var blendedUserHeight;
        var blendedSystemHeight;
        var blendedOtherHeight;
        if (this.pbFirstUpdate) {
            // Don't blend, since there is nothing to smooth out.
            blendedUserHeight     = perfectUserHeight;
            blendedSystemHeight   = perfectSystemHeight;
            blendedOtherHeight    = perfectOtherHeight;
        }
        else {
            blendedUserHeight     = (3*this.pbUserHeight   + 2*perfectUserHeight)   / 5;
            blendedSystemHeight   = (3*this.pbSystemHeight + 2*perfectSystemHeight) / 5;
            blendedOtherHeight    = (3*this.pbOtherHeight  + 2*perfectOtherHeight)  / 5;
        }
        var blendedIdleHeight     = saturate0(PB_PIXEL_HEIGHT - (blendedUserHeight + blendedSystemHeight + blendedOtherHeight));

        var x = this.pbX;
        var x_width = PB_PIXEL_WIDTH_BAR;
        var y;
        var y_height;

        // user (green)
        y = blendedIdleHeight + blendedOtherHeight + blendedSystemHeight;
        y_height = blendedUserHeight;
        this.fill(ctx, "#00FF00", x, y, x_width, y_height);

        // system (red)
        y = blendedIdleHeight + blendedOtherHeight;
        y_height = blendedSystemHeight;
        this.fill(ctx, "#FF0000", x, y, x_width, y_height);

        // other (white)
        y = blendedIdleHeight;
        y_height = blendedOtherHeight;
        this.fill(ctx, "#DDDDDD", x, y, x_width, y_height);

        // idle (blue)
        y = 0;
        y_height = blendedIdleHeight;
        this.fill(ctx, "#0000FF", x, y, x_width, y_height);

        this.pbUserTicks = userTicks;
        this.pbSystemTicks = systemTicks;
        this.pbOtherTicks = otherTicks;
        this.pbIdleTicks = idleTicks;

        this.pbUserHeight = blendedUserHeight;
        this.pbSystemHeight = blendedSystemHeight;
        this.pbOtherHeight = blendedOtherHeight;

        this.pbFirstUpdate = false;
    };
}

function Perfbar(nodeName, nodeIdx, numCores) {
    this.pbFirstUpdate = true;
    this.pbCtx = null;
    this.pbNodeName = nodeName;
    this.pbNodeIdx = nodeIdx;
    this.pbNumCores = numCores;
    this.pbCores = new Array(numCores);

    console.log("instantiating:", this.pbNodeName, this.pbNodeIdx);

    for (var i = 0; i < numCores; i++) {
        this.pbCores[i] = new PerfbarCore (i);
    }

    this.docWriteCanvas = function() {
        var width = (numCores * PB_PIXEL_WIDTH_BAR) + ((numCores - 1) * PB_PIXEL_WIDTH_SPACING);

        var s = "<canvas id=\"" +
            nodeName + "" +
            "\" width=\"" +
            width +
            "\" height=\"" +
            (PB_PIXEL_HEIGHT + PB_PIXEL_HEIGHT_SPACING + PB_PIXEL_HEIGHT_NODENAME) +
            "\" style=\"background-color: white;\"></canvas>\n";
            console.log("docWriteCanvas: ", s);
        document.write(s);
    };

    this.docGetElement = function() {
        // console.log("docGetElement called");
        var c = document.getElementById(this.pbNodeName);
        this.pbCtx = c.getContext("2d");
        this.pbCtx.fontStyle = "10px sans-serif";
    };

    this.initializeTicks = function(cpuTicks) {
        if (cpuTicks.length != this.pbNumCores) {
            // This is really bad.
            console.log("ERROR: ", cpuTicks.length, "!=", this.pbNumCores);
        }

        for (var i = 0; i < this.pbNumCores; i++) {
            this.pbCores[i].initializeTicks(cpuTicks[i][0], cpuTicks[i][1], cpuTicks[i][2], cpuTicks[i][3]);
        }
    };

    this.updateTicks = function(cpuTicks) {
        if (this.pbFirstUpdate) {
            console.log("calling fillText");
            this.pbCtx.fillStyle = "black";
            this.pbCtx.fillText(
                this.pbNodeName,
                0,
                PB_PIXEL_HEIGHT + PB_PIXEL_HEIGHT_SPACING + PB_PIXEL_HEIGHT_NODENAME);
            this.pbFirstUpdate = false;
        }

        if (cpuTicks.length != this.pbNumCores) {
            // This is really bad.
            console.log("ERROR: ", cpuTicks.length, "!=", this.pbNumCores);
        }

        for (var i = 0; i < this.pbNumCores; i++) {
            this.pbCores[i].updateTicks(this.pbCtx, cpuTicks[i][0], cpuTicks[i][1], cpuTicks[i][2], cpuTicks[i][3]);
        }
    };
}

var perfbars = null;
var timeouts = null;
var timeoutDelayMillis = 200;
var cloud_size = -1;
var acknowledged_cloud_size = 0;

initializeCloud();

function initializeCloud() {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            console.log(xmlhttp.responseText);
            var obj = JSON.parse(xmlhttp.responseText);
            cloud_size = obj.cloud_size;
            console.log("cloud size is " + cloud_size);
            perfbars = new Array(cloud_size);
            for (var i = 0; i < cloud_size; i = i + 1) {
                initializeNode(i);
            }
            timeouts = new Array(cloud_size);
        }
    };
    xmlhttp.open("GET","/2/Cloud.json",true);
    xmlhttp.send();
}

function initializeNode(nodeIdx) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            var nodeName = "node " + nodeIdx;

            console.log("initializeNode ", nodeIdx, "response: ", xmlhttp.responseText);
            var obj = JSON.parse(xmlhttp.responseText);
            var cpuTicks = obj.cpuTicks;
            if (cpuTicks.length == 0) {
                console.log("ticks array has length " + cpuTicks.length);
                return;
            }

            var numCpus = cpuTicks.length;
            var pb = new Perfbar(nodeName, nodeIdx, numCpus);
            perfbars[nodeIdx] = pb;
            pb.initializeTicks(cpuTicks);

            // Only emit the doc elements once all nodes have checked in.
            // This way they are laid out synchronously and in order.
            acknowledged_cloud_size = acknowledged_cloud_size + 1;
            if (acknowledged_cloud_size == cloud_size) {
                for (var i = 0; i < cloud_size; i++) {
                    var pb2 = perfbars[i];
                    pb2.docWriteCanvas();
                    pb2.docGetElement();

                    timeouts[i] = setTimeout(function(idx) {
                        repaintAndArmTimeout(idx);
                    }, timeoutDelayMillis, i);
                }
            }
        }
    };
    xmlhttp.open("GET","/2/WaterMeterCpuTicks.json?node_idx=" + nodeIdx,true);
    xmlhttp.send();
}

function repaintAndArmTimeout(nodeIdx) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            console.log("repaintAndArmTimeout", nodeIdx, "response: ", xmlhttp.responseText);
            var obj = JSON.parse(xmlhttp.responseText);
            var cpuTicks = obj.cpuTicks;
            perfbars[nodeIdx].updateTicks(cpuTicks);

            timeouts[nodeIdx] = setTimeout(function(idx) {
                repaintAndArmTimeout(idx);
            }, timeoutDelayMillis, nodeIdx);
        }
    };
    xmlhttp.open("GET", "/2/WaterMeterCpuTicks.json?node_idx=" + nodeIdx, true);
    xmlhttp.send();
}
<|endoftext|>


<commit_before>var async = require('async');

module.exports = [
    // Post authorization.
    function (payload, run, done) {
        // if no response is provided, there's nothing to do, and probably means that the request errored out
        // let the actual request command handle whatever needs to be done.
        if (!payload._response) { return done(); }

        var item = payload._item,
            response = payload._response,
            cursor = payload.coords;

        async.waterfall([
            // Post verify
            function (next) {
                run.authorizer.postVerify(item, response, cursor, run, next);
            },
            // Call initialize if necessary
            function (verified, next) {
                // If verification succeeds or the request is already a replay,
                // move on to the next request
                if (verified || payload._replay) { return next(null); }

                payload._replay = true;
                run.authorizer.init(item, run, cursor, function (err) {
                    return next(err);
                });
            }
        ], done);
    }
];
<commit_msg>simplified the replay logic<commit_after>var async = require('async');

module.exports = [
    // Post authorization.
    function (payload, run, done) {
        // if no response is provided, there's nothing to do, and probably means that the request errored out
        // let the actual request command handle whatever needs to be done.
        if (!payload._response) { return done(); }

        var item = payload._item,
            response = payload._response,
            cursor = payload.coords;

        async.waterfall([
            // Post verify
            function (next) {
                run.authorizer.postVerify(item, response, cursor, run, next);
            },
            // Call initialize if necessary
            function (verified, next) {
                // If verification fails & the request is not already replayed,
                // indicate that a replay should be done here.
                (!verified && !payload._replay) && (payload._replay = true);
                return next();
            }
        ], done);
    }
];
<|endoftext|>


<commit_before>Vps.Component.Pages = Ext.extend(Ext.Panel, {
    initComponent : function()
    {
        this.treePanel = new Vps.Auto.TreePanel({
            controllerUrl: '/admin/component/pages',
            title       : 'Seitenbaum',
            region      : 'west',
            split       : true,
            width       : 300,
            collapsible : true,
            minSize     : 200,
            maxSize     : 600,
            tbar        : []
        });
        this.contentTabPanel = new Ext.TabPanel({
            region      : 'center',
            id          : 'contentTabPanel',
            mainComponentText: 'Document'
        });

        this.layout = 'border';
        this.actions = {};
        this.items = [this.treePanel, this.contentTabPanel];
        Vps.Component.Pages.superclass.initComponent.call(this);

        this.treePanel.on('loaded', this.onTreePanelLoaded, this);
        this.on('editcomponent', this.loadComponent, this);
        this.setupEditform();
    },

    setupEditform : function ()
    {
        this.editDialog = new Vps.Auto.Form.Window({
            width: 400,
            height: 400,
            controllerUrl: '/admin/component/pageEdit'
        });
        this.editDialog.on('datachange', function() {
            var tree = this.treePanel.tree;
            if (this.editDialog.getAutoForm().getBaseParams().parent_id != undefined) {
                tree.selModel.selNode.parentNode.reload();
            } else {
                values = this.editDialog.getForm().getValues();
                id = tree.selModel.selNode.id;
                node = tree.getNodeById(id).setText(values.name);
            }
        }, this);
    },

    onTreePanelLoaded : function(tree)
    {
        this.pageButton = new Ext.Toolbar.Button({
            cls     : 'x-btn-text-icon bmenu',
            text    :'Page',
            menu    : [
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome')
            ],
            icon    : '/assets/silkicons/page.png',
            disabled: true
        });

        this.treePanel.getTopToolbar().add(
            this.getAction('edit'),
            '-',
            this.pageButton,
            '-',
            new Ext.Toolbar.Button({
                cls: 'x-btn-text-icon bmenu',
                text:'Navigation',
                icon : '/assets/silkicons/weather_sun.png',
                menu: [
                    this.getAction('reloadAll'),
                    this.getAction('expandAll'),
                    this.getAction('collapseAll')
                ]
            })
        );

        this.contextMenu = new Ext.menu.Menu({
             items: [
                this.getAction('edit'),
                '-',
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome'),
                '-',
                this.getAction('reloadAll'),
                this.getAction('expand'),
                this.getAction('collapse')
            ]
        });

        tree.on('click', this.treeSelectionchange, this);
        tree.on('contextmenu', function (node) {
            node.select();
            this.treeSelectionchange(node);
            this.contextMenu.show(node.ui.getAnchor());
        }, this);

        tree.on('dblclick', function (o, e) {
            this.fireEvent('editcomponent', {id: o.attributes.id, cls: o.attributes.data.component_class, text: o.text})
        }, this);
    },

    treeSelectionchange : function (node) {
        if (node) {
            this.pageButton.enable();
            if (node.attributes.type == 'category') {
                this.getAction('edit').disable();
                this.getAction('properties').disable();
                this.getAction('delete').disable();
                this.getAction('visible').disable();
                this.getAction('makeHome').disable();
            } else {
                this.getAction('edit').enable();
                this.getAction('properties').enable();
                this.getAction('delete').enable();
                this.getAction('visible').enable();
                this.getAction('makeHome').enable();
            }
        }
    },

    loadComponent: function(data)
    {
        if (this.contentTabPanel.getItem(data.text)) {
            var panel = this.contentTabPanel.getItem(data.text);
        } else {
            var panel = this.createComponentPanel(data);
            this.contentTabPanel.add(panel);
        }
        this.contentTabPanel.setActiveTab(panel);

        panel.applyBaseParams({
            id: data.id
        });
        panel.load({
            componentClass: data.cls
        });
    },

    createComponentPanel: function(data)
    {
        var panel = new Vps.Component.ComponentPanel({
            id          : data.text,
            title       : data.text,
            region      : 'center',
            closable    : true
        });
        return panel;
    },

    getAction : function(type)
    {
        if (this.actions[type]) return this.actions[type];

        if (type == 'edit') {
            this.actions[type] = new Ext.Action({
                text    : 'Edit Content',
                disabled: true,
                handler : function (o, e) {
                    node = this.treePanel.tree.getSelectionModel().getSelectedNode();
                    this.fireEvent('editcomponent', {id: node.attributes.id, cls: node.attributes.data.component_class, text: node.text});
                },
                icon    : '/assets/silkicons/page_edit.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'properties') {
            this.actions[type] = new Ext.Action({
                text    : 'Properties of selected Page',
                handler : function () {
                    this.editDialog.getAutoForm().setBaseParams({});
                    this.editDialog.showEdit(this.treePanel.tree.selModel.selNode.id);
                },
                icon    : '/assets/silkicons/page_gear.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'add') {
            this.actions[type] = new Ext.Action({
                text    : 'Add new Subpage',
                handler : function () {
                    this.editDialog.getAutoForm().setBaseParams({
                        parent_id: this.treePanel.tree.selModel.selNode.id
                    });
                    this.editDialog.showAdd();
                },
                icon    : '/assets/silkicons/page_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'delete') {
            this.actions[type] = new Ext.Action({
                text    : 'Delete selected Page',
                handler : this.treePanel.onDelete,
                icon    : '/assets/silkicons/page_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this.treePanel
            });
        } else if (type == 'visible') {
            this.actions[type] = new Ext.Action({
                text    : 'Toggle Visibility of selected Page',
                handler : this.treePanel.onVisible,
                icon    : '/assets/silkicons/page_red.png',
                cls     : 'x-btn-text-icon',
                scope   : this.treePanel
            });
        } else if (type == 'makeHome') {
            this.actions[type] = new Ext.Action({
                text    : 'Make selected Page Homepage',
                handler : function (o, e) {
                    Ext.Ajax.request({
                        url: '/admin/component/pages/jsonMakeHome',
                        success: function(r) {
                            response = Ext.decode(r.responseText);
                            var oldhome = this.treePanel.tree.getNodeById(response.oldhome);
                            oldhome.attributes.visible = response.oldhomeVisible;
                            this.treePanel.setVisible(oldhome);
                            var home = this.treePanel.tree.getNodeById(response.home);
                            home.ui.iconNode.style.backgroundImage = 'url(/assets/silkicons/application_home.png)';
                        },
                        params: {id: this.treePanel.tree.getSelectionModel().getSelectedNode().id },
                        scope: this
                    });
                },
                icon    : '/assets/silkicons/application_home.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'reloadAll') {
            this.actions[type] = new Ext.Action({
                text    : 'Reload all',
                handler : function () { this.treePanel.tree.getRootNode().reload(); },
                icon    : '/assets/silkicons/bullet_star.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'expand') {
            this.actions[type] = new Ext.Action({
                text    : 'Expand here',
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().expand(true); },
                icon    : '/assets/silkicons/bullet_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'collapse') {
            this.actions[type] = new Ext.Action({
                text    : 'Collapse here',
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().collapse(true); },
                icon    : '/assets/silkicons/bullet_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'expandAll') {
            this.actions[type] = new Ext.Action({
                text    : 'Expand All',
                handler : function () { this.treePanel.tree.expandAll(); },
                icon    : '/assets/silkicons/bullet_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'collapseAll') {
            this.actions[type] = new Ext.Action({
                text    : 'Collapse all',
                handler : function () { this.treePanel.tree.collapseAll(); },
                icon    : '/assets/silkicons/bullet_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else {
            throw 'unknown action-type: ' + type;
        }
        return this.actions[type];
    }

});

Vps.Component.PagesNode = Ext.extend(Vps.Auto.TreeNode, {
    onDblClick : function(e){
        e.preventDefault();
        this.fireEvent("dblclick", this.node, e);
    }
});
<commit_msg>bugfix: zwei seiten mit gleichem namen öffnen jetzt auch zwei tabs<commit_after>Vps.Component.Pages = Ext.extend(Ext.Panel, {
    initComponent : function()
    {
        this.treePanel = new Vps.Auto.TreePanel({
            controllerUrl: '/admin/component/pages',
            title       : 'Seitenbaum',
            region      : 'west',
            split       : true,
            width       : 300,
            collapsible : true,
            minSize     : 200,
            maxSize     : 600,
            tbar        : []
        });
        this.contentTabPanel = new Ext.TabPanel({
            region      : 'center'
        });

        this.layout = 'border';
        this.actions = {};
        this.items = [this.treePanel, this.contentTabPanel];
        Vps.Component.Pages.superclass.initComponent.call(this);

        this.treePanel.on('loaded', this.onTreePanelLoaded, this);
        this.on('editcomponent', this.loadComponent, this);
        this.setupEditform();
    },

    setupEditform : function ()
    {
        this.editDialog = new Vps.Auto.Form.Window({
            width: 400,
            height: 400,
            controllerUrl: '/admin/component/pageEdit'
        });
        this.editDialog.on('datachange', function() {
            var tree = this.treePanel.tree;
            if (this.editDialog.getAutoForm().getBaseParams().parent_id != undefined) {
                tree.selModel.selNode.parentNode.reload();
            } else {
                values = this.editDialog.getForm().getValues();
                id = tree.selModel.selNode.id;
                node = tree.getNodeById(id).setText(values.name);
            }
        }, this);
    },

    onTreePanelLoaded : function(tree)
    {
        this.pageButton = new Ext.Toolbar.Button({
            cls     : 'x-btn-text-icon bmenu',
            text    :'Page',
            menu    : [
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome')
            ],
            icon    : '/assets/silkicons/page.png',
            disabled: true
        });

        this.treePanel.getTopToolbar().add(
            this.getAction('edit'),
            '-',
            this.pageButton,
            '-',
            new Ext.Toolbar.Button({
                cls: 'x-btn-text-icon bmenu',
                text:'Navigation',
                icon : '/assets/silkicons/weather_sun.png',
                menu: [
                    this.getAction('reloadAll'),
                    this.getAction('expandAll'),
                    this.getAction('collapseAll')
                ]
            })
        );

        this.contextMenu = new Ext.menu.Menu({
             items: [
                this.getAction('edit'),
                '-',
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome'),
                '-',
                this.getAction('reloadAll'),
                this.getAction('expand'),
                this.getAction('collapse')
            ]
        });

        tree.on('click', this.treeSelectionchange, this);
        tree.on('contextmenu', function (node) {
            node.select();
            this.treeSelectionchange(node);
            this.contextMenu.show(node.ui.getAnchor());
        }, this);

        tree.on('dblclick', function (o, e) {
            this.fireEvent('editcomponent', {id: o.attributes.id, cls: o.attributes.data.component_class, text: o.text})
        }, this);
    },

    treeSelectionchange : function (node) {
        if (node) {
            this.pageButton.enable();
            if (node.attributes.type == 'category') {
                this.getAction('edit').disable();
                this.getAction('properties').disable();
                this.getAction('delete').disable();
                this.getAction('visible').disable();
                this.getAction('makeHome').disable();
            } else {
                this.getAction('edit').enable();
                this.getAction('properties').enable();
                this.getAction('delete').enable();
                this.getAction('visible').enable();
                this.getAction('makeHome').enable();
            }
        }
    },

    loadComponent: function(data)
    {
        var panel = this.contentTabPanel.getItem('page'+data.id);
        if (!panel)
            panel = this.createComponentPanel(data);
            this.contentTabPanel.add(panel);
        }
        this.contentTabPanel.setActiveTab(panel);

        panel.applyBaseParams({
            id: data.id
        });
        panel.load({
            componentClass: data.cls
        });
    },

    createComponentPanel: function(data)
    {
        var panel = new Vps.Component.ComponentPanel({
            id          : 'page'+data.id,
            title       : data.text,
            region      : 'center',
            closable    : true
        });
        return panel;
    },

    getAction : function(type)
    {
        if (this.actions[type]) return this.actions[type];

        if (type == 'edit') {
            this.actions[type] = new Ext.Action({
                text    : 'Edit Content',
                disabled: true,
                handler : function (o, e) {
                    node = this.treePanel.tree.getSelectionModel().getSelectedNode();
                    this.fireEvent('editcomponent', {id: node.attributes.id, cls: node.attributes.data.component_class, text: node.text});
                },
                icon    : '/assets/silkicons/page_edit.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'properties') {
            this.actions[type] = new Ext.Action({
                text    : 'Properties of selected Page',
                handler : function () {
                    this.editDialog.getAutoForm().setBaseParams({});
                    this.editDialog.showEdit(this.treePanel.tree.selModel.selNode.id);
                },
                icon    : '/assets/silkicons/page_gear.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'add') {
            this.actions[type] = new Ext.Action({
                text    : 'Add new Subpage',
                handler : function () {
                    this.editDialog.getAutoForm().setBaseParams({
                        parent_id: this.treePanel.tree.selModel.selNode.id
                    });
                    this.editDialog.showAdd();
                },
                icon    : '/assets/silkicons/page_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'delete') {
            this.actions[type] = new Ext.Action({
                text    : 'Delete selected Page',
                handler : this.treePanel.onDelete,
                icon    : '/assets/silkicons/page_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this.treePanel
            });
        } else if (type == 'visible') {
            this.actions[type] = new Ext.Action({
                text    : 'Toggle Visibility of selected Page',
                handler : this.treePanel.onVisible,
                icon    : '/assets/silkicons/page_red.png',
                cls     : 'x-btn-text-icon',
                scope   : this.treePanel
            });
        } else if (type == 'makeHome') {
            this.actions[type] = new Ext.Action({
                text    : 'Make selected Page Homepage',
                handler : function (o, e) {
                    Ext.Ajax.request({
                        url: '/admin/component/pages/jsonMakeHome',
                        success: function(r) {
                            response = Ext.decode(r.responseText);
                            var oldhome = this.treePanel.tree.getNodeById(response.oldhome);
                            oldhome.attributes.visible = response.oldhomeVisible;
                            this.treePanel.setVisible(oldhome);
                            var home = this.treePanel.tree.getNodeById(response.home);
                            home.ui.iconNode.style.backgroundImage = 'url(/assets/silkicons/application_home.png)';
                        },
                        params: {id: this.treePanel.tree.getSelectionModel().getSelectedNode().id },
                        scope: this
                    });
                },
                icon    : '/assets/silkicons/application_home.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'reloadAll') {
            this.actions[type] = new Ext.Action({
                text    : 'Reload all',
                handler : function () { this.treePanel.tree.getRootNode().reload(); },
                icon    : '/assets/silkicons/bullet_star.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'expand') {
            this.actions[type] = new Ext.Action({
                text    : 'Expand here',
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().expand(true); },
                icon    : '/assets/silkicons/bullet_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'collapse') {
            this.actions[type] = new Ext.Action({
                text    : 'Collapse here',
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().collapse(true); },
                icon    : '/assets/silkicons/bullet_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'expandAll') {
            this.actions[type] = new Ext.Action({
                text    : 'Expand All',
                handler : function () { this.treePanel.tree.expandAll(); },
                icon    : '/assets/silkicons/bullet_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'collapseAll') {
            this.actions[type] = new Ext.Action({
                text    : 'Collapse all',
                handler : function () { this.treePanel.tree.collapseAll(); },
                icon    : '/assets/silkicons/bullet_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else {
            throw 'unknown action-type: ' + type;
        }
        return this.actions[type];
    }

});

Vps.Component.PagesNode = Ext.extend(Vps.Auto.TreeNode, {
    onDblClick : function(e){
        e.preventDefault();
        this.fireEvent("dblclick", this.node, e);
    }
});
<|endoftext|>


<commit_before>var Supports = require('./Utils/Supports');
var Scene = require('./Utils/Scene');
var Camera = require('./Utils/Camera');
var Listener = require('./Utils/Listener');
var Renderer = require('./Utils/Renderer');
var Ui = require('./UI');

var Terrain = require('./Terrain');
var Sounds = require('./Sounds');
var Fish = require('./Models/fish.js');
var Rockbass = require('./Models/rockbass.js');
var Jellyfish = require('./Models/jellyfish.js');
var Catfish = require('./Models/catfish.js');
var Particles = require('./Models/particles.js');
var Lights = require('./Models/lights.js');
var Lantern = require('./Models/lantern.js');
var Gauge = require('./UI/gauge.js');
var Controls = require('./Controls');
var Raycaster = require('./Controls/raycaster.js');

var fishList = require('./fishList');
var dbg = require('debug')('luma:app');

// Enable debug
window.myDebug = require("debug");

var App = {

    init:function() {
        dbg('init');
        this.scene = Scene.create();
        this.camera = Camera.create();
        this.listener = Listener.create(this.camera);
        this.renderer = Renderer.create();
        this.fishes = [];
        this.rockbasses = [];
        this.catfishes = [];
        this.jellyfishes = [];
        this.progressStatus = [];
        Ui.createTarget(this.camera);

        this.clock = new THREE.Clock();

        this.initElements();
        this.initEvents();
        this.getDevice();
        this.launch();
        this.createElements();
        this.initAssets();

        return this;
    },

    initElements: function() {
        dbg('initialize elements');
        this.$els = {
            toggleFullScreenBtn: document.getElementById('playBtn'),
            toggleAudioBtn: document.getElementById('toggleAudioBtn'),
            wrapper: document.getElementById('wrapper'),
            window: window
        };
    },

    initEvents: function() {
        dbg('initialize events');
        this.$els.toggleFullScreenBtn.addEventListener('click', this.toggleFullScreen.bind(this));
        this.$els.toggleAudioBtn.addEventListener('click', this.toggleAudio.bind(this));
        this.$els.window.addEventListener('resize', this.onWindowResize.bind(this), false );
    },

    toggleFullScreen: function() {
        Ui.toggleFullScreen(this.$els.wrapper,  Supports);
    },

    toggleAudio: function() {
        Ui.toggleAudio(Listener);
    },

    onWindowResize: function() {
        Ui.onWindowResize(Camera, Renderer);
    },

    initAssets: function() {
        dbg('load assets');
        Fish.loadAssets(this.createFishes.bind(this), this.assetsLoadingProgress.bind(this));
        Rockbass.loadAssets(this.createRockbass.bind(this), this.assetsLoadingProgress.bind(this));
        Catfish.loadAssets(this.createCatfish.bind(this), this.assetsLoadingProgress.bind(this));
        Jellyfish.loadAssets(this.createJellyfish.bind(this), this.assetsLoadingProgress.bind(this));
    },

    assetsLoadingProgress: function(progress) {
        this.progressStatus[progress.key] = progress.value;
        var sum = 0;
        var divider = 0;
        for(var key in this.progressStatus) {
            sum += this.progressStatus[key];
            divider ++;
        }
        var percentage = sum / divider;
        dbg('Global asset loading progress', percentage);
    },

    launch: function() {
        dbg('launch');
        this.scene.add(this.camera);
        this.sound = Sounds.create(this.listener);
    },

    createElements: function() {
        dbg('create elements');
        Lights.addAsChild(this.camera, this.scene);
        Lantern.attachAsChild(this.scene);
        this.gauge = Gauge.create(this.camera);
        this.terrain = Terrain.create(this.scene, this.camera, this.renderer);
        this.particles = Particles.create(this.camera);
        this.raycaster = Raycaster.create(this.scene, this.camera, Ui, this.terrain);
    },

    createFishes: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the fish';
            this.fishes.push(Fish.create(this.scene, this.listener, fishName));
        }
    },

    createRockbass: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the rockbass';
            this.rockbasses.push(Rockbass.create(this.scene, this.listener, fishName));
        }
    },

    createCatfish: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the catfish';
            this.catfishes.push(Catfish.create(this.scene, this.listener, fishName));
        }
    },

    createJellyfish: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the jellyfish';
            this.jellyfishes.push(Jellyfish.create(this.scene, this.listener, fishName));
        }
    },

    getDevice: function() {
        dbg('get device');
        touchControls = Controls.initTouchMovements(this.camera);

        if(Supports.isMobile()) {
            this.rotationControls = Controls.create(this.camera);
            this.renderer = Renderer.setCardboardEffect();
        } else {
            this.rotationControls = Controls.createMouse(this.camera, this.renderer);
        }
    },

    render: function() {
        var delta = 0.75 * this.clock.getDelta();

        requestAnimationFrame(this.render.bind(this));

        this.rotationControls.update();
        //touchControls.update();
        this.raycaster.update();
        Camera.render();

        this.renderer.render(this.scene, this.camera);

        Fish.update(this.fishes, delta);
        Rockbass.update(this.rockbasses, delta);
        Catfish.update(this.catfishes, delta);
        Jellyfish.update(this.jellyfishes, delta);
        this.gauge.update();
    }
};

var app = App.init();
app.render();<commit_msg>this.animals array contain all animals that need updates<commit_after>var Supports = require('./Utils/Supports');
var Scene = require('./Utils/Scene');
var Camera = require('./Utils/Camera');
var Listener = require('./Utils/Listener');
var Renderer = require('./Utils/Renderer');
var Ui = require('./UI');

var Terrain = require('./Terrain');
var Sounds = require('./Sounds');
var Animal = require('./Models/animal.js');
var Fish = require('./Models/fish.js');
var Rockbass = require('./Models/rockbass.js');
var Jellyfish = require('./Models/jellyfish.js');
var Catfish = require('./Models/catfish.js');
var Particles = require('./Models/particles.js');
var Lights = require('./Models/lights.js');
var Lantern = require('./Models/lantern.js');
var Gauge = require('./UI/gauge.js');
var Controls = require('./Controls');
var Raycaster = require('./Controls/raycaster.js');

var fishList = require('./fishList');
var dbg = require('debug')('luma:app');

// Enable debug
window.myDebug = require("debug");

var App = {

    init:function() {
        dbg('init');
        this.scene = Scene.create();
        this.camera = Camera.create();
        this.listener = Listener.create(this.camera);
        this.renderer = Renderer.create();
        this.animals = [];
        this.progressStatus = [];
        Ui.createTarget(this.camera);

        this.clock = new THREE.Clock();

        this.initElements();
        this.initEvents();
        this.getDevice();
        this.launch();
        this.createElements();
        this.initAssets();

        return this;
    },

    initElements: function() {
        dbg('initialize elements');
        this.$els = {
            toggleFullScreenBtn: document.getElementById('playBtn'),
            toggleAudioBtn: document.getElementById('toggleAudioBtn'),
            wrapper: document.getElementById('wrapper'),
            window: window
        };
    },

    initEvents: function() {
        dbg('initialize events');
        this.$els.toggleFullScreenBtn.addEventListener('click', this.toggleFullScreen.bind(this));
        this.$els.toggleAudioBtn.addEventListener('click', this.toggleAudio.bind(this));
        this.$els.window.addEventListener('resize', this.onWindowResize.bind(this), false );
    },

    toggleFullScreen: function() {
        Ui.toggleFullScreen(this.$els.wrapper,  Supports);
    },

    toggleAudio: function() {
        Ui.toggleAudio(Listener);
    },

    onWindowResize: function() {
        Ui.onWindowResize(Camera, Renderer);
    },

    initAssets: function() {
        dbg('load assets');
        Fish.loadAssets(this.createFishes.bind(this), this.assetsLoadingProgress.bind(this));
        Rockbass.loadAssets(this.createRockbass.bind(this), this.assetsLoadingProgress.bind(this));
        Catfish.loadAssets(this.createCatfish.bind(this), this.assetsLoadingProgress.bind(this));
        Jellyfish.loadAssets(this.createJellyfish.bind(this), this.assetsLoadingProgress.bind(this));
    },

    assetsLoadingProgress: function(progress) {
        this.progressStatus[progress.key] = progress.value;
        var sum = 0;
        var divider = 0;
        for(var key in this.progressStatus) {
            sum += this.progressStatus[key];
            divider ++;
        }
        var percentage = sum / divider;
        dbg('Global asset loading progress', percentage);
    },

    launch: function() {
        dbg('launch');
        this.scene.add(this.camera);
        this.sound = Sounds.create(this.listener);
    },

    createElements: function() {
        dbg('create elements');
        Lights.addAsChild(this.camera, this.scene);
        Lantern.attachAsChild(this.scene);
        this.gauge = Gauge.create(this.camera);
        this.terrain = Terrain.create(this.scene, this.camera, this.renderer);
        this.particles = Particles.create(this.camera);
        this.raycaster = Raycaster.create(this.scene, this.camera, Ui, this.terrain);
    },

    createFishes: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the fish';
            this.animals.push(Fish.create(this.scene, this.listener, fishName));
        }
    },

    createRockbass: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the rockbass';
            this.animals.push(Rockbass.create(this.scene, this.listener, fishName));
        }
    },

    createCatfish: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the catfish';
            this.animals.push(Catfish.create(this.scene, this.listener, fishName));
        }
    },

    createJellyfish: function() {
        for(var i = 0 ; i < fishList.length; i++) {
            var fishName = fishList[i].name + ' the jellyfish';
            this.animals.push(Jellyfish.create(this.scene, this.listener, fishName));
        }
    },

    getDevice: function() {
        dbg('get device');
        touchControls = Controls.initTouchMovements(this.camera);

        if(Supports.isMobile()) {
            this.rotationControls = Controls.create(this.camera);
            this.renderer = Renderer.setCardboardEffect();
        } else {
            this.rotationControls = Controls.createMouse(this.camera, this.renderer);
        }
    },

    render: function() {
        var delta = 0.75 * this.clock.getDelta();

        requestAnimationFrame(this.render.bind(this));

        this.rotationControls.update();
        //touchControls.update();
        this.raycaster.update();
        Camera.render();

        this.renderer.render(this.scene, this.camera);

        Animal.update(this.animals, delta);
        this.gauge.update();
    }
};

var app = App.init();
app.render();<|endoftext|>


<commit_before>// returns a linear transformation of the coordinates such that the given list of values
// fits between [0, 1]

Shade.Utils.fit = function(data) {
    // this makes float attribute buffers work, but it might be confusing to the
    // user that there exist values v for which Shade.Utils.fit(v) works,
    // but Shade.Utils.fit(Shade.make(v)) does not
    var t = data._shade_type;
    if (t === 'attribute_buffer') {
        if (data.itemSize !== 1)
            throw "only dimension-1 attribute buffers are supported";
        if (_.isUndefined(data.array))
            throw "Shade.Utils.fit on attribute buffers requires keep_array:true in options";
        data = data.array;
    }

    var min = _.min(data), max = _.max(data);
    return Shade.Utils.linear(min, max, 0, 1);
};
<commit_msg>uses Shade.Scale.linear<commit_after>// returns a linear transformation of the coordinates such that the given list of values
// fits between [0, 1]

Shade.Utils.fit = function(data) {
    // this makes float attribute buffers work, but it might be confusing to the
    // user that there exist values v for which Shade.Utils.fit(v) works,
    // but Shade.Utils.fit(Shade.make(v)) does not
    var t = data._shade_type;
    if (t === 'attribute_buffer') {
        if (data.itemSize !== 1)
            throw "only dimension-1 attribute buffers are supported";
        if (_.isUndefined(data.array))
            throw "Shade.Utils.fit on attribute buffers requires keep_array:true in options";
        data = data.array;
    }

    var min = _.min(data), max = _.max(data);
    return Shade.Scale.linear({domain: [min, max]},
                              {range: [0, 1]});
};
<|endoftext|>


<commit_before>/*
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*
these are the configuration settings for TinyMCE. a complete list
of options can be found in the excellent manual at
http://tinymce.moxiecode.com/tinymce/docs/reference_configuration.html
*/

    currentURL = location.href.replace(/\?.*$/,"");
    //alert(currentURL);
    config = {

    /* enable customizable theme */
    theme    : "advanced",

    /* only the element whose ID is listed under "elements" will be editable */
    mode     : "exact",
    elements : "tinymce.content",

    /* FIXME: how do I get the user's language preference for authoring? */
    language : "en",

    /* enable plugins for custom save function, fullscreen editing
      and search-and-replace. */
    plugins  : "save,fullscreen,searchreplace,table,contextmenu,simplebrowser",

       plugin_simplebrowser_width : '800', //default
       plugin_simplebrowser_height : '600', //default

       plugin_simplebrowser_browselinkurl : currentURL + '?lenya.module=tinymce&lenya.step=link-show&language=en',
       plugin_simplebrowser_browseimageurl : currentURL + '?lenya.usecase=tinymce.insertAsset',
       plugin_simplebrowser_browseflashurl : '',

    /* grey out the "save" button unless there are unsaved changes: */
    save_enablewhendirty : false,

    /* some special settings for fullscreen mode (they override the
      settings further down) */
    fullscreen_settings : {
            auto_resize : false,
            theme_advanced_toolbar_location : "top",
            theme_advanced_statusbar_location : "bottom"
    },

    /* auto-resize the editing area. docs say this is "experimental"! */
    auto_resize : true,

    /* characters that should be replaced by named XHTML entities.
       cocoon does not define entities by default, so we use none. */
    entities        : "",

    /* do not make unicode references, output all special characters unchanged. */
    entity_encoding : "raw",

    /* keep linebreaks, don't put everything on one line. this is
       important for advanced users who want to use the source editor. */
    remove_linebreaks       : false,

    /* prettyprint sourcecode on saving FIXME: test. does this do anything? */
    apply_source_formatting : true,

    /* if the user inserts a table into a p, split p to create correct code.
       for nested lists, the inner list is correctly placed in a

    fix_list_elements: true;
    fix_table_elements: true;

    /* let tinymce do the layout by itself */
    theme_advanced_layout_manager     : "SimpleLayout",

    /* the toolbar is placed at the top of the editable area. */
    theme_advanced_toolbar_location   : "top",

    /* the statusbar is placed at the bottom. it displays the element path. */
    theme_advanced_statusbar_location : "bottom",

    /* the following items define the function buttons your users get to see.
      for a complete list, see
      http://tinymce.moxiecode.com/tinymce/docs/reference_buttons.html */

    theme_advanced_buttons1 :
            "save,undo,redo,search,replace,separator," +
            "cleanup,code,charmap,visualaid,fullscreen,separator," +
            "formatselect,styleselect",

    theme_advanced_buttons2 :
            "bold,italic,underline,strikethrough,sub,sup,removeformat,separator," +
            "bullist,numlist,table,separator," +
            "indent,outdent,separator," +
            "link,unlink,image,separator," +
            "help",

    /* three button rows are active by default. override. */
    theme_advanced_buttons3 : "",

    /* the following items define the allowed elements and attributes on your site.
      the default setting is very restrictive to enforce a corporate design and clean
      code at the expense of flexibility. */
    theme_advanced_blockformats       : "p,h1,h2,h3,h4",

/*
Lenya/TinyMCE glue code
*/

    /* this callback can override arbitrary tinymce commands. neato!
       currently used hooks are "insert image", "insert link" and "save".
       the handler sits in tiny_lenya_glue.js. */
    execcommand_callback : "LenyaExecCommandHandler",

    /* insert custom save handler to do some extra clean-up. */
    save_callback : "LenyaSaveContent"
    };

<commit_msg>added the anchor button to the tinymce editor<commit_after>/*
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*
these are the configuration settings for TinyMCE. a complete list
of options can be found in the excellent manual at
http://tinymce.moxiecode.com/tinymce/docs/reference_configuration.html
*/

    currentURL = location.href.replace(/\?.*$/,"");
    //alert(currentURL);
    config = {

    /* enable customizable theme */
    theme    : "advanced",

    /* only the element whose ID is listed under "elements" will be editable */
    mode     : "exact",
    elements : "tinymce.content",

    /* FIXME: how do I get the user's language preference for authoring? */
    language : "en",

    /* enable plugins for custom save function, fullscreen editing
      and search-and-replace. */
    plugins  : "save,fullscreen,searchreplace,table,contextmenu,simplebrowser",

       plugin_simplebrowser_width : '800', //default
       plugin_simplebrowser_height : '600', //default

       plugin_simplebrowser_browselinkurl : currentURL + '?lenya.module=tinymce&lenya.step=link-show&language=en',
       plugin_simplebrowser_browseimageurl : currentURL + '?lenya.usecase=tinymce.insertAsset',
       plugin_simplebrowser_browseflashurl : '',

    /* grey out the "save" button unless there are unsaved changes: */
    save_enablewhendirty : false,

    /* some special settings for fullscreen mode (they override the
      settings further down) */
    fullscreen_settings : {
            auto_resize : false,
            theme_advanced_toolbar_location : "top",
            theme_advanced_statusbar_location : "bottom"
    },

    /* auto-resize the editing area. docs say this is "experimental"! */
    auto_resize : true,

    /* characters that should be replaced by named XHTML entities.
       cocoon does not define entities by default, so we use none. */
    entities        : "",

    /* do not make unicode references, output all special characters unchanged. */
    entity_encoding : "raw",

    /* keep linebreaks, don't put everything on one line. this is
       important for advanced users who want to use the source editor. */
    remove_linebreaks       : false,

    /* prettyprint sourcecode on saving FIXME: test. does this do anything? */
    apply_source_formatting : true,

    /* if the user inserts a table into a p, split p to create correct code.
       for nested lists, the inner list is correctly placed in a

    fix_list_elements: true;
    fix_table_elements: true;

    /* let tinymce do the layout by itself */
    theme_advanced_layout_manager     : "SimpleLayout",

    /* the toolbar is placed at the top of the editable area. */
    theme_advanced_toolbar_location   : "top",

    /* the statusbar is placed at the bottom. it displays the element path. */
    theme_advanced_statusbar_location : "bottom",

    /* the following items define the function buttons your users get to see.
      for a complete list, see
      http://tinymce.moxiecode.com/tinymce/docs/reference_buttons.html */

    theme_advanced_buttons1 :
            "save,undo,redo,search,replace,separator," +
            "cleanup,code,charmap,visualaid,fullscreen,separator," +
            "formatselect,styleselect",

    theme_advanced_buttons2 :
            "bold,italic,underline,strikethrough,sub,sup,removeformat,separator," +
            "bullist,numlist,table,separator," +
            "indent,outdent,separator," +
            "anchor,link,unlink,image,separator," +
            "help",

    /* three button rows are active by default. override. */
    theme_advanced_buttons3 : "",

    /* the following items define the allowed elements and attributes on your site.
      the default setting is very restrictive to enforce a corporate design and clean
      code at the expense of flexibility. */
    theme_advanced_blockformats       : "p,h1,h2,h3,h4",

/*
Lenya/TinyMCE glue code
*/

    /* this callback can override arbitrary tinymce commands. neato!
       currently used hooks are "insert image", "insert link" and "save".
       the handler sits in tiny_lenya_glue.js. */
    execcommand_callback : "LenyaExecCommandHandler",

    /* insert custom save handler to do some extra clean-up. */
    save_callback : "LenyaSaveContent"
    };

<|endoftext|>


<commit_before>(function( global, $ ) {
  var plugins = {},
      MAX_IMAGE_WIDTH = 1280,
      MAX_IMAGE_HEIGHT = 740;

  var EditorHelper = function() {
    throw "Do not use EditorHelper in this manner. Use EditorHelper.init instead.";
  };

  // This fix is to ensure content-editable still updates correctly, and deals with ie9 not reading document.activeElement properly
  function blurActiveEl() {
   if ( document.activeElement ) {
      document.activeElement.blur();
    }
  }

  EditorHelper.init = function( butter ) {

    /**
     * Member: draggable
     *
     * Makes a container draggable using jQueryUI
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when position changes
     * @param {DOMElement} dragContainer: the container which to apply draggable to
     * @param {media} The current media's target element in Butter ( parent container )
     * @param {Object} extra options to apply to the draggable call
     *                 Options are:
     *                    {DOMElement} handle: Restrict drag start event to this element
     *                    {Function} start: Function to execute on drag start event
     *                    {Function} end: Fucntion to execute on drag end event
     */
    global.EditorHelper.draggable = function( trackEvent, dragContainer, targetContainer, options ) {
      var target = targetContainer.getBoundingClientRect(),
          iframeCover = targetContainer.querySelector( ".butter-iframe-fix" );

      options = options || {};

      function createHelper( suffix ) {
        var el = document.createElement( "div" );
        el.classList.add( "ui-draggable-handle" );
        el.classList.add( "ui-draggable-" + suffix );
        return el;
      }

      dragContainer.appendChild( createHelper( "top" ) );
      dragContainer.appendChild( createHelper( "bottom" ) );
      dragContainer.appendChild( createHelper( "left" ) );
      dragContainer.appendChild( createHelper( "right" ) );
      dragContainer.appendChild( createHelper( "grip" ) );

      $( dragContainer ).draggable({
        handle: ".ui-draggable-handle",
        containment: "parent",
        start: function() {
          iframeCover.style.display = "block";

          // Open the editor
          butter.editor.editTrackEvent( trackEvent );

          if ( options.start ) {
            options.start();
          }
        },
        stop: function( event, ui ) {

          var top = ui.position.top,
              left = ui.position.left;

          target = targetContainer.getBoundingClientRect();

          if ( options.end ) {
            options.end();
          }

          if ( top < 0 ) {
            top = 0;
          }

          if ( left < 0 ) {
            left = 0;
          }

          iframeCover.style.display = "none";
          blurActiveEl();

          trackEvent.update({
            top: ( top / target.height ) * 100,
            left: ( left / target.width ) * 100
          });
        }
      });
    };

    /**
     * Member: resizable
     *
     * Makes a container resizable using jQueryUI
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when size changes
     * @param {DOMElement} resizeContainer: the container which to apply resizable to
     * @param {media} The current media's target element in Butter ( parent container )
     * @param {Object} extra options to apply to the resizeable call
     *                 Options are:
     *                    {String} handlePositions: describes where to position resize handles ( i.e. "n,s,e,w" )
     *                    {Function} start: Function to execute on resize start event
     *                    {Function} end: Fucntion to execute on resize end event
     *                    {Number} minWidth: Minimum width that the resizeContainer should be
     *                    {Number} minHeight: Minimum height that the resizeContainer should be
     */
    global.EditorHelper.resizable = function( trackEvent, resizeContainer, targetContainer, options ) {
      var iframeCover = targetContainer.querySelector( ".butter-iframe-fix" );

      options = options || {};

      $( resizeContainer ).resizable({
        handles: options.handlePositions,
        start: function() {
          iframeCover.style.display = "block";

          // Open the editor
          butter.editor.editTrackEvent( trackEvent );

          if ( options.start ) {
            options.start();
          }
        },
        containment: "parent",
        stop: function( event, ui ) {
          var media = targetContainer.getBoundingClientRect(),
              height = ( ui.size.height + resizeContainer.offsetTop ) <= media.height ? ui.size.height : media.height - resizeContainer.offsetTop,
              width = ( ui.size.width + resizeContainer.offsetLeft ) <= media.width ? ui.size.width : media.width - resizeContainer.offsetLeft,
              top = ( ui.position.top / media.height ) * 100,
              left = ( ui.position.left / media.width ) * 100;

          iframeCover.style.display = "none";

          if ( options.end ) {
            options.end();
          }

          height = ( height / media.height ) * 100;
          width = ( width / media.width ) * 100;
          height = height >= options.minHeight ? height : options.minHeight;
          width = width >= options.minWidth ? width : options.minWidth;

          blurActiveEl();

          trackEvent.update({
            height: height,
            width: width,
            top: top,
            left: left
          });
        }
      });
    };

    /**
     * Member: contentEditable
     *
     * Makes a container's content editable using contenteditable
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when content changes
     * @param {DOMElement} contentContainer: the container which to listen for changes and set as editable
     */
    global.EditorHelper.contentEditable = function( trackEvent, contentContainers ) {
      var newText = "",
          contentContainer,
          updateText,
          updateTrackEvent,
          onBlur,
          onKeyDown,
          onMouseDown;

      updateText = function() {
        newText = "";
        for ( var i = 0, l = contentContainers.length; i < l; i++ ) {
          contentContainer = contentContainers[ i ];
          contentContainer.innerHTML = contentContainer.innerHTML.replace( /
/g, "\n" );
          newText += contentContainer.textContent;
          if ( i < l - 1 ) {
            newText += "\n";
          }
        }
      };
      updateTrackEvent = function() {
        blurActiveEl();
        trackEvent.update({
          text: newText
        });
      };
      onBlur = function( e ) {
        // store the new text.
        updateText();
        // update the text after any existing events are done.
        // this way we do not revert any other event's changes.
        setTimeout( updateTrackEvent, 0 );
      };
      onKeyDown = function( e ) {
        // enter key for an update.
        // shift + enter for newline.
        if ( !e.shiftKey && e.keyCode === 13 ) {
          updateText();
          updateTrackEvent();
        }
      };
      onMouseDown = function( e ) {
        e.stopPropagation();

        // Open the editor
        butter.editor.editTrackEvent( trackEvent );

        $( contentContainer ).draggable( "destroy" );
      };

      for ( var i = 0, l = contentContainers.length; i < l; i++ ) {
        contentContainer = contentContainers[ i ];
        if ( contentContainer ) {
          contentContainer.addEventListener( "blur", onBlur, false );
          contentContainer.addEventListener( "keydown", onKeyDown, false );
          contentContainer.addEventListener( "mousedown", onMouseDown, false );
          contentContainer.setAttribute( "contenteditable", "true" );
        }
      }
    };

    /**
     * Member: droppable
     *
     * Make a container listen for drop events for loading images from a local machine
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when content changes
     * @param {DOMElement} dropContainer: The container that listens for the drop events
     */

    global.EditorHelper.droppable = function( trackEvent, dropContainer ) {
      dropContainer.addEventListener( "dragover", function( e ) {
        e.preventDefault();
        dropContainer.classList.add( "butter-dragover" );
      }, false );

      dropContainer.addEventListener( "dragleave", function( e ) {
        e.preventDefault();
        dropContainer.classList.remove( "butter-dragover" );
      }, false );

      dropContainer.addEventListener( "drop", function( e ) {
        var file, imgSrc, imgURI, image, div;

        e.preventDefault();
        e.stopPropagation();

        dropContainer.classList.add( "butter-dropped" );

        if ( !e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files[ 0 ] ) {
          butter.dispatch( "droppable-unsupported" );
          return;
        }

        file = e.dataTransfer.files[ 0 ];

        if ( window.URL && window.URL.createObjectURL ) {
          imgSrc = window.URL.createObjectURL( file );
        } else if ( window.webkitURL && window.webkitURL.createObjectURL ) {
          imgSrc = window.webkitURL.createObjectURL( file );
        } else {
          butter.dispatch( "droppable-unsupported" );
        }

        // So yeah, Opera has the functionality namespaced but all it currently does is:
        // window.URL.createObjectURL = function(obj) {
        //   return obj;
        // };
        if ( imgSrc === file ) {
          butter.dispatch( "droppable-unsupported" );
          return;
        } else {

          image = document.createElement( "img" );
          image.onload = function() {
            var width = this.width,
                height = this.height,
                wRatio, hRatio, resizeRatio,
                scaledWidth, scaledHeight,
                canvas = document.createElement( "canvas" ),
                context;

            // Fit image nicely into our largest embed size, using
            // the longest side and aspect ratio. Inspired by:
            // http://stackoverflow.com/questions/7863653/algorithm-to-resize-image-and-maintain-aspect-ratio-to-fit-iphone
            if ( width >= height ) {
              if ( width <= MAX_IMAGE_WIDTH && height <= MAX_IMAGE_HEIGHT ) {
                scaledWidth = width;
                scaledHeight = height;
              } else {
                wRatio = MAX_IMAGE_WIDTH / width;
                hRatio = MAX_IMAGE_HEIGHT / height;
                resizeRatio = Math.min( wRatio, hRatio );
                scaledHeight = height * resizeRatio;
                scaledWidth = width * resizeRatio;
              }
            } else {
              if ( height <= MAX_IMAGE_WIDTH && width <= MAX_IMAGE_HEIGHT ) {
                scaledWidth = width;
                scaledHeight = height;
              } else {
                wRatio = MAX_IMAGE_HEIGHT / width;
                hRatio = MAX_IMAGE_WIDTH / height;
                resizeRatio = Math.min( wRatio, hRatio );
                scaledHeight = height * resizeRatio;
                scaledWidth = width * resizeRatio;
              }
            }

            canvas.width = scaledWidth;
            canvas.height = scaledHeight;
            context = canvas.getContext( "2d" );
            context.drawImage( this, 0, 0, scaledWidth, scaledHeight );

            imgURI = canvas.toDataURL();
            trackEvent.update( { src: imgURI } );

            if ( window.URL && window.URL.revokeObjectURL ) {
              window.URL.revokeObjectURL( imgSrc );
            } else if ( window.webkitURL && window.webkitURL.revokeObjectURL ) {
              window.webkitURL.revokeObjectURL( imgSrc );
            }
          };
          image.src = imgSrc;

          // Open the editor
          butter.editor.editTrackEvent( trackEvent );

          // Force image to download, esp. Opera. We can't use
          // "display: none", since that makes it invisible, and
          // thus not load.  Opera also requires the image be
          // in the DOM before it will load.
          div = document.createElement( "div" );
          div.setAttribute( "data-butter-exclude", "true" );
          div.className = "butter-image-preload";
          div.appendChild( image );
          document.body.appendChild( div );
        }
      }, false );
    };

    function _updateFunction( e ) {

      var _trackEvent;

      if ( e.type === "trackeventadded" ) {
        _trackEvent = e.data;
      } else if ( e.type === "trackeventupdated" ) {
        _trackEvent = e.target;
      }

      if ( plugins[ _trackEvent.type ] ) {
        plugins[ _trackEvent.type ]( _trackEvent, butter.currentMedia.popcorn.popcorn );
      }
    } //updateFunction

    butter.listen( "trackeventadded", _updateFunction );
    butter.listen( "trackeventupdated", _updateFunction );
  };

  EditorHelper.addPlugin = function( plugin, callback ) {
    plugins[ plugin ] = callback;
  };

  global.EditorHelper = EditorHelper;

}( window, window.jQuery ));
<commit_msg>[#2638] Prevent images inside droppable containers being draggable. Ensure drag over class is removed properly<commit_after>(function( global, $ ) {
  var plugins = {},
      MAX_IMAGE_WIDTH = 1280,
      MAX_IMAGE_HEIGHT = 740;

  var EditorHelper = function() {
    throw "Do not use EditorHelper in this manner. Use EditorHelper.init instead.";
  };

  // This fix is to ensure content-editable still updates correctly, and deals with ie9 not reading document.activeElement properly
  function blurActiveEl() {
   if ( document.activeElement ) {
      document.activeElement.blur();
    }
  }

  EditorHelper.init = function( butter ) {

    /**
     * Member: draggable
     *
     * Makes a container draggable using jQueryUI
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when position changes
     * @param {DOMElement} dragContainer: the container which to apply draggable to
     * @param {media} The current media's target element in Butter ( parent container )
     * @param {Object} extra options to apply to the draggable call
     *                 Options are:
     *                    {DOMElement} handle: Restrict drag start event to this element
     *                    {Function} start: Function to execute on drag start event
     *                    {Function} end: Fucntion to execute on drag end event
     */
    global.EditorHelper.draggable = function( trackEvent, dragContainer, targetContainer, options ) {
      var target = targetContainer.getBoundingClientRect(),
          iframeCover = targetContainer.querySelector( ".butter-iframe-fix" );

      options = options || {};

      function createHelper( suffix ) {
        var el = document.createElement( "div" );
        el.classList.add( "ui-draggable-handle" );
        el.classList.add( "ui-draggable-" + suffix );
        return el;
      }

      dragContainer.appendChild( createHelper( "top" ) );
      dragContainer.appendChild( createHelper( "bottom" ) );
      dragContainer.appendChild( createHelper( "left" ) );
      dragContainer.appendChild( createHelper( "right" ) );
      dragContainer.appendChild( createHelper( "grip" ) );

      $( dragContainer ).draggable({
        handle: ".ui-draggable-handle",
        containment: "parent",
        start: function() {
          iframeCover.style.display = "block";

          // Open the editor
          butter.editor.editTrackEvent( trackEvent );

          if ( options.start ) {
            options.start();
          }
        },
        stop: function( event, ui ) {

          var top = ui.position.top,
              left = ui.position.left;

          target = targetContainer.getBoundingClientRect();

          if ( options.end ) {
            options.end();
          }

          if ( top < 0 ) {
            top = 0;
          }

          if ( left < 0 ) {
            left = 0;
          }

          iframeCover.style.display = "none";
          blurActiveEl();

          trackEvent.update({
            top: ( top / target.height ) * 100,
            left: ( left / target.width ) * 100
          });
        }
      });
    };

    /**
     * Member: resizable
     *
     * Makes a container resizable using jQueryUI
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when size changes
     * @param {DOMElement} resizeContainer: the container which to apply resizable to
     * @param {media} The current media's target element in Butter ( parent container )
     * @param {Object} extra options to apply to the resizeable call
     *                 Options are:
     *                    {String} handlePositions: describes where to position resize handles ( i.e. "n,s,e,w" )
     *                    {Function} start: Function to execute on resize start event
     *                    {Function} end: Fucntion to execute on resize end event
     *                    {Number} minWidth: Minimum width that the resizeContainer should be
     *                    {Number} minHeight: Minimum height that the resizeContainer should be
     */
    global.EditorHelper.resizable = function( trackEvent, resizeContainer, targetContainer, options ) {
      var iframeCover = targetContainer.querySelector( ".butter-iframe-fix" );

      options = options || {};

      $( resizeContainer ).resizable({
        handles: options.handlePositions,
        start: function() {
          iframeCover.style.display = "block";

          // Open the editor
          butter.editor.editTrackEvent( trackEvent );

          if ( options.start ) {
            options.start();
          }
        },
        containment: "parent",
        stop: function( event, ui ) {
          var media = targetContainer.getBoundingClientRect(),
              height = ( ui.size.height + resizeContainer.offsetTop ) <= media.height ? ui.size.height : media.height - resizeContainer.offsetTop,
              width = ( ui.size.width + resizeContainer.offsetLeft ) <= media.width ? ui.size.width : media.width - resizeContainer.offsetLeft,
              top = ( ui.position.top / media.height ) * 100,
              left = ( ui.position.left / media.width ) * 100;

          iframeCover.style.display = "none";

          if ( options.end ) {
            options.end();
          }

          height = ( height / media.height ) * 100;
          width = ( width / media.width ) * 100;
          height = height >= options.minHeight ? height : options.minHeight;
          width = width >= options.minWidth ? width : options.minWidth;

          blurActiveEl();

          trackEvent.update({
            height: height,
            width: width,
            top: top,
            left: left
          });
        }
      });
    };

    /**
     * Member: contentEditable
     *
     * Makes a container's content editable using contenteditable
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when content changes
     * @param {DOMElement} contentContainer: the container which to listen for changes and set as editable
     */
    global.EditorHelper.contentEditable = function( trackEvent, contentContainers ) {
      var newText = "",
          contentContainer,
          updateText,
          updateTrackEvent,
          onBlur,
          onKeyDown,
          onMouseDown;

      updateText = function() {
        newText = "";
        for ( var i = 0, l = contentContainers.length; i < l; i++ ) {
          contentContainer = contentContainers[ i ];
          contentContainer.innerHTML = contentContainer.innerHTML.replace( /
/g, "\n" );
          newText += contentContainer.textContent;
          if ( i < l - 1 ) {
            newText += "\n";
          }
        }
      };
      updateTrackEvent = function() {
        blurActiveEl();
        trackEvent.update({
          text: newText
        });
      };
      onBlur = function( e ) {
        // store the new text.
        updateText();
        // update the text after any existing events are done.
        // this way we do not revert any other event's changes.
        setTimeout( updateTrackEvent, 0 );
      };
      onKeyDown = function( e ) {
        // enter key for an update.
        // shift + enter for newline.
        if ( !e.shiftKey && e.keyCode === 13 ) {
          updateText();
          updateTrackEvent();
        }
      };
      onMouseDown = function( e ) {
        e.stopPropagation();

        // Open the editor
        butter.editor.editTrackEvent( trackEvent );

        $( contentContainer ).draggable( "destroy" );
      };

      for ( var i = 0, l = contentContainers.length; i < l; i++ ) {
        contentContainer = contentContainers[ i ];
        if ( contentContainer ) {
          contentContainer.addEventListener( "blur", onBlur, false );
          contentContainer.addEventListener( "keydown", onKeyDown, false );
          contentContainer.addEventListener( "mousedown", onMouseDown, false );
          contentContainer.setAttribute( "contenteditable", "true" );
        }
      }
    };

    /**
     * Member: droppable
     *
     * Make a container listen for drop events for loading images from a local machine
     *
     * @param {TrackEvent} trackEvent: The trackEvent to update when content changes
     * @param {DOMElement} dropContainer: The container that listens for the drop events
     */

    global.EditorHelper.droppable = function( trackEvent, dropContainer ) {
      dropContainer.addEventListener( "dragover", function( e ) {
        e.preventDefault();
        dropContainer.classList.add( "butter-dragover" );
      }, false );

      dropContainer.addEventListener( "dragleave", function( e ) {
        e.preventDefault();
        dropContainer.classList.remove( "butter-dragover" );
      }, false );

      dropContainer.addEventListener( "mousedown", function( e ) {
        // Prevent being able to drag the images inside and re drop them
        e.preventDefault();
      }, false );

      dropContainer.addEventListener( "drop", function( e ) {
        var file, imgSrc, imgURI, image, div;

        e.preventDefault();
        e.stopPropagation();

        dropContainer.classList.remove( "butter-dragover" );

        if ( !e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files[ 0 ] ) {
          butter.dispatch( "droppable-unsupported" );
          return;
        }

        file = e.dataTransfer.files[ 0 ];

        if ( window.URL && window.URL.createObjectURL ) {
          imgSrc = window.URL.createObjectURL( file );
        } else if ( window.webkitURL && window.webkitURL.createObjectURL ) {
          imgSrc = window.webkitURL.createObjectURL( file );
        } else {
          butter.dispatch( "droppable-unsupported" );
        }

        // So yeah, Opera has the functionality namespaced but all it currently does is:
        // window.URL.createObjectURL = function(obj) {
        //   return obj;
        // };
        if ( imgSrc === file ) {
          butter.dispatch( "droppable-unsupported" );
          return;
        } else {

          image = document.createElement( "img" );
          image.onload = function() {
            var width = this.width,
                height = this.height,
                wRatio, hRatio, resizeRatio,
                scaledWidth, scaledHeight,
                canvas = document.createElement( "canvas" ),
                context;

            // Fit image nicely into our largest embed size, using
            // the longest side and aspect ratio. Inspired by:
            // http://stackoverflow.com/questions/7863653/algorithm-to-resize-image-and-maintain-aspect-ratio-to-fit-iphone
            if ( width >= height ) {
              if ( width <= MAX_IMAGE_WIDTH && height <= MAX_IMAGE_HEIGHT ) {
                scaledWidth = width;
                scaledHeight = height;
              } else {
                wRatio = MAX_IMAGE_WIDTH / width;
                hRatio = MAX_IMAGE_HEIGHT / height;
                resizeRatio = Math.min( wRatio, hRatio );
                scaledHeight = height * resizeRatio;
                scaledWidth = width * resizeRatio;
              }
            } else {
              if ( height <= MAX_IMAGE_WIDTH && width <= MAX_IMAGE_HEIGHT ) {
                scaledWidth = width;
                scaledHeight = height;
              } else {
                wRatio = MAX_IMAGE_HEIGHT / width;
                hRatio = MAX_IMAGE_WIDTH / height;
                resizeRatio = Math.min( wRatio, hRatio );
                scaledHeight = height * resizeRatio;
                scaledWidth = width * resizeRatio;
              }
            }

            canvas.width = scaledWidth;
            canvas.height = scaledHeight;
            context = canvas.getContext( "2d" );
            context.drawImage( this, 0, 0, scaledWidth, scaledHeight );

            imgURI = canvas.toDataURL();
            trackEvent.update( { src: imgURI } );

            if ( window.URL && window.URL.revokeObjectURL ) {
              window.URL.revokeObjectURL( imgSrc );
            } else if ( window.webkitURL && window.webkitURL.revokeObjectURL ) {
              window.webkitURL.revokeObjectURL( imgSrc );
            }
          };
          image.src = imgSrc;

          // Open the editor
          butter.editor.editTrackEvent( trackEvent );

          // Force image to download, esp. Opera. We can't use
          // "display: none", since that makes it invisible, and
          // thus not load.  Opera also requires the image be
          // in the DOM before it will load.
          div = document.createElement( "div" );
          div.setAttribute( "data-butter-exclude", "true" );
          div.className = "butter-image-preload";
          div.appendChild( image );
          document.body.appendChild( div );
        }
      }, false );
    };

    function _updateFunction( e ) {

      var _trackEvent;

      if ( e.type === "trackeventadded" ) {
        _trackEvent = e.data;
      } else if ( e.type === "trackeventupdated" ) {
        _trackEvent = e.target;
      }

      if ( plugins[ _trackEvent.type ] ) {
        plugins[ _trackEvent.type ]( _trackEvent, butter.currentMedia.popcorn.popcorn );
      }
    } //updateFunction

    butter.listen( "trackeventadded", _updateFunction );
    butter.listen( "trackeventupdated", _updateFunction );
  };

  EditorHelper.addPlugin = function( plugin, callback ) {
    plugins[ plugin ] = callback;
  };

  global.EditorHelper = EditorHelper;

}( window, window.jQuery ));
<|endoftext|>


<commit_before>exports.Context = function()
{
	this.servers = [];

	this.run = function()
	{
		for(var kServer in this.servers)
		{
			this.servers[kServer].connect();
		}
	}
}
<commit_msg>Changed Context.servers from array to object<commit_after>exports.Context = function()
{
	this.servers = {};

	this.run = function()
	{
		for(var kServer in this.servers)
		{
			this.servers[kServer].connect();
		}
	}
}
<|endoftext|>


<commit_before>require('babel-polyfill');

import Express from 'express';
import webpack from 'webpack';
import DashboardPlugin from 'webpack-dashboard/plugin';
import config from '../app/config';
import webpackConfig from './dev.config';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import path from 'path';

const app = new Express();
const host = config.host || 'localhost';
const port = (Number(config.port) + 1) || 3001;

console.log(path.resolve(__dirname, '../static/dist'));
const compiler = webpack(webpackConfig[0]);
const serverOptions = {
  contentBase: path.resolve(__dirname, '../static'),
  quiet: false,
  noInfo: false,
  hot: true,
  inline: true,
  lazy: false,
  publicPath: webpackConfig[0].output.publicPath,
  headers: {'Access-Control-Allow-Origin': '*'},
  stats: {colors: true}
};
const devMiddleware =  webpackDevMiddleware(compiler, serverOptions);
const hotMiddleware = webpackHotMiddleware(compiler);

app.use(devMiddleware);
app.use(hotMiddleware);

// app.get('*', function(req, res) {
//   const htmlBuffer = devMiddleware.fileSystem.readFileSync(`${webpackConfig[0].output.path}/index.html`)
//   res.send(htmlBuffer.toString())
// });

app.listen(port, (err) => {
  if (err) {
    console.error(err);
  } else {
    console.info('==> 🚧  Webpack development server listening on port %s', port);
  }
});
<commit_msg>quiet webpack<commit_after>require('babel-polyfill');

import Express from 'express';
import webpack from 'webpack';
import DashboardPlugin from 'webpack-dashboard/plugin';
import config from '../app/config';
import webpackConfig from './dev.config';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import path from 'path';

const app = new Express();
const host = config.host || 'localhost';
const port = (Number(config.port) + 1) || 3001;

console.log(path.resolve(__dirname, '../static/dist'));
const compiler = webpack(webpackConfig[0]);
const serverOptions = {
  contentBase: path.resolve(__dirname, '../static'),
  quiet: true,
  noInfo: true,
  hot: true,
  inline: true,
  lazy: false,
  publicPath: webpackConfig[0].output.publicPath,
  headers: {'Access-Control-Allow-Origin': '*'},
  stats: {colors: true}
};
const devMiddleware =  webpackDevMiddleware(compiler, serverOptions);
const hotMiddleware = webpackHotMiddleware(compiler);

app.use(devMiddleware);
app.use(hotMiddleware);

// app.get('*', function(req, res) {
//   const htmlBuffer = devMiddleware.fileSystem.readFileSync(`${webpackConfig[0].output.path}/index.html`)
//   res.send(htmlBuffer.toString())
// });

app.listen(port, (err) => {
  if (err) {
    console.error(err);
  } else {
    console.info('==> 🚧  Webpack development server listening on port %s', port);
  }
});
<|endoftext|>