<commit_before>/*
 * jQuery UI translucent 1.0
 * Copyright (c) 2017, Sanggyeong Jo
 * Lisensed under the MIT
 *
 * Dependencies:
 *  jQuery >= 1.6
 *  jQuery.ui.core
 *  jQuery.ui.widget
 *  jQuery.ui.mouse
 *
 * Contacts
 *  Github : github.com/byeolbit
 *  Email : info@byeolbit.com
 *          sanggyeong.jo@gmail.com
 *
 * You can find this project at https://github.com/byeolbit/translucent.js
 */

(function($){
    $.fn.translucent = function(bgElement, options){
        var settings = $.extend({
            filterValue : 10,
            cardColor : 'white',
            draggable : true,
            shadow : true
        }, options);

        this.each( function() {
            var $this = $(this),
                filterValue = settings.filterValue,
                cardColor = settings.cardColor,
                draggable = settings.draggable,
                shadow = settings.shadow;

            var $card = $this.children('.tpc-card'),
                $cardCt = $this.children('.tpc-card-background-container'),
                $cardCont = $card.children('.tpc-card-contents'),
                $cardBg =  $cardCt.children('.tpc-card-bg'),
                $targetBg = $(bgElement),
                $window = $(window),
                bgAttach;

            var cssColorClear = {
                    'background-color' : 'rgba(255,255,255,0)'
                },
                cssColorWhite = {
                    'background-color' : 'rgba(255,255,255,0.4)'
                },
                cssColorGrey = {
                    'background-color' : 'rgba(120,120,120,0.4)'
                },
                cssColorBlack = {
                    'background-color' : 'rgba(30,30,30,0.7)'
                }

            $card.css({
                'border': 'rgba(200,200,200,0.5) solid 1px',
                'border-radius' : '10px',
                'overflow' : 'hidden',
                'position' : 'relative',
                'transition' : 'box-shadow 0.4s ease',
            });

            if (shadow){
                $card.css({
                    'box-shadow' : '0px 20px 20px rgba(0,0,0,0.5)'
                });
            }

            $cardCt.css({
                'border-radius': '10px',
                'position': 'relative',
                'overflow': 'hidden'
            });

            $cardCont.css({
                'border-radiu' : '10px',
                'height' : $card.height(),
                'position' : 'relative',
                'width' : $card.width(),
                'overflow' : 'hidden'
            });

            $card.offset({left:500, top:30});

            cardInit($card, $cardBg, $cardCt, $targetBg, filterValue);

            switch (cardColor) {
                case 'clear' :
                    $cardCont.css(cssColorClear);
                    break;
                case 'white' :
                    $cardCont.css(cssColorWhite);
                    break;
                case 'grey' :
                    $cardCont.css(cssColorGrey);
                    break;
                case 'black' :
                    $cardCont.css(cssColorBlack);
                    break;
                default :
                    $cardCont.css('background-color',cardColor);
            }

            //Card background reacts to change of window size
            $window.resize(function() {
                cardInit($card, $cardBg, $cardCt, $targetBg, filterValue);
            });

            if (draggable){
                $card.css({'cursor' : 'move'});
                $card.draggable({
                    containment:bgElement,
                    start:function(event,ui){
                        if (shadow){
                            $card.css({
                                'box-shadow' : '0px 40px 30px rgba(0,0,0,0.7)'
                            });
                        }
                    },
                    drag:function(event, ui){
                        applyTransparent($card, $cardBg, $cardCt,
                                         $targetBg, filterValue);
                    },
                    stop:function(event, ui){
                        if (shadow){
                            $card.css({
                                'box-shadow' : '0px 20px 20px rgba(0,0,0,0.5)'
                            });
                        }
                        applyTransparent($card, $cardBg, $cardCt,
                                         $targetBg, filterValue);
                    }
                });
            }

            //Initialize card.
            function cardInit($card, $cardBg, $cardCt, $targetBg, filterValue){
                var bgImg = $targetBg.css('background-image'),
                    bgRepeat = $targetBg.css('background-repeat'),
                    bgSize = $targetBg.css('background-size'),
                    cardHeight = $card.height(),
                    cardWidth = $card.width();

                $cardBg.css('background-image',bgImg);
                $cardBg.css('background-repeat',bgRepeat);
                $cardBg.css('background-size',bgSize);
                $cardBg.css('filter','blur('+filterValue+'px)');
                $cardBg.css('margin-left','-'+(filterValue)+'px');
                $cardBg.css('margin-top','-'+(filterValue)+'px');
                $cardBg.height(cardHeight+filterValue*2);
                $cardBg.width(cardWidth+filterValue*2);

                applyTransparent($card, $cardBg, $cardCt,
                                 $targetBg, filterValue);
            }

            // Blurred background tracks offset of card.
            function applyTransparent($card, $cardBg, $cardCt,
                                      $targetBg, filterValue){
                var bgAtt = $targetBg.css('background-attachment'),
                    bgOffset = $targetBg.offset();
                    cardOffset = $card.offset(),

                $cardCt.offset({left:cardOffset.left+1,top:cardOffset.top+1});
                $cardBg.css('background-attachment',bgAtt);

                // If background-attachment is fixed,
                // don't need to track the card offset.
                if (bgAtt != 'fixed') {
                    $cardBg.css('background-position',
                                (bgOffset.left-
                                (cardOffset.left-filterValue))+'px '+
                                (bgOffset.top-
                                (cardOffset.top-filterValue))+'px');
                }
            }
        });
    }
}(jQuery));<commit_msg>Use the universal module definition<commit_after>/*
 * jQuery UI translucent 1.0
 * Copyright (c) 2017, Sanggyeong Jo
 * Lisensed under the MIT
 *
 * Dependencies:
 *  jQuery >= 1.6
 *  jQuery.ui.core
 *  jQuery.ui.widget
 *  jQuery.ui.mouse
 *
 * Contacts
 *  Github : github.com/byeolbit
 *  Email : info@byeolbit.com
 *          sanggyeong.jo@gmail.com
 *
 * You can find this project at https://github.com/byeolbit/translucent.js
 */

(function($, window, document, undefined){
    $.fn.translucent = function(bgElement, options){
        var settings = $.extend({
            filterValue : 10,
            cardColor : 'white',
            draggable : true,
            shadow : true
        }, options);

        this.each( function() {
            var $this = $(this),
                filterValue = settings.filterValue,
                cardColor = settings.cardColor,
                draggable = settings.draggable,
                shadow = settings.shadow;

            var $card = $this.children('.tpc-card'),
                $cardCt = $this.children('.tpc-card-background-container'),
                $cardCont = $card.children('.tpc-card-contents'),
                $cardBg =  $cardCt.children('.tpc-card-bg'),
                $targetBg = $(bgElement),
                $window = $(window),
                bgAttach;

            var cssColorClear = {
                    'background-color' : 'rgba(255,255,255,0)'
                },
                cssColorWhite = {
                    'background-color' : 'rgba(255,255,255,0.4)'
                },
                cssColorGrey = {
                    'background-color' : 'rgba(120,120,120,0.4)'
                },
                cssColorBlack = {
                    'background-color' : 'rgba(30,30,30,0.7)'
                }

            $card.css({
                'border': 'rgba(200,200,200,0.5) solid 1px',
                'border-radius' : '10px',
                'overflow' : 'hidden',
                'position' : 'relative',
                'transition' : 'box-shadow 0.4s ease',
            });

            if (shadow){
                $card.css({
                    'box-shadow' : '0px 20px 20px rgba(0,0,0,0.5)'
                });
            }

            $cardCt.css({
                'border-radius': '10px',
                'position': 'relative',
                'overflow': 'hidden'
            });

            $cardCont.css({
                'border-radiu' : '10px',
                'height' : $card.height(),
                'position' : 'relative',
                'width' : $card.width(),
                'overflow' : 'hidden'
            });

            $card.offset({left:500, top:30});

            cardInit($card, $cardBg, $cardCt, $targetBg, filterValue);

            switch (cardColor) {
                case 'clear' :
                    $cardCont.css(cssColorClear);
                    break;
                case 'white' :
                    $cardCont.css(cssColorWhite);
                    break;
                case 'grey' :
                    $cardCont.css(cssColorGrey);
                    break;
                case 'black' :
                    $cardCont.css(cssColorBlack);
                    break;
                default :
                    $cardCont.css('background-color',cardColor);
            }

            //Card background reacts to change of window size
            $window.resize(function() {
                cardInit($card, $cardBg, $cardCt, $targetBg, filterValue);
            });

            if (draggable){
                $card.css({'cursor' : 'move'});
                $card.draggable({
                    containment:bgElement,
                    start:function(event,ui){
                        if (shadow){
                            $card.css({
                                'box-shadow' : '0px 40px 30px rgba(0,0,0,0.7)'
                            });
                        }
                    },
                    drag:function(event, ui){
                        applyTransparent($card, $cardBg, $cardCt,
                                         $targetBg, filterValue);
                    },
                    stop:function(event, ui){
                        if (shadow){
                            $card.css({
                                'box-shadow' : '0px 20px 20px rgba(0,0,0,0.5)'
                            });
                        }
                        applyTransparent($card, $cardBg, $cardCt,
                                         $targetBg, filterValue);
                    }
                });
            }

            //Initialize card.
            function cardInit($card, $cardBg, $cardCt, $targetBg, filterValue){
                var bgImg = $targetBg.css('background-image'),
                    bgRepeat = $targetBg.css('background-repeat'),
                    bgSize = $targetBg.css('background-size'),
                    cardHeight = $card.height(),
                    cardWidth = $card.width();

                $cardBg.css('background-image',bgImg);
                $cardBg.css('background-repeat',bgRepeat);
                $cardBg.css('background-size',bgSize);
                $cardBg.css('filter','blur('+filterValue+'px)');
                $cardBg.css('margin-left','-'+(filterValue)+'px');
                $cardBg.css('margin-top','-'+(filterValue)+'px');
                $cardBg.height(cardHeight+filterValue*2);
                $cardBg.width(cardWidth+filterValue*2);

                applyTransparent($card, $cardBg, $cardCt,
                                 $targetBg, filterValue);
            }

            // Blurred background tracks offset of card.
            function applyTransparent($card, $cardBg, $cardCt,
                                      $targetBg, filterValue){
                var bgAtt = $targetBg.css('background-attachment'),
                    bgOffset = $targetBg.offset();
                    cardOffset = $card.offset(),

                $cardCt.offset({left:cardOffset.left+1,top:cardOffset.top+1});
                $cardBg.css('background-attachment',bgAtt);

                // If background-attachment is fixed,
                // don't need to track the card offset.
                if (bgAtt != 'fixed') {
                    $cardBg.css('background-position',
                                (bgOffset.left-
                                (cardOffset.left-filterValue))+'px '+
                                (bgOffset.top-
                                (cardOffset.top-filterValue))+'px');
                }
            }
        });
    }
}(jQuery, window, document));<|endoftext|>


