<commit_before>/**
 * A tiny javascript library that makes progress bars out of the favicon placeholders
 * Check nicolasbize.github.io/faviconx/ for latest updates.
 *
 * Author:       Nicolas Bize
 * Created:      Oct 10th 2013
 * Last Updated: Oct 16th 2014
 * Version:      1.0.1
 * Licence:      FavIconX is licenced under MIT licence (http://opensource.org/licenses/MIT)
 */
var FavIconX = (function() {
    // my private parts, do not mess with them.
    var originalIcon;
    var value = 0;
    var animValue = 0;
    var canvas = document.createElement('canvas');
    var context;
    var icon; // image storage
    var animInterval = null;
    var animCallback = null;
    var oldTitle = "";
    var head = null;
    var isReset = null;

    // default values for properties accessed through .config() method:
    var shape;
    var animated;
    var animationSpeed; // ms to go from one value to the one from setValue
    var borderColor;
    var borderColor2;
    var shadowColor;
    var borderWidth;
    var fillColor;
    var fillColor2;
    var updateTitle;
    var titleRenderer;

    function setDefaults(){
        shape = 'circle';
        animated = false;
        animationSpeed = 2000;
        animCallback = null;
        borderColor = '#3A70B1';
        borderColor2 = null;
        shadowColor = 'rgba(255, 0, 0, 0)';
        borderWidth = 1;
        fillColor = '#3A70B1';
        fillColor2 = null;
        updateTitle = true;
        value = 0;
        isReset = true;
        titleRenderer = function(val, title){
            return '[' + val + '%] - ' + title;
        };
    }

    // Generates the wanted shape
    function generateBitmap(v){
        if(shape === 'circle'){
            generateCircle(v);
        } else if(shape === 'doughnut'){
            generateDoughnut(v);
        } else if(shape === 'square'){
            generateSquare(v);
        }
    }

    // (255, 0, 0) => "#FF0000"
    function rgbToHex(r, g, b) {
        return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
    }

    // "#FF0000" => [255, 0, 0]
    function hexToRgb(hex) {
        hex = hex.indexOf("#") === 0 ? hex.substring(1) : hex;
        var nb = parseInt(hex, 16);
        var r = (nb >> 16) & 255;
        var g = (nb >> 8) & 255;
        var b = nb & 255;
        return [r,g,b];
    }

    // because i don't speak in radians
    function toRad(deg){
        return deg * Math.PI / 180;
    }

    // gets a mid color according to current value
    // col1 = 0%, col2 = 100%
    function getMidColor(col1, col2){
        var rgb1 = hexToRgb(col1);
        var rgb2 = hexToRgb(col2);
        var avg = [0, 0, 0];
        var inv_v = (100 - (animValue || value)) / 100;
        for(var i=0; i<3; i++){
            avg[i] = rgb1[i] * inv_v + rgb2[i] * (1-inv_v);
        }
        return rgbToHex(Math.round(avg[0]), Math.round(avg[1]), Math.round(avg[2]));
    }

    // let's get a boring circle first
    function generateCircle(v){
        var graphValue = v || value;
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var radius = 7 - borderWidth / 2;
        var deg = graphValue * 3.6 - 90;

        canvas.width = canvas.width;
        context.lineWidth = borderWidth;
        context.strokeStyle = borderColor2 ? getMidColor(borderColor, borderColor2) : borderColor;
        context.beginPath();
        context.arc(centerX, centerY, radius, 0, toRad(360), false);
        context.closePath();
        context.fillStyle = shadowColor;
        context.fill();
        context.stroke();
        if(graphValue > 0){
            context.fillStyle = fillColor2 ? getMidColor(fillColor, fillColor2) : fillColor;
            context.beginPath();
            context.moveTo(8,8);
            context.arc(centerX, centerY, radius, toRad(-90), toRad(deg), false);
            context.closePath();
            context.fill();
        }
    }

    // spelling doughnut just feels wrong
    function generateDoughnut(v){
        var graphValue = v || value;
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var deg = graphValue * 3.6 - 90;

        canvas.width = canvas.width;
        if(graphValue > 0){
            context.lineWidth = borderWidth;
            context.strokeStyle = shadowColor;
            context.beginPath();
            context.arc(centerX, centerY, 6, 0, toRad(360), false);
            context.arc(centerX, centerY, 6 - borderWidth, 0, toRad(360), true);
            context.closePath();
            context.stroke();

            context.strokeStyle = fillColor2 ? getMidColor(fillColor, fillColor2) : fillColor;
            context.beginPath();
            context.arc(centerX, centerY, 6, toRad(-90), toRad(deg), false);
            context.arc(centerX, centerY, 6 - borderWidth, toRad(deg), toRad(-90), true);
            context.closePath();
            context.stroke();
        }
    }

    // something a bit more fancy
    function generateSquare(v){
        var graphValue = v || value;
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var borderRadius = 2;
        var x = 1;
        var y = 1;
        var width = 14;
        var height = 14;
        var deg = graphValue * 3.6 - 90;

        canvas.width = canvas.width;
        context.beginPath();
        context.strokeStyle = borderColor2 ? getMidColor(borderColor, borderColor2) : borderColor;
        context.lineWidth = borderWidth;
        context.fillStyle = shadowColor;
        context.moveTo(x + borderRadius, y);
        context.lineTo(x + width - borderRadius, y);
        context.quadraticCurveTo(x + width, y, x + width, y + borderRadius);
        context.lineTo(x + width, y + height - borderRadius);
        context.quadraticCurveTo(x + width, y + height, x + width - borderRadius, y + height);
        context.lineTo(x + borderRadius, y + height);
        context.quadraticCurveTo(x, y + height, x, y + height - borderRadius);
        context.lineTo(x, y + borderRadius);
        context.quadraticCurveTo(x, y, x + borderRadius, y);
        context.closePath();
        context.stroke();
        if(graphValue > 0){
            context.clip();
            context.beginPath();
            context.moveTo(8,8);
            context.fillStyle = 'rgba(255, 0, 0, 0)';
            context.arc(centerX, centerY, 12, toRad(-90), toRad(deg), false); // we clip the rest
            context.closePath();
            context.fill();
            context.clip();
            context.beginPath();
            context.fillStyle = fillColor2 ? getMidColor(fillColor, fillColor2) : fillColor;
            context.moveTo(x + borderRadius, y);
            context.lineTo(x + width - borderRadius, y);
            context.quadraticCurveTo(x + width, y, x + width, y + borderRadius);
            context.lineTo(x + width, y + height - borderRadius);
            context.quadraticCurveTo(x + width, y + height, x + width - borderRadius, y + height);
            context.lineTo(x + borderRadius, y + height);
            context.quadraticCurveTo(x, y + height, x, y + height - borderRadius);
            context.lineTo(x, y + borderRadius);
            context.quadraticCurveTo(x, y, x + borderRadius, y);
            context.closePath();
            context.fill();
        }
    }

    // draw me a check mark
    function generateSuccess(bgColor, fgColor){
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;

        canvas.width = canvas.width;
        context.beginPath();
        context.arc(centerX, centerY, 8, 0, 2 * Math.PI, false);
        context.fillStyle = bgColor || '#53C516';
        context.fill();

        context.beginPath();
        context.lineWidth = 2;
        context.strokeStyle = fgColor || '#FFFFFF';
        context.moveTo(4, 9);
        context.lineTo(8, 12);
        context.lineTo(12, 4);
        context.stroke();

    }

    // how about the red cross of death?
    function generateFailure(bgColor, fgColor){
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;

      context.beginPath();
      context.arc(centerX, centerY, 8, 0, 2 * Math.PI, false);
      context.fillStyle = bgColor || '#F6491F';
      context.fill();

      context.beginPath();
      context.lineWidth = 2;
      context.strokeStyle = fgColor || '#FFFFFF';
      context.moveTo(5, 4);
      context.lineTo(11, 12);
      context.moveTo(11, 4);
      context.lineTo(5, 12);
      context.stroke();

    }

    // refresh the tab favicon
    function refreshFavIcon(){
        head.removeChild(icon);
        icon.setAttribute('href', canvas.toDataURL("image/x-icon"));
        head.appendChild(icon);
        if(updateTitle){
            document.title = titleRenderer.call(this, animValue || value, oldTitle);
        }
    }

    // either we already have a favicon and we want to keep it for resets...
    // or we create one that we call bob and that we care for
    function getIconRef(){
        head = document.getElementsByTagName('head')[0];
        var els = document.getElementsByTagName('link');
        if(els.length > 0){
            for(var i=0; i<els.length; i++){
                if(els[i].getAttribute('rel').split(' ').indexOf('icon') > -1){
                    originalIcon = els[i].cloneNode(true); // keep the original for reset()
                    return els[i];
                }
            }
        }
        // no favicon found. create one.
        var newIcon = document.createElement('link');
        newIcon.setAttribute('rel', 'shortcut icon');
        newIcon.setAttribute('type', 'image/png');
        head.appendChild(newIcon);
        return newIcon;
    }

    // starting point to the app... couldn't hide it in the code better
    function init(){
        if(canvas && canvas.getContext){
            icon = getIconRef();
            oldTitle = document.title;
            canvas.height = canvas.width = 16;
            context = canvas.getContext('2d');
        } else {
            throw 'No support for Canvas, no chocolate for you! =(';
        }
    }

    // animation: called again and again until we get to the right value
    function incValue(inc){
        animValue += inc;
        if(isReset !== true){
            generateBitmap(animValue);
            refreshFavIcon();
            if(animValue !== null && animated){
                if(animValue === value){
                    stopAnim();
                } else {
                    setTimeout(function(){
                        incValue(animValue > value ? -1 : 1);
                    }, animInterval);
                }
            }
        }
    }

    // this, as the method name suggests, is called once the anim has stopped.
    function stopAnim(){
        if(animCallback){
            animCallback.call(this, value);
            animCallback = null;
        }
    }

    // let's get things started.
    setDefaults();
    init();

    // we get to the public methods now.
    return {
        // a helper to configure mucho settings at once
        config: function(cfg){
            shape = cfg.shape || shape;
            isReset = false;
            animated = cfg.animated || animated;
            animationSpeed = cfg.animationSpeed || animationSpeed;
            borderColor = cfg.borderColor || borderColor;
            borderColor2 = cfg.borderColor2 || borderColor2;
            borderWidth = cfg.borderWidth || borderWidth;
            shadowColor = cfg.shadowColor || shadowColor;
            fillColor = cfg.fillColor || fillColor;
            fillColor2 = cfg.fillColor2 || fillColor2;
            updateTitle = cfg.updateTitle || updateTitle;
            titleRenderer = cfg.titleRenderer || titleRenderer;
            animCallback = cfg.callback !== undefined ? cfg.callback : animCallback;
            generateBitmap();
            refreshFavIcon();
            return FavIconX;
        },

        // setValue(value, [animated], [speed], [callback])
        // value must be between 0 and 100
        // when specified the animated overrides the component setting.
        // when specified the speed orrides the component setting
        // callback called once the animation is finished
        setValue: function(v, isAnimated, animSpeed, callback){
            if(v<0 || v>100) throw 'value must be between 0 and 100';
            animCallback = callback !== undefined ? callback : animCallback;
            animValue = value;
            value = v;
            isReset = false;
            if(isAnimated !== undefined ? isAnimated : animated){
                var steps = animValue - value;
                if(animValue !== value){
                    animInterval = Math.abs(Math.ceil((animSpeed !== undefined ? animSpeed : animationSpeed) / steps));
                    incValue(animValue > value ? -1 : 1);
                }
            } else {
                animValue = null;
                generateBitmap();
                refreshFavIcon();
                if(animCallback){
                    animCallback.call(this, v);
                }
            }
            return FavIconX;
        },

        // returns the current value of the widget
        getValue: function(){
            return animValue || value;
        },

        // restoring the past... or is it...
        reset: function(){
            setDefaults();
            if(originalIcon){
                head.removeChild(icon);
                icon = originalIcon.cloneNode(true);
                head.appendChild(icon);
            }
            if(updateTitle){
                document.title = oldTitle;
            }
            return FavIconX;
        },

        // displays the awesome checkbox. colors can be tweaked here
        complete: function(fgColor, bgColor){
            isReset = false;
            generateSuccess(fgColor, bgColor);
            refreshFavIcon();
            document.title = oldTitle;
        },

        // displays the even more awesome cross. colors can be tweaked here
        fail: function(fgColor, bgColor){
            isReset = false;
            generateFailure(fgColor, bgColor);
            refreshFavIcon();
            document.title = oldTitle;
        }
    };
})();
<commit_msg>modified faviconx-library for displaying overlay-icons (play,pause)<commit_after>/**
 * A tiny javascript library that makes progress bars out of the favicon placeholders
 * Check nicolasbize.github.io/faviconx/ for latest updates.
 *
 * Author:       Nicolas Bize
 * Created:      Oct 10th 2013
 * Last Updated: Oct 16th 2014
 * Version:      1.0.1
 * Licence:      FavIconX is licenced under MIT licence (http://opensource.org/licenses/MIT)
 */
var FavIconX = (function() {
    // my private parts, do not mess with them.
    var originalIcon;
    var value = 0;
    var animValue = 0;
    var canvas = document.createElement('canvas');
    var context;
    var icon; // image storage
    var animInterval = null;
    var animCallback = null;
    var oldTitle = "";
    var head = null;
    var isReset = null;

    // default values for properties accessed through .config() method:
    var shape;
    var doughnutDiameter;
    var overlay;
    var overlayColor;
    var animated;
    var animationSpeed; // ms to go from one value to the one from setValue
    var borderColor;
    var borderColor2;
    var shadowColor;
    var borderWidth;
    var fillColor;
    var fillColor2;
    var updateTitle;
    var titleRenderer;

    function setDefaults(){
        shape = 'circle';
        doughnutDiameter = 6;
        overlay = false;
        overlayColor = '#000';
        animated = false;
        animationSpeed = 2000;
        animCallback = null;
        borderColor = '#3A70B1';
        borderColor2 = null;
        shadowColor = 'rgba(255, 0, 0, 0)';
        borderWidth = 1;
        fillColor = '#3A70B1';
        fillColor2 = null;
        updateTitle = true;
        value = 0;
        isReset = true;
        titleRenderer = function(val, title){
            return '[' + val + '%] - ' + title;
        };
    }

    // Generates the wanted shape
    function generateBitmap(v){
        if(shape === 'circle'){
            generateCircle(v);
        } else if(shape === 'doughnut'){
            generateDoughnut(v);
        } else if(shape === 'square'){
            generateSquare(v);
        }
    }

    // Generates the overlay shape
    // TODO: support overlay functionality for square-shape
    function generateOverlay(ctx, w, h){
        ctx.strokeStyle = overlayColor;
        ctx.fillStyle = overlayColor;
        if(overlay === 'play'){
            ctx.beginPath();
            ctx.moveTo(w*0.38, h*0.3);
            ctx.lineTo(w*0.38, h*0.7);
            ctx.lineTo(w*0.75, h*0.5);
            ctx.lineTo(w*0.38, h*0.3);
            ctx.closePath();
            ctx.fill();
        } else if(overlay === 'pause'){
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(w*0.38,h*0.3);
            ctx.lineTo(w*0.38,h*0.7);
            ctx.closePath();
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(w*0.62,h*0.3);
            ctx.lineTo(w*0.62,h*0.7);
            ctx.closePath();
            ctx.stroke();
        }
    }

    // (255, 0, 0) => "#FF0000"
    function rgbToHex(r, g, b) {
        return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
    }

    // "#FF0000" => [255, 0, 0]
    function hexToRgb(hex) {
        hex = hex.indexOf("#") === 0 ? hex.substring(1) : hex;
        var nb = parseInt(hex, 16);
        var r = (nb >> 16) & 255;
        var g = (nb >> 8) & 255;
        var b = nb & 255;
        return [r,g,b];
    }

    // because i don't speak in radians
    function toRad(deg){
        return deg * Math.PI / 180;
    }

    // gets a mid color according to current value
    // col1 = 0%, col2 = 100%
    function getMidColor(col1, col2){
        var rgb1 = hexToRgb(col1);
        var rgb2 = hexToRgb(col2);
        var avg = [0, 0, 0];
        var inv_v = (100 - (animValue || value)) / 100;
        for(var i=0; i<3; i++){
            avg[i] = rgb1[i] * inv_v + rgb2[i] * (1-inv_v);
        }
        return rgbToHex(Math.round(avg[0]), Math.round(avg[1]), Math.round(avg[2]));
    }

    // let's get a boring circle first
    function generateCircle(v){
        var graphValue = v || value;
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var radius = 7 - borderWidth / 2;
        var deg = graphValue * 3.6 - 90;

        canvas.width = canvas.width;
        context.lineWidth = borderWidth;
        context.strokeStyle = borderColor2 ? getMidColor(borderColor, borderColor2) : borderColor;
        context.beginPath();
        context.arc(centerX, centerY, radius, 0, toRad(360), false);
        context.closePath();
        context.fillStyle = shadowColor;
        context.fill();
        context.stroke();
        if(graphValue > 0){
            context.fillStyle = fillColor2 ? getMidColor(fillColor, fillColor2) : fillColor;
            context.beginPath();
            context.moveTo(8,8);
            context.arc(centerX, centerY, radius, toRad(-90), toRad(deg), false);
            context.closePath();
            context.fill();
        }
        generateOverlay(context, canvas.width, canvas.height);
    }

    // spelling doughnut just feels wrong
    function generateDoughnut(v){
        var graphValue = v || value;
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var deg = graphValue * 3.6 - 90;

        canvas.width = canvas.width;
        if(graphValue > 0){
            context.lineWidth = borderWidth;
            context.strokeStyle = shadowColor;
            context.beginPath();
            context.arc(centerX, centerY, doughnutDiameter, 0, toRad(360), false);
            context.arc(centerX, centerY, doughnutDiameter - borderWidth, 0, toRad(360), true);
            context.closePath();
            context.stroke();

            context.strokeStyle = fillColor2 ? getMidColor(fillColor, fillColor2) : fillColor;
            context.beginPath();
            context.arc(centerX, centerY, doughnutDiameter, toRad(-90), toRad(deg), false);
            context.arc(centerX, centerY, doughnutDiameter - borderWidth, toRad(deg), toRad(-90), true);
            context.closePath();
            context.stroke();
        }
        generateOverlay(context, canvas.width, canvas.height);
    }

    // something a bit more fancy
    function generateSquare(v){
        var graphValue = v || value;
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var borderRadius = 2;
        var x = 1;
        var y = 1;
        var width = 14;
        var height = 14;
        var deg = graphValue * 3.6 - 90;

        canvas.width = canvas.width;
        context.beginPath();
        context.strokeStyle = borderColor2 ? getMidColor(borderColor, borderColor2) : borderColor;
        context.lineWidth = borderWidth;
        context.fillStyle = shadowColor;
        context.moveTo(x + borderRadius, y);
        context.lineTo(x + width - borderRadius, y);
        context.quadraticCurveTo(x + width, y, x + width, y + borderRadius);
        context.lineTo(x + width, y + height - borderRadius);
        context.quadraticCurveTo(x + width, y + height, x + width - borderRadius, y + height);
        context.lineTo(x + borderRadius, y + height);
        context.quadraticCurveTo(x, y + height, x, y + height - borderRadius);
        context.lineTo(x, y + borderRadius);
        context.quadraticCurveTo(x, y, x + borderRadius, y);
        context.closePath();
        context.stroke();
        if(graphValue > 0){
            context.clip();
            context.beginPath();
            context.moveTo(8,8);
            context.fillStyle = 'rgba(255, 0, 0, 0)';
            context.arc(centerX, centerY, 12, toRad(-90), toRad(deg), false); // we clip the rest
            context.closePath();
            context.fill();
            context.clip();
            context.beginPath();
            context.fillStyle = fillColor2 ? getMidColor(fillColor, fillColor2) : fillColor;
            context.moveTo(x + borderRadius, y);
            context.lineTo(x + width - borderRadius, y);
            context.quadraticCurveTo(x + width, y, x + width, y + borderRadius);
            context.lineTo(x + width, y + height - borderRadius);
            context.quadraticCurveTo(x + width, y + height, x + width - borderRadius, y + height);
            context.lineTo(x + borderRadius, y + height);
            context.quadraticCurveTo(x, y + height, x, y + height - borderRadius);
            context.lineTo(x, y + borderRadius);
            context.quadraticCurveTo(x, y, x + borderRadius, y);
            context.closePath();
            context.fill();
        }
        generateOverlay(context, canvas.width, canvas.height);
    }

    // draw me a check mark
    function generateSuccess(bgColor, fgColor){
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;

        canvas.width = canvas.width;
        context.beginPath();
        context.arc(centerX, centerY, 8, 0, 2 * Math.PI, false);
        context.fillStyle = bgColor || '#53C516';
        context.fill();

        context.beginPath();
        context.lineWidth = 2;
        context.strokeStyle = fgColor || '#FFFFFF';
        context.moveTo(4, 9);
        context.lineTo(8, 12);
        context.lineTo(12, 4);
        context.stroke();

    }

    // how about the red cross of death?
    function generateFailure(bgColor, fgColor){
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;

      context.beginPath();
      context.arc(centerX, centerY, 8, 0, 2 * Math.PI, false);
      context.fillStyle = bgColor || '#F6491F';
      context.fill();

      context.beginPath();
      context.lineWidth = 2;
      context.strokeStyle = fgColor || '#FFFFFF';
      context.moveTo(5, 4);
      context.lineTo(11, 12);
      context.moveTo(11, 4);
      context.lineTo(5, 12);
      context.stroke();

    }

    // refresh the tab favicon
    function refreshFavIcon(){
        head.removeChild(icon);
        icon.setAttribute('href', canvas.toDataURL("image/x-icon"));
        head.appendChild(icon);
        if(updateTitle){
            document.title = titleRenderer.call(this, animValue || value, oldTitle);
        }
    }

    // either we already have a favicon and we want to keep it for resets...
    // or we create one that we call bob and that we care for
    function getIconRef(){
        head = document.getElementsByTagName('head')[0];
        var els = document.getElementsByTagName('link');
        if(els.length > 0){
            for(var i=0; i<els.length; i++){
                if(els[i].getAttribute('rel').split(' ').indexOf('icon') > -1){
                    originalIcon = els[i].cloneNode(true); // keep the original for reset()
                    return els[i];
                }
            }
        }
        // no favicon found. create one.
        var newIcon = document.createElement('link');
        newIcon.setAttribute('rel', 'shortcut icon');
        newIcon.setAttribute('type', 'image/png');
        head.appendChild(newIcon);
        return newIcon;
    }

    // starting point to the app... couldn't hide it in the code better
    function init(){
        if(canvas && canvas.getContext){
            icon = getIconRef();
            oldTitle = document.title;
            canvas.height = canvas.width = 16;
            context = canvas.getContext('2d');
        } else {
            throw 'No support for Canvas, no chocolate for you! =(';
        }
    }

    // animation: called again and again until we get to the right value
    function incValue(inc){
        animValue += inc;
        if(isReset !== true){
            generateBitmap(animValue);
            refreshFavIcon();
            if(animValue !== null && animated){
                if(animValue === value){
                    stopAnim();
                } else {
                    setTimeout(function(){
                        incValue(animValue > value ? -1 : 1);
                    }, animInterval);
                }
            }
        }
    }

    // this, as the method name suggests, is called once the anim has stopped.
    function stopAnim(){
        if(animCallback){
            animCallback.call(this, value);
            animCallback = null;
        }
    }

    // let's get things started.
    setDefaults();
    init();

    // we get to the public methods now.
    return {
        // a helper to configure mucho settings at once
        config: function(cfg){
            shape = cfg.shape || shape;
            doughnutDiameter = cfg.doughnutDiameter || doughnutDiameter;
            overlay = cfg.overlay || overlay;
            overlayColor = cfg.overlayColor || overlayColor;
            isReset = false;
            animated = cfg.animated || animated;
            animationSpeed = cfg.animationSpeed || animationSpeed;
            borderColor = cfg.borderColor || borderColor;
            borderColor2 = cfg.borderColor2 || borderColor2;
            borderWidth = cfg.borderWidth || borderWidth;
            shadowColor = cfg.shadowColor || shadowColor;
            fillColor = cfg.fillColor || fillColor;
            fillColor2 = cfg.fillColor2 || fillColor2;
            updateTitle = cfg.updateTitle || updateTitle;
            titleRenderer = cfg.titleRenderer || titleRenderer;
            animCallback = cfg.callback !== undefined ? cfg.callback : animCallback;
            generateBitmap();
            refreshFavIcon();
            return FavIconX;
        },

        // setValue(value, [animated], [speed], [callback])
        // value must be between 0 and 100
        // when specified the animated overrides the component setting.
        // when specified the speed orrides the component setting
        // callback called once the animation is finished
        setValue: function(v, isAnimated, animSpeed, callback){
            if(v<0 || v>100) throw 'value must be between 0 and 100';
            animCallback = callback !== undefined ? callback : animCallback;
            animValue = value;
            value = v;
            isReset = false;
            if(isAnimated !== undefined ? isAnimated : animated){
                var steps = animValue - value;
                if(animValue !== value){
                    animInterval = Math.abs(Math.ceil((animSpeed !== undefined ? animSpeed : animationSpeed) / steps));
                    incValue(animValue > value ? -1 : 1);
                }
            } else {
                animValue = null;
                generateBitmap();
                refreshFavIcon();
                if(animCallback){
                    animCallback.call(this, v);
                }
            }
            return FavIconX;
        },

        // returns the current value of the widget
        getValue: function(){
            return animValue || value;
        },

        // restoring the past... or is it...
        reset: function(){
            setDefaults();
            if(originalIcon){
                head.removeChild(icon);
                icon = originalIcon.cloneNode(true);
                head.appendChild(icon);
            }
            if(updateTitle){
                document.title = oldTitle;
            }
            return FavIconX;
        },

        // displays the awesome checkbox. colors can be tweaked here
        complete: function(fgColor, bgColor){
            isReset = false;
            generateSuccess(fgColor, bgColor);
            refreshFavIcon();
            document.title = oldTitle;
        },

        // displays the even more awesome cross. colors can be tweaked here
        fail: function(fgColor, bgColor){
            isReset = false;
            generateFailure(fgColor, bgColor);
            refreshFavIcon();
            document.title = oldTitle;
        }
    };
})();
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2020
 */

import { TEMPERATURE_SYNC_ACTIONS } from '../actions/TemperatureSyncActions';
import { REHYDRATE } from '../utilities';

export const TEMPERATURE_SYNC_STATES = {
  SCANNING: 'SCANNING',
  SCAN_ERROR: 'SCAN_ERROR',
  DOWNLOADING_LOGS: 'DOWNLOADING_LOGS',
  DOWNLOADING_LOGS_ERROR: 'DOWNLOADING_LOGS_ERROR',
  RESETTING_ADVERTISEMENT_FREQUENCY: 'RESETTING_ADVERTISEMENT_FREQUENCY',
  RESETTING_LOG_FREQUENCY: 'RESETTING_LOG_FREQUENCY',
  ERROR_RESETTING_ADVERTISEMENT_FREQUENCY: 'ERROR_RESETTING_ADVERTISEMENT_FREQUENCY',
  ERROR_RESETTING_LOG_FREQUENCY: 'ERROR_RESETTING_LOG_FREQUENCY',
  SAVING_LOGS: 'SAVING_LOGS',
  NO_SENSORS: 'NO_SENSORS',
  SYNCING: 'SYNCING',
};

const initialState = () => ({
  progress: 0,
  total: 0,
  syncState: null,
  isSyncing: false,
  modalIsOpen: false,
  lastTemperatureSync: null,
  lastSyncError: null,
  currentSensorName: null,
});

export const TemperatureSyncReducer = (state = initialState(), action) => {
  const { type } = action;

  switch (type) {
    case REHYDRATE: {
      const { payload: previousState } = action;
      const { temperatureSync: previousTemperatureSyncState } = previousState;
      const { lastTemperatureSync } = previousTemperatureSyncState;

      return { ...initialState(), lastTemperatureSync };
    }

    case TEMPERATURE_SYNC_ACTIONS.UPDATE_SENSOR_PROGRESS: {
      const { payload } = action;
      const { sensor } = payload;
      const { name: currentSensorName } = sensor;

      return { ...state, currentSensorName };
    }

    case TEMPERATURE_SYNC_ACTIONS.OPEN_MODAL: {
      return { ...state, modalIsOpen: true };
    }
    case TEMPERATURE_SYNC_ACTIONS.CLOSE_MODAL: {
      return { ...state, modalIsOpen: false };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_SCAN: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.SCANNING, isSyncing: true };
    }
    case TEMPERATURE_SYNC_ACTIONS.SCAN_COMPLETE: {
      return { ...state, syncState: null, isSyncing: false };
    }
    case TEMPERATURE_SYNC_ACTIONS.SCAN_ERROR: {
      return {
        ...state,
        syncState: '',
        syncError: TEMPERATURE_SYNC_STATES.SCAN_ERROR,
        isSyncing: false,
      };
    }
    case TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_START: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.DOWNLOADING_LOGS, progress: 1 };
    }
    case TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_ERROR: {
      return {
        ...state,
        syncState: '',
        isSyncing: false,
        syncError: TEMPERATURE_SYNC_STATES.DOWNLOADING_LOGS_ERROR,
      };
    }
    case TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_COMPLETE: {
      return { ...state, syncState: null };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_RESETTING_LOG_FREQUENCY: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.RESETTING_LOG_FREQUENCY, progress: 2 };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_LOG_FREQUENCY: {
      return { ...state, syncState: null };
    }
    case TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_LOG_FREQUENCY: {
      return {
        ...state,
        syncState: TEMPERATURE_SYNC_STATES.ERROR_RESETTING_LOG_FREQUENCY,
        isSyncing: false,
      };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_RESETTING_ADVERTISEMENT_FREQUENCY: {
      return {
        ...state,
        syncState: TEMPERATURE_SYNC_STATES.RESETTING_ADVERTISEMENT_FREQUENCY,
        progress: 3,
      };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_ADVERTISEMENT_FREQUENCY: {
      return { ...state, syncState: null };
    }
    case TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_ADVERTISEMENT_FREQUENCY: {
      return { ...state, syncError: TEMPERATURE_SYNC_STATES.ERROR_RESETTING_LOG_FREQUENCY };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_SAVING_TEMPERATURE_LOGS: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.SAVING_LOGS, progress: 4 };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_SAVING_TEMPERATURE_LOGS: {
      return { ...state, syncState: null };
    }

    case TEMPERATURE_SYNC_ACTIONS.ERROR_NO_SENSORS: {
      return {
        ...state,
        syncError: TEMPERATURE_SYNC_STATES.NO_SENSORS,
        syncState: null,
        isSyncing: false,
      };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_SYNC: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.SYNCING, isSyncing: true, total: 5 };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_SYNC: {
      const { syncError, lastTemperatureSync } = state;
      return {
        ...state,
        syncState: null,
        isSyncing: false,
        lastTemperatureSync: syncError ? lastTemperatureSync : new Date(),
        progress: 5,
        currentSensorName: null,
      };
    }
    default:
      return state;
  }
};
<commit_msg>Add update temperatureSyncReducer persistance bug<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2020
 */

import { TEMPERATURE_SYNC_ACTIONS } from '../actions/TemperatureSyncActions';
import { REHYDRATE } from '../utilities';

export const TEMPERATURE_SYNC_STATES = {
  SCANNING: 'SCANNING',
  SCAN_ERROR: 'SCAN_ERROR',
  DOWNLOADING_LOGS: 'DOWNLOADING_LOGS',
  DOWNLOADING_LOGS_ERROR: 'DOWNLOADING_LOGS_ERROR',
  RESETTING_ADVERTISEMENT_FREQUENCY: 'RESETTING_ADVERTISEMENT_FREQUENCY',
  RESETTING_LOG_FREQUENCY: 'RESETTING_LOG_FREQUENCY',
  ERROR_RESETTING_ADVERTISEMENT_FREQUENCY: 'ERROR_RESETTING_ADVERTISEMENT_FREQUENCY',
  ERROR_RESETTING_LOG_FREQUENCY: 'ERROR_RESETTING_LOG_FREQUENCY',
  SAVING_LOGS: 'SAVING_LOGS',
  NO_SENSORS: 'NO_SENSORS',
  SYNCING: 'SYNCING',
};

const initialState = () => ({
  progress: 0,
  total: 0,
  syncState: null,
  isSyncing: false,
  modalIsOpen: false,
  lastTemperatureSync: null,
  lastSyncError: null,
  currentSensorName: null,
});

export const TemperatureSyncReducer = (state = initialState(), action) => {
  const { type } = action;

  switch (type) {
    case REHYDRATE: {
      const { payload: previousState } = action;
      const { temperatureSync: previousTemperatureSyncState } = previousState ?? {};
      const { lastTemperatureSync = null } = previousTemperatureSyncState ?? {};

      return { ...initialState(), lastTemperatureSync };
    }

    case TEMPERATURE_SYNC_ACTIONS.UPDATE_SENSOR_PROGRESS: {
      const { payload } = action;
      const { sensor } = payload;
      const { name: currentSensorName } = sensor;

      return { ...state, currentSensorName };
    }

    case TEMPERATURE_SYNC_ACTIONS.OPEN_MODAL: {
      return { ...state, modalIsOpen: true };
    }
    case TEMPERATURE_SYNC_ACTIONS.CLOSE_MODAL: {
      return { ...state, modalIsOpen: false };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_SCAN: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.SCANNING, isSyncing: true };
    }
    case TEMPERATURE_SYNC_ACTIONS.SCAN_COMPLETE: {
      return { ...state, syncState: null, isSyncing: false };
    }
    case TEMPERATURE_SYNC_ACTIONS.SCAN_ERROR: {
      return {
        ...state,
        syncState: '',
        syncError: TEMPERATURE_SYNC_STATES.SCAN_ERROR,
        isSyncing: false,
      };
    }
    case TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_START: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.DOWNLOADING_LOGS, progress: 1 };
    }
    case TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_ERROR: {
      return {
        ...state,
        syncState: '',
        isSyncing: false,
        syncError: TEMPERATURE_SYNC_STATES.DOWNLOADING_LOGS_ERROR,
      };
    }
    case TEMPERATURE_SYNC_ACTIONS.DOWNLOAD_LOGS_COMPLETE: {
      return { ...state, syncState: null };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_RESETTING_LOG_FREQUENCY: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.RESETTING_LOG_FREQUENCY, progress: 2 };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_LOG_FREQUENCY: {
      return { ...state, syncState: null };
    }
    case TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_LOG_FREQUENCY: {
      return {
        ...state,
        syncState: TEMPERATURE_SYNC_STATES.ERROR_RESETTING_LOG_FREQUENCY,
        isSyncing: false,
      };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_RESETTING_ADVERTISEMENT_FREQUENCY: {
      return {
        ...state,
        syncState: TEMPERATURE_SYNC_STATES.RESETTING_ADVERTISEMENT_FREQUENCY,
        progress: 3,
      };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_RESETTING_ADVERTISEMENT_FREQUENCY: {
      return { ...state, syncState: null };
    }
    case TEMPERATURE_SYNC_ACTIONS.ERROR_RESETTING_ADVERTISEMENT_FREQUENCY: {
      return { ...state, syncError: TEMPERATURE_SYNC_STATES.ERROR_RESETTING_LOG_FREQUENCY };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_SAVING_TEMPERATURE_LOGS: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.SAVING_LOGS, progress: 4 };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_SAVING_TEMPERATURE_LOGS: {
      return { ...state, syncState: null };
    }

    case TEMPERATURE_SYNC_ACTIONS.ERROR_NO_SENSORS: {
      return {
        ...state,
        syncError: TEMPERATURE_SYNC_STATES.NO_SENSORS,
        syncState: null,
        isSyncing: false,
      };
    }

    case TEMPERATURE_SYNC_ACTIONS.START_SYNC: {
      return { ...state, syncState: TEMPERATURE_SYNC_STATES.SYNCING, isSyncing: true, total: 5 };
    }
    case TEMPERATURE_SYNC_ACTIONS.COMPLETE_SYNC: {
      const { syncError, lastTemperatureSync } = state;
      return {
        ...state,
        syncState: null,
        isSyncing: false,
        lastTemperatureSync: syncError ? lastTemperatureSync : new Date(),
        progress: 5,
        currentSensorName: null,
      };
    }
    default:
      return state;
  }
};
<|endoftext|>


<commit_before>const hideAxis = {
    xAxis: [
        {
            show: false,
            splitLine: {
                show: false
            },
            splitArea: {
                show: false
            }
        }
    ],
    yAxis: [
        {
            show: false,
            splitLine: {
                show: false
            },
            splitArea: {
                show: false
            }
        }
    ]
};

const showAxis = {
    xAxis: [
        {
            type: 'category',
            show: true,
            boundaryGap: false,
            data: ['abc', 'def', 'ghi', 'jk', 'lm', 'no', 'pq'],
            splitLine: {
                show: false
            },
            splitArea: {
                show: false
            },
            axisTick: {
                interval: 0
            }
        }
    ],
    yAxis: [
        {
            type: 'value',
            show: true,
            splitLine: {
                show: true
            },
            splitArea: {
                show: true
            },
            scale: false
        }
    ]
};

export const chartTypes = {
    line: {
        name: 'Líneas',
        value: 'line',
        config: {
            ...showAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'line'
                }
            },
            area: {
                name: 'Área',
                value: 'area',
                config: {},
                seriesConfig: {
                    type: 'line',
                    smooth: true,
                    itemStyle: { normal: { areaStyle: { type: 'default' } } }
                }
            }
        },
        controls: {
            subtype: true,
            columnPanel: {
                xAxis: true,
                yAxis: true,
                data: false,
                tree: true
            },
            dataPanel: {
                range: true,
                invert: true,
                transpose: true
            }
        }
    },
    bar: {
        name: 'Barras',
        value: 'bar',
        config: {
            ...showAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            waterfall: {
                name: 'Cascada',
                value: 'waterfall',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            stackedBars: {
                name: 'Barras apiladas',
                value: 'stackedBars',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            splitBars: {
                name: 'Barras divididas',
                value: 'splitBars',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            crossedBars: {
                name: 'Barras cruzadas',
                value: 'crossedBars',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            }
        },
        controls: {
            subtype: true,
            columnPanel: {
                xAxis: true,
                yAxis: true,
                data: false,
                tree: true
            },
            dataPanel: {
                range: true,
                invert: true,
                transpose: true
            }
        }
    },
    pie: {
        name: 'Torta',
        value: 'pie',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'pie',
                    legendHoverLink: false
                }
            },
            doughnut: {
                name: 'Dona',
                value: 'doughnut',
                config: {},
                seriesConfig: {
                    type: 'pie',
                    legendHoverLink: false,
                    radius: ['25%', '75%']
                }
            },
            compound: {
                name: 'Compuesto',
                value: 'compound',
                config: {},
                seriesConfig: {
                    type: 'pie',
                    legendHoverLink: false
                }
            }
        },
        controls: {
            subtype: true,
            columnPanel: {
                xAxis: false,
                yAxis: true,
                data: true,
                tree: false
            },
            dataPanel: {
                range: false,
                invert: true,
                transpose: false
            }
        }
    },
    scatter: {
        name: 'Dispersión',
        value: 'scatter',
        config: {
            ...showAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'scatter'
                }
            },
            bubbles: {
                name: 'Burbujas',
                value: 'bubbles',
                config: {},
                seriesConfig: {
                    type: 'scatter'
                }
            },
            largeScale: {
                name: 'Gran escala',
                value: 'largeScale',
                config: {},
                seriesConfig: {
                    type: 'scatter'
                }
            }
        }
    },
    radar: {
        name: 'Radar',
        value: 'radar',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {

                },
                seriesConfig: {
                    type: 'radar',
                    polarIndex: 1
                }
            },
            filled: {
                name: 'Relleno',
                value: 'filled',
                config: {

                },
                seriesConfig: {
                    type: 'radar'
                }
            }
        }
    },
    chord: {
        name: 'Cuerdas',
        value: 'chord',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {

                },
                seriesConfig: {
                    type: 'chord'
                }
            },
            alternative: {
                name: 'Alternativo',
                value: 'alternative',
                config: {

                },
                seriesConfig: {
                    type: 'chord'
                }
            }
        }
    },
    force: {
        name: 'Grafos',
        value: 'force',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {

                },
                seriesConfig: {
                    type: 'force'
                }
            },
            tree: {
                name: 'Árbol',
                value: 'tree',
                config: {

                },
                seriesConfig: {
                    type: 'force'
                }
            }
        }
    },
    mixed: {
        name: 'Combinados',
        value: 'combined',
        config: {
            ...showAxis
        },
        subtypes: {
            linePlusBars: {
                name: 'Líneas + barras',
                value: 'linePlusBars',
                config: {

                },
                seriesConfig: {
                    type: 'line'
                }
            },
            linePlusScatter: {
                name: 'Líneas + dispersión',
                value: 'linePlusScatter',
                config: {

                },
                seriesConfig: {
                    type: 'line'
                }
            }
        }
    }
};

export const chartSubtype = {
    line: 'basic',
    bar: 'basic',
    pie: 'basic',
    scatter: 'basic',
    radar: 'basic',
    chord: 'basic',
    force: 'basic',
    mixed: 'basic'
};<commit_msg>Cleanup<commit_after>const hideAxis = {
    xAxis: [
        {
            show: false,
            splitLine: {
                show: false
            },
            splitArea: {
                show: false
            }
        }
    ],
    yAxis: [
        {
            show: false,
            splitLine: {
                show: false
            },
            splitArea: {
                show: false
            }
        }
    ]
};

const showAxis = {
    xAxis: [
        {
            type: 'category',
            show: true,
            boundaryGap: false,
            data: ['abc', 'def', 'ghi', 'jk', 'lm', 'no', 'pq'],
            splitLine: {
                show: false
            },
            splitArea: {
                show: false
            },
            axisTick: {
                interval: 0
            }
        }
    ],
    yAxis: [
        {
            type: 'value',
            show: true,
            splitLine: {
                show: true
            },
            splitArea: {
                show: true
            },
            scale: false
        }
    ]
};

export const chartTypes = {
    line: {
        name: 'Líneas',
        value: 'line',
        config: {
            ...showAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'line'
                }
            },
            area: {
                name: 'Área',
                value: 'area',
                config: {},
                seriesConfig: {
                    type: 'line',
                    smooth: true,
                    itemStyle: { normal: { areaStyle: { type: 'default' } } }
                }
            }
        },
        controls: {
            subtype: true,
            columnPanel: {
                xAxis: true,
                yAxis: true,
                data: false,
                tree: true
            },
            dataPanel: {
                range: true,
                invert: true,
                transpose: true
            }
        }
    },
    bar: {
        name: 'Barras',
        value: 'bar',
        config: {
            ...showAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            waterfall: {
                name: 'Cascada',
                value: 'waterfall',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            stackedBars: {
                name: 'Barras apiladas',
                value: 'stackedBars',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            splitBars: {
                name: 'Barras divididas',
                value: 'splitBars',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            },
            crossedBars: {
                name: 'Barras cruzadas',
                value: 'crossedBars',
                config: {},
                seriesConfig: {
                    type: 'bar'
                }
            }
        },
        controls: {
            subtype: true,
            columnPanel: {
                xAxis: true,
                yAxis: true,
                data: false,
                tree: true
            },
            dataPanel: {
                range: true,
                invert: true,
                transpose: true
            }
        }
    },
    pie: {
        name: 'Torta',
        value: 'pie',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'pie',
                    legendHoverLink: false
                }
            },
            doughnut: {
                name: 'Dona',
                value: 'doughnut',
                config: {},
                seriesConfig: {
                    type: 'pie',
                    legendHoverLink: false,
                    radius: ['30%', '75%']
                }
            }
        },
        controls: {
            subtype: true,
            columnPanel: {
                xAxis: false,
                yAxis: true,
                data: true,
                tree: false
            },
            dataPanel: {
                range: false,
                invert: true,
                transpose: false
            }
        }
    },
    scatter: {
        name: 'Dispersión',
        value: 'scatter',
        config: {
            ...showAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {},
                seriesConfig: {
                    type: 'scatter'
                }
            },
            bubbles: {
                name: 'Burbujas',
                value: 'bubbles',
                config: {},
                seriesConfig: {
                    type: 'scatter'
                }
            },
            largeScale: {
                name: 'Gran escala',
                value: 'largeScale',
                config: {},
                seriesConfig: {
                    type: 'scatter'
                }
            }
        }
    },
    radar: {
        name: 'Radar',
        value: 'radar',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {

                },
                seriesConfig: {
                    type: 'radar',
                    polarIndex: 1
                }
            },
            filled: {
                name: 'Relleno',
                value: 'filled',
                config: {

                },
                seriesConfig: {
                    type: 'radar'
                }
            }
        }
    },
    chord: {
        name: 'Cuerdas',
        value: 'chord',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {

                },
                seriesConfig: {
                    type: 'chord'
                }
            },
            alternative: {
                name: 'Alternativo',
                value: 'alternative',
                config: {

                },
                seriesConfig: {
                    type: 'chord'
                }
            }
        }
    },
    force: {
        name: 'Grafos',
        value: 'force',
        config: {
            ...hideAxis
        },
        subtypes: {
            basic: {
                name: 'Básico',
                value: 'basic',
                config: {

                },
                seriesConfig: {
                    type: 'force'
                }
            },
            tree: {
                name: 'Árbol',
                value: 'tree',
                config: {

                },
                seriesConfig: {
                    type: 'force'
                }
            }
        }
    },
    mixed: {
        name: 'Combinados',
        value: 'combined',
        config: {
            ...showAxis
        },
        subtypes: {
            linePlusBars: {
                name: 'Líneas + barras',
                value: 'linePlusBars',
                config: {

                },
                seriesConfig: {
                    type: 'line'
                }
            },
            linePlusScatter: {
                name: 'Líneas + dispersión',
                value: 'linePlusScatter',
                config: {

                },
                seriesConfig: {
                    type: 'line'
                }
            }
        }
    }
};

export const chartSubtype = {
    line: 'basic',
    bar: 'basic',
    pie: 'basic',
    scatter: 'basic',
    radar: 'basic',
    chord: 'basic',
    force: 'basic',
    mixed: 'basic'
};<|endoftext|>


<commit_before>
ForceMap = function(_parentElement, _districtData){

    this.parentElement = _parentElement;
    this.districtData = _districtData;

    this.initVis();
};

ForceMap.prototype.initVis = function() {

    var vis = this;

    var height = 400;
    var width = 400;
    var padding = 40;
    var radiusEthnic = 20;

    var svg_force = d3.select("#force-layout")
        .append("svg")
        .attr({"width": width, "height": height});

    var circleEthnic = [
        {"group": "Shia", "x": (width / 2), "y": (radiusEthnic + padding)},
        {"group": "Sunni", "x": (radiusEthnic + padding), "y": (height - radiusEthnic - padding)},
        {"group": "Kurdish", "x": (width - radiusEthnic - padding), "y": (height - radiusEthnic - padding)}
    ];

    /** Create a circle for each ethnic group: */
    var nodesEthnic = svg_force.selectAll("#nodesEthnic")
        .data(circleEthnic)
        .enter()
        .append("circle")
        .attr("r", radiusEthnic)
        .attr("cx", function (d) {
            return d.x
        })
        .attr("cy", function (d) {
            return d.y
        });

    var districts = d3.keys(vis.districtData);

    /** Create a circle for each ethnic group: */
    var nodesDistricts = svg_force.selectAll("circle")
        .data(districts)
        .enter()
        .append("circle")
        // radius should be proportional to violence (not done in this first "sketch")
        .attr("r", 10)
        .attr("cx", function(d) {
            if (vis.districtData[d].Shia == 0) {
                return (width - 2*radiusEthnic - 2*padding) * vis.districtData[d].Kurdish + radiusEthnic + padding;
            }
            else if (vis.districtData[d].Kurdish == 0) {
                return (height - (height - 2*radiusEthnic - 2*padding) * vis.districtData[d].Sunni) / 2;
            }
            else {
                return ((width - 2*radiusEthnic - 2*padding) * vis.districtData[d].Kurdish) * (1 - vis.districtData[d].Shia) + radiusEthnic + padding + (width - 2*radiusEthnic - 2*padding) * vis.districtData[d].Shia;
            }
        })
        .attr("cy", function(d) {
            if (vis.districtData[d].Shia == 0) {
                return height - radiusEthnic - padding;
            }
            else if (vis.districtData[d].Kurdish == 0) {
                return (height - 2*radiusEthnic - 2*padding) * vis.districtData[d].Sunni + radiusEthnic + padding;
            }
            else {
                return (height - 2*radiusEthnic - 2*padding) * (1 - vis.districtData[d].Shia) + radiusEthnic + padding;
            }
        })
        .style("fill", "red");

};

/** Teddy's code:

var width = 500,
    height = 500;

var svg = d3.select("#force-layout").append("svg")
    .attr("width", width)
    .attr("height", height);

var force = d3.layout.force()
    .size([width,height])
    .gravity(0.1);

var data;

d3.csv("data/ethnicity_cleaned.csv",function(error, links){

    if (error) throw error;

    links.filter(function(link){
        link.sunni = +link.sunni;
        link.kurd = +link.kurd;
        link.shia = +link.shia;
        link.total = +link.total;
    });

    console.log(links);

    data = links;

    updateVisualization();
    $('#button').click();

});

function updateVisualization(){

    var district = d3.select("#button").property("value");

    var gnodes = svg.selectAll('gnode')
        .data(data)
        .enter()
        .append('g')
        .classed('gnode', true)
        .call(force.drag);

    var node = gnodes.append("circle").attr("class", "node")
        .filter(function(d){
            return d.district == district;
        })
        .attr("r",function(d){
            return d.sunni;
        })
        .attr("fill","green");

    var node1 = gnodes.append("circle").attr("class", "node1")
        .filter(function(d){
            return d.district == district;
        })
        .attr("r",function(d){
            return d.shia;
        })
        .attr("fill","blue");

    var node2 = gnodes.append("circle").attr("class", "node2")
        .filter(function(d){
            return d.district == district;
        })
        .attr("r",function(d){
            return d.kurd;
        })
        .attr("fill","red");

    var node3 = gnodes.append("circle").attr("class", "node3")
        .filter(function(d){
            return d.district == district;
        })
        .attr('opacity',0.5)
        .attr("r",function(d) {
            return (d.total);
        });

    // ASK //
    //node3.exit().remove();
    // ASK //
    node.transition()
        .duration(10000);
    node1.transition()
        .duration(10000);
    node2.transition()
        .duration(10000);
    node3.transition()
        .duration(10000);
    // ASK //
    var label = gnodes.append("text")
        .text("text");

    force
        .nodes(data)
        .on('tick', tick)
        .start();

    function tick() {
        node.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y+30});
        node1.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y+50});
        node2.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y+75});
        node3.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y});
        //label.attr("x", function(d){return d.x})
        //  .attr("y", function(d){return d.y})

    }
}

 */<commit_msg>corrected typo<commit_after>
ForceMap = function(_parentElement, _districtData){

    this.parentElement = _parentElement;
    this.districtData = _districtData;

    this.initVis();
};

ForceMap.prototype.initVis = function() {

    var vis = this;

    var height = 400;
    var width = 400;
    var padding = 40;
    var radiusEthnic = 20;

    var svg_force = d3.select("#force-layout")
        .append("svg")
        .attr({"width": width, "height": height});

    var circleEthnic = [
        {"group": "Shia", "x": (width / 2), "y": (radiusEthnic + padding)},
        {"group": "Sunni", "x": (radiusEthnic + padding), "y": (height - radiusEthnic - padding)},
        {"group": "Kurdish", "x": (width - radiusEthnic - padding), "y": (height - radiusEthnic - padding)}
    ];

    /** Create a circle for each ethnic group: */
    var nodesEthnic = svg_force.selectAll("#nodesEthnic")
        .data(circleEthnic)
        .enter()
        .append("circle")
        .attr("r", radiusEthnic)
        .attr("cx", function (d) {
            return d.x
        })
        .attr("cy", function (d) {
            return d.y
        });

    var districts = d3.keys(vis.districtData);

    /** Create a circle for each district: */
    var nodesDistricts = svg_force.selectAll("#nodesDistricts")
        .data(districts)
        .enter()
        .append("circle")
        // radius should be proportional to violence (not done in this first "sketch")
        .attr("r", 10)
        .attr("cx", function(d) {
            if (vis.districtData[d].Shia == 0) {
                return (width - 2*radiusEthnic - 2*padding) * vis.districtData[d].Kurdish + radiusEthnic + padding;
            }
            else if (vis.districtData[d].Kurdish == 0) {
                return (height - (height - 2*radiusEthnic - 2*padding) * vis.districtData[d].Sunni) / 2;
            }
            else {
                return ((width - 2*radiusEthnic - 2*padding) * vis.districtData[d].Kurdish) * (1 - vis.districtData[d].Shia) + radiusEthnic + padding + (width - 2*radiusEthnic - 2*padding) * vis.districtData[d].Shia;
            }
        })
        .attr("cy", function(d) {
            if (vis.districtData[d].Shia == 0) {
                return height - radiusEthnic - padding;
            }
            else if (vis.districtData[d].Kurdish == 0) {
                return (height - 2*radiusEthnic - 2*padding) * vis.districtData[d].Sunni + radiusEthnic + padding;
            }
            else {
                return (height - 2*radiusEthnic - 2*padding) * (1 - vis.districtData[d].Shia) + radiusEthnic + padding;
            }
        })
        .style("fill", "red");

};

/** Teddy's code:

var width = 500,
    height = 500;

var svg = d3.select("#force-layout").append("svg")
    .attr("width", width)
    .attr("height", height);

var force = d3.layout.force()
    .size([width,height])
    .gravity(0.1);

var data;

d3.csv("data/ethnicity_cleaned.csv",function(error, links){

    if (error) throw error;

    links.filter(function(link){
        link.sunni = +link.sunni;
        link.kurd = +link.kurd;
        link.shia = +link.shia;
        link.total = +link.total;
    });

    console.log(links);

    data = links;

    updateVisualization();
    $('#button').click();

});

function updateVisualization(){

    var district = d3.select("#button").property("value");

    var gnodes = svg.selectAll('gnode')
        .data(data)
        .enter()
        .append('g')
        .classed('gnode', true)
        .call(force.drag);

    var node = gnodes.append("circle").attr("class", "node")
        .filter(function(d){
            return d.district == district;
        })
        .attr("r",function(d){
            return d.sunni;
        })
        .attr("fill","green");

    var node1 = gnodes.append("circle").attr("class", "node1")
        .filter(function(d){
            return d.district == district;
        })
        .attr("r",function(d){
            return d.shia;
        })
        .attr("fill","blue");

    var node2 = gnodes.append("circle").attr("class", "node2")
        .filter(function(d){
            return d.district == district;
        })
        .attr("r",function(d){
            return d.kurd;
        })
        .attr("fill","red");

    var node3 = gnodes.append("circle").attr("class", "node3")
        .filter(function(d){
            return d.district == district;
        })
        .attr('opacity',0.5)
        .attr("r",function(d) {
            return (d.total);
        });

    // ASK //
    //node3.exit().remove();
    // ASK //
    node.transition()
        .duration(10000);
    node1.transition()
        .duration(10000);
    node2.transition()
        .duration(10000);
    node3.transition()
        .duration(10000);
    // ASK //
    var label = gnodes.append("text")
        .text("text");

    force
        .nodes(data)
        .on('tick', tick)
        .start();

    function tick() {
        node.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y+30});
        node1.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y+50});
        node2.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y+75});
        node3.attr("cx", function(d){return d.x})
            .attr("cy", function(d){return d.y});
        //label.attr("x", function(d){return d.x})
        //  .attr("y", function(d){return d.y})

    }
}

 */<|endoftext|>


<commit_before>(function($) {
  "use strict";
  /**
   * @constructor
   * Create a GitHub event object.
   * @param {String} id Event ID.
   * @param {String} url Event url.
   * @param {String} sha Event SHA value or branch name.
   * @param {String} date Event date.
   * @param {String} repo Event repo.
   * @param {String} event Event type.
   * @param {String} msg Event message.
   */
  function GHEvent(id, url, sha, date, repo, repoUrl, event, msg) {
    this.id        = id;
    this.msg       = msg;
    this.url       = url;
    this.sha       = sha;
    this.date      = date;
    this.repo      = repo;
    this.event     = event;
    this.final     = null;
    this.repoUrl   = repoUrl;
    this.selector  = "#gh-" + id;
    this.container = "

";
  }

  /**
   * @constant
   * @type {Number}
   * The number of characters the commit message should be limited to.
   * This is a hard limit and may increase cut off part of a word.
   */
  GHEvent.prototype.charLimit = 80;

  /**
   * Summarize a commit message.
   * @returns {Boolean} true.
   */
  GHEvent.prototype.summarize = function() {
    if (this.msg.length > this.charLimit) {
      this.msg = this.msg.substr(0, this.charLimit) + "...";
    }

    // Preserve any new lines
    this.msg = this.msg.replace(/\n/, "
");

    // Check for any issue/PR references and generate links
    var issueRef = this.msg.match( /(?:gh-|#)(\d+)/);
    if (issueRef) {
      var issueLink = "" + issueRef[0] + "";
      this.msg = this.msg.replace(issueRef[0], issueLink);
    }
    return true;
  };

  GHEvent.prototype.compile = function() {
    var final = ["
"];

    // Event title, date, and URL
    final.push("
", this.event);
    final.push("",
               this.sha, " @ ", this.repo, " on ", this.date, "
");

    // Post body
    this.summarize();
    final.push("
", this.msg, "
");

    // Finally, close off the container
    final.push("
");
    this.final = final.join("");

  };

  var EventUtils = {
    /**
     * Convert an API url into a web interface one.
     * @param {String} url
     * @returns {Sring}
     */
    makeURL: function(url) {
      return url.replace(/(?:api\.|repos\/)/gi, "").replace(/commits/gi, "commit");
    },

    /**
     * Capitalize the first letter of the given text.
     * @param {String} text
     * @returns {String}
     */
    capitalFirst: function(text) {
      return text.charAt(0).toUpperCase() + text.substr(1);
    },

    /**
     * Construct a proper event name.
     * @param {String}  name The event name.
     * @param {Boolean} [activeTense=false] If true, the event name
     *     will be converted to an active tense verb.
     * @returns {String} The corrected name.
     */
    makeEventName: function(name, activeTense) {
      // Default to leaving verb tense as-is
      if (activeTense === undefined) {
        activeTense = false;
      }

      // Capitalize the first letter
      name = this.capitalFirst(name);

      // Convert verb to active tense
      if (activeTense) {
        var changeTense = {
          "Closed": "Close",
          "Opened": "Open",
          "Published": "Publish"
        };

        // If a replacement is defined, use it
        if (changeTense[name] !== undefined) {
          name = changeTense[name];
        }
      }
      return name;
    }
  };

  /**
   * Create a date stamp in the format "DD Month, YYYY".
   * @param {String} rawDate GitHub timestamp.
   * @returns {String}.
   */
  function _createDate(date) {
    var months = {"01": "January", "02": "February", "03": "March", "04": "April",
                  "05": "May", "06": "June", "07": "July", "08": "August", "09": "September",
                  "10": "October", "11": "November", "12": "December"
                 };

    var dateParts  = date.split("T")[0].split("-"),
        dateFormat = [dateParts[2], dateParts[1], dateParts[0]];
    dateFormat[1]  = months[dateFormat[1]] + ",";
    return dateFormat.join(" ");
  }

  var events = [];

  /**
   * Process the fetched GitHub event feed.
   * @param {Object} data [[Description]].
   */
  function loadEvents(data) {
    for (var i = 0, limit = 7; i < limit; i += 1) {
      var curEvent  = data[i],
          id        = curEvent.id,
          url       = "#",
          sha       = "",
          repo      = curEvent.repo.name,
          date      = _createDate(curEvent.created_at).substring(0, curEvent.created_at.length - 1),
          repoUrl   = EventUtils.makeURL(curEvent.repo.url),
          message   = "No commit message available.",
          eventName = curEvent.type.replace(/event/i, "");

      // Do not report certain events
      if (/comment|fork|watch/gi.test(eventName)) {
        limit += 1;
        continue;
      }

      switch(eventName) {
          // Create event
          case "Create":
          // Filter out create tag events
          var _eventType = curEvent.payload.ref_type;
            if (/tag/.test(_eventType))  {
              continue;
            }

            sha = curEvent.payload.ref;
            message = "Create " + curEvent.payload.ref_type;

            // New branch
            if (/branch/.test(_eventType)) {
              url = EventUtils.makeURL(curEvent.repo.url) + "/tree/" + curEvent.payload.ref;
            }

            // TODO New repo
            break;

          // New release
          case "Release":
            eventName = EventUtils.makeEventName(curEvent.payload.action, true);
            sha = curEvent.payload.release.tag_name;
            url = curEvent.payload.release.html_url;
            message = "\"" + curEvent.payload.release.name + "\"";
            break;

          // Open/close issue
          case "Issues":
            eventName = EventUtils.makeEventName(curEvent.payload.action, true);
            sha = "#" + curEvent.payload.issue.number;
            url = curEvent.payload.issue.html_url;
            message = EventUtils.makeEventName(curEvent.payload.action) +
                      " \"" + curEvent.payload.issue.title + "\"";
            break;

          // Delete event
          case "Delete":
            eventName = "Delete";
            sha = curEvent.payload.ref;
            url = EventUtils.makeURL(curEvent.repo.url);
            message = "Delete " + curEvent.payload.ref_type;
            break;

          // Wiki edit
          case "Gollum":
            eventName = "Wiki Edit";
            sha = curEvent.payload.pages[0].sha.substr(0, 10);
            url = curEvent.payload.pages[0].html_url;

            message = EventUtils.capitalFirst(curEvent.payload.pages[0].action);
            message += " \"" + curEvent.payload.pages[0].title + "\"";
            break;

          // Pull request
          case "PullRequest":
            eventName = "Pull Request";
            sha = "#" + curEvent.payload.number;
            url = curEvent.payload.pull_request.html_url;
            message = EventUtils.capitalFirst(curEvent.payload.pull_request.state);
            message += " \"" + curEvent.payload.pull_request.title + "\"";
            break;

          // Push event
          default:
            url = EventUtils.makeURL(curEvent.payload.commits[0].url);
            sha = curEvent.payload.commits[0].sha.substr(0, 10);
            message = curEvent.payload.commits[0].message;
            break;
      }

      // Create a new event object
      var ghEvent = new GHEvent(id, url, sha, date, repo, repoUrl, eventName, message);
      ghEvent.compile();
      events.push(ghEvent);
    }
  }

  /**
   * Add the events to the page.
   * @returns {Boolean} Always returns true.
   */
  function displayEvents() {
    var $container = $(".gh-events");
    events.forEach(function(event) {
      $container.append(event.final);
      return true;
    });
  }

  // Poll the GitHub API
  $.ajax({
    dataType: "json",
    url: "https://api.github.com/users/le717/events/public",
    success: [loadEvents, displayEvents],
    error: function() {
      var msg = "Unfortunately that information cannot be loaded right now";
      $(".gh-events").html(msg);
      return false;
    }
  });
})(jQuery);
<commit_msg>Spacebar [ci skip]<commit_after>(function($) {
  "use strict";
  /**
   * @constructor
   * Create a GitHub event object.
   * @param {String} id Event ID.
   * @param {String} url Event url.
   * @param {String} sha Event SHA value or branch name.
   * @param {String} date Event date.
   * @param {String} repo Event repo.
   * @param {String} event Event type.
   * @param {String} msg Event message.
   */
  function GHEvent(id, url, sha, date, repo, repoUrl, event, msg) {
    this.id        = id;
    this.msg       = msg;
    this.url       = url;
    this.sha       = sha;
    this.date      = date;
    this.repo      = repo;
    this.event     = event;
    this.final     = null;
    this.repoUrl   = repoUrl;
    this.selector  = "#gh-" + id;
    this.container = "

";
  }

  /**
   * @constant
   * @type {Number}
   * The number of characters the commit message should be limited to.
   * This is a hard limit and may increase cut off part of a word.
   */
  GHEvent.prototype.charLimit = 80;

  /**
   * Summarize a commit message.
   * @returns {Boolean} true.
   */
  GHEvent.prototype.summarize = function() {
    if (this.msg.length > this.charLimit) {
      this.msg = this.msg.substr(0, this.charLimit) + "...";
    }

    // Preserve any new lines
    this.msg = this.msg.replace(/\n/, "
");

    // Check for any issue/PR references and generate links
    var issueRef = this.msg.match( /(?:gh-|#)(\d+)/);
    if (issueRef) {
      var issueLink = "" + issueRef[0] + "";
      this.msg = this.msg.replace(issueRef[0], issueLink);
    }
    return true;
  };

  GHEvent.prototype.compile = function() {
    var final = ["
"];

    // Event title, date, and URL
    final.push("
", this.event, " ");
    final.push("",
               this.sha, " @ ", this.repo, " on ", this.date, "
");

    // Post body
    this.summarize();
    final.push("
", this.msg, "
");

    // Finally, close off the container
    final.push("
");
    this.final = final.join("");

  };

  var EventUtils = {
    /**
     * Convert an API url into a web interface one.
     * @param {String} url
     * @returns {Sring}
     */
    makeURL: function(url) {
      return url.replace(/(?:api\.|repos\/)/gi, "").replace(/commits/gi, "commit");
    },

    /**
     * Capitalize the first letter of the given text.
     * @param {String} text
     * @returns {String}
     */
    capitalFirst: function(text) {
      return text.charAt(0).toUpperCase() + text.substr(1);
    },

    /**
     * Construct a proper event name.
     * @param {String}  name The event name.
     * @param {Boolean} [activeTense=false] If true, the event name
     *     will be converted to an active tense verb.
     * @returns {String} The corrected name.
     */
    makeEventName: function(name, activeTense) {
      // Default to leaving verb tense as-is
      if (activeTense === undefined) {
        activeTense = false;
      }

      // Capitalize the first letter
      name = this.capitalFirst(name);

      // Convert verb to active tense
      if (activeTense) {
        var changeTense = {
          "Closed": "Close",
          "Opened": "Open",
          "Published": "Publish"
        };

        // If a replacement is defined, use it
        if (changeTense[name] !== undefined) {
          name = changeTense[name];
        }
      }
      return name;
    }
  };

  /**
   * Create a date stamp in the format "DD Month, YYYY".
   * @param {String} rawDate GitHub timestamp.
   * @returns {String}.
   */
  function _createDate(date) {
    var months = {"01": "January", "02": "February", "03": "March", "04": "April",
                  "05": "May", "06": "June", "07": "July", "08": "August", "09": "September",
                  "10": "October", "11": "November", "12": "December"
                 };

    var dateParts  = date.split("T")[0].split("-"),
        dateFormat = [dateParts[2], dateParts[1], dateParts[0]];
    dateFormat[1]  = months[dateFormat[1]] + ",";
    return dateFormat.join(" ");
  }

  var events = [];

  /**
   * Process the fetched GitHub event feed.
   * @param {Object} data [[Description]].
   */
  function loadEvents(data) {
    for (var i = 0, limit = 7; i < limit; i += 1) {
      var curEvent  = data[i],
          id        = curEvent.id,
          url       = "#",
          sha       = "",
          repo      = curEvent.repo.name,
          date      = _createDate(curEvent.created_at).substring(0, curEvent.created_at.length - 1),
          repoUrl   = EventUtils.makeURL(curEvent.repo.url),
          message   = "No commit message available.",
          eventName = curEvent.type.replace(/event/i, "");

      // Do not report certain events
      if (/comment|fork|watch/gi.test(eventName)) {
        limit += 1;
        continue;
      }

      switch(eventName) {
          // Create event
          case "Create":
          // Filter out create tag events
          var _eventType = curEvent.payload.ref_type;
            if (/tag/.test(_eventType))  {
              continue;
            }

            sha = curEvent.payload.ref;
            message = "Create " + curEvent.payload.ref_type;

            // New branch
            if (/branch/.test(_eventType)) {
              url = EventUtils.makeURL(curEvent.repo.url) + "/tree/" + curEvent.payload.ref;
            }

            // TODO New repo
            break;

          // New release
          case "Release":
            eventName = EventUtils.makeEventName(curEvent.payload.action, true);
            sha = curEvent.payload.release.tag_name;
            url = curEvent.payload.release.html_url;
            message = "\"" + curEvent.payload.release.name + "\"";
            break;

          // Open/close issue
          case "Issues":
            eventName = EventUtils.makeEventName(curEvent.payload.action, true);
            sha = "#" + curEvent.payload.issue.number;
            url = curEvent.payload.issue.html_url;
            message = EventUtils.makeEventName(curEvent.payload.action) +
                      " \"" + curEvent.payload.issue.title + "\"";
            break;

          // Delete event
          case "Delete":
            eventName = "Delete";
            sha = curEvent.payload.ref;
            url = EventUtils.makeURL(curEvent.repo.url);
            message = "Delete " + curEvent.payload.ref_type;
            break;

          // Wiki edit
          case "Gollum":
            eventName = "Wiki Edit";
            sha = curEvent.payload.pages[0].sha.substr(0, 10);
            url = curEvent.payload.pages[0].html_url;

            message = EventUtils.capitalFirst(curEvent.payload.pages[0].action);
            message += " \"" + curEvent.payload.pages[0].title + "\"";
            break;

          // Pull request
          case "PullRequest":
            eventName = "Pull Request";
            sha = "#" + curEvent.payload.number;
            url = curEvent.payload.pull_request.html_url;
            message = EventUtils.capitalFirst(curEvent.payload.pull_request.state);
            message += " \"" + curEvent.payload.pull_request.title + "\"";
            break;

          // Push event
          default:
            url = EventUtils.makeURL(curEvent.payload.commits[0].url);
            sha = curEvent.payload.commits[0].sha.substr(0, 10);
            message = curEvent.payload.commits[0].message;
            break;
      }

      // Create a new event object
      var ghEvent = new GHEvent(id, url, sha, date, repo, repoUrl, eventName, message);
      ghEvent.compile();
      events.push(ghEvent);
    }
  }

  /**
   * Add the events to the page.
   * @returns {Boolean} Always returns true.
   */
  function displayEvents() {
    var $container = $(".gh-events");
    events.forEach(function(event) {
      $container.append(event.final);
      return true;
    });
  }

  // Poll the GitHub API
  $.ajax({
    dataType: "json",
    url: "https://api.github.com/users/le717/events/public",
    success: [loadEvents, displayEvents],
    error: function() {
      var msg = "Unfortunately that information cannot be loaded right now";
      $(".gh-events").html(msg);
      return false;
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>import React from "react";
import PropTypes from "prop-types";
import { DatePickerAndroid, TimePickerAndroid } from "react-native";

export default class CustomDatePickerAndroid extends React.PureComponent {
  static propTypes = {
    date: PropTypes.instanceOf(Date),
    mode: PropTypes.oneOf(["date", "time", "datetime"]),
    onCancel: PropTypes.func.isRequired,
    onConfirm: PropTypes.func.isRequired,
    onHideAfterConfirm: PropTypes.func,
    is24Hour: PropTypes.bool,
    isVisible: PropTypes.bool,
    datePickerModeAndroid: PropTypes.oneOf(["calendar", "spinner", "default"]),
    minimumDate: PropTypes.instanceOf(Date),
    maximumDate: PropTypes.instanceOf(Date)
  };

  static defaultProps = {
    date: new Date(),
    mode: "date",
    datePickerModeAndroid: "default",
    is24Hour: true,
    isVisible: false,
    onHideAfterConfirm: () => {}
  };

  componentDidUpdate = prevProps => {
    if (!prevProps.isVisible && this.props.isVisible) {
      if (this.props.mode === "date" || this.props.mode === "datetime") {
        this._showDatePickerAndroid().catch(console.error);
      } else {
        this._showTimePickerAndroid().catch(console.error);
      }
    }
  };

  componentDidMount = () => {
    if (this.props && this.props.isVisible) {
      if (this.props.mode === "date" || this.props.mode === "datetime") {
        this._showDatePickerAndroid().catch(console.error);
      } else {
        this._showTimePickerAndroid().catch(console.error);
      }
    }
  };

  _showDatePickerAndroid = async () => {
    let picked;
    try {
      picked = await DatePickerAndroid.open({
        date: this.props.date,
        minDate: this.props.minimumDate,
        maxDate: this.props.maximumDate,
        mode: this.props.datePickerModeAndroid
      });
    } catch ({ message }) {
      console.warn("Cannot open date picker", message);
      return;
    }

    const { action, year, month, day } = picked;
    if (action !== DatePickerAndroid.dismissedAction) {
      let date;
      if (this.props.date && !isNaN(this.props.date.getTime())) {
        let hour = this.props.date.getHours();
        let minute = this.props.date.getMinutes();
        date = new Date(year, month, day, hour, minute);
      } else {
        date = new Date(year, month, day);
      }

      if (this.props.mode === "datetime") {
        // Prepopulate and show time picker
        const timeOptions = {
          is24Hour: this.props.is24Hour,
          mode: this.props.datePickerModeAndroid
        };
        if (this.props.date) {
          timeOptions.hour = this.props.date.getHours();
          timeOptions.minute = this.props.date.getMinutes();
        }

        let pickedTime;
        try {
          pickedTime = await TimePickerAndroid.open(timeOptions);
        } catch ({ message }) {
          console.warn("Cannot open time picker", message);
          return;
        }

        const { action: timeAction, hour, minute } = pickedTime;
        if (timeAction !== TimePickerAndroid.dismissedAction) {
          const selectedDate = new Date(year, month, day, hour, minute);
          this.props.onConfirm(selectedDate);
          this.props.onHideAfterConfirm(selectedDate);
        } else {
          this.props.onCancel();
        }
      } else {
        this.props.onConfirm(date);
        this.props.onHideAfterConfirm(date);
      }
    } else {
      this.props.onCancel();
    }
  };

  _showTimePickerAndroid = async () => {
    let picked;
    try {
      picked = await TimePickerAndroid.open({
        hour: this.props.date.getHours(),
        minute: this.props.date.getMinutes(),
        is24Hour: this.props.is24Hour,
        mode: this.props.datePickerModeAndroid
      });
    } catch ({ message }) {
      console.warn("Cannot open time picker", message);
      return;
    }

    const { action, hour, minute } = picked;
    if (action !== TimePickerAndroid.dismissedAction) {
      let date;
      if (this.props.date) {
        // This prevents losing the Date elements, see issue #71
        const year = this.props.date.getFullYear();
        const month = this.props.date.getMonth();
        const day = this.props.date.getDate();
        date = new Date(year, month, day, hour, minute);
      } else {
        date = new Date().setHours(hour).setMinutes(minute);
      }
      this.props.onConfirm(date);
      this.props.onHideAfterConfirm(date);
    } else {
      this.props.onCancel();
    }
  };

  render() {
    return null;
  }
}
<commit_msg>Added timePickerModeAndroid prop<commit_after>import React from "react";
import PropTypes from "prop-types";
import { DatePickerAndroid, TimePickerAndroid } from "react-native";

export default class CustomDatePickerAndroid extends React.PureComponent {
  static propTypes = {
    date: PropTypes.instanceOf(Date),
    mode: PropTypes.oneOf(["date", "time", "datetime"]),
    onCancel: PropTypes.func.isRequired,
    onConfirm: PropTypes.func.isRequired,
    onHideAfterConfirm: PropTypes.func,
    is24Hour: PropTypes.bool,
    isVisible: PropTypes.bool,
    datePickerModeAndroid: PropTypes.oneOf(["calendar", "spinner", "default"]),
    timePickerModeAndroid: PropTypes.oneOf(["clock", "spinner", "default"]),
    minimumDate: PropTypes.instanceOf(Date),
    maximumDate: PropTypes.instanceOf(Date)
  };

  static defaultProps = {
    date: new Date(),
    mode: "date",
    datePickerModeAndroid: "default",
    timePickerModeAndroid: "default",
    is24Hour: true,
    isVisible: false,
    onHideAfterConfirm: () => {}
  };

  componentDidUpdate = prevProps => {
    if (!prevProps.isVisible && this.props.isVisible) {
      if (this.props.mode === "date" || this.props.mode === "datetime") {
        this._showDatePickerAndroid().catch(console.error);
      } else {
        this._showTimePickerAndroid().catch(console.error);
      }
    }
  };

  componentDidMount = () => {
    if (this.props && this.props.isVisible) {
      if (this.props.mode === "date" || this.props.mode === "datetime") {
        this._showDatePickerAndroid().catch(console.error);
      } else {
        this._showTimePickerAndroid().catch(console.error);
      }
    }
  };

  _showDatePickerAndroid = async () => {
    let picked;
    try {
      picked = await DatePickerAndroid.open({
        date: this.props.date,
        minDate: this.props.minimumDate,
        maxDate: this.props.maximumDate,
        mode: this.props.datePickerModeAndroid
      });
    } catch ({ message }) {
      console.warn("Cannot open date picker", message);
      return;
    }

    const { action, year, month, day } = picked;
    if (action !== DatePickerAndroid.dismissedAction) {
      let date;
      if (this.props.date && !isNaN(this.props.date.getTime())) {
        let hour = this.props.date.getHours();
        let minute = this.props.date.getMinutes();
        date = new Date(year, month, day, hour, minute);
      } else {
        date = new Date(year, month, day);
      }

      if (this.props.mode === "datetime") {
        // Prepopulate and show time picker
        const timeOptions = {
          is24Hour: this.props.is24Hour,
          mode: this.props.timePickerModeAndroid
        };
        if (this.props.date) {
          timeOptions.hour = this.props.date.getHours();
          timeOptions.minute = this.props.date.getMinutes();
        }

        let pickedTime;
        try {
          pickedTime = await TimePickerAndroid.open(timeOptions);
        } catch ({ message }) {
          console.warn("Cannot open time picker", message);
          return;
        }

        const { action: timeAction, hour, minute } = pickedTime;
        if (timeAction !== TimePickerAndroid.dismissedAction) {
          const selectedDate = new Date(year, month, day, hour, minute);
          this.props.onConfirm(selectedDate);
          this.props.onHideAfterConfirm(selectedDate);
        } else {
          this.props.onCancel();
        }
      } else {
        this.props.onConfirm(date);
        this.props.onHideAfterConfirm(date);
      }
    } else {
      this.props.onCancel();
    }
  };

  _showTimePickerAndroid = async () => {
    let picked;
    try {
      picked = await TimePickerAndroid.open({
        hour: this.props.date.getHours(),
        minute: this.props.date.getMinutes(),
        is24Hour: this.props.is24Hour,
        mode: this.props.timePickerModeAndroid
      });
    } catch ({ message }) {
      console.warn("Cannot open time picker", message);
      return;
    }

    const { action, hour, minute } = picked;
    if (action !== TimePickerAndroid.dismissedAction) {
      let date;
      if (this.props.date) {
        // This prevents losing the Date elements, see issue #71
        const year = this.props.date.getFullYear();
        const month = this.props.date.getMonth();
        const day = this.props.date.getDate();
        date = new Date(year, month, day, hour, minute);
      } else {
        date = new Date().setHours(hour).setMinutes(minute);
      }
      this.props.onConfirm(date);
      this.props.onHideAfterConfirm(date);
    } else {
      this.props.onCancel();
    }
  };

  render() {
    return null;
  }
}
<|endoftext|>