<commit_before>pc.extend(pc, function () {

    var maxSize = 2048;
    var maskDynamic = 1;
    var maskBaked = 2;
    var maskLightmap = 4;

    var sceneLightmaps = [];
    var lmCamera;
    var tempVec = new pc.Vec3();

    function collectModels(node, nodes, allNodes) {
        if (!node.enabled) return;

        if (node.model && node.model.model) {
            allNodes.push(node);
            if (node.model.data.lightmapped) {
                nodes.push(node);
            }
        }
        var children = node.getChildren();
        for(var i=0; i<children.length; i++) {
            collectModels(children[i], nodes, allNodes);
        }
    }

    var Lightmapper = function (device, root, scene, renderer, assets) {
        this.device = device;
        this.root = root;
        this.scene = scene;
        this.renderer = renderer;
        this.assets = assets;
    };

    Lightmapper.prototype = {
        bake: function() {
            var i;
            var device = this.device;
            var scene = this.scene;

            // Delete old lightmaps, if present
            for(i=0; i<sceneLightmaps.length; i++) {
                sceneLightmaps[i].destroy();
            }
            sceneLightmaps = [];

            // Collect bakeable models
            var nodes = [];
            var allNodes = [];
            collectModels(this.root, nodes, allNodes);

            // Calculate lightmap sizes and allocate textures
            var texSize = [];
            var lmaps = [];
            var area, size;
            var sizeMult = scene.lightmapSizeMultiplier || 1;
            var scale = new pc.Vec3();
            var parent;
            var tex;
            var instances;
            for(i=0; i<nodes.length; i++) {
                area = {x:1, y:1, z:1};
                if (nodes[i].model.asset) {
                    var area1 = this.assets.get(nodes[i].model.asset).data.area || area;
                    area = {x:area1, y:area1, z:area1};
                } else if (nodes[i].model._area) {
                    area = nodes[i].model._area;
                }
                var areaMult = nodes[i].model.lightmapSizeMultiplier || 1;
                area.x *= areaMult;
                area.y *= areaMult;
                area.z *= areaMult;

                scale.copy(nodes[i].getLocalScale());
                parent = nodes[i].getParent();
                while(parent) {
                    scale.mul(parent.getLocalScale());
                    parent = parent.getParent();
                }

                size = Math.min(pc.math.nextPowerOfTwo((area.x*scale.x + area.y*scale.y + area.z*scale.z) * sizeMult), maxSize);
                texSize.push(size);

                tex = new pc.Texture(device, {width:size,
                                              height:size,
                                              format:pc.PIXELFORMAT_R8_G8_B8_A8,
                                              autoMipmap:false,
                                              rgbm:true});
                tex.addressU = pc.ADDRESS_CLAMP_TO_EDGE;
                tex.addressV = pc.ADDRESS_CLAMP_TO_EDGE;
                tex._minFilter = pc.FILTER_LINEAR;
                tex._magFilter = pc.FILTER_LINEAR;
                lmaps.push(tex);
            }

            // Collect bakeable lights
            var lights = [];
            var origMask = [];
            var origShadowMode = [];
            var origEnabled = [];
            var sceneLights = scene._lights;
            var mask;
            for(i=0; i<sceneLights.length; i++) {
                if (sceneLights[i]._enabled) {
                    mask = sceneLights[i].mask;
                    if ((mask & maskLightmap) !==0) {
                        origMask.push(mask);
                        origShadowMode.push(sceneLights[i].shadowUpdateMode);
                        sceneLights[i].setMask(0xFFFFFFFF);
                        sceneLights[i].shadowUpdateMode = pc.SHADOWUPDATE_THISFRAME;
                        lights.push(sceneLights[i]);
                    }
                }
                origEnabled.push(sceneLights[i]._enabled);
                sceneLights[i].setEnabled(false);
            }

            // Init shaders
            var chunks = pc.shaderChunks;
            var xformUv1 = chunks.transformUv1VS;
            var bakeLmEnd = chunks.bakeLmEndPS;
            var dilate = chunks.dilatePS;

            var dilateShader = chunks.createShaderFromCode(device, chunks.fullscreenQuadVS, dilate, "lmDilate");
            var constantTexSource = device.scope.resolve("source");
            var constantPixelOffset = device.scope.resolve("pixelOffset");
            var i, j;

            var lms = {};
            var lm, m, mat;
            var drawCalls = scene.drawCalls;

            // update scene matrices
            for(i=0; i<drawCalls.length; i++) {
                if (drawCalls[i].node) drawCalls[i].node.getWorldTransform();
            }

            // Store scene values
            var origFog = scene.fog;
            var origDrawCalls = scene.drawCalls;

            scene.fog = pc.FOG_NONE;

            // Create pseudo-camera
            if (!lmCamera) {
                lmCamera = new pc.Camera();
                lmCamera._node = new pc.GraphNode();
                lmCamera.setClearOptions({color:null, depth:1, flags:0});
            }

            var node;
            var lm, rcv, mat;

            // Disable existing scene lightmaps
            for(node=0; node<allNodes.length; node++) {
                rcv = allNodes[node].model.model.meshInstances;
                for(i=0; i<rcv.length; i++) {
                    rcv[i]._shaderDefs &= ~pc.SHADERDEF_LM;
                    rcv[i].mask |= pc.MASK_DYNAMIC;
                    rcv[i].mask &= ~pc.MASK_LIGHTMAP;
                }
            }

            // Change shadow casting
            var origCastShadows = [];
            for(node=0; node<allNodes.length; node++) {
                origCastShadows[node] = allNodes[node].model.castShadows;
                allNodes[node].model.castShadows = allNodes[node].model.data.castShadowsLightmap;
            }

            var origXform = [];
            var origEnd = [];
            var origAlpha = [];
            var origAlphaOpaque = [];
            var origAlphaPremul = [];
            var origCull = [];
            var origForceUv1 = [];

            // Render lightmaps
            for(node=0; node<nodes.length; node++) {
                lm = lmaps[node];
                rcv = nodes[node].model.model.meshInstances;
                scene.drawCalls = [];

                // Calculate model AABB
                var bounds = new pc.BoundingBox();
                if (rcv.length > 0) {
                    bounds.copy(rcv[0].aabb);
                    for(i=0; i<rcv.length; i++) {
                        rcv[i].node.getWorldTransform();
                        bounds.add(rcv[i].aabb);
                    }
                }

                // Store original material values to be changed
                for(i=0; i<rcv.length; i++) {
                    mat = rcv[i].material;
                    origXform.push(mat.chunks.transformVS);
                    origEnd.push(mat.chunks.endPS);
                    origAlpha.push(mat.chunks.outputAlphaPS);
                    origAlphaOpaque.push(mat.chunks.outputAlphaOpaquePS);
                    origAlphaPremul.push(mat.chunks.outputAlphaPremulPS);
                    origCull.push(mat.cull);
                    origForceUv1.push(mat.forceUv1);
                }

                for(i=0; i<rcv.length; i++) {
                    // patch meshInstance
                    m = rcv[i];
                    m._shaderDefs &= ~pc.SHADERDEF_LM; // disable LM define, if set, to get bare ambient on first pass
                    m.mask = maskLightmap; // only affected by LM lights

                    // patch material
                    mat = m.material;
                    mat.chunks.transformVS = xformUv1; // draw UV1
                    mat.chunks.endPS = bakeLmEnd; // encode to RGBM

                    // avoid writing unrelated things to alpha
                    mat.chunks.outputAlphaPS = "\n";
                    mat.chunks.outputAlphaOpaquePS = "\n";
                    mat.chunks.outputAlphaPremulPS = "\n";
                    mat.cull = pc.CULLFACE_NONE;
                    mat.forceUv1 = true; // provide data to xformUv1
                    mat.update();

                    scene.drawCalls.push(m);
                }

                var targ = new pc.RenderTarget(device, lm, {
                    depth: false
                });

                // Create 2nd LM for ping-pong
                var texTmp = new pc.Texture(device, {width:lm.width,
                                                  height:lm.height,
                                                  format:lm.format,
                                                  autoMipmap:false,
                                                  rgbm:true});
                texTmp.addressU = lm.addressU;
                texTmp.addressV = lm.addressV;
                texTmp._minFilter = pc.FILTER_LINEAR;
                texTmp._magFilter = pc.FILTER_LINEAR;
                var targTmp = new pc.RenderTarget(device, texTmp, {
                    depth: false
                });

                // Disable all bakeable lights
                for(j=0; j<lights.length; j++) {
                    lights[j].setEnabled(false);
                }

                // Accumulate lights into RGBM texture
                var curTarg;
                for(i=0; i<lights.length; i++) {
                    lights[i].setEnabled(true); // enable next light

                    // Tweak camera to fully see the model, so directional light frustum will also see it
                    if (lights[i].getType()===pc.LIGHTTYPE_DIRECTIONAL) {
                        tempVec.copy(bounds.center);
                        tempVec.y += bounds.halfExtents.y;

                        lmCamera._node.setPosition(tempVec);
                        lmCamera._node.setEulerAngles(-90, 0, 0);

                        var frustumSize = Math.max(bounds.halfExtents.x, bounds.halfExtents.z);

                        lmCamera.setProjection( pc.PROJECTION_ORTHOGRAPHIC );
                        lmCamera.setNearClip( 0 );
                        lmCamera.setFarClip( bounds.halfExtents.y * 2 );
                        lmCamera.setAspectRatio( 1 );
                        lmCamera.setOrthoHeight( frustumSize );
                    }

                    // ping-ponging output
                    curTarg = i%2===0? targ : targTmp;
                    lmCamera.setRenderTarget(curTarg);

                    //console.log("Baking light "+lights[i]._node.name + " on model " + nodes[node].name);
                    this.renderer.render(scene, lmCamera);

                    for(j=0; j<rcv.length; j++) {
                        m = rcv[j];
                        m.setParameter("texture_lightMap", i%2===0? lm : texTmp); // ping-ponging input
                        m._shaderDefs |= pc.SHADERDEF_LM; // force using LM even if material doesn't have it
                    }

                    lights[i].setEnabled(false); // disable that light
                }

                if (curTarg!==targ) {
                    var tmp = targTmp;
                    targTmp = targ;
                    targ = tmp;

                    tmp = texTmp;
                    texTmp = lm;
                    lm = tmp;
                }

                // Dilate
                var numDilates2x = 4; // 8 dilates
                var pixelOffset = new pc.Vec2(1/lm.width, 1/lm.height);
                constantPixelOffset.setValue(pixelOffset.data);
                for(i=0; i<numDilates2x; i++) {
                    constantTexSource.setValue(lm);
                    pc.drawQuadWithShader(device, targTmp, dilateShader);

                    constantTexSource.setValue(texTmp);
                    pc.drawQuadWithShader(device, targ, dilateShader);
                }

                for(i=0; i<rcv.length; i++) {
                    m = rcv[i];
                    m.mask = maskBaked;

                    // roll material back
                    mat = m.material;
                    mat.chunks.transformVS = origXform[i];
                    mat.chunks.endPS = origEnd[i];
                    mat.chunks.outputAlphaPS = origAlpha[i];
                    mat.chunks.outputAlphaOpaquePS = origAlphaOpaque[i];
                    mat.chunks.outputAlphaPremulPS = origAlphaPremul[i];
                    mat.cull = origCull[i];
                    mat.forceUv1 = origForceUv1[i];
                    mat.update();

                    // Set lightmap
                    rcv[i].setParameter("texture_lightMap", lm);
                }
                nodes[node].model.castShadows = origCastShadows[node];

                sceneLightmaps.push(lm);

                // Clean up
                targ.destroy();
                targTmp.destroy();
                texTmp.destroy();
            }

            // Revert shadow casting
            for(node=0; node<allNodes.length; node++) {
                allNodes[node].model.castShadows = origCastShadows[node];
            }

            // Enable all lights back
            for(i=0; i<lights.length; i++) {
                lights[i].setMask(origMask[i]);
                lights[i].shadowUpdateMode = origShadowMode[i];
            }

            for(i=0; i<sceneLights.length; i++) {
                sceneLights[i].setEnabled(origEnabled[i]);
            }

            // Roll back scene stuff
            scene.drawCalls = origDrawCalls;
            scene.fog = origFog;
        }
    };

    return {
        Lightmapper: Lightmapper,
        MASK_DYNAMIC: maskDynamic,
        MASK_BAKED: maskBaked,
        MASK_LIGHTMAP: maskLightmap
    };
}());
<commit_msg>use xyz area<commit_after>pc.extend(pc, function () {

    var maxSize = 2048;
    var maskDynamic = 1;
    var maskBaked = 2;
    var maskLightmap = 4;

    var sceneLightmaps = [];
    var lmCamera;
    var tempVec = new pc.Vec3();

    function collectModels(node, nodes, allNodes) {
        if (!node.enabled) return;

        if (node.model && node.model.model) {
            allNodes.push(node);
            if (node.model.data.lightmapped) {
                nodes.push(node);
            }
        }
        var children = node.getChildren();
        for(var i=0; i<children.length; i++) {
            collectModels(children[i], nodes, allNodes);
        }
    }

    var Lightmapper = function (device, root, scene, renderer, assets) {
        this.device = device;
        this.root = root;
        this.scene = scene;
        this.renderer = renderer;
        this.assets = assets;
    };

    Lightmapper.prototype = {
        bake: function() {
            var i;
            var device = this.device;
            var scene = this.scene;

            // Delete old lightmaps, if present
            for(i=0; i<sceneLightmaps.length; i++) {
                sceneLightmaps[i].destroy();
            }
            sceneLightmaps = [];

            // Collect bakeable models
            var nodes = [];
            var allNodes = [];
            collectModels(this.root, nodes, allNodes);

            // Calculate lightmap sizes and allocate textures
            var texSize = [];
            var lmaps = [];
            var area, size;
            var sizeMult = scene.lightmapSizeMultiplier || 1;
            var scale = new pc.Vec3();
            var parent;
            var tex;
            var instances;
            for(i=0; i<nodes.length; i++) {
                area = {x:1, y:1, z:1};
                if (nodes[i].model.asset) {
                    area = this.assets.get(nodes[i].model.asset).data.area || area;
                } else if (nodes[i].model._area) {
                    area = nodes[i].model._area;
                }
                var areaMult = nodes[i].model.lightmapSizeMultiplier || 1;
                area.x *= areaMult;
                area.y *= areaMult;
                area.z *= areaMult;

                scale.copy(nodes[i].getLocalScale());
                parent = nodes[i].getParent();
                while(parent) {
                    scale.mul(parent.getLocalScale());
                    parent = parent.getParent();
                }

                size = Math.min(pc.math.nextPowerOfTwo((area.x*scale.x + area.y*scale.y + area.z*scale.z) * sizeMult), maxSize);
                texSize.push(size);

                tex = new pc.Texture(device, {width:size,
                                              height:size,
                                              format:pc.PIXELFORMAT_R8_G8_B8_A8,
                                              autoMipmap:false,
                                              rgbm:true});
                tex.addressU = pc.ADDRESS_CLAMP_TO_EDGE;
                tex.addressV = pc.ADDRESS_CLAMP_TO_EDGE;
                tex._minFilter = pc.FILTER_LINEAR;
                tex._magFilter = pc.FILTER_LINEAR;
                lmaps.push(tex);
            }

            // Collect bakeable lights
            var lights = [];
            var origMask = [];
            var origShadowMode = [];
            var origEnabled = [];
            var sceneLights = scene._lights;
            var mask;
            for(i=0; i<sceneLights.length; i++) {
                if (sceneLights[i]._enabled) {
                    mask = sceneLights[i].mask;
                    if ((mask & maskLightmap) !==0) {
                        origMask.push(mask);
                        origShadowMode.push(sceneLights[i].shadowUpdateMode);
                        sceneLights[i].setMask(0xFFFFFFFF);
                        sceneLights[i].shadowUpdateMode = pc.SHADOWUPDATE_THISFRAME;
                        lights.push(sceneLights[i]);
                    }
                }
                origEnabled.push(sceneLights[i]._enabled);
                sceneLights[i].setEnabled(false);
            }

            // Init shaders
            var chunks = pc.shaderChunks;
            var xformUv1 = chunks.transformUv1VS;
            var bakeLmEnd = chunks.bakeLmEndPS;
            var dilate = chunks.dilatePS;

            var dilateShader = chunks.createShaderFromCode(device, chunks.fullscreenQuadVS, dilate, "lmDilate");
            var constantTexSource = device.scope.resolve("source");
            var constantPixelOffset = device.scope.resolve("pixelOffset");
            var i, j;

            var lms = {};
            var lm, m, mat;
            var drawCalls = scene.drawCalls;

            // update scene matrices
            for(i=0; i<drawCalls.length; i++) {
                if (drawCalls[i].node) drawCalls[i].node.getWorldTransform();
            }

            // Store scene values
            var origFog = scene.fog;
            var origDrawCalls = scene.drawCalls;

            scene.fog = pc.FOG_NONE;

            // Create pseudo-camera
            if (!lmCamera) {
                lmCamera = new pc.Camera();
                lmCamera._node = new pc.GraphNode();
                lmCamera.setClearOptions({color:null, depth:1, flags:0});
            }

            var node;
            var lm, rcv, mat;

            // Disable existing scene lightmaps
            for(node=0; node<allNodes.length; node++) {
                rcv = allNodes[node].model.model.meshInstances;
                for(i=0; i<rcv.length; i++) {
                    rcv[i]._shaderDefs &= ~pc.SHADERDEF_LM;
                    rcv[i].mask |= pc.MASK_DYNAMIC;
                    rcv[i].mask &= ~pc.MASK_LIGHTMAP;
                }
            }

            // Change shadow casting
            var origCastShadows = [];
            for(node=0; node<allNodes.length; node++) {
                origCastShadows[node] = allNodes[node].model.castShadows;
                allNodes[node].model.castShadows = allNodes[node].model.data.castShadowsLightmap;
            }

            var origXform = [];
            var origEnd = [];
            var origAlpha = [];
            var origAlphaOpaque = [];
            var origAlphaPremul = [];
            var origCull = [];
            var origForceUv1 = [];

            // Render lightmaps
            for(node=0; node<nodes.length; node++) {
                lm = lmaps[node];
                rcv = nodes[node].model.model.meshInstances;
                scene.drawCalls = [];

                // Calculate model AABB
                var bounds = new pc.BoundingBox();
                if (rcv.length > 0) {
                    bounds.copy(rcv[0].aabb);
                    for(i=0; i<rcv.length; i++) {
                        rcv[i].node.getWorldTransform();
                        bounds.add(rcv[i].aabb);
                    }
                }

                // Store original material values to be changed
                for(i=0; i<rcv.length; i++) {
                    mat = rcv[i].material;
                    origXform.push(mat.chunks.transformVS);
                    origEnd.push(mat.chunks.endPS);
                    origAlpha.push(mat.chunks.outputAlphaPS);
                    origAlphaOpaque.push(mat.chunks.outputAlphaOpaquePS);
                    origAlphaPremul.push(mat.chunks.outputAlphaPremulPS);
                    origCull.push(mat.cull);
                    origForceUv1.push(mat.forceUv1);
                }

                for(i=0; i<rcv.length; i++) {
                    // patch meshInstance
                    m = rcv[i];
                    m._shaderDefs &= ~pc.SHADERDEF_LM; // disable LM define, if set, to get bare ambient on first pass
                    m.mask = maskLightmap; // only affected by LM lights

                    // patch material
                    mat = m.material;
                    mat.chunks.transformVS = xformUv1; // draw UV1
                    mat.chunks.endPS = bakeLmEnd; // encode to RGBM

                    // avoid writing unrelated things to alpha
                    mat.chunks.outputAlphaPS = "\n";
                    mat.chunks.outputAlphaOpaquePS = "\n";
                    mat.chunks.outputAlphaPremulPS = "\n";
                    mat.cull = pc.CULLFACE_NONE;
                    mat.forceUv1 = true; // provide data to xformUv1
                    mat.update();

                    scene.drawCalls.push(m);
                }

                var targ = new pc.RenderTarget(device, lm, {
                    depth: false
                });

                // Create 2nd LM for ping-pong
                var texTmp = new pc.Texture(device, {width:lm.width,
                                                  height:lm.height,
                                                  format:lm.format,
                                                  autoMipmap:false,
                                                  rgbm:true});
                texTmp.addressU = lm.addressU;
                texTmp.addressV = lm.addressV;
                texTmp._minFilter = pc.FILTER_LINEAR;
                texTmp._magFilter = pc.FILTER_LINEAR;
                var targTmp = new pc.RenderTarget(device, texTmp, {
                    depth: false
                });

                // Disable all bakeable lights
                for(j=0; j<lights.length; j++) {
                    lights[j].setEnabled(false);
                }

                // Accumulate lights into RGBM texture
                var curTarg;
                for(i=0; i<lights.length; i++) {
                    lights[i].setEnabled(true); // enable next light

                    // Tweak camera to fully see the model, so directional light frustum will also see it
                    if (lights[i].getType()===pc.LIGHTTYPE_DIRECTIONAL) {
                        tempVec.copy(bounds.center);
                        tempVec.y += bounds.halfExtents.y;

                        lmCamera._node.setPosition(tempVec);
                        lmCamera._node.setEulerAngles(-90, 0, 0);

                        var frustumSize = Math.max(bounds.halfExtents.x, bounds.halfExtents.z);

                        lmCamera.setProjection( pc.PROJECTION_ORTHOGRAPHIC );
                        lmCamera.setNearClip( 0 );
                        lmCamera.setFarClip( bounds.halfExtents.y * 2 );
                        lmCamera.setAspectRatio( 1 );
                        lmCamera.setOrthoHeight( frustumSize );
                    }

                    // ping-ponging output
                    curTarg = i%2===0? targ : targTmp;
                    lmCamera.setRenderTarget(curTarg);

                    //console.log("Baking light "+lights[i]._node.name + " on model " + nodes[node].name);
                    this.renderer.render(scene, lmCamera);

                    for(j=0; j<rcv.length; j++) {
                        m = rcv[j];
                        m.setParameter("texture_lightMap", i%2===0? lm : texTmp); // ping-ponging input
                        m._shaderDefs |= pc.SHADERDEF_LM; // force using LM even if material doesn't have it
                    }

                    lights[i].setEnabled(false); // disable that light
                }

                if (curTarg!==targ) {
                    var tmp = targTmp;
                    targTmp = targ;
                    targ = tmp;

                    tmp = texTmp;
                    texTmp = lm;
                    lm = tmp;
                }

                // Dilate
                var numDilates2x = 4; // 8 dilates
                var pixelOffset = new pc.Vec2(1/lm.width, 1/lm.height);
                constantPixelOffset.setValue(pixelOffset.data);
                for(i=0; i<numDilates2x; i++) {
                    constantTexSource.setValue(lm);
                    pc.drawQuadWithShader(device, targTmp, dilateShader);

                    constantTexSource.setValue(texTmp);
                    pc.drawQuadWithShader(device, targ, dilateShader);
                }

                for(i=0; i<rcv.length; i++) {
                    m = rcv[i];
                    m.mask = maskBaked;

                    // roll material back
                    mat = m.material;
                    mat.chunks.transformVS = origXform[i];
                    mat.chunks.endPS = origEnd[i];
                    mat.chunks.outputAlphaPS = origAlpha[i];
                    mat.chunks.outputAlphaOpaquePS = origAlphaOpaque[i];
                    mat.chunks.outputAlphaPremulPS = origAlphaPremul[i];
                    mat.cull = origCull[i];
                    mat.forceUv1 = origForceUv1[i];
                    mat.update();

                    // Set lightmap
                    rcv[i].setParameter("texture_lightMap", lm);
                }
                nodes[node].model.castShadows = origCastShadows[node];

                sceneLightmaps.push(lm);

                // Clean up
                targ.destroy();
                targTmp.destroy();
                texTmp.destroy();
            }

            // Revert shadow casting
            for(node=0; node<allNodes.length; node++) {
                allNodes[node].model.castShadows = origCastShadows[node];
            }

            // Enable all lights back
            for(i=0; i<lights.length; i++) {
                lights[i].setMask(origMask[i]);
                lights[i].shadowUpdateMode = origShadowMode[i];
            }

            for(i=0; i<sceneLights.length; i++) {
                sceneLights[i].setEnabled(origEnabled[i]);
            }

            // Roll back scene stuff
            scene.drawCalls = origDrawCalls;
            scene.fog = origFog;
        }
    };

    return {
        Lightmapper: Lightmapper,
        MASK_DYNAMIC: maskDynamic,
        MASK_BAKED: maskBaked,
        MASK_LIGHTMAP: maskLightmap
    };
}());
<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('3.3.0');
		this.setClientTag('node:18-04-13');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('3.3.0');
		this.setClientTag('node:18-04-14');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.3.0');
		this.setClientTag('node:18-07-25');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.3.0');
		this.setClientTag('node:18-07-26');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.6.0');
		this.setClientTag('node:18-08-30');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.6.0');
		this.setClientTag('node:18-08-31');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2020  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('16.11.0');
		this.setClientTag('node:20-11-08');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2020  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('16.11.0');
		this.setClientTag('node:20-11-09');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.12.0');
		this.setClientTag('node:19-01-20');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.12.0');
		this.setClientTag('node:19-01-21');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2020  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('16.11.0');
		this.setClientTag('node:20-11-12');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2020  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('16.11.0');
		this.setClientTag('node:20-11-13');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>'use strict';

/* global app:true kongConfig:true appConfig:true */
(function (angular, app, kongConfig, appConfig) {

    if (typeof app === 'undefined') throw 'app-index.js: app is undefined';

    /**
     * Holds current page title, current host URL and
     * URL of the previous page.
     */
    app.factory('viewFactory', function () {
        return { title: '', prevUrl: '', host: kongConfig.host };
    });

    /**
     * Configures route provider and ajax provider.
     */
    app.config(['$routeProvider', 'ajaxProvider' , function ($routeProvider, ajaxProvider) {
        ajaxProvider.setHost(kongConfig.host);
        ajaxProvider.contentType('application/json; charset=utf-8');
        ajaxProvider.accept('application/json');

        /* Add a basic authorization header
         if username and password are provided in the settings. */
        if (typeof kongConfig.username === 'string' && kongConfig.username) {
            ajaxProvider.basicAuth(kongConfig.username, kongConfig.password || '');
        }

        /* Configure routes. */
        $routeProvider
            .when('/', {
                templateUrl: 'views/dashboard.html',
                controller: 'DashboardController'
            })
            .when('/cluster', {
                templateUrl: 'views/cluster-list.html',
                controller: 'ClusterListController'
            })
            .when('/api', {
                templateUrl: 'views/api-list.html',
                controller: 'ApiListController'
            })
            .when('/api/:apiId', {
                templateUrl: 'views/api-edit.html',
                controller: 'ApiEditController'
            })
            .when('/api/:apiId/plugins', {
                templateUrl: 'views/plugin-edit.html',
                controller: 'PluginEditController'
            })
            .when('/plugins', {
                templateUrl: 'views/plugin-list.html',
                controller: 'PluginListController'
            })
            .when('/plugins/:pluginId', {
                templateUrl: 'views/plugin-edit.html',
                controller: 'PluginEditController'
            })
            .when('/consumers', {
                templateUrl: 'views/consumer-list.html',
                controller: 'ConsumerListController'
            })
            .when('/consumers/:consumerId', {
                templateUrl: 'views/consumer-edit.html',
                controller: 'ConsumerEditController'
            })
            .when('/consumers/:consumerId/plugins', {
                templateUrl: 'views/plugin-list.html',
                controller: 'PluginListController'
            })
            .when('/certificates', {
                templateUrl: 'views/certificate-list.html',
                controller: 'CertificateListController'
            })
            .when('/certificates/:certificateId', {
                templateUrl: 'views/certificate-edit.html',
                controller: 'CertificateEditController'
            })
            .when('/upstreams', {
                templateUrl: 'views/upstream-list.html',
                controller: 'UpstreamListController'
            })
            .when('/upstreams/:upstreamId', {
                templateUrl: 'views/upstream-edit.html',
                controller: 'UpstreamEditController'
            })
            .when('/settings', {
                templateUrl: 'views/settings.html',
                controller: 'SettingsController'
            })
            .otherwise({
                templateUrl: 'views/dashboard.html',
                controller: 'DashboardController'
            });
    }]);

    /**
     * Detects and highlights the correct
     * sidebar link upon location change.
     */
    app.run(['$rootScope', 'viewFactory', function ($rootScope, viewFactory) {
        $rootScope.ngViewAnimation = appConfig.enableAnimation ? 'slide-right' : '';

        $rootScope.$on('$locationChangeStart', function (event, next, current) {
            viewFactory.deleteAction = null;
            viewFactory.prevUrl = current;

            if (next.indexOf('#') > 1) {
                let refArray = next.split('#!/')[1].split('/');
                let href = '#!/' + refArray[0];
                let nav  = angular.element('nav.navigation');

                nav.find('a.navigation__link').removeClass('active');
                nav.find('.navigation__link[data-ng-href="' + href + '"]').addClass('active');
            }
        });
    }]);

})(window.angular, app, kongConfig, appConfig);

/* global angular:true ipcRenderer:true */
(function (angular, content, ipcRenderer) {

    ipcRenderer.on('open-settings-view', function () {
        /* TODO: use $location */
        window.location.href = '#!/settings';
    });

    /**
     * Open all external links in default browser.
     */
    content.on('click', 'a[href^="http"]', function (event) {
        event.preventDefault();
        ipcRenderer.send('open-external', event.target.href);
    });

    /**
     * Deletes a resource when a delete button is pressed.
     */
    content.on('click', '.delete', function (event) {
        event.preventDefault();

        let target = angular.element(event.target), action = 'Delete';

        if (target.hasClass('disable')) action = 'Disable';

        if (confirm (action + ' this ' + target.data('target') + '?')) {
            let ajax  = angular.element('html').injector().get('ajax');
            let toast = angular.element('body').injector().get('toast');

            ajax.delete({ resource: target.data('url') }).then(function () {
                toast.success(target.data('target') + ' ' + action.toLowerCase() + 'd');

                if ( event.target.nodeName === 'I' ) target.parents('tr').fadeOut(200);
                else window.location.href = target.data('redirect');

            }, function (response) {
                toast.error(response.data);
            });
        }
    });

})(window.angular, angular.element('main.content'), ipcRenderer);
<commit_msg>change: simplify if condition with ternary operator<commit_after>'use strict';

/* global app:true kongConfig:true appConfig:true */
(function (angular, app, kongConfig, appConfig) {

    if (typeof app === 'undefined') throw 'app-index.js: app is undefined';

    /**
     * Holds current page title, current host URL and
     * URL of the previous page.
     */
    app.factory('viewFactory', function () {
        return { title: '', prevUrl: '', host: kongConfig.host };
    });

    /**
     * Configures route provider and ajax provider.
     */
    app.config(['$routeProvider', 'ajaxProvider' , function ($routeProvider, ajaxProvider) {
        ajaxProvider.setHost(kongConfig.host);
        ajaxProvider.contentType('application/json; charset=utf-8');
        ajaxProvider.accept('application/json');

        /* Add a basic authorization header
         if username and password are provided in the settings. */
        if (typeof kongConfig.username === 'string' && kongConfig.username) {
            ajaxProvider.basicAuth(kongConfig.username, kongConfig.password || '');
        }

        /* Configure routes. */
        $routeProvider
            .when('/', {
                templateUrl: 'views/dashboard.html',
                controller: 'DashboardController'
            })
            .when('/cluster', {
                templateUrl: 'views/cluster-list.html',
                controller: 'ClusterListController'
            })
            .when('/api', {
                templateUrl: 'views/api-list.html',
                controller: 'ApiListController'
            })
            .when('/api/:apiId', {
                templateUrl: 'views/api-edit.html',
                controller: 'ApiEditController'
            })
            .when('/api/:apiId/plugins', {
                templateUrl: 'views/plugin-edit.html',
                controller: 'PluginEditController'
            })
            .when('/plugins', {
                templateUrl: 'views/plugin-list.html',
                controller: 'PluginListController'
            })
            .when('/plugins/:pluginId', {
                templateUrl: 'views/plugin-edit.html',
                controller: 'PluginEditController'
            })
            .when('/consumers', {
                templateUrl: 'views/consumer-list.html',
                controller: 'ConsumerListController'
            })
            .when('/consumers/:consumerId', {
                templateUrl: 'views/consumer-edit.html',
                controller: 'ConsumerEditController'
            })
            .when('/consumers/:consumerId/plugins', {
                templateUrl: 'views/plugin-list.html',
                controller: 'PluginListController'
            })
            .when('/certificates', {
                templateUrl: 'views/certificate-list.html',
                controller: 'CertificateListController'
            })
            .when('/certificates/:certificateId', {
                templateUrl: 'views/certificate-edit.html',
                controller: 'CertificateEditController'
            })
            .when('/upstreams', {
                templateUrl: 'views/upstream-list.html',
                controller: 'UpstreamListController'
            })
            .when('/upstreams/:upstreamId', {
                templateUrl: 'views/upstream-edit.html',
                controller: 'UpstreamEditController'
            })
            .when('/settings', {
                templateUrl: 'views/settings.html',
                controller: 'SettingsController'
            })
            .otherwise({
                templateUrl: 'views/dashboard.html',
                controller: 'DashboardController'
            });
    }]);

    /**
     * Detects and highlights the correct
     * sidebar link upon location change.
     */
    app.run(['$rootScope', 'viewFactory', function ($rootScope, viewFactory) {
        $rootScope.ngViewAnimation = appConfig.enableAnimation ? 'slide-right' : '';

        $rootScope.$on('$locationChangeStart', function (event, next, current) {
            viewFactory.deleteAction = null;
            viewFactory.prevUrl = current;

            if (next.indexOf('#') > 1) {
                let refArray = next.split('#!/')[1].split('/');
                let href = '#!/' + refArray[0], nav  = angular.element('nav.navigation');

                nav.find('a.navigation__link').removeClass('active');
                nav.find('.navigation__link[data-ng-href="' + href + '"]').addClass('active');
            }
        });
    }]);

})(window.angular, app, kongConfig, appConfig);

/* global angular:true ipcRenderer:true */
(function (window, angular, content, ipcRenderer) {

    ipcRenderer.on('open-settings-view', function () {
        /* TODO: use $location */
        window.location.href = '#!/settings';
    });

    /**
     * Open all external links in default browser.
     */
    content.on('click', 'a[href^="http"]', function (event) {
        event.preventDefault();
        ipcRenderer.send('open-external', event.target.href);
    });

    /**
     * Deletes a resource when a delete button is pressed.
     */
    content.on('click', '.delete', function (event) {
        event.preventDefault();

        let target = angular.element(event.target);
        let action = target.hasClass('disable') ? 'Disable' : 'Delete';

        if (confirm (action + ' this ' + target.data('target') + '?')) {
            let ajax  = angular.element('html').injector().get('ajax');
            let toast = angular.element('body').injector().get('toast');

            ajax.delete({ resource: target.data('url') }).then(function () {
                toast.success(target.data('target') + ' ' + action.toLowerCase() + 'd');

                if ( event.target.nodeName === 'I' ) target.parents('tr').fadeOut(200);
                else window.location.href = target.data('redirect');

            }, function (response) {
                toast.error(response.data);
            });
        }
    });

})(window, window.angular, angular.element('main.content'), ipcRenderer);
<|endoftext|>


<commit_before>import fs from 'fs'
import path from 'path'
import { exec } from 'child_process'
import crypto from 'crypto'
import router from 'koa-router'

export default router()
.post('/api/hooks', async(ctx, next) => {
    const { fields, headers } = ctx.request
    const signature = getSecret(JSON.stringify(fields))

    if (signature === headers['x-hub-signature'].substr(5)) {
        console.info('Signature matched, restarting server...')
        pullAndUpdate()
    } else {
        console.warn('Signature mismatch')
    }

    ctx.body = {
        success: true
    }
})

// Checks if we're authorized to restart the server
function getSecret(body) {
    const INFERNOJS_SECRET = fs.readFileSync(path.join(__dirname, 'INFERNOJS_SECRET'))
    const secret = process.env.INFERNOJS_SECRET || INFERNOJS_SECRET
    const hash = crypto.createHmac('sha1', secret).update(body).digest('hex')
    return hash
}

function pullAndUpdate() {
    const cd = execute('cd /www/infernojs')
    cd.on('exit', function() {
        execute('git pull')
    })
}

function execute(cmd) {
    return exec(cmd, function(err, stdout, stderr) {
        if (err) throw err;

        stdout && console.log(stdout)
        stderr && console.log(stderr)
        console.log('Executed:', cmd)
    })
}
<commit_msg>Add comment<commit_after>import fs from 'fs'
import path from 'path'
import { exec } from 'child_process'
import crypto from 'crypto'
import router from 'koa-router'

export default router()
.post('/api/hooks', async(ctx, next) => {
    const { fields, headers } = ctx.request
    const signature = getSecret(JSON.stringify(fields))

    if (signature === headers['x-hub-signature'].substr(5)) {
        console.info('Signature matched, restarting server...')
        pullAndUpdate()
    } else {
        console.warn('Signature mismatch')
    }

    ctx.body = {
        success: true
    }
})

// Checks if we're authorized to restart the server
function getSecret(body) {
    const INFERNOJS_SECRET = fs.readFileSync(path.join(__dirname, 'INFERNOJS_SECRET'))
    const secret = process.env.INFERNOJS_SECRET || INFERNOJS_SECRET
    const hash = crypto.createHmac('sha1', secret).update(body).digest('hex')
    return hash
}

// Pulls master from github while our watcher automatically rebuilds the bundle
function pullAndUpdate() {
    const cd = execute('cd /www/infernojs')
    cd.on('exit', function() {
        execute('git pull')
    })
}

function execute(cmd) {
    return exec(cmd, function(err, stdout, stderr) {
        if (err) throw err;

        stdout && console.log(stdout)
        stderr && console.log(stderr)
        console.log('Executed:', cmd)
    })
}
<|endoftext|>


<commit_before>var Cookiebar = (function(doc) {

    function _(el) {
        if (!(this instanceof _)) {
            return new _(el);
        }

        var first = el.charAt(0);

        if (first === "#") {
            this.el = doc.getElementById(el.substr(1));
        } else if (first === ".") {
            this.el = doc.getElementsByClassName(el.substr(1));
        } else {
            this.el = doc.getElementsByTagName(el);
        }
    }

    _.prototype.fade = function fade(type, ms, dis) {
        var isIn = type === 'in',
            opacity = isIn ? 0 : 1,
            interval = 50,
            duration = ms,
            gap = interval / duration,
            display = dis ? dis : 'inline',
            self = this;

        if (isIn) {
            self.el.style.display = display;
            self.el.style.opacity = opacity;
        }

        function func() {
            opacity = isIn ? opacity + gap : opacity - gap;
            self.el.style.opacity = opacity;

            if (opacity <= 0) self.el.style.display = 'none';
            if (opacity <= 0 || opacity >= 1) window.clearInterval(fading);
        }

        var fading = window.setInterval(func, interval);
    };

    var Vanilla = function() {};

    Vanilla.prototype.extend = function(target) {
        for (var i = 1; i < arguments.length; ++i) {
            var from = arguments[i];
            if (typeof from !== 'object') continue;
            for (var j in from) {
                if (from.hasOwnProperty(j)) {
                    target[j] = typeof from[j] === 'object' ?
                        this.extend({}, target[j], from[j]) : from[j];
                }
            }
        }
        return target;
    };

    Vanilla.prototype.trigger = function(el, eventName) {
        var event = doc.createEvent('Event');
        event.initEvent(eventName, true, true);
        el.dispatchEvent(event);
    };

    /**
     * Vanilla JavaScript support IE8+.
     *
     * @link https://plainjs.com
     */

    Vanilla.prototype.addEvent = function(el, type, handler) {
        return (el[window.attachEvent ? 'attachEvent' : 'addEventListener'](
            (window.attachEvent ? 'on' : '')+type, handler, true
        ));
    };

    Vanilla.prototype.removeEvent = function(el, type, handler) {
        if (el.detachEvent) el.detachEvent('on' + type, handler);
        else el.removeEventListener(type, handler);
    };

    Vanilla.prototype.parseTemplate = function(str, data) {
        return str.replace(/\$\{(\w+)\}/gi, function(match, parensMatch) {
            if (data[parensMatch] !== undefined) {
                return data[parensMatch];
            }

            return match;
        });
    };

    var v = new Vanilla();

    var Cookiebar = function(opt) {
        var self = this;
        this.opt = v.extend({
            id: "cookiebar",
            cls: "cookiebar",
            cookie: "cookiebar",
            content: {
                description: "Az oldal sütiket használ a működéshez. Szolgáltatásaink igénybevételével Ön beleegyezik a sütik használatába!",
                link: "További információk",
                href: "http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm",
                button: "Elfogadom",
                more: "Az EU-s jogszabályok értelmében fel kell hívnunk a figyelmét, hogy oldalaink sütiket (cookie) használnak. Ezek miniatűr, ártalmatlan fájlok, melyeket az ön gépére helyezünk el, hogy a szolgáltatásaink használatát egyszerűbbé tegyük az ön számára. A sütiket természetesen letilthatja a böngészőjében, azonban ha az Elfogadom feliratú gombra kattint, akkor elfogadja azok használatát."
            },
            fade: {
                type: "in",
                ms: "500",
                display: "inline"
            },
            debug: 0,
            exits: true
        }, opt || {});

        this.bar = null;
        this.data = this.opt;
        this.bodyMargBotBackup = doc.body.style.marginBottom || "";
        this.accepted = false;
        this.events = {
            btnClick: function(e) {
                if (e && e.preventDefault) e.preventDefault();
                else if (typeof e === 'object') e.returnValue = false;

                self.accept();
            },
            winResize: function() {
                if (self.accepted) { return; }
                doc.body.style.marginBottom = self.bar.offsetHeight + "px";
            }
        };
        //Initialize
        this.init();
    };

    Cookiebar.prototype.init = function() {
        var self = this;

        if (self.data.debug) {
            self.setCookie('debug_cookibar', "test", 365, function() {
                self.delCookie(self.data.id);
                self.checkCookie();
            });
        } else {
            self.checkCookie();
        }
    };

    Cookiebar.prototype.getCookie = function(cname) {
        var name = cname + "=";
        var ca = doc.cookie.split(';');

        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) === 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    };

    Cookiebar.prototype.setCookie = function(cname, value, exdays, cb) {
        var ex = new Date();
        ex.setDate(ex.getDate() + exdays);

        var cvalue = escape(value) + (
            exdays === null ? "" : "; expires=" + ex.toUTCString() + "; path=/;"
        );

        doc.cookie = cname + "=" + cvalue;

        if (typeof cb === "function") {
            cb.call(this);
        }
    };

    Cookiebar.prototype.delCookie = function(cname) {
        doc.cookie = cname + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
    };

    Cookiebar.prototype.html = function() {
        var html = '
' +
            '
${des}
' +
            '
' +
            '${link}' +
            '
' +
            '
' +
            '<button type="button" name="${cls}-button" class="${cls}-btn">${btn}</button>' +
            '
' +
            '
${more}
' +
            '
';

        return v.parseTemplate(html, {
            cls: this.data.cls,
            href: this.data.content.href,
            link: this.data.content.link,
            more: this.data.content.more,
            btn: this.data.content.button,
            des: this.data.content.description
        });
    };

    Cookiebar.prototype.denny = function() {
        this.delCookie(this.data.id);
        this.accepted = false;
    };

    Cookiebar.prototype.accept = function() {
        this.accepted = true;
        this.setCookie(this.data.cookie, true, 365);

        v.removeEvent(window, 'resize', this.events.winResize);

        if (this.bar) {
            this.bar.style.display = 'none';
        }
        if (doc.body.style.marginBottom !== this.bodyMargBotBackup) {
            doc.body.style.marginBottom = this.bodyMargBotBackup;
        }
    };

    Cookiebar.prototype.draw = function() {
        var self = this, btn;

        if (self.accepted) { return; }

        if (!self.bar) {
            self.bar = doc.createElement('div');
            self.bar.id = self.data.id;
            self.bar.className = self.data.cls;
            self.bar.innerHTML = self.html();
            doc.body.insertBefore(self.bar, doc.body.firstChild);
            btn = self.bar.getElementsByClassName(self.data.cls + '-btn')[0];
            v.addEvent(btn, 'click', self.events.btnClick);
        }

        v.addEvent(window, 'resize', self.events.winResize);
        v.trigger(window, 'resize');

        _("#" + self.data.id).fade(self.data.fade.type, self.data.fade.ms);

        self.setCookie(self.data.cookie, null, 365);
    };

    Cookiebar.prototype.checkCookie = function() {
        this.accepted = this.getCookie(this.data.cookie) === "true";

        if (!this.accepted) { this.draw(); }
    };

    Cookiebar.prototype.getStatus = function() {
        return this.accepted;
    };

    return Cookiebar;
})(document);
<commit_msg>Update cookiebar.js<commit_after>var Cookiebar = (function(doc) {

    function _(el) {
        if (!(this instanceof _)) {
            return new _(el);
        }

        var first = el.charAt(0);

        if (first === "#") {
            this.el = doc.getElementById(el.substr(1));
        } else if (first === ".") {
            this.el = doc.getElementsByClassName(el.substr(1));
        } else {
            this.el = doc.getElementsByTagName(el);
        }
    }

    _.prototype.fade = function fade(type, ms, dis) {
        var isIn = type === 'in',
            opacity = isIn ? 0 : 1,
            interval = 50,
            duration = ms,
            gap = interval / duration,
            display = dis ? dis : 'inline',
            self = this;

        if (isIn) {
            self.el.style.display = display;
            self.el.style.opacity = opacity;
        }

        function func() {
            opacity = isIn ? opacity + gap : opacity - gap;
            self.el.style.opacity = opacity;

            if (opacity <= 0) self.el.style.display = 'none';
            if (opacity <= 0 || opacity >= 1) window.clearInterval(fading);
        }

        var fading = window.setInterval(func, interval);
    };

    var Vanilla = function() {};

    Vanilla.prototype.extend = function(target) {
        for (var i = 1; i < arguments.length; ++i) {
            var from = arguments[i];
            if (typeof from !== 'object') continue;
            for (var j in from) {
                if (from.hasOwnProperty(j)) {
                    target[j] = typeof from[j] === 'object' ?
                        this.extend({}, target[j], from[j]) : from[j];
                }
            }
        }
        return target;
    };

    Vanilla.prototype.trigger = function(el, eventName) {
        var event = doc.createEvent('Event');
        event.initEvent(eventName, true, true);
        el.dispatchEvent(event);
    };

    /**
     * Vanilla JavaScript support IE8+.
     *
     * @link https://plainjs.com
     */

    Vanilla.prototype.addEvent = function(el, type, handler) {
        return (el[window.attachEvent ? 'attachEvent' : 'addEventListener'](
            (window.attachEvent ? 'on' : '')+type, handler, true
        ));
    };

    Vanilla.prototype.removeEvent = function(el, type, handler) {
        if (el.detachEvent) el.detachEvent('on' + type, handler);
        else el.removeEventListener(type, handler);
    };

    Vanilla.prototype.parseTemplate = function(str, data) {
        return str.replace(/\$\{(\w+)\}/gi, function(match, parensMatch) {
            if (data[parensMatch] !== undefined) {
                return data[parensMatch];
            }

            return match;
        });
    };

    var v = new Vanilla();

    var Cookiebar = function(opt) {
        var self = this;
        this.opt = v.extend({
            id: "cookiebar",
            cls: "cookiebar",
            cookie: "cookiebar",
            content: {
                description: "Az oldal sütiket használ a működéshez. Szolgáltatásaink igénybevételével Ön beleegyezik a sütik használatába!",
                link: "További információk",
                href: "http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm",
                button: "Elfogadom",
                more: "Az EU-s jogszabályok értelmében fel kell hívnunk a figyelmét, hogy oldalaink sütiket (cookie) használnak. Ezek miniatűr, ártalmatlan fájlok, melyeket az ön gépére helyezünk el, hogy a szolgáltatásaink használatát egyszerűbbé tegyük az ön számára. A sütiket természetesen letilthatja a böngészőjében, azonban ha az Elfogadom feliratú gombra kattint, akkor elfogadja azok használatát."
            },
            fade: {
                type: "in",
                ms: "500",
                display: "inline"
            },
            debug: 0,
            exits: true
        }, opt || {});

        this.bar = null;
        this.data = this.opt;
        this.bodyMargBotBackup = doc.body.style.marginBottom || "";
        this.accepted = false;
        this.events = {
            btnClick: function(e) {
                if (e && e.preventDefault) e.preventDefault();
                else if (typeof e === 'object') e.returnValue = false;
                self.accept();
            },
            winResize: function() {
                if (self.accepted) { return; }
                doc.body.style.marginBottom = self.bar.offsetHeight + "px";
            }
        };
        //Initialize
        this.init();
    };

    Cookiebar.prototype.init = function() {
        var self = this;

        if (self.data.debug) {
            self.setCookie('debug_cookibar', "test", 365, function() {
                self.withdraw();
            });
        } else {
            self.checkCookie();
        }
    };

    Cookiebar.prototype.getCookie = function(cname) {
        var name = cname + "=";
        var ca = doc.cookie.split(';');

        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) === 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    };

    Cookiebar.prototype.setCookie = function(cname, value, exdays, cb) {
        var ex = new Date();
        ex.setDate(ex.getDate() + exdays);

        var cvalue = escape(value) + (
            exdays === null ? "" : "; expires=" + ex.toUTCString() + "; path=/;"
        );

        doc.cookie = cname + "=" + cvalue;

        if (typeof cb === "function") {
            cb.call(this);
        }
    };

    Cookiebar.prototype.delCookie = function(cname) {
        doc.cookie = cname + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
    };

    Cookiebar.prototype.html = function() {
        var html = '
' +
            '
${des}
' +
            '
' +
            '${link}' +
            '
' +
            '
' +
            '<button type="button" name="${cls}-button" class="${cls}-btn">${btn}</button>' +
            '
' +
            '
${more}
' +
            '
';

        return v.parseTemplate(html, {
            cls: this.data.cls,
            href: this.data.content.href,
            link: this.data.content.link,
            more: this.data.content.more,
            btn: this.data.content.button,
            des: this.data.content.description
        });
    };

    Cookiebar.prototype.withdraw = function() {
        this.delCookie(this.data.id);
        this.accepted = false;
        this.checkCookie();
    };

    Cookiebar.prototype.accept = function() {
        this.accepted = true;
        this.setCookie(this.data.cookie, true, 365);

        v.removeEvent(window, 'resize', this.events.winResize);

        if (this.bar) {
            this.bar.style.display = 'none';
        }
        if (doc.body.style.marginBottom !== this.bodyMargBotBackup) {
            doc.body.style.marginBottom = this.bodyMargBotBackup;
        }
    };

    Cookiebar.prototype.draw = function() {
        var self = this, btn;

        if (self.accepted) { return; }

        if (!self.bar) {
            self.bar = doc.createElement('div');
            self.bar.id = self.data.id;
            self.bar.className = self.data.cls;
            self.bar.innerHTML = self.html();
            doc.body.insertBefore(self.bar, doc.body.firstChild);
            btn = self.bar.getElementsByClassName(self.data.cls + '-btn')[0];
            v.addEvent(btn, 'click', self.events.btnClick);
        }

        v.addEvent(window, 'resize', self.events.winResize);
        v.trigger(window, 'resize');

        _("#" + self.data.id).fade(self.data.fade.type, self.data.fade.ms);

        self.setCookie(self.data.cookie, null, 365);
    };

    Cookiebar.prototype.checkCookie = function() {
        this.accepted = this.getCookie(this.data.cookie) === "true";
        if (!this.accepted) { this.draw(); }
    };

    Cookiebar.prototype.getStatus = function() {
        return this.accepted;
    };

    return Cookiebar;
})(document);
<|endoftext|>


<commit_before>(function(){
   "use strict";

    var server = require("./server.js");
    server.start("homepage.html", "404.html", 8080, function(){
        console.log("Server started");
    });
}());<commit_msg>port read from passed parameters inserver startup<commit_after>(function(){
   "use strict";

    var server = require("./server.js");
    var port = process.argv[2];
    server.start("homepage.html", "404.html", port, function(){
        console.log("Server started");
    });
}());<|endoftext|>


<commit_before>/**
 * The SelectionWatcher module watches for selection changes inside
 * of editable blocks.
 *
 * @module core
 * @submodule selectionWatcher
 */
var selectionWatcher = (function() {

  var rangySelection,
      currentSelection,
      currentRange;

  /**
   * Return a RangeContainer if the current selection is within an editable
   * otherwise return an empty RangeContainer
   */
  var getRangeContainer = function() {
    if (rangySelection) {
      rangySelection.refresh();
    } else {
      rangySelection = rangy.getSelection();
    }

    // rangeCount is 0 or 1 in all browsers except firefox
    // firefox can work with multiple ranges
    // (I don't know if this occurs from normal use though)
    if (rangySelection.rangeCount) {
      var range = rangySelection.getRangeAt(0);
      var editableSelector = '.' + config.editableClass;
      var hostNode = $(range.commonAncestorContainer).closest(editableSelector);
      if (hostNode.length) {
        return new RangeContainer(hostNode[0], range);
      }
    }

    // return an empty range container
    return new RangeContainer();
  };

  return {

    /**
     * Gets a fresh RangeContainer with the current selection or cursor.
     *
     * @return RangeContainer instance
     */
    getFreshRange: function() {
      return getRangeContainer();
    },

    /**
     * Gets a fresh RangeContainer with the current selection or cursor.
     *
     * @return Either a Cursor or Selection instance or undefined if
     * there is neither a selection or cursor.
     */
    getFreshSelection: function() {
      var range = getRangeContainer();

      return range.isCursor ?
        range.getCursor() :
        range.getSelection();
    },

    /**
     * Get the selection set by the last selectionChanged event.
     * Sometimes the event does not fire fast enough and the seleciton
     * you get is not the one the user sees.
     * In those cases use #getFreshSelection()
     *
     * @return Either a Cursor or Selection instance or undefined if
     * there is neither a selection or cursor.
     */
    getSelection: function() {
      return currentSelection;
    },

    forceCursor: function() {
      var range = getRangeContainer();
      return range.forceCursor();
    },

    selectionChanged: function() {
      var newRange = getRangeContainer();
      if (newRange.isDifferentFrom(currentRange)) {
        var lastSelection = currentSelection;
        currentRange = newRange;

        // empty selection or cursor
        if (lastSelection) {
          if (lastSelection.isCursor && !currentRange.isCursor) {
            dispatcher.notifyListeners('cursor', lastSelection.host);
          } else if (lastSelection.isSelection && !currentRange.isSelection) {
            dispatcher.notifyListeners('selection', lastSelection.host);
          }
        }

        // set new selection or cursor and fire event
        if (currentRange.isCursor) {
          currentSelection = new Cursor(currentRange.host, currentRange.range);
          dispatcher.notifyListeners('cursor', currentSelection.host, currentSelection);
        } else if (currentRange.isSelection) {
          currentSelection = new Selection(currentRange.host, currentRange.range);
          dispatcher.notifyListeners('selection', currentSelection.host, currentSelection);
        } else {
          currentSelection = undefined;
        }
      }
    }
  };
})();
<commit_msg>Always create new ranges for RangeContainers<commit_after>/**
 * The SelectionWatcher module watches for selection changes inside
 * of editable blocks.
 *
 * @module core
 * @submodule selectionWatcher
 */
var selectionWatcher = (function() {

  var rangySelection,
      currentSelection,
      currentRange;

  /**
   * Return a RangeContainer if the current selection is within an editable
   * otherwise return an empty RangeContainer
   */
  var getRangeContainer = function() {
    rangySelection = rangy.getSelection();

    // rangeCount is 0 or 1 in all browsers except firefox
    // firefox can work with multiple ranges
    // (I don't know if this occurs from normal use though)
    if (rangySelection.rangeCount) {
      var range = rangySelection.getRangeAt(0);
      var editableSelector = '.' + config.editableClass;
      var hostNode = $(range.commonAncestorContainer).closest(editableSelector);
      if (hostNode.length) {
        return new RangeContainer(hostNode[0], range);
      }
    }

    // return an empty range container
    return new RangeContainer();
  };

  return {

    /**
     * Gets a fresh RangeContainer with the current selection or cursor.
     *
     * @return RangeContainer instance
     */
    getFreshRange: function() {
      return getRangeContainer();
    },

    /**
     * Gets a fresh RangeContainer with the current selection or cursor.
     *
     * @return Either a Cursor or Selection instance or undefined if
     * there is neither a selection or cursor.
     */
    getFreshSelection: function() {
      var range = getRangeContainer();

      return range.isCursor ?
        range.getCursor() :
        range.getSelection();
    },

    /**
     * Get the selection set by the last selectionChanged event.
     * Sometimes the event does not fire fast enough and the seleciton
     * you get is not the one the user sees.
     * In those cases use #getFreshSelection()
     *
     * @return Either a Cursor or Selection instance or undefined if
     * there is neither a selection or cursor.
     */
    getSelection: function() {
      return currentSelection;
    },

    forceCursor: function() {
      var range = getRangeContainer();
      return range.forceCursor();
    },

    selectionChanged: function() {
      var newRange = getRangeContainer();
      if (newRange.isDifferentFrom(currentRange)) {
        var lastSelection = currentSelection;
        currentRange = newRange;

        // empty selection or cursor
        if (lastSelection) {
          if (lastSelection.isCursor && !currentRange.isCursor) {
            dispatcher.notifyListeners('cursor', lastSelection.host);
          } else if (lastSelection.isSelection && !currentRange.isSelection) {
            dispatcher.notifyListeners('selection', lastSelection.host);
          }
        }

        // set new selection or cursor and fire event
        if (currentRange.isCursor) {
          currentSelection = new Cursor(currentRange.host, currentRange.range);
          dispatcher.notifyListeners('cursor', currentSelection.host, currentSelection);
        } else if (currentRange.isSelection) {
          currentSelection = new Selection(currentRange.host, currentRange.range);
          dispatcher.notifyListeners('selection', currentSelection.host, currentSelection);
        } else {
          currentSelection = undefined;
        }
      }
    }
  };
})();
<|endoftext|>