<commit_before>define(function(require){

	var Constructor = require('../managerAPI');
	var _ = require('underscore');
	var isDev = /^(localhost|127.0.0.1)/.test(location.host) || window.DEBUG;
	var decorator = require('APIs/pi/APIdecorator');

	var messageTemplate = require('text!./messageTemplate.jst');
	var messageTemplateDebrief = require('text!./messageTemplateDebrief.jst');
	var messageTemplatePanel = require('text!./messageTemplatePanel.jst');

	/**
	 * Constructor for PIPlayer script creator
	 * @return {Object}		Script creator
	 */
	function API(){
		Constructor.call(this);
		this.settings.onPreTask = onPreTask;
	}

	decorator(API);

	// create API functions
	_.extend(API.prototype, Constructor.prototype);

	// annotate onPreTask
	onPreTask.$inject = ['currentTask', '$http','$rootScope','managerBeforeUnload','templateDefaultContext'];

	return API;

	/**
	 * Before each task,
	 * 		post to /implicit/PiManager
	 * 		in case this is a quest/pip added logging meta
	 *
	 * @param  {Object} currentTask The task Object
	 * @param  {Object} $http       The $http service
	 * @return {Promise}            Resolved when server responds
	 */
	function onPreTask(currentTask, $http, $rootScope, beforeUnload, templateDefaultContext){

		var global = $rootScope.global;
		var settings, context = {};
		var data = {taskName: currentTask.name || 'namelessTask', taskNumber: currentTask.$meta.number};

		// add logging meta
		if (currentTask.type == 'quest' || currentTask.type == 'pip'){
			currentTask.$script.serial = currentTask.$meta.number;
			settings = currentTask.$script.settings;
			settings.logger = settings.logger || {};
			settings.logger.meta = angular.extend(settings.logger.meta || {}, data);
		}

		// add feedback functions to the default template context
		_.extend(templateDefaultContext,{
			showFeedback: _.bind(showFeedback,null,global),
			showPanel: showPanel
		});

		if (currentTask.type == 'message' && currentTask.piTemplate){
			_.extend(context, templateDefaultContext, {
				global: global,
				current: global.current,
				task: currentTask
			});

			// compile template here so that we have all the addtional functions available
			// event when the template is loaded from a file.
			context.content = currentTask.$template = _.template(currentTask.$template)(context);

			if (currentTask.piTemplate == 'debrief'){
				currentTask.$template = _.template(messageTemplateDebrief)(context); // insert into meta template
				currentTask.$template = _.template(currentTask.$template)(context); // render secondary template with extended context
			} else {
				currentTask.$template = _.template(messageTemplate)(context); // insert into meta template
			}
		}

		// set last task flag
		if (currentTask.last){
			data.sessionStatus = "C";
			beforeUnload.deactivate();
		}

		if (currentTask.last && global.$mTurk){
			var $mTurk = global.$mTurk;
			var url = $mTurk.isProduction ?  'http://www.mturk.com/mturk/externalSubmit' : 'https://workersandbox.mturk.com/mturk/externalSubmit';
			var onPost = currentTask.post || _.noop;

			if (!_.every(['assignmentId','hitId','workerId'], function(prop){return _.has($mTurk, prop);})){
				throw new Error ('$mTurk is missing a crucial property (assignmentId,hitId,workerId)');
			}

			currentTask.post = function(){
				onPost.apply(this, arguments);
				postRedirect(url,_.omit($mTurk,'isProduction'));
			};
		}

		if (window._err && window._err.meta){
			var meta = window._err.meta;
			meta.subtaskName = currentTask.name;
			meta.subtaskURL = currentTask.scriptUrl || currentTask.templateUrl;
		}

		return isDev ? true : $http.post('/implicit/PiManager', data);
	}

	function postRedirect(path, params, method) {
	    method = method || "post"; // Set method to post by default if not specified.

	    // The rest of this code assumes you are not using a library.
	    // It can be made less wordy if you use one.
	    var form = document.createElement("form");
	    form.setAttribute("method", method);
	    form.setAttribute("action", path);

	    for(var key in params) {
	        if(params.hasOwnProperty(key)) {
	            var hiddenField = document.createElement("input");
	            hiddenField.setAttribute("type", "hidden");
	            hiddenField.setAttribute("name", key);
	            hiddenField.setAttribute("value", params[key]);

	            form.appendChild(hiddenField);
	         }
	    }

	    document.body.appendChild(form);
	    form.submit();
	}

	function showPanel(content, header, footer){
		return _.template(messageTemplatePanel)({
			content: content,
			header: header,
			footer: footer
		});
	}

	function showFeedback(global, options){
		_.isPlainObject(options) || (options = {});

		_.defaults(options,{
			pre: '
',
			post: '
',
			wrap: true,
			header: '',
			noFeedback: '
No feedback was found
',
			property: 'feedback',
			exclude: []
		});

		var feedback = _(global)
			.filter(function(task,taskName){
				if (!_.isArray(options.exclude)) { throw Error('Exclude must be an array'); }
				// make sure task is an object
				// make sure feedback is defined
				// make sure this task is not excluded
				return _.isPlainObject(task) && !_.isUndefined(task[options.property]) && (_.indexOf(options.exclude,taskName) === -1);
			})
			.mapValues(function(task){
				return options.pre + task[options.property] + options.post;
			})
			.reduce(function(result, feedback){
				return result + feedback;
			},'') || options.noFeedback;

		return options.wrap ? showPanel(feedback,options.header,options.footer) : feedback;
	}
})
;
<commit_msg>fix(PI): post taskURL as part of the pre task update<commit_after>define(function(require){

	var Constructor = require('../managerAPI');
	var _ = require('underscore');
	var isDev = /^(localhost|127.0.0.1)/.test(location.host) || window.DEBUG;
	var decorator = require('APIs/pi/APIdecorator');

	var messageTemplate = require('text!./messageTemplate.jst');
	var messageTemplateDebrief = require('text!./messageTemplateDebrief.jst');
	var messageTemplatePanel = require('text!./messageTemplatePanel.jst');

	/**
	 * Constructor for PIPlayer script creator
	 * @return {Object}		Script creator
	 */
	function API(){
		Constructor.call(this);
		this.settings.onPreTask = onPreTask;
	}

	decorator(API);

	// create API functions
	_.extend(API.prototype, Constructor.prototype);

	// annotate onPreTask
	onPreTask.$inject = ['currentTask', '$http','$rootScope','managerBeforeUnload','templateDefaultContext'];

	return API;

	/**
	 * Before each task,
	 * 		post to /implicit/PiManager
	 * 		in case this is a quest/pip added logging meta
	 *
	 * @param  {Object} currentTask The task Object
	 * @param  {Object} $http       The $http service
	 * @return {Promise}            Resolved when server responds
	 */
	function onPreTask(currentTask, $http, $rootScope, beforeUnload, templateDefaultContext){

		var global = $rootScope.global;
		var settings, context = {};
		var data = {taskName: currentTask.name || 'namelessTask', taskNumber: currentTask.$meta.number, taskURL:currentTask.scriptUrl || currentTask.templateUrl};

		// add logging meta
		if (currentTask.type == 'quest' || currentTask.type == 'pip'){
			currentTask.$script.serial = currentTask.$meta.number;
			settings = currentTask.$script.settings;
			settings.logger = settings.logger || {};
			settings.logger.meta = angular.extend(settings.logger.meta || {}, data);
		}

		// add feedback functions to the default template context
		_.extend(templateDefaultContext,{
			showFeedback: _.bind(showFeedback,null,global),
			showPanel: showPanel
		});

		if (currentTask.type == 'message' && currentTask.piTemplate){
			_.extend(context, templateDefaultContext, {
				global: global,
				current: global.current,
				task: currentTask
			});

			// compile template here so that we have all the addtional functions available
			// event when the template is loaded from a file.
			context.content = currentTask.$template = _.template(currentTask.$template)(context);

			if (currentTask.piTemplate == 'debrief'){
				currentTask.$template = _.template(messageTemplateDebrief)(context); // insert into meta template
				currentTask.$template = _.template(currentTask.$template)(context); // render secondary template with extended context
			} else {
				currentTask.$template = _.template(messageTemplate)(context); // insert into meta template
			}
		}

		// set last task flag
		if (currentTask.last){
			data.sessionStatus = "C";
			beforeUnload.deactivate();
		}

		if (currentTask.last && global.$mTurk){
			var $mTurk = global.$mTurk;
			var url = $mTurk.isProduction ?  'http://www.mturk.com/mturk/externalSubmit' : 'https://workersandbox.mturk.com/mturk/externalSubmit';
			var onPost = currentTask.post || _.noop;

			if (!_.every(['assignmentId','hitId','workerId'], function(prop){return _.has($mTurk, prop);})){
				throw new Error ('$mTurk is missing a crucial property (assignmentId,hitId,workerId)');
			}

			currentTask.post = function(){
				onPost.apply(this, arguments);
				postRedirect(url,_.omit($mTurk,'isProduction'));
			};
		}

		if (window._err && window._err.meta){
			var meta = window._err.meta;
			meta.subtaskName = currentTask.name;
			meta.subtaskURL = currentTask.scriptUrl || currentTask.templateUrl;
		}

		return isDev ? true : $http.post('/implicit/PiManager', data);
	}

	function postRedirect(path, params, method) {
	    method = method || "post"; // Set method to post by default if not specified.

	    // The rest of this code assumes you are not using a library.
	    // It can be made less wordy if you use one.
	    var form = document.createElement("form");
	    form.setAttribute("method", method);
	    form.setAttribute("action", path);

	    for(var key in params) {
	        if(params.hasOwnProperty(key)) {
	            var hiddenField = document.createElement("input");
	            hiddenField.setAttribute("type", "hidden");
	            hiddenField.setAttribute("name", key);
	            hiddenField.setAttribute("value", params[key]);

	            form.appendChild(hiddenField);
	         }
	    }

	    document.body.appendChild(form);
	    form.submit();
	}

	function showPanel(content, header, footer){
		return _.template(messageTemplatePanel)({
			content: content,
			header: header,
			footer: footer
		});
	}

	function showFeedback(global, options){
		_.isPlainObject(options) || (options = {});

		_.defaults(options,{
			pre: '
',
			post: '
',
			wrap: true,
			header: '',
			noFeedback: '
No feedback was found
',
			property: 'feedback',
			exclude: []
		});

		var feedback = _(global)
			.filter(function(task,taskName){
				if (!_.isArray(options.exclude)) { throw Error('Exclude must be an array'); }
				// make sure task is an object
				// make sure feedback is defined
				// make sure this task is not excluded
				return _.isPlainObject(task) && !_.isUndefined(task[options.property]) && (_.indexOf(options.exclude,taskName) === -1);
			})
			.mapValues(function(task){
				return options.pre + task[options.property] + options.post;
			})
			.reduce(function(result, feedback){
				return result + feedback;
			},'') || options.noFeedback;

		return options.wrap ? showPanel(feedback,options.header,options.footer) : feedback;
	}
})
;
<|endoftext|>


<commit_before>import AppDispatcher from '../dispatcher/AppDispatcher';
import AppConstants  from '../constants/AppConstants';

import app from '../constants/app.js';

import mmd      from 'musicmetadata';
import fs       from 'fs';
import path     from 'path';
import mime     from 'mime';
import walkSync from 'walk-sync';

import remote from 'remote';

var globalShortcut = remote.require('global-shortcut');
var dialog         = remote.require('dialog');

var AppActions = {

    init: function() {

        // Usual tasks
        this.app.start();
        this.getTracks();
        this.settings.checkTheme();
        this.settings.checkDevMode();
        this.app.initShortcuts();

        // Prevent some events
        window.addEventListener('dragover', function (e) {
            e.preventDefault();
        }, false);

        window.addEventListener('drop', function (e) {
            e.preventDefault();
        }, false);

        // Remember dimensions and positionning
        var currentWindow = app.browserWindows.main;

        currentWindow.on('resize', function() {
            AppActions.app.saveBounds();
        });

        currentWindow.on('move', function() {
            AppActions.app.saveBounds();
        });
    },

    /**
     * Refresh the library
     */
    getTracks: function() {
        app.db.find({}).sort({ 'lArtist': 1, 'year': 1, 'album': 1, 'disk': 1, 'track.no': 1 }).exec(function (err, tracks) {
            if (err) throw err;
            else {
                AppDispatcher.dispatch({
                    actionType : AppConstants.APP_REFRESH_LIBRARY,
                    tracks     : tracks
                });
            }
        });
    },

    /**
     * Select and play a track
     */
    selectAndPlay: function(id) {

        AppDispatcher.dispatch({
            actionType : AppConstants.APP_SELECT_AND_PLAY,
            id         : id
        });
    },

    /**
     * Search
     */
    filterSearch: function(search) {

        AppDispatcher.dispatch({
            actionType : AppConstants.APP_FILTER_SEARCH,
            search     : search
        });
    },

    app: {

        start: function() {
            var bounds        = app.initialConfig.bounds;
            var currentWindow = app.browserWindows.main;
            currentWindow.setBounds(bounds);
            currentWindow.show();
        },

        close: function() {
            app.browserWindows.main.close();
        },

        saveBounds: function() {

            var self = AppActions;
            var now = window.performance.now();

            if (now - self.lastFilterSearch < 250) {
                clearTimeout(self.filterSearchTimeOut);
            }

            self.lastFilterSearch = now;

            self.filterSearchTimeOut = setTimeout(() => {

                var currentWindow = app.browserWindows.main;
                var config        = JSON.parse(localStorage.getItem('config'));
                    config.bounds = currentWindow.getBounds();

                localStorage.setItem('config', JSON.stringify(config));
            }, 250);
        },

        initShortcuts: function() {

            // Global shortcuts
            globalShortcut.register('MediaPlayPause', function () {
                AppActions.player.playToggle();
            });

            globalShortcut.register('MediaPreviousTrack', function () {
                AppActions.player.previous();
            });

            globalShortcut.register('MediaNextTrack', function () {
                AppActions.player.next();
            });
        }
    },

    player: {

        toggle: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_TOGGLE
            });
        },

        play: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_PLAY
            });
        },

        pause: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_PAUSE
            });
        },

        stop: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_STOP
            });
        },

        next: function(e) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_NEXT,
                e          : e
            });
        },

        previous: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_PREVIOUS
            });
        },

        shuffle: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_SHUFFLE
            });
        },

        setVolume: function(volume) {
            app.audio.volume = volume;
            var config = JSON.parse(localStorage.getItem('config'));
                config.volume = volume;

            localStorage.setItem('config', JSON.stringify(config));
        },

        repeat: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_REPEAT
            });
        },

        jumpTo: function(to) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_JUMP_TO,
                to         : to
            });
        }
    },

    queue: {

        clear: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_CLEAR
            });
        },

        remove: function(index) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_REMOVE,
                index      : index
            });
        },

        add: function(selected) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_ADD,
                selected   : selected
            });
        },

        addNext: function(selected) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_ADD_NEXT,
                selected   : selected
            });
        },

        setPlaylist: function(playlist) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_SET_PLAYLIST,
                playlist   : playlist
            });
        }
    },

    library: {

        addFolders(folders) {

            var folders = dialog.showOpenDialog({ properties: ['openDirectory', 'multiSelections']});

            if(folders !== undefined) {
                AppDispatcher.dispatch({
                    actionType : AppConstants.APP_LIBRARY_ADD_FOLDERS,
                    folders    : folders
                });
            }
        },

        removeFolder(index) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REMOVE_FOLDER,
                index      : index
            });
        },

        reset() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REFRESH_START,
            });

            app.db.remove({ }, { multi: true }, function (err, numRemoved) {
                app.db.loadDatabase(function (err) {
                    if(err) {
                        throw err
                    } else {
                        AppActions.getTracks();
                        AppDispatcher.dispatch({
                            actionType : AppConstants.APP_LIBRARY_REFRESH_END,
                        });
                    }
                });
            });
        },

        refresh() {

            var folders = JSON.parse(localStorage.getItem('config')).musicFolders;

            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REFRESH_START
            });

            // Start the big thing
            app.db.remove({ }, { multi: true }, function (err, numRemoved) {
                app.db.loadDatabase(function (err) {
                    if(err) throw err;
                    else {

                        var filesList = [];

                        // Loop through folders
                        folders.forEach(function(folder, index, folders) {
                            // Get the list of files
                            filesList = filesList.concat(walkSync(folder, { directories: false }).map((d) =>  path.join(folder, d)));
                        });

                        var filesListFiltered = [];

                        // Get the metadatas of all the files
                        filesList.forEach((file, i) => {
                            if(app.supportedFormats.indexOf(mime.lookup(file)) > -1) filesListFiltered.push(file);
                        });

                        // Fake sync async loop
                        (function forloop(i){
                            if(i < filesListFiltered.length) {

                                var file   = filesListFiltered[i];
                                var stream = fs.createReadStream(file);

                                // store in DB here
                                mmd(stream, { duration: true }, function (err, metadata) {

                                    AppActions.settings.refreshProgress(parseInt(i * 100 / filesListFiltered.length));

                                    forloop(i + 1);
                                    if (err) console.warn('An error occured while reading ' + file + ' id3 tags: ' + err);

                                    delete metadata.picture;
                                    metadata.path = file;
                                    metadata.lArtist = metadata.artist.length === 0 ? ['unknown artist'] : metadata.artist[0].toLowerCase();

                                    if(metadata.artist.length === 0) metadata.artist = ['Unknown artist'];
                                    if(metadata.album === null || metadata.album === '') metadata.album = 'Unknown';
                                    if(metadata.title === null || metadata.title === '') metadata.title = path.parse(file).base;
                                    if(metadata.duration == '') metadata.duration = 0;

                                    // Let's insert in the data
                                    app.db.insert(metadata, function (err, newDoc) {
                                        if(err) throw err;
                                        if(i === filesListFiltered.length - 1) {
                                            AppActions.getTracks();
                                            AppDispatcher.dispatch({
                                                actionType : AppConstants.APP_LIBRARY_REFRESH_END
                                            });
                                        }
                                    });
                                });
                            }
                        })(0);
                    }
                });
            });
        }
    },

    settings: {

        checkTheme: function() {
            var themeName = JSON.parse(localStorage.getItem('config')).theme;
            document.querySelector('body').classList.add('theme-' + themeName);
        },

        toggleDarkTheme: function() {

            var config   = JSON.parse(localStorage.getItem('config'));

            var theme = config.theme === 'light' ? 'dark' : 'light';

            document.querySelector('body').classList.remove('theme-' + config.theme);
            document.querySelector('body').classList.add('theme-' + theme);

            config.theme = theme;

            localStorage.setItem('config', JSON.stringify(config));

            AppDispatcher.dispatch({
                actionType : AppConstants.APP_REFRESH_CONFIG
            });
        },

        checkDevMode: function() {
            if(JSON.parse(localStorage.getItem('config')).devMode) app.browserWindows.main.openDevTools();
        },

        toggleDevMode: function() {

            var config  = JSON.parse(localStorage.getItem('config'));

            config.devMode = !config.devMode;

            // Open dev tools if needed
            if(config.devMode) app.browserWindows.main.openDevTools();
            else app.browserWindows.main.closeDevTools();

            localStorage.setItem('config', JSON.stringify(config));

            AppDispatcher.dispatch({
                actionType : AppConstants.APP_REFRESH_CONFIG
            });
        },

        refreshProgress: function(percentage) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REFRESH_PROGRESS,
                percentage : percentage
            });
        }
    }
};

export default AppActions;
<commit_msg>Fix audio stop playing when opening dialog<commit_after>import AppDispatcher from '../dispatcher/AppDispatcher';
import AppConstants  from '../constants/AppConstants';

import app from '../constants/app.js';

import mmd      from 'musicmetadata';
import fs       from 'fs';
import path     from 'path';
import mime     from 'mime';
import walkSync from 'walk-sync';

import remote from 'remote';

var globalShortcut = remote.require('global-shortcut');
var dialog         = remote.require('dialog');

var AppActions = {

    init: function() {

        // Usual tasks
        this.app.start();
        this.getTracks();
        this.settings.checkTheme();
        this.settings.checkDevMode();
        this.app.initShortcuts();

        // Prevent some events
        window.addEventListener('dragover', function (e) {
            e.preventDefault();
        }, false);

        window.addEventListener('drop', function (e) {
            e.preventDefault();
        }, false);

        // Remember dimensions and positionning
        var currentWindow = app.browserWindows.main;

        currentWindow.on('resize', function() {
            AppActions.app.saveBounds();
        });

        currentWindow.on('move', function() {
            AppActions.app.saveBounds();
        });
    },

    /**
     * Refresh the library
     */
    getTracks: function() {
        app.db.find({}).sort({ 'lArtist': 1, 'year': 1, 'album': 1, 'disk': 1, 'track.no': 1 }).exec(function (err, tracks) {
            if (err) throw err;
            else {
                AppDispatcher.dispatch({
                    actionType : AppConstants.APP_REFRESH_LIBRARY,
                    tracks     : tracks
                });
            }
        });
    },

    /**
     * Select and play a track
     */
    selectAndPlay: function(id) {

        AppDispatcher.dispatch({
            actionType : AppConstants.APP_SELECT_AND_PLAY,
            id         : id
        });
    },

    /**
     * Search
     */
    filterSearch: function(search) {

        AppDispatcher.dispatch({
            actionType : AppConstants.APP_FILTER_SEARCH,
            search     : search
        });
    },

    app: {

        start: function() {
            var bounds        = app.initialConfig.bounds;
            var currentWindow = app.browserWindows.main;
            currentWindow.setBounds(bounds);
            currentWindow.show();
        },

        close: function() {
            app.browserWindows.main.close();
        },

        saveBounds: function() {

            var self = AppActions;
            var now = window.performance.now();

            if (now - self.lastFilterSearch < 250) {
                clearTimeout(self.filterSearchTimeOut);
            }

            self.lastFilterSearch = now;

            self.filterSearchTimeOut = setTimeout(() => {

                var currentWindow = app.browserWindows.main;
                var config        = JSON.parse(localStorage.getItem('config'));
                    config.bounds = currentWindow.getBounds();

                localStorage.setItem('config', JSON.stringify(config));
            }, 250);
        },

        initShortcuts: function() {

            // Global shortcuts
            globalShortcut.register('MediaPlayPause', function () {
                AppActions.player.playToggle();
            });

            globalShortcut.register('MediaPreviousTrack', function () {
                AppActions.player.previous();
            });

            globalShortcut.register('MediaNextTrack', function () {
                AppActions.player.next();
            });
        }
    },

    player: {

        toggle: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_TOGGLE
            });
        },

        play: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_PLAY
            });
        },

        pause: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_PAUSE
            });
        },

        stop: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_STOP
            });
        },

        next: function(e) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_NEXT,
                e          : e
            });
        },

        previous: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_PREVIOUS
            });
        },

        shuffle: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_SHUFFLE
            });
        },

        setVolume: function(volume) {
            app.audio.volume = volume;
            var config = JSON.parse(localStorage.getItem('config'));
                config.volume = volume;

            localStorage.setItem('config', JSON.stringify(config));
        },

        repeat: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_REPEAT
            });
        },

        jumpTo: function(to) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_PLAYER_JUMP_TO,
                to         : to
            });
        }
    },

    queue: {

        clear: function() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_CLEAR
            });
        },

        remove: function(index) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_REMOVE,
                index      : index
            });
        },

        add: function(selected) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_ADD,
                selected   : selected
            });
        },

        addNext: function(selected) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_ADD_NEXT,
                selected   : selected
            });
        },

        setPlaylist: function(playlist) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_QUEUE_SET_PLAYLIST,
                playlist   : playlist
            });
        }
    },

    library: {

        addFolders(folders) {

            dialog.showOpenDialog({ properties: ['openDirectory', 'multiSelections']}, (folders) => {
                if(folders !== undefined) {
                    AppDispatcher.dispatch({
                        actionType : AppConstants.APP_LIBRARY_ADD_FOLDERS,
                        folders    : folders
                    });
                }
            });
        },

        removeFolder(index) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REMOVE_FOLDER,
                index      : index
            });
        },

        reset() {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REFRESH_START,
            });

            app.db.remove({ }, { multi: true }, function (err, numRemoved) {
                app.db.loadDatabase(function (err) {
                    if(err) {
                        throw err
                    } else {
                        AppActions.getTracks();
                        AppDispatcher.dispatch({
                            actionType : AppConstants.APP_LIBRARY_REFRESH_END,
                        });
                    }
                });
            });
        },

        refresh() {

            var folders = JSON.parse(localStorage.getItem('config')).musicFolders;

            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REFRESH_START
            });

            // Start the big thing
            app.db.remove({ }, { multi: true }, function (err, numRemoved) {
                app.db.loadDatabase(function (err) {
                    if(err) throw err;
                    else {

                        var filesList = [];

                        // Loop through folders
                        folders.forEach(function(folder, index, folders) {
                            // Get the list of files
                            filesList = filesList.concat(walkSync(folder, { directories: false }).map((d) =>  path.join(folder, d)));
                        });

                        var filesListFiltered = [];

                        // Get the metadatas of all the files
                        filesList.forEach((file, i) => {
                            if(app.supportedFormats.indexOf(mime.lookup(file)) > -1) filesListFiltered.push(file);
                        });

                        // Fake sync async loop
                        (function forloop(i){
                            if(i < filesListFiltered.length) {

                                var file   = filesListFiltered[i];
                                var stream = fs.createReadStream(file);

                                // store in DB here
                                mmd(stream, { duration: true }, function (err, metadata) {

                                    AppActions.settings.refreshProgress(parseInt(i * 100 / filesListFiltered.length));

                                    forloop(i + 1);
                                    if (err) console.warn('An error occured while reading ' + file + ' id3 tags: ' + err);

                                    delete metadata.picture;
                                    metadata.path = file;
                                    metadata.lArtist = metadata.artist.length === 0 ? ['unknown artist'] : metadata.artist[0].toLowerCase();

                                    if(metadata.artist.length === 0) metadata.artist = ['Unknown artist'];
                                    if(metadata.album === null || metadata.album === '') metadata.album = 'Unknown';
                                    if(metadata.title === null || metadata.title === '') metadata.title = path.parse(file).base;
                                    if(metadata.duration == '') metadata.duration = 0;

                                    // Let's insert in the data
                                    app.db.insert(metadata, function (err, newDoc) {
                                        if(err) throw err;
                                        if(i === filesListFiltered.length - 1) {
                                            AppActions.getTracks();
                                            AppDispatcher.dispatch({
                                                actionType : AppConstants.APP_LIBRARY_REFRESH_END
                                            });
                                        }
                                    });
                                });
                            }
                        })(0);
                    }
                });
            });
        }
    },

    settings: {

        checkTheme: function() {
            var themeName = JSON.parse(localStorage.getItem('config')).theme;
            document.querySelector('body').classList.add('theme-' + themeName);
        },

        toggleDarkTheme: function() {

            var config   = JSON.parse(localStorage.getItem('config'));

            var theme = config.theme === 'light' ? 'dark' : 'light';

            document.querySelector('body').classList.remove('theme-' + config.theme);
            document.querySelector('body').classList.add('theme-' + theme);

            config.theme = theme;

            localStorage.setItem('config', JSON.stringify(config));

            AppDispatcher.dispatch({
                actionType : AppConstants.APP_REFRESH_CONFIG
            });
        },

        checkDevMode: function() {
            if(JSON.parse(localStorage.getItem('config')).devMode) app.browserWindows.main.openDevTools();
        },

        toggleDevMode: function() {

            var config  = JSON.parse(localStorage.getItem('config'));

            config.devMode = !config.devMode;

            // Open dev tools if needed
            if(config.devMode) app.browserWindows.main.openDevTools();
            else app.browserWindows.main.closeDevTools();

            localStorage.setItem('config', JSON.stringify(config));

            AppDispatcher.dispatch({
                actionType : AppConstants.APP_REFRESH_CONFIG
            });
        },

        refreshProgress: function(percentage) {
            AppDispatcher.dispatch({
                actionType : AppConstants.APP_LIBRARY_REFRESH_PROGRESS,
                percentage : percentage
            });
        }
    }
};

export default AppActions;
<|endoftext|>


<commit_before>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import TransitionGroup from 'react-addons-transition-group';
import classnames from 'classnames';

const CLASS_ROOT = 'animate';

class AnimateChild extends Component {
  constructor (props) {
    super(props);
    this.state = {
      enterClass: '',
      leaveClass: ''
    };
  }

  componentWillAppear (callback) {
    this.enter(callback);
  }

  componentWillEnter (callback) {
    this.enter(callback);
  }

  componentDidAppear () {
    this.entered();
  }

  componentDidEnter () {
    this.entered();
  }

  componentWillLeave (callback) {
    this.leave(callback);
  }

  enter (callback) {
    const {
      enter: {
        animation: enterAnimation,
        delay
      },
      leave: {
        animation: leaveAnimation
      }
    } = this.props;
    const node = ReactDOM.findDOMNode(this);

    const enterClass = enterAnimation;
    const leaveClass = leaveAnimation || enterAnimation;
    this.setState({enterClass});
    this.setState({leaveClass});

    node.style.transitionDuration = '';
    node.classList.remove('animate', `${leaveClass}--leave`);
    node.classList.add(`${enterClass}--enter`);
    setTimeout(callback, delay);
  }

  entered () {
    const { enter: { duration } } = this.props;
    const node = ReactDOM.findDOMNode(this);
    const enterClass = this.state.enterClass;
    node.classList.remove(`${enterClass}--enter`);
    if (duration) {
      node.style.transitionDuration = `${duration}ms`;
    }
    node.classList.add('animate', `${enterClass}--enter-active`);
    setTimeout(() => {
      node.style.transitionDuration = '';
      node.classList.remove('animate');
    }, parseFloat(getComputedStyle(node).transitionDuration) * 1000);
  }

  leave (callback) {
    const { leave: { duration, delay } } = this.props;
    const node = ReactDOM.findDOMNode(this);

    if (duration) {
      node.style.transitionDuration = `${duration}ms`;
    }

    return setTimeout(() => {
      node.classList.remove(`${this.state.enterClass}--enter-active`);
      node.classList.add('animate', `${this.state.leaveClass}--leave`);
      setTimeout(callback, parseFloat(getComputedStyle(node).transitionDuration) * 1000);
    }, delay);
  }

  render () {
    return this.props.children;
  }
};

AnimateChild.defaultProps = {
  enter: {},
  leave: {}
};

class Animate extends Component {
  constructor (props) {
    super(props);
    this.state = {
      animationState: 'enter',
      animation: props.enter.animation
    };
  }

  componentWillReceiveProps (nextProps) {
    const { visible, keep } = this.props;
    const { animationState } = this.state;

    if (keep && visible !== nextProps.visible) {
      let state = '';
      if (!nextProps.visible) {
        state = (animationState === 'leave') ? 'enter' : 'leave';
      }
      this.setState({
        animationState: state,
        animation: state ? nextProps[state].animation : ''
      });

      // Reset animation state back to enter after leave animation is finished
      if (state === 'leave') {
        const node = ReactDOM.findDOMNode(this);
        clearTimeout(this.animationTimer);
        this.animationTimer = setTimeout(() => {
          this.setState({
            animationState: 'enter',
            animation: nextProps.enter.animation
          });
        }, (parseFloat(getComputedStyle(node).transitionDuration) +
        parseFloat(getComputedStyle(node).transitionDelay)) * 1000);
      }
    }
  }

  render () {
    const {
      enter,
      leave,
      className,
      children,
      component,
      visible,
      keep,
      style,
      ...props
    } = this.props;

    const animateChildren = React.Children.map(children, (child, index) => {
      const key = (child && child.key) ? child.key : `animate-${index}`;
      return (
        <AnimateChild
          key={key}
          enter={enter}
          leave={leave}
        >
          {child}
        </AnimateChild>
      );
    });

    let classes = className;
    let styles = {...style};
    if (keep) {
      classes = classnames(
        CLASS_ROOT,
        className,
        {
          [`${this.state.animation}--${this.state.animationState}`]: !visible
        }
      );
      styles = {
        ...style,
        transitionDuration: `${enter.duration}ms`,
        transitionDelay: `${enter.delay}ms`
      };
    }

    return (
      <TransitionGroup
        {...props}
        className={classes}
        component={component}
        style={styles}
      >
        {(visible || visible === undefined || keep) &&
          animateChildren
        }
      </TransitionGroup>
    );
  }
};

export default Animate;
<commit_msg>Check node exists before changing properties<commit_after>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import TransitionGroup from 'react-addons-transition-group';
import classnames from 'classnames';

const CLASS_ROOT = 'animate';

class AnimateChild extends Component {
  constructor (props) {
    super(props);
    this.state = {
      enterClass: '',
      leaveClass: ''
    };
  }

  componentWillAppear (callback) {
    this.enter(callback);
  }

  componentWillEnter (callback) {
    this.enter(callback);
  }

  componentDidAppear () {
    this.entered();
  }

  componentDidEnter () {
    this.entered();
  }

  componentWillLeave (callback) {
    this.leave(callback);
  }

  enter (callback) {
    const {
      enter: {
        animation: enterAnimation,
        delay
      },
      leave: {
        animation: leaveAnimation
      }
    } = this.props;
    const node = ReactDOM.findDOMNode(this);

    const enterClass = enterAnimation;
    const leaveClass = leaveAnimation || enterAnimation;
    this.setState({enterClass});
    this.setState({leaveClass});

    if (node) {
      node.style.transitionDuration = '';
      node.classList.remove('animate', `${leaveClass}--leave`);
      node.classList.add(`${enterClass}--enter`);
      setTimeout(callback, delay);
    }
  }

  entered () {
    const { enter: { duration } } = this.props;
    const node = ReactDOM.findDOMNode(this);
    const enterClass = this.state.enterClass;
    node.classList.remove(`${enterClass}--enter`);
    if (duration) {
      node.style.transitionDuration = `${duration}ms`;
    }
    node.classList.add('animate', `${enterClass}--enter-active`);
    setTimeout(() => {
      node.style.transitionDuration = '';
      node.classList.remove('animate');
    }, parseFloat(getComputedStyle(node).transitionDuration) * 1000);
  }

  leave (callback) {
    const { leave: { duration, delay } } = this.props;
    const node = ReactDOM.findDOMNode(this);

    if (duration) {
      node.style.transitionDuration = `${duration}ms`;
    }

    return setTimeout(() => {
      node.classList.remove(`${this.state.enterClass}--enter-active`);
      node.classList.add('animate', `${this.state.leaveClass}--leave`);
      setTimeout(callback, parseFloat(getComputedStyle(node).transitionDuration) * 1000);
    }, delay);
  }

  render () {
    return this.props.children;
  }
};

AnimateChild.defaultProps = {
  enter: {},
  leave: {}
};

class Animate extends Component {
  constructor (props) {
    super(props);
    this.state = {
      animationState: 'enter',
      animation: props.enter.animation
    };
  }

  componentWillReceiveProps (nextProps) {
    const { visible, keep } = this.props;
    const { animationState } = this.state;

    if (keep && visible !== nextProps.visible) {
      let state = '';
      if (!nextProps.visible) {
        state = (animationState === 'leave') ? 'enter' : 'leave';
      }
      this.setState({
        animationState: state,
        animation: state ? nextProps[state].animation : ''
      });

      // Reset animation state back to enter after leave animation is finished
      if (state === 'leave') {
        const node = ReactDOM.findDOMNode(this);
        clearTimeout(this.animationTimer);
        this.animationTimer = setTimeout(() => {
          this.setState({
            animationState: 'enter',
            animation: nextProps.enter.animation
          });
        }, (parseFloat(getComputedStyle(node).transitionDuration) +
        parseFloat(getComputedStyle(node).transitionDelay)) * 1000);
      }
    }
  }

  render () {
    const {
      enter,
      leave,
      className,
      children,
      component,
      visible,
      keep,
      style,
      ...props
    } = this.props;

    const animateChildren = React.Children.map(children, (child, index) => {
      const key = (child && child.key) ? child.key : `animate-${index}`;
      return (
        <AnimateChild
          key={key}
          enter={enter}
          leave={leave}
        >
          {child}
        </AnimateChild>
      );
    });

    let classes = className;
    let styles = {...style};
    if (keep) {
      classes = classnames(
        CLASS_ROOT,
        className,
        {
          [`${this.state.animation}--${this.state.animationState}`]: !visible
        }
      );
      styles = {
        ...style,
        transitionDuration: `${enter.duration}ms`,
        transitionDelay: `${enter.delay}ms`
      };
    }

    return (
      <TransitionGroup
        {...props}
        className={classes}
        component={component}
        style={styles}
      >
        {(visible || visible === undefined || keep) &&
          animateChildren
        }
      </TransitionGroup>
    );
  }
};

export default Animate;
<|endoftext|>


<commit_before>import React from 'react';
import Header from '../header/common-header';
import Footer from '../footer/footer';
import { connect } from "react-redux";
import { updateHeader, getBikeData, filterBikeDataRoot } from "../../redux/actions/update-header-actions"
import { bindActionCreators } from "redux";

class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {};
    };
    //=== Mounting lifecycle
    componentWillMount() {
        //console.log("componentWillMount")
    };
    componentDidMount() {
        //console.log("componentDidMount");
    };
    //=== Update lifecycle
    componentWillReceiveProps(nextProps) {
        // console.log("componentWillReceiveProps: nextProps ",nextProps)
    };
    // shouldComponentUpdate() {
    //     //console.log("shouldComponentUpdate");
    // };
    componentWillUpdate() {
        //console.log("componentWillUpdate");
    };
    //=== Unmount lifecycle
    componentWillUnmount() {
        //console.log("componentWillUnmount");
    };
    componentDidUpdate() {
        //console.log("componentDidUpdate");
    };
    //----
    onButtonClick() {
        this.props.updateHeader("new header " + String(Math.ceil(Math.random() * 100)));
    }

    filterBikeData() {
        this.props.filterBikeDataRoot("description", "" )
    }

    //=== Render
    render() {
        return (

Main App: {this.props.state.header}

                    <button className="btn btn-default" onClick={this.onButtonClick.bind(this)}>Update header</button>
                    <button className="btn btn-default" onClick={this.props.getBikeData}>Get bike crime stats</button>
                    <button className="btn btn-default" onClick={this.filterBikeData.bind(this)}>filter bike crime stats</button>

                    { this.props.state.bikeCrime.map((d,i)=>{
                        return (

{ d.title }

)
                    }) }

        );
    }
}

const mapStateToProps = (state) => {
    return { state: state }
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        updateHeader: updateHeader ,
        getBikeData : getBikeData,
        filterBikeDataRoot: filterBikeDataRoot
    }, dispatch);
}

// Default state and props
App.defaultProps = {};

export default connect(mapStateToProps, mapDispatchToProps)(App);<commit_msg>Added the redered filtered data from the reducer.<commit_after>import React from 'react';
import Header from '../header/common-header';
import Footer from '../footer/footer';
import { connect } from "react-redux";
import { updateHeader, getBikeData, filterBikeDataRoot } from "../../redux/actions/update-header-actions"
import { bindActionCreators } from "redux";

class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {};
    };
    //=== Mounting lifecycle
    componentWillMount() {
        //console.log("componentWillMount")
    };
    componentDidMount() {
        //console.log("componentDidMount");
    };
    //=== Update lifecycle
    componentWillReceiveProps(nextProps) {
        // console.log("componentWillReceiveProps: nextProps ",nextProps)
    };
    // shouldComponentUpdate() {
    //     //console.log("shouldComponentUpdate");
    // };
    componentWillUpdate() {
        //console.log("componentWillUpdate");
    };
    //=== Unmount lifecycle
    componentWillUnmount() {
        //console.log("componentWillUnmount");
    };
    componentDidUpdate() {
        //console.log("componentDidUpdate");
    };
    //----
    onButtonClick() {
        this.props.updateHeader("new header " + String(Math.ceil(Math.random() * 100)));
    }

    filterBikeData() {
        this.props.filterBikeDataRoot("description", "" )
    }

    //=== Render
    render() {
        return (

Main App: {this.props.state.header}

                    <button className="btn btn-default" onClick={this.onButtonClick.bind(this)}>Update header</button>
                    <button className="btn btn-default" onClick={this.props.getBikeData}>Get bike crime stats</button>
                    <button className="btn btn-default" onClick={this.filterBikeData.bind(this)}>filter bike crime stats</button>

                    { this.props.state.bikeCrimeFiltered.map((d,i)=>{
                        return (

filtered: { d.title }

)
                    }) }

                    { this.props.state.bikeCrime.map((d,i)=>{
                        return (

{ d.title }

)
                    }) }

        );
    }
}

const mapStateToProps = (state) => {
    return { state: state }
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        updateHeader,
        getBikeData,
        filterBikeDataRoot
    }, dispatch);
}

// Default state and props
App.defaultProps = {};

export default connect(mapStateToProps, mapDispatchToProps)(App);<|endoftext|>


<commit_before>var display = function() {

  var duration = 1000;
  var increment = 10;
  var fontSize = 54;
  var valueKey = 0;
  var segmentPath = [];
  var devices = ['desktop','mobile','tablet'];
  var colors = {
    'desktop': [
      '#b56969',
      '#F58F8F',
      '#6E4040',
      '#A66161',
      '#6E2A27',
      '#B54641',
      '#F55E58',
      '#9B3C38',
      '#F57F90',
      '#6E3940'
    ],
    'mobile':[
      '#3fb0ac',
      '#56F0EB',
      '#369693',
      '#256966',
      '#1F9BB0',
      '#2AD4F0',
      '#1A8596',
      '#125C69',
      '#38B0AB',
      '#4DF0E9',
      '#216966'
    ],
    'tablet':[
      '#e6cf8b',
      '#FFE59A',
      '#CCB87C',
      '#9F8F60',
      '#E6D074',
      '#FFE79C',
      '#E6D77F',
      '#FFEE8C',
      '#9F9457',
      '#D7C976'
    ]
  };
  var maxAmount = 0;
  var levels = [
    'all',
    'device',
    'browser',
    'age',
    'version'
  ];

  var init = function() {
    registerEvents();
    document.querySelector('[data-js-container]').classList.add('mode--all');
  };

  var registerEvents = function() {
    // CLICK ON BACKGROUND
    document.querySelector('[data-js-background-click]').addEventListener('click', function(e) {
      back(e);
    });
    // CLICK ON RADAR
    document.querySelector('[data-js-container]').addEventListener('click', function(e){
      if (currentMode() !== 'all') {
        return;
      }
      var target = e.target;
      if (target.matches('[data-js-radar]') || target.closest('[data-js-radar]')) {
        e.stopPropagation();
        modeToggle(target.closest('[data-js-radar]'),'device',false);
      }
    });
    // CLICK ON ARC
    document.querySelector('[data-js-container]').addEventListener('click', function(e){
      if (currentMode() === 'all') {
        return;
      }
      var target = e.target.closest('[data-js-radar-arc-grp]');
      if (target) {
        e.stopPropagation();

        var pie = target.closest('[data-js-radar]');
        var viewId = pie.id;
        var arc = target.querySelector('[data-js-arc-thismode]');
        var thisMode = arc.getAttribute('data-js-arc-thismode');
        var nextMode = arc.getAttribute('data-js-arc-nextmode');
        var segment = arc.getAttribute('data-js-arc-segment');
        // end of the line?
        if (nextMode === 'undefined') {
          return;
        }
        // no further data?
        var radarChildren = radarFromPath(viewId,segmentPath);
        radarChildren = radarChildren[segment];
        var radarChildrenKeys = Object.keys(radarChildren);
        if (!radarChildrenKeys.length || radarChildrenKeys.length === 1) {
          return;
        }
        // remove other active arcs
        if( pie.querySelector('[data-js-radar-g-' + thisMode + '-arcs] .radar__arc__grp--active')) {
            pie.querySelector('[data-js-radar-g-' + thisMode + '-arcs] .radar__arc__grp--active').classList.remove('radar__arc__grp--active');
        }
        target.classList.add('radar__arc__grp--active');
        // run the mode change
        modeToggle(pie,nextMode,segment)
        // then start the build of the next mode
        .then(function() {
          segmentPath.push(segment);
          buildAllArcs(pie.id,nextMode,segmentPath);
        });
      }
    });
  };

  var back = function(e) {
    var mode = currentMode();
    if (mode === 'device') {
      modeToggle(null,'all');
    } else if (mode === 'browser') {
      segmentPath.pop();
      modeToggle(null,'device').then(function() {
        killAllArcs(mode);
      });
    } else {
      segmentPath.pop();
      var nextMode = levels[levels.indexOf(mode) - 1] || 'all';
      modeToggle(null,nextMode,segmentPath).then(function() {
        killAllArcs(mode);
      });
    }
  };

  var radarFromPath = function(viewId,path) {
    var output = radar[viewId];
    for(var i=0; i<path.length; i++) {
      output = output[path[i]];
    }
    return output;
  };

  var buildPie = function(viewIndex) {

    var view = gaConfig.views[viewIndex];
    var viewId = view.abbr;
    var totalAmount = radar[viewId].TOTAL[valueKey];

    var svgEl = drawSVG(viewId,totalAmount,maxAmount);
    if (svgEl) {
      document.querySelector('[data-js-container]').appendChild(svgEl);
      buildAllArcs(viewId);
      buildPieText(viewIndex);
    }

  };

  var buildAllArcs = function(viewId,nextMode,path) {

    var pathLevel = nextMode || 'device';
    var prevLevel = levels[levels.indexOf(pathLevel)-1];
    var pathChildren = path || [];
    var device = ( pathChildren.length ? pathChildren[0] : null );
    var timeDuration = 500;
    var radarChildren = radarFromPath(viewId,pathChildren);
    var totalAmount = radarChildren.TOTAL[valueKey];
    var angleAllStart = -90;
    var angleAllArc = 360;

    if (path !== undefined && path.length) {
      var triggerArc = document.querySelector('#' + viewId + ' #radar-arc-' + prevLevel + '-' + path[path.length - 1].replace(/ /g,'-'));
      if (triggerArc) {
        angleAllStart = parseFloat(triggerArc.getAttribute('data-js-arc-angle-start'));
        angleAllArc = parseFloat(triggerArc.getAttribute('data-js-arc-angle-arc'));
      }
    }

    // SORT
    var radarChildrenSorted = [];
    var radarChildrenSortedOther = null;
    for(var key in radarChildren) {
      // if there's an "other" slice, reserve it for the end
      if (key === 'OTHER') {
        radarChildrenSortedOther = {
          'key': key,
          'TOTAL': radarChildren[key].TOTAL[valueKey]
        };
        continue;
      } else if (key !== 'TOTAL' && key !== 'MAX' && radarChildren[key].TOTAL[valueKey] > 0) {
        radarChildrenSorted.push({
          'key': key,
          'TOTAL': radarChildren[key].TOTAL[valueKey]
        });
      }
    }
    radarChildrenSorted.sort(function compare(a,b) {
      if (a.TOTAL < b.TOTAL)
        return 1;
      if (a.TOTAL > b.TOTAL)
        return -1;
      return 0;
    });
    // re-attach the "other" slice
    if (radarChildrenSortedOther) {
      radarChildrenSorted.push(radarChildrenSortedOther);
    }

    // loop through the sorted data
    var i = 0;
    var buildAllArcsLoop = function(degNew) {
      arc = radarChildrenSorted.shift();
      if(!arc) {
        return;
      }
      var angleArc = ( ( arc.TOTAL/totalAmount ) * angleAllArc );
      // if the angle is too small, continue
      if (angleArc < 1 && radarChildrenSorted.length) {
        buildAllArcsLoop(degNew);
      }
      var config = {
        'viewId'              : viewId,
        'arcThisMode'         : pathLevel,
        'arcNextMode'         : levels[levels.indexOf(pathLevel) + 1],
        'arcSelector'         : arc.key,
        'arcAmount'         : arc.TOTAL,
        'totalAmount'       : totalAmount,
        'angleStart'          : degNew || angleAllStart,
        'angleArc'            : angleArc,
        'timeStart'           : 0,
        'timeDuration'        : Math.round(arc.TOTAL/totalAmount * timeDuration),
        'color'               : ( !device ? colors[arc.key][0] : colors[device][i] ),
        'labelTitle'          : arc.key,
        'labelValTotal'       : arc.TOTAL,
        'labelValTotalPerc'   : radar[viewId].TOTAL,
        'labelValDevicePerc'  : ( device ? radar[viewId][device].TOTAL : null )
      };
      buildArc(config).then(function(val) {
        i++;
        if (radarChildrenSorted.length) {
          buildAllArcsLoop(val);
        }
      });
    };
    buildAllArcsLoop();

  };

  var buildArc = function(options) {

    return new Promise(function(resolve, reject) {

      if (options.angleArc < 1) {
        resolve(options.angleStart);
        return;
      }

      viewId            = options.viewId;
      level             = options.level;
      arcId             = options.arcId;
      arcThisMode       = options.arcThisMode;
      arcNextMode       = options.arcNextMode;
      arcSelector       = options.arcSelector;
      arcAmount       = options.arcAmount;
      totalAmount     = options.totalAmount;
      timeStart         = options.timeStart;
      timeDuration      = options.timeDuration;
      angleStart        = options.angleStart || 0;
      angleArc          = options.angleArc;
      color             = options.color || 'red';

      var config = {
        'viewId': viewId,
        'arcId': arcId,
        'arcThisMode': arcThisMode,
        'arcNextMode': arcNextMode,
        'arcSelector': arc.key,
        'arcSelector': arcSelector,
        'color': color,
        'angleStart': angleStart,
        'angleArc': angleArc,
        'timeStart': 0,
        'timeDuration': timeDuration
      };
      drawSVGArc(config).then(function(angle) {
        resolve(angle);
      });
    });
  };

  var buildPieText = function(viewIndex) {

    var view = gaConfig.views[viewIndex];
    var viewId = view.abbr;

    drawSVGText(viewIndex,'title');
    drawSVGText(viewIndex,'value',radar[viewId].TOTAL[valueKey]);

  };

  var buildAll = function() {

    console.log('build');

    // clear ballpit
    ballpit.killBalls();

    // start the ballpit animation timer
    ballpit.start();

    // find the type of value we're looking for
    getValueType();

    // find max amount
    calcMaxAmount();

    // create the SVG for each view
    for (i=0; i<gaConfig.views.length;i++) {
      buildPie(i);
      ballpit.addBall(gaConfig.views[i].abbr);
    }

  };

  var getValueType = function() {
    var controlValue = document.querySelector('[data-js-control-value]:checked');
    valueKey = controlValue.value;
  };

  var calcMaxAmount = function() {
    maxAmount = 0;
    for (var key in radar) {
      if (radar[key].TOTAL[valueKey] > maxAmount) {
        maxAmount = radar[key].TOTAL[valueKey];
      }
    }
  };

  var killAll = function() {

    var svgs = document.querySelectorAll('[data-js-radar]');
    for (var i=0; i<svgs.length;i++) {
      svgs[i].parentNode.removeChild(svgs[i]);
    }

  };

  var killAllArcs = function(arcLevel) {

    var pie = document.querySelector('.radar--active');
    if (pie) {
      var arcGrps = pie.querySelectorAll('[data-js-radar-arc-grp-' + arcLevel + ']');
      for(var i=0; i<arcGrps.length; i++) {
        arcGrps[i].parentNode.removeChild(arcGrps[i]);
      }
      var arcDefs = pie.querySelectorAll('[data-js-radar-arcdef-' + arcLevel + ']');
      for(i=0; i<arcDefs.length; i++) {
        arcDefs[i].parentNode.removeChild(arcDefs[i]);
      }
    }

  };

  var currentMode = function() {
    var allClasses = document.querySelector('[data-js-container]').classList;
    var modeClasses = [];
    allClasses = Array.prototype.slice.call(allClasses, 0);
    modeClasses = allClasses.map(function(cssClass){
      return (cssClass.indexOf('mode') >= 0 ? cssClass : false );
    });
    return modeClasses.join('').replace(/false/g,'').replace('mode--','');
  };

  var modeToggleTimer = null;
  var modeToggleClass = function(modeNew) {

    return new Promise(function(resolve, reject) {

      clearTimeout(modeToggleTimer);

      modeToggleTimer = setTimeout(function() {
        for (var i=0; i<levels.length; i++) {
          if (levels[i] === modeNew) {
            document.querySelector('[data-js-container]').classList.add('mode--' + levels[i]);
          } else {
            document.querySelector('[data-js-container]').classList.remove('mode--' + levels[i]);
          }
        }
        resolve(true);
      },50);
    });

  };

  var modeToggle = function(target,nextMode,segment) {

    var oldMode = currentMode();

    return new Promise(function(resolve, reject) {

      // LEAVING ALL
      if (oldMode === 'all' && nextMode !== 'all') {
        target.classList.add('radar--active');
        ballpit.stop();
        resolve(true);
      // ENTERING ALL
      } else if (nextMode === 'all') {
        var activeRadar = document.querySelector('.radar--active');
        if (activeRadar) {
          activeRadar.classList.remove('radar--active');
          ballpit.start();
        }
        resolve(true);
      // entering and leaving all other modes
      } else {
        var transformingElement = document.querySelector('[data-js-radar-g-' + oldMode + '-arcs]');
        if (transformingElement) {
          var radarTransition = function() {
            resolve(true);
            transformingElement.removeEventListener('transitionend',radarTransition);
          };
          transformingElement.addEventListener('transitionend',radarTransition);
        }
      }
      modeToggleClass(nextMode);

    });

  };

  return {
    init: init(),
    buildPie: buildPie,
    buildAll: buildAll,
    killAll: killAll,
    modeToggle: modeToggle
  };

}();<commit_msg>display: minor refactor<commit_after>var display = function() {

  var duration = 1000;
  var increment = 10;
  var fontSize = 54;
  var valueKey = 0;
  var segmentPath = [];
  var devices = ['desktop','mobile','tablet'];
  var colors = {
    'desktop': [
      '#b56969',
      '#F58F8F',
      '#6E4040',
      '#A66161',
      '#6E2A27',
      '#B54641',
      '#F55E58',
      '#9B3C38',
      '#F57F90',
      '#6E3940'
    ],
    'mobile':[
      '#3fb0ac',
      '#56F0EB',
      '#369693',
      '#256966',
      '#1F9BB0',
      '#2AD4F0',
      '#1A8596',
      '#125C69',
      '#38B0AB',
      '#4DF0E9',
      '#216966'
    ],
    'tablet':[
      '#e6cf8b',
      '#FFE59A',
      '#CCB87C',
      '#9F8F60',
      '#E6D074',
      '#FFE79C',
      '#E6D77F',
      '#FFEE8C',
      '#9F9457',
      '#D7C976'
    ]
  };
  var maxAmount = 0;
  var levels = [
    'all',
    'device',
    'browser',
    'age',
    'version'
  ];

  var init = function() {
    registerEvents();
    document.querySelector('[data-js-container]').classList.add('mode--all');
  };

  var registerEvents = function() {
    // CLICK ON BACKGROUND
    document.querySelector('[data-js-background-click]').addEventListener('click', function(e) {
      back(e);
    });
    // CLICK ON RADAR
    document.querySelector('[data-js-container]').addEventListener('click', function(e){
      if (currentMode() !== 'all') {
        return;
      }
      var target = e.target;
      if (target.matches('[data-js-radar]') || target.closest('[data-js-radar]')) {
        e.stopPropagation();
        modeToggle(target.closest('[data-js-radar]'),'device',false);
      }
    });
    // CLICK ON ARC
    document.querySelector('[data-js-container]').addEventListener('click', function(e){
      if (currentMode() === 'all') {
        return;
      }
      var target = e.target.closest('[data-js-radar-arc-grp]');
      if (target) {
        e.stopPropagation();

        var pie = target.closest('[data-js-radar]');
        var viewId = pie.id;
        var arc = target.querySelector('[data-js-arc-thismode]');
        var thisMode = arc.getAttribute('data-js-arc-thismode');
        var nextMode = arc.getAttribute('data-js-arc-nextmode');
        var segment = arc.getAttribute('data-js-arc-segment');
        // end of the line?
        if (nextMode === 'undefined') {
          return;
        }
        // no further data?
        var radarChildren = radarFromPath(viewId,segmentPath);
        radarChildren = radarChildren[segment];
        var radarChildrenKeys = Object.keys(radarChildren);
        if (!radarChildrenKeys.length || radarChildrenKeys.length === 1) {
          return;
        }
        // remove other active arcs
        if( pie.querySelector('[data-js-radar-g-' + thisMode + '-arcs] .radar__arc__grp--active')) {
            pie.querySelector('[data-js-radar-g-' + thisMode + '-arcs] .radar__arc__grp--active').classList.remove('radar__arc__grp--active');
        }
        target.classList.add('radar__arc__grp--active');
        // run the mode change
        modeToggle(pie,nextMode,segment)
        // then start the build of the next mode
        .then(function() {
          segmentPath.push(segment);
          buildAllArcs(pie.id,nextMode,segmentPath);
        });
      }
    });
  };

  var back = function(e) {
    var mode = currentMode();
    if (mode === 'device') {
      modeToggle(null,'all');
    } else if (mode === 'browser') {
      segmentPath.pop();
      modeToggle(null,'device').then(function() {
        killAllArcs(mode);
      });
    } else {
      segmentPath.pop();
      var nextMode = levels[levels.indexOf(mode) - 1] || 'all';
      modeToggle(null,nextMode,segmentPath).then(function() {
        killAllArcs(mode);
      });
    }
  };

  var radarFromPath = function(viewId,path) {
    var output = radar[viewId];
    for(var i=0; i<path.length; i++) {
      output = output[path[i]];
    }
    return output;
  };

  var buildPie = function(viewIndex) {

    var view = gaConfig.views[viewIndex];
    var viewId = view.abbr;
    var totalAmount = radar[viewId].TOTAL[valueKey];

    var svgEl = drawSVG(viewId,totalAmount,maxAmount);
    if (svgEl) {
      document.querySelector('[data-js-container]').appendChild(svgEl);
      buildAllArcs(viewId);
      buildPieText(viewIndex);
    }

  };

  var buildAllArcs = function(viewId,nextMode,path) {

    var pathLevel = nextMode || 'device';
    var prevLevel = levels[levels.indexOf(pathLevel)-1];
    var pathChildren = path || [];
    var device = ( pathChildren.length ? pathChildren[0] : null );
    var timeDuration = 500;
    var radarChildren = radarFromPath(viewId,pathChildren);
    var totalAmount = radarChildren.TOTAL[valueKey];
    var angleAllStart = -90;
    var angleAllArc = 360;

    if (path !== undefined && path.length) {
      var triggerArc = document.querySelector('#' + viewId + ' #radar-arc-' + prevLevel + '-' + path[path.length - 1].replace(/ /g,'-'));
      if (triggerArc) {
        angleAllStart = parseFloat(triggerArc.getAttribute('data-js-arc-angle-start'));
        angleAllArc = parseFloat(triggerArc.getAttribute('data-js-arc-angle-arc'));
      }
    }

    // SORT
    var radarChildrenSorted = [];
    var radarChildrenSortedOther = null;
    for(var key in radarChildren) {
      // if there's an "other" slice, reserve it for the end
      if (key === 'OTHER') {
        radarChildrenSortedOther = {
          'key': key,
          'TOTAL': radarChildren[key].TOTAL[valueKey]
        };
        continue;
      } else if (key !== 'TOTAL' && key !== 'MAX' && radarChildren[key].TOTAL[valueKey] > 0) {
        radarChildrenSorted.push({
          'key': key,
          'TOTAL': radarChildren[key].TOTAL[valueKey]
        });
      }
    }
    radarChildrenSorted.sort(function compare(a,b) {
      if (a.TOTAL < b.TOTAL)
        return 1;
      if (a.TOTAL > b.TOTAL)
        return -1;
      return 0;
    });
    // re-attach the "other" slice
    if (radarChildrenSortedOther) {
      radarChildrenSorted.push(radarChildrenSortedOther);
    }

    // loop through the sorted data
    var i = 0;
    var buildAllArcsLoop = function(degNew) {
      arc = radarChildrenSorted.shift();
      if(!arc) {
        return;
      }
      var angleArc = ( ( arc.TOTAL/totalAmount ) * angleAllArc );
      // if the angle is too small, continue
      if (angleArc < 1 && radarChildrenSorted.length) {
        buildAllArcsLoop(degNew);
      }
      var config = {
        'viewId'              : viewId,
        'arcThisMode'         : pathLevel,
        'arcNextMode'         : levels[levels.indexOf(pathLevel) + 1],
        'arcSelector'         : arc.key,
        'arcAmount'         : arc.TOTAL,
        'totalAmount'       : totalAmount,
        'angleStart'          : degNew || angleAllStart,
        'angleArc'            : angleArc,
        'timeStart'           : 0,
        'timeDuration'        : Math.round(arc.TOTAL/totalAmount * timeDuration),
        'color'               : ( !device ? colors[arc.key][0] : colors[device][i] ),
        'labelTitle'          : arc.key,
        'labelValTotal'       : arc.TOTAL,
        'labelValTotalPerc'   : radar[viewId].TOTAL,
        'labelValDevicePerc'  : ( device ? radar[viewId][device].TOTAL : null )
      };
      buildArc(config).then(function(val) {
        i++;
        if (radarChildrenSorted.length) {
          buildAllArcsLoop(val);
        }
      });
    };
    buildAllArcsLoop();

  };

  var buildArc = function(options) {

    return new Promise(function(resolve, reject) {

      if (options.angleArc < 1) {
        resolve(options.angleStart);
        return;
      }

      viewId            = options.viewId;
      level             = options.level;
      arcId             = options.arcId;
      arcThisMode       = options.arcThisMode;
      arcNextMode       = options.arcNextMode;
      arcSelector       = options.arcSelector;
      arcAmount       = options.arcAmount;
      totalAmount     = options.totalAmount;
      timeStart         = options.timeStart;
      timeDuration      = options.timeDuration;
      angleStart        = options.angleStart || 0;
      angleArc          = options.angleArc;
      color             = options.color || 'red';

      var config = {
        'viewId': viewId,
        'arcId': arcId,
        'arcThisMode': arcThisMode,
        'arcNextMode': arcNextMode,
        'arcSelector': arc.key,
        'arcSelector': arcSelector,
        'color': color,
        'angleStart': angleStart,
        'angleArc': angleArc,
        'timeStart': 0,
        'timeDuration': timeDuration
      };
      drawSVGArc(config).then(function(angle) {
        resolve(angle);
      });
    });
  };

  var buildPieText = function(viewIndex) {

    var view = gaConfig.views[viewIndex];
    var viewId = view.abbr;

    drawSVGText(viewIndex,'title');
    drawSVGText(viewIndex,'value',radar[viewId].TOTAL[valueKey]);

  };

  var buildAll = function() {

    console.log('build');

    // clear ballpit
    ballpit.killBalls();

    // start the ballpit animation timer
    ballpit.start();

    // find the type of value we're looking for
    getValueType();

    // find max amount
    calcMaxAmount();

    // create the SVG for each view
    for (i=0; i<gaConfig.views.length;i++) {
      buildPie(i);
      ballpit.addBall(gaConfig.views[i].abbr);
    }

  };

  var getValueType = function() {
    var controlValue = document.querySelector('[data-js-control-value]:checked');
    valueKey = controlValue.value;
  };

  var calcMaxAmount = function() {
    maxAmount = 0;
    for (var key in radar) {
      if (key === 'TOTAL') {
        continue;
      }
      if (radar[key].TOTAL[valueKey] > maxAmount) {
        maxAmount = radar[key].TOTAL[valueKey];
      }
    }
  };

  var killAll = function() {

    var svgs = document.querySelectorAll('[data-js-radar]');
    for (var i=0; i<svgs.length;i++) {
      svgs[i].parentNode.removeChild(svgs[i]);
    }

  };

  var killAllArcs = function(arcLevel) {

    var pie = document.querySelector('.radar--active');
    if (pie) {
      var arcGrps = pie.querySelectorAll('[data-js-radar-arc-grp-' + arcLevel + ']');
      for(var i=0; i<arcGrps.length; i++) {
        arcGrps[i].parentNode.removeChild(arcGrps[i]);
      }
      var arcDefs = pie.querySelectorAll('[data-js-radar-arcdef-' + arcLevel + ']');
      for(i=0; i<arcDefs.length; i++) {
        arcDefs[i].parentNode.removeChild(arcDefs[i]);
      }
    }

  };

  var currentMode = function() {
    var allClasses = document.querySelector('[data-js-container]').classList;
    var modeClasses = [];
    allClasses = Array.prototype.slice.call(allClasses, 0);
    modeClasses = allClasses.map(function(cssClass){
      return (cssClass.indexOf('mode') >= 0 ? cssClass : false );
    });
    return modeClasses.join('').replace(/false/g,'').replace('mode--','');
  };

  var modeToggleTimer = null;
  var modeToggleClass = function(modeNew) {

    return new Promise(function(resolve, reject) {

      clearTimeout(modeToggleTimer);

      modeToggleTimer = setTimeout(function() {
        for (var i=0; i<levels.length; i++) {
          if (levels[i] === modeNew) {
            document.querySelector('[data-js-container]').classList.add('mode--' + levels[i]);
          } else {
            document.querySelector('[data-js-container]').classList.remove('mode--' + levels[i]);
          }
        }
        resolve(true);
      },50);
    });

  };

  var modeToggle = function(target,nextMode,segment) {

    var oldMode = currentMode();

    return new Promise(function(resolve, reject) {

      // LEAVING ALL
      if (oldMode === 'all' && nextMode !== 'all') {
        target.classList.add('radar--active');
        ballpit.stop();
        resolve(true);
      // ENTERING ALL
      } else if (nextMode === 'all') {
        var activeRadar = document.querySelector('.radar--active');
        if (activeRadar) {
          activeRadar.classList.remove('radar--active');
          ballpit.start();
        }
        resolve(true);
      // entering and leaving all other modes
      } else {
        var transformingElement = document.querySelector('[data-js-radar-g-' + oldMode + '-arcs]');
        if (transformingElement) {
          var radarTransition = function() {
            resolve(true);
            transformingElement.removeEventListener('transitionend',radarTransition);
          };
          transformingElement.addEventListener('transitionend',radarTransition);
        }
      }
      modeToggleClass(nextMode);

    });

  };

  return {
    init: init(),
    buildPie: buildPie,
    buildAll: buildAll,
    killAll: killAll,
    modeToggle: modeToggle
  };

}();<|endoftext|>