<commit_before>(function( $ ) {
    var userAgent = navigator.userAgent.toLowerCase();
    var browser = {}
    browser.mozilla = /mozilla/.test(userAgent) && !/webkit/.test(userAgent);
    browser.webkit = /webkit/.test(userAgent);
    browser.opera = /opera/.test(userAgent);
    browser.msie = /msie/.test(userAgent);

    var defaults = {
        max: 4,
        partial: 2,
        hintText: 'Click to reveal completely'
    }

    var alertShown = false

    $.fn.spoilerAlert = function(opts) {
        opts = $.extend(defaults, opts || {})
        var maxBlur = opts.max
        var partialBlur = opts.partial
        var hintText = opts.hintText
        if (!alertShown && browser.msie) {
            alert("WARNING, this site contains spoilers!")
            alertShown = true
        }
        return this.each(function() {
            var $spoiler = $(this)
            $spoiler.data('spoiler-alert-state', 'shrouded')

            var animationTimer = null
            var currentBlur = maxBlur

            var cancelTimer = function() {
                if (animationTimer) {
                    clearTimeout(animationTimer)
                    animationTimer = null
                }
            }

            var applyBlur = function(radius) {
                currentBlur = radius
                if (browser.msie) {
                    var filterValue = "progid:DXImageTransform.Microsoft.Blur(pixelradius="+radius+")"
                    $spoiler.css('filter', filterValue)
                } else if (browser.mozilla) {
                    var filterValue = radius > 0 ? "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'>" +
                    "<filter id='blur'><feGaussianBlur stdDeviation='" + radius + "' /></filter></svg>#blur\")" : ''
                    $spoiler.css('filter', filterValue)
                } else {
                    var filterValue = radius > 0 ? 'blur('+radius+'px)' : ''
                    $spoiler.css('filter', filterValue)
                        .css('-webkit-filter', filterValue)
                        .css('-moz-filter', filterValue)
                        .css('-o-filter', filterValue)
                        .css('-ms-filter', filterValue)
                }
            }

            var performBlur = function(targetBlur, direction) {
                cancelTimer()
                if (currentBlur != targetBlur) {
                    applyBlur(currentBlur + direction)
                    animationTimer = setTimeout(function() { performBlur(targetBlur, direction) }, 10)
                }
            }

            // Does the user have IE 9 or less?
            var ieLessThanTen = function() {
                // This conditional check will return true if browser supports CANVAS
                // IE9 and under do not support CANVAS and this function is only ever
                // called by the IE checking function anyway
                return !document.createElement('canvas').getContext
            }

            applyBlur(currentBlur)

            $spoiler.on('mouseover', function(e) {
                $spoiler.css('cursor', 'pointer')
                    .attr('title', hintText)
                if ($spoiler.data('spoiler-alert-state') == 'shrouded') performBlur(partialBlur, -1)
            })
            $spoiler.on('mouseout', function(e) {
                if ($spoiler.data('spoiler-alert-state') == 'shrouded') performBlur(maxBlur, 1)
            })
            $spoiler.on('click', function(e) {
                if ($spoiler.data('spoiler-alert-state') == 'shrouded') {
                    $spoiler.data('spoiler-alert-state', 'revealed')
                        .attr('title', '')
                        .css('cursor', 'auto')
                    performBlur(0, -1)
                } else {
                    $spoiler.data('spoiler-alert-state', 'shrouded')
                        .attr('title', hintText)
                        .css('cursor', 'pointer')
                    performBlur(partialBlur, 1)
                }
            })
        })

    };
})( jQuery );
<commit_msg>IE10/11 Browser User Agent Fix<commit_after>(function( $ ) {
    var userAgent = navigator.userAgent.toLowerCase();
    var browser = {}
    browser.mozilla = /mozilla/.test(userAgent) && !/webkit/.test(userAgent);
    browser.webkit = /webkit/.test(userAgent);
    browser.opera = /opera/.test(userAgent);
    browser.msie = /msie/.test(userAgent) || /trident/.test(userAgent);

    var defaults = {
        max: 4,
        partial: 2,
        hintText: 'Click to reveal completely'
    }

    var alertShown = false

    $.fn.spoilerAlert = function(opts) {
        opts = $.extend(defaults, opts || {})
        var maxBlur = opts.max
        var partialBlur = opts.partial
        var hintText = opts.hintText
        if (!alertShown && browser.msie) {
            alert("WARNING, this site contains spoilers!")
            alertShown = true
        }
        return this.each(function() {
            var $spoiler = $(this)
            $spoiler.data('spoiler-alert-state', 'shrouded')

            var animationTimer = null
            var currentBlur = maxBlur

            var cancelTimer = function() {
                if (animationTimer) {
                    clearTimeout(animationTimer)
                    animationTimer = null
                }
            }

            var applyBlur = function(radius) {
                currentBlur = radius
                if (browser.msie) {
                    var filterValue = "progid:DXImageTransform.Microsoft.Blur(pixelradius="+radius+")"
                    $spoiler.css('filter', filterValue)
                } else if (browser.mozilla) {
                    var filterValue = radius > 0 ? "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'>" +
                    "<filter id='blur'><feGaussianBlur stdDeviation='" + radius + "' /></filter></svg>#blur\")" : ''
                    $spoiler.css('filter', filterValue)
                } else {
                    var filterValue = radius > 0 ? 'blur('+radius+'px)' : ''
                    $spoiler.css('filter', filterValue)
                        .css('-webkit-filter', filterValue)
                        .css('-moz-filter', filterValue)
                        .css('-o-filter', filterValue)
                        .css('-ms-filter', filterValue)
                }
            }

            var performBlur = function(targetBlur, direction) {
                cancelTimer()
                if (currentBlur != targetBlur) {
                    applyBlur(currentBlur + direction)
                    animationTimer = setTimeout(function() { performBlur(targetBlur, direction) }, 10)
                }
            }

            // Does the user have IE 9 or less?
            var ieLessThanTen = function() {
                // This conditional check will return true if browser supports CANVAS
                // IE9 and under do not support CANVAS and this function is only ever
                // called by the IE checking function anyway
                return !document.createElement('canvas').getContext
            }

            applyBlur(currentBlur)

            $spoiler.on('mouseover', function(e) {
                $spoiler.css('cursor', 'pointer')
                    .attr('title', hintText)
                if ($spoiler.data('spoiler-alert-state') == 'shrouded') performBlur(partialBlur, -1)
            })
            $spoiler.on('mouseout', function(e) {
                if ($spoiler.data('spoiler-alert-state') == 'shrouded') performBlur(maxBlur, 1)
            })
            $spoiler.on('click', function(e) {
                if ($spoiler.data('spoiler-alert-state') == 'shrouded') {
                    $spoiler.data('spoiler-alert-state', 'revealed')
                        .attr('title', '')
                        .css('cursor', 'auto')
                    performBlur(0, -1)
                } else {
                    $spoiler.data('spoiler-alert-state', 'shrouded')
                        .attr('title', hintText)
                        .css('cursor', 'pointer')
                    performBlur(partialBlur, 1)
                }
            })
        })

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


<commit_before>
(function (app_container) {

    var introText = [
        " ",
        "A história se passa em um castelo onde o herói \nse encontra aprisionado no calabouço.",
        "Ele foi aprisionado por ser considerado uma ameaça \naos planos do vilão (sem nome).",
        "Ao vasculhar a área, encontra uma mensagem num computador, \nde seu mentor informando o que deve ser feito para ele \nconseguir sair daquele local:",
        "1) deve procurar por artefatos espalhados e monta-los \npara encaixar na porta de acesso.",
        "Nesse calabouço também existem instrumentos úteis \npara a batalha contra o chefão, esses itens tornaram\n o vilão mais vulneráveis aos ataques do herói.",
        "No final da história o herói consegue \nvencer/derrotar o vilão e sai do Ryokan,",
        "onde ele terá que enfrentar um exército de ninjas \n(mas o jogo não mostra essa batalha, só fica subentendido)."
    ];

    function StoryPresentation() {

        this.content = null;

        this.index = 0;

        this.line = '';
    };

    StoryPresentation.prototype = {

        create: function () {

            this.content = introText;

            this.stage.backgroundColor = '#000';

            var style = { font: "22px pixelFont", fill: "#ffffff"};

            this.storyText = this.game.add.text(10, 500, '', style);

            this.nextLine();
        },

        update: function() {
            //SKIP
            if (this.game.input.keyboard.isDown(Phaser.Keyboard.S)) {
                this.exit();
            }
        },

        updateLine: function() {

            if (this.line.length < this.content[this.index].length) {
                this.line = this.content[this.index].substr(0, this.line.length + 1);
                this.storyText.setText(this.line);
            }
            else {
                //  Wait 2 seconds then start a new line
                this.game.time.events.add(Phaser.Timer.SECOND * 2, this.nextLine, this);
            }

        },

        nextLine: function() {

            this.index++;

            if (this.index < this.content.length) {
                this.line = '';
                this.game.time.events.repeat(80, this.content[this.index].length + 1, this.updateLine, this);
            } else {
                this.exit();
            }

        },

        exit: function() {
            this.game.state.start('Menu');
        }

    };

    app_container.StoryPresentation = StoryPresentation;

}(window.app_container = window.app_container || {}));<commit_msg>update text presentation<commit_after>
(function (app_container) {

    var introText = [
        " ",
        "A história se passa em um castelo onde o herói \nse encontra aprisionado no calabouço.",
        "Ele foi aprisionado por ser considerado uma ameaça \naos planos do vilão (sem nome).",
        "Ao vasculhar a área, encontra uma mensagem num computador, \nde seu mentor informando o que deve ser feito para ele \nconseguir sair daquele local:",
        "deve procurar por artefatos espalhados e monta-los \npara encaixar na porta de acesso.",
        "Nesse calabouço também existem instrumentos úteis \npara a batalha contra o chefão, esses itens tornarão\no vilão mais vulneráveis aos ataques do herói.",
        //"No final da história o herói consegue \nvencer/derrotar o vilão e sai do Ryokan,",
        //"onde ele terá que enfrentar um exército de ninjas \n(mas o jogo não mostra essa batalha, só fica subentendido)."
    ];

    function StoryPresentation() {

        this.content = null;

        this.index = 0;

        this.line = '';
    };

    StoryPresentation.prototype = {

        create: function () {

            this.content = introText;

            this.stage.backgroundColor = '#000';

            var style = { font: "22px pixelFont", fill: "#ffffff"};

            this.storyText = this.game.add.text(10, 500, '', style);

            this.nextLine();
        },

        update: function() {
            //SKIP
            if (this.game.input.keyboard.isDown(Phaser.Keyboard.S)) {
                this.exit();
            }
        },

        updateLine: function() {

            if (this.line.length < this.content[this.index].length) {
                this.line = this.content[this.index].substr(0, this.line.length + 1);
                this.storyText.setText(this.line);
            }
            else {
                //  Wait 2 seconds then start a new line
                this.game.time.events.add(Phaser.Timer.SECOND * 2, this.nextLine, this);
            }

        },

        nextLine: function() {

            this.index++;

            if (this.index < this.content.length) {
                this.line = '';
                this.game.time.events.repeat(80, this.content[this.index].length + 1, this.updateLine, this);
            } else {
                this.exit();
            }

        },

        exit: function() {
            this.game.state.start('Menu');
        }

    };

    app_container.StoryPresentation = StoryPresentation;

}(window.app_container = window.app_container || {}));<|endoftext|>


<commit_before>import React from 'react';
import bukovelAPI from './dataAccess/bukovelApi';
import CardNumberInput from './CardNumberInput';

const TEST_CARD_NUMBER = '01-2167-30-92545';

export default class App extends React.Component {
  constructor() {
    super();

    this.state = {
      html: '',
      cardNumber: TEST_CARD_NUMBER
    };
    this.handleCardNumberChange = this.handleCardNumberChange.bind(this);
  }

  // componentWillMount() {
  //   setTimeout(() => {
  //     this.setState({
  //       cardNumber: TEST_CARD_NUMBER
  //     })
  //   })
  // }

  handleCardNumberChange(event) {
    if (event.isValid) {
      bukovelAPI
        .getCardBalance(event.text)
        .then(data => {
          this.setState({
            html: JSON.stringify(data, null, '\t')
          });
        })
    }
  }

  render() {
    return (

        <CardNumberInput onChange={this.handleCardNumberChange} value={this.state.cardNumber} />

{this.state.html}

    );
  }
}<commit_msg>Remove commented code.<commit_after>import React from 'react';
import bukovelAPI from './dataAccess/bukovelApi';
import CardNumberInput from './CardNumberInput';

const TEST_CARD_NUMBER = '01-2167-30-92545';

export default class App extends React.Component {
  constructor() {
    super();

    this.state = {
      html: '',
      cardNumber: TEST_CARD_NUMBER
    };
    this.handleCardNumberChange = this.handleCardNumberChange.bind(this);
  }

  handleCardNumberChange(event) {
    if (event.isValid) {
      bukovelAPI
        .getCardBalance(event.text)
        .then(data => {
          this.setState({
            html: JSON.stringify(data, null, '\t')
          });
        })
    }
  }

  render() {
    return (

        <CardNumberInput onChange={this.handleCardNumberChange} value={this.state.cardNumber} />

{this.state.html}

    );
  }
}<|endoftext|>


<commit_before>require.config({

    baseUrl: "/scripts",

    /* starting point for application */
    deps: ['backbone.marionette', 'bootstrap', 'main'],

    shim: {
        backbone: {
            deps: [
                'underscore',
                'jquery'
            ],
            exports: 'Backbone'
        },
        bootstrap: {
            deps: ['jquery'],
            exports: 'jquery'
        },
        leaflet: {
            exports: 'L'
        },
        leaflet_providers: ['leaflet'],

		// backbone upload manager and its dependencies
		"jquery.ui.widget": ["jquery"],
		"jquery.file_upload": ["jquery", "jquery.ui.widget", 'jquery.iframe-transport'],
		"backbone_upload_manager": [
			'jquery.file_upload',
			'backbone_defered_view_loader'
		]
    },

    paths: {
        jquery: '../bower_components/jquery/jquery',
        backbone: '../bower_components/backbone-amd/backbone',
        underscore: '../bower_components/underscore-amd/underscore',

        /* alias all marionette libs */
        'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette',
        'backbone.wreqr': '../bower_components/backbone.wreqr/lib/amd/backbone.wreqr',
        'backbone.babysitter': '../bower_components/backbone.babysitter/lib/amd/backbone.babysitter',

        /* alias the bootstrap js lib */
        bootstrap: 'vendor/bootstrap',

        /* Alias text.js for template loading and shortcut the templates dir to tmpl */
        text: '../bower_components/requirejs-text/text',
        tmpl: "../templates",

        /* handlebars from the require handlerbars plugin below */
        handlebars: '../bower_components/require-handlebars-plugin/Handlebars',

        /* require handlebars plugin - Alex Sexton */
        i18nprecompile: '../bower_components/require-handlebars-plugin/hbs/i18nprecompile',
        json2: '../bower_components/require-handlebars-plugin/hbs/json2',
        hbs: '../bower_components/require-handlebars-plugin/hbs',

        /* mapping related */
        leaflet: "../bower_components/leaflet/leaflet",
        leaflet_providers: "../bower_components/leaflet-providers/leaflet-providers",

        /* form related*/
		"jquery.ui.widget": "../bower_components/jquery-file-upload/js/vendor/jquery.ui.widget",
		"jquery.iframe-transport": "../bower_components/jquery-file-upload/js/jquery.iframe-transport",
		"jquery.file_upload": "../bower_components/jquery-file-upload/js/jquery.fileupload",
        "backbone_defered_view_loader": "../bower_components/backbone-defered-view-loader/js/backbone-defered-view-loader",
        "backbone_upload_manager": "../bower_components/backbone-upload-manager/js/backbone.upload-manager",
		"backbone.syphon": "../bower_components/backbone.syphon/lib/amd/backbone.syphon.min"
    },

    hbs: {
        disableI18n: true
    }
});
<commit_msg>Replacing tabs with spaces in app/scripts/init.js as the rest of that file is formatted this way. Have to find out whether its really necessary to have spaces there as our convention is to use tabs for js files.<commit_after>require.config({

    baseUrl: "/scripts",

    /* starting point for application */
    deps: ['backbone.marionette', 'bootstrap', 'main'],

    shim: {
        backbone: {
            deps: [
                'underscore',
                'jquery'
            ],
            exports: 'Backbone'
        },
        bootstrap: {
            deps: ['jquery'],
            exports: 'jquery'
        },
        leaflet: {
            exports: 'L'
        },
        leaflet_providers: ['leaflet'],

        // backbone upload manager and its dependencies
        "jquery.ui.widget": ["jquery"],
        "jquery.file_upload": ["jquery", "jquery.ui.widget", 'jquery.iframe-transport'],
        "backbone_upload_manager": [
            'jquery.file_upload',
            'backbone_defered_view_loader'
        ]
    },

    paths: {
        jquery: '../bower_components/jquery/jquery',
        backbone: '../bower_components/backbone-amd/backbone',
        underscore: '../bower_components/underscore-amd/underscore',

        /* alias all marionette libs */
        'backbone.marionette': '../bower_components/backbone.marionette/lib/core/amd/backbone.marionette',
        'backbone.wreqr': '../bower_components/backbone.wreqr/lib/amd/backbone.wreqr',
        'backbone.babysitter': '../bower_components/backbone.babysitter/lib/amd/backbone.babysitter',

        /* alias the bootstrap js lib */
        bootstrap: 'vendor/bootstrap',

        /* Alias text.js for template loading and shortcut the templates dir to tmpl */
        text: '../bower_components/requirejs-text/text',
        tmpl: "../templates",

        /* handlebars from the require handlerbars plugin below */
        handlebars: '../bower_components/require-handlebars-plugin/Handlebars',

        /* require handlebars plugin - Alex Sexton */
        i18nprecompile: '../bower_components/require-handlebars-plugin/hbs/i18nprecompile',
        json2: '../bower_components/require-handlebars-plugin/hbs/json2',
        hbs: '../bower_components/require-handlebars-plugin/hbs',

        /* mapping related */
        leaflet: "../bower_components/leaflet/leaflet",
        leaflet_providers: "../bower_components/leaflet-providers/leaflet-providers",

        /* form related*/
        "jquery.ui.widget": "../bower_components/jquery-file-upload/js/vendor/jquery.ui.widget",
        "jquery.iframe-transport": "../bower_components/jquery-file-upload/js/jquery.iframe-transport",
        "jquery.file_upload": "../bower_components/jquery-file-upload/js/jquery.fileupload",
        "backbone_defered_view_loader": "../bower_components/backbone-defered-view-loader/js/backbone-defered-view-loader",
        "backbone_upload_manager": "../bower_components/backbone-upload-manager/js/backbone.upload-manager",
        "backbone.syphon": "../bower_components/backbone.syphon/lib/amd/backbone.syphon.min"
    },

    hbs: {
        disableI18n: true
    }
});
<|endoftext|>


<commit_before>String.prototype.capitalize = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
};

String.prototype.toObjectNotation = function(){
	return this.replace(/(\_[a-z])/g, function($1){return $1.toUpperCase().replace('_','');}).capitalize();
};

String.prototype.stripFileDesignation = function(){
	return this.substring(0, this.indexOf('.'));
};

String.prototype.handlerify = function(){
	return this.concat("Handler");
};

String.prototype.deHandlerify = function(){
	return this.substring(0, this.indexOf('Handler'));
};

var requiredServicesList = {};
var actionEmitter = require("./action_emitter.js");
var fs = require("fs");
//Comment this out if you want to just manually require each service
//this will just require every service defined in the database folder.

fs.readdirSync("services/database").forEach(function(file) {
	var filename = file.stripFileDesignation();
	requiredServicesList[filename] = require("./database/" + file);
});

fs.readdirSync("services/parsers").forEach(function(file) {
	var filename = file.stripFileDesignation();
	requiredServicesList[filename+"_parser"] = require("./parsers/" + file);
});

//If there are a large number of services and you only want to require a select few
//you can define manually each one by simply following the paradigm below for each service you want to use.
//make sure that if you would like to manually include this files that you comment out
//the above loop to require all services
//**requiredServicesList['alpha_report'] = require("./database/alpha_report.js");**

module.exports = function(models, io, logger) {
	var serviceList = {};
	var self = this;
	//This loop will automatically create a new Object of the type of the service using standard Object notation
	//Example for alpha report it would call:
	//var AlphaReport = new requiredServicesList['alpha_report'](models,io,logger,actionEmitter);
	for(var service in requiredServicesList) {
		if(typeof(requiredServicesList[service.toString()]) === typeof(Function)) {//eval("var " + service.toObjectNotation() + "= new "+ "requiredServicesList['" + service + "'](models,io,logger);");
			serviceList[service.toObjectNotation()] = new requiredServicesList[service.toString()](models,io,logger);
		}
	}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ll
	/**
	*All you have to do, is for an event defined in action_emitter create a function with the same name followed by
	*"Handler" then you can call any of the methods defined in any of the services.
	*THIS IS THE ONLY FUNCTION YOU NEED TO MODIFY TO IMPLEMENT NEW EVENT HANDLERS.
	**/
	var Listener = function(){
		//This converts the arguments to an array so that any number of arguments can be passed to the method.
		Function.prototype.callWithAllArgs = function() {
			return this.apply(this, Array.prototype.slice.call(arguments[0][0], 0));
		};

	  	this.sampleListEventHandler = function() {
	  		serviceList.Profile.sampleProfileEvent.callWithAllArgs(arguments);
	  	};

  		this.saveAlphaReportEventHandler = function() {
  			serviceList.AlphaReport.saveAlphaReport.callWithAllArgs(arguments);
	  	};

	  	this.updateAlphaReportEventHandler = function() {
  			serviceList.AlphaReport.updateAlphaReportX.callWithAllArgs(arguments);
	  	};

	  	this.validateAlphaReportEventHandler = function() {
  			serviceList.AlphaReport.validateAlphaReport.callWithAllArgs(arguments);
	  	};

  		this.twitterDataRecievedEventHandler = function() {
  			//Services that are prototyped out must be called this way.
  			var self = serviceList.RawFeed;
  			self.create.apply(self, Array.prototype.slice.call(arguments[0], 0));
	  	};

	  	this.saveFeedEventHandler = function() {
	  		//Services that are prototyped out must be called this way.
  			var self = serviceList.RawFeed;
  			self.saveFeed.apply(self, Array.prototype.slice.call(arguments[0], 0));
	  	};

	  	this.rawFeedParseEventHandler = function() {
  			serviceList.RawFeedParser.parseAndSave.callWithAllArgs(arguments);
	  	};

	  	//More Implemented event handlers below....
	};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	var listener = new Listener();
	var eventerEventList = actionEmitter.eventList;

	//Sets up the corresponding Handlers for each event defined in the action_emitter.js file.
	for(var i = 0; i < eventerEventList.length; i++) {
		var currentEvent = eventerEventList[i];
		//For each event call the appropriate handler above.
		if(listener[currentEvent.handlerify()]) {
		 	actionEmitter.on(currentEvent,listener[currentEvent.handlerify()]);
		} else {
			//If there are events defined in action_emitter but no handler defined above, log an error.
			logger.error("There is no " + currentEvent.handlerify() + " defined in action_handler.js\n");
		}
	}

	//Checks if a handler is defined above, but no associated event in action_emitter.js.  Outputs an error if it cannot find the
	//Associated Event for a Handler.
	for(var fun in listener) {
		if(eventerEventList.indexOf(fun.deHandlerify()) === -1 && fun !== 'callWithAllArgs') {
			logger.error("Handler:  " + fun + " defined but " + fun.deHandlerify() +" not defined in action_emitter.js \n");
		}
	}
};
<commit_msg>Testing with socketio<commit_after>String.prototype.capitalize = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
};

String.prototype.toObjectNotation = function(){
	return this.replace(/(\_[a-z])/g, function($1){return $1.toUpperCase().replace('_','');}).capitalize();
};

String.prototype.stripFileDesignation = function(){
	return this.substring(0, this.indexOf('.'));
};

String.prototype.handlerify = function(){
	return this.concat("Handler");
};

String.prototype.deHandlerify = function(){
	return this.substring(0, this.indexOf('Handler'));
};

var requiredServicesList = {};
var actionEmitter = require("./action_emitter.js");
var fs = require("fs");
//Comment this out if you want to just manually require each service
//this will just require every service defined in the database folder.

fs.readdirSync("services/database").forEach(function(file) {
	var filename = file.stripFileDesignation();
	requiredServicesList[filename] = require("./database/" + file);
});

fs.readdirSync("services/parsers").forEach(function(file) {
	var filename = file.stripFileDesignation();
	requiredServicesList[filename+"_parser"] = require("./parsers/" + file);
});

//If there are a large number of services and you only want to require a select few
//you can define manually each one by simply following the paradigm below for each service you want to use.
//make sure that if you would like to manually include this files that you comment out
//the above loop to require all services
//**requiredServicesList['alpha_report'] = require("./database/alpha_report.js");**

module.exports = function(models, io, logger) {
	var serviceList = {};
	var self = this;
	//This loop will automatically create a new Object of the type of the service using standard Object notation
	//Example for alpha report it would call:
	//var AlphaReport = new requiredServicesList['alpha_report'](models,io,logger,actionEmitter);
	for(var service in requiredServicesList) {
		if(typeof(requiredServicesList[service.toString()]) === typeof(Function)) {//eval("var " + service.toObjectNotation() + "= new "+ "requiredServicesList['" + service + "'](models,io,logger);");
			serviceList[service.toObjectNotation()] = new requiredServicesList[service.toString()](models,io,logger);
		}
	}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ll
	/**
	*All you have to do, is for an event defined in action_emitter create a function with the same name followed by
	*"Handler" then you can call any of the methods defined in any of the services.
	*THIS IS THE ONLY FUNCTION YOU NEED TO MODIFY TO IMPLEMENT NEW EVENT HANDLERS.
	**/
	var Listener = function(){
		//This converts the arguments to an array so that any number of arguments can be passed to the method.
		Function.prototype.callWithAllArgs = function() {
			return this.apply(this, Array.prototype.slice.call(arguments[0][0], 0));
		};

	  	this.sampleListEventHandler = function() {
	  		serviceList.Profile.sampleProfileEvent.callWithAllArgs(arguments);
	  	};

  		this.saveAlphaReportEventHandler = function() {
  			serviceList.AlphaReport.saveAlphaReport.callWithAllArgs(arguments);
	  	};

	  	this.updateAlphaReportEventHandler = function() {
  			serviceList.AlphaReport.updateAlphaReportX.callWithAllArgs(arguments);
	  	};

	  	this.validateAlphaReportEventHandler = function() {
  			serviceList.AlphaReport.validateAlphaReport.callWithAllArgs(arguments);
	  	};

  		this.twitterDataRecievedEventHandler = function() {
  			//Services that are prototyped out must be called this way.
  			var self = serviceList.RawFeed;
  			self.create.apply(self, Array.prototype.slice.call(arguments[0], 0));
	  	};

	  	this.saveFeedEventHandler = function() {
	  		io.sockets.in('EVEREST.data.workflow').emit('item_saved', {type: "RawFeed"});

	  		//Services that are prototyped out must be called this way.
  			var self = serviceList.RawFeed;
  			self.saveFeed.apply(self, Array.prototype.slice.call(arguments[0], 0));
	  	};

	  	this.rawFeedParseEventHandler = function() {
  			serviceList.RawFeedParser.parseAndSave.callWithAllArgs(arguments);
	  	};

	  	//More Implemented event handlers below....
	};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	var listener = new Listener();
	var eventerEventList = actionEmitter.eventList;

	//Sets up the corresponding Handlers for each event defined in the action_emitter.js file.
	for(var i = 0; i < eventerEventList.length; i++) {
		var currentEvent = eventerEventList[i];
		//For each event call the appropriate handler above.
		if(listener[currentEvent.handlerify()]) {
		 	actionEmitter.on(currentEvent,listener[currentEvent.handlerify()]);
		} else {
			//If there are events defined in action_emitter but no handler defined above, log an error.
			logger.error("There is no " + currentEvent.handlerify() + " defined in action_handler.js\n");
		}
	}

	//Checks if a handler is defined above, but no associated event in action_emitter.js.  Outputs an error if it cannot find the
	//Associated Event for a Handler.
	for(var fun in listener) {
		if(eventerEventList.indexOf(fun.deHandlerify()) === -1 && fun !== 'callWithAllArgs') {
			logger.error("Handler:  " + fun + " defined but " + fun.deHandlerify() +" not defined in action_emitter.js \n");
		}
	}
};
<|endoftext|>


<commit_before>(function() {

  window.SelectTree = function(node, parent) {
    var self       = this;
    this.node      = node;
    this.parent    = parent;
    this.children  = [ ];
    this.linked    = null;
    this.listeners = [ ];
    this.total     = 0;

    SelectTree.byParent(this.name()).each(function() {
      self.children.push(new SelectTree($(this), self));
    });

    node.on('change', function() {
      self.onChange($(this).prop('checked'));
    });
  }

  SelectTree.prototype = {
    constructor: SelectTree,

    data: function(key) {
      return this.node[0].getAttribute('data-' + SelectTree.data_prefix + '-' + key);
    },

    name: function() {
      return this.data('name');
    },

    countTotal: function() {
      return this.data('count-total');
    },

    onChange: function(bool) {
      var linked = this.findLinked();

      this.node.prop('checked', bool);

      this.eachChild(function(child) {
        child.onChange(bool);
      });

      for(var i = 0; i < linked.length; ++i) {
        if(linked[i].node.prop('checked') != bool) {
          linked[i].onChange(bool);
        }
      }

      this.fireEvent('change', self);
    },

    addListener: function(event, listener) {
      /* only the root node has listeners */
      if(this.parent) {
        this.parent.addListener(event, listener);
      }
      else {
        this.listeners.push({ event : event, callback : listener });
      }
    },

    fireEvent: function(event, data) {
      if(this.parent) {
        this.parent.fireEvent(event, data);
      }
      else {
        var self = this;

        this.eachListener(function(l) {
          if(l.event == event) {
            l.callback(self, data);
          }
        });
      }
    },

    calcTotalSelected: function() {
      var total = 0;

      if(this.node.prop('checked') && this.countTotal()) {
        total += 1;
      }

      this.eachChild(function(c) {
        total += c.calcTotalSelected();
      });

      this.total = total;

      return this.total;
    },

    eachListener: function(cb) {
      for(var i = 0; i < this.listeners.length; ++i) {
        cb(this.listeners[i]);
      }
    },

    eachChild: function(cb) {
      for(var i = 0; i < this.children.length; ++i) {
        cb(this.children[i]);
      }
    },

    /*
     * find all nodes in the tree with the
     * specified name
     */
    findNamed: function(name) {
      if(this.parent) {
        return this.parent.findNamed(name);
      }
      else {
        return this.findNamedChildren(name);
      }
    },

    /*
     * find all child nodes with the given name
     */
    findNamedChildren: function(name) {
      var nodes =[ ];

      this.eachChild(function(child) {
        if(child.name() == name) {
          nodes.push(child);
        }
        $.merge(nodes, child.findNamedChildren(name));
      });

      return nodes;
    },

    /*
     * a linked node is a node in the same
     * tree with the same name as this node
     */
    findLinked: function() {
      if(this.linked) {
        return this.linked;
      }
      else {
        this.linked = this.findNamed(this.name());
        return this.linked;
      }
    },

    /*
     * Walks the given path in child branches looking for the tree whose node
     * is the last item, and replaces it. Meant to be used with AJAX updates.
     */
    rebind: function(path) {
      for(var i = 0; i < this.children.length; ++i) {
        var child = this.children[i];
        if (path.length == 1 && path[0].getAttribute('data-select-tree-name') == child.node[0].getAttribute('data-select-tree-name')) {
          child.node = $(path[0]);
          return true;
        }
        else if (child.node[0] == path[0]) {
          path.shift();
          return child.rebind(path);
        }
      }

      return false;
    }
  }

  SelectTree.data_prefix = 'select-tree';

  var $all, $trees;

  SelectTree.all = function() {
    if (!$all)
      $all = $('input[type="checkbox"][data-bind="' + this.data_prefix + '"]');

    return $all;
  }

  SelectTree.allRoots = function() {
    return this.byParent(null);
  }

  SelectTree.byParent = function(name) {
    var self = this;
    return this.all().filter(function() {
      return (this.getAttribute('data-' + self.data_prefix + '-parent') == name);
    });
  }

  SelectTree.byName = function(name) {
    var self = this;
    return this.all().filter(function() {
      return (this.getAttribute('data-' + self.data_prefix + '-name') == name);
    });
  }

  SelectTree.buildAll = function() {
    $trees = [ ];
    $all   = null; // Refresh

    this.allRoots().each(function() {
      var tree = new SelectTree($(this));
      $trees.push(tree);
    });
  }

  /* Given a piece of updated HTML via AJAX, looks up the select-tree boxes,
   * builds a path to the root, and then calls rebind() on it */
  SelectTree.rebind = function(html) {
    var self = this;
    $(html).find('[data-bind="' + this.data_prefix + '"]').each(function() {
      // Go up to the root
      var item = this;
      var path = [ ];

      while(item != null) {
        path.unshift(item);

        item = item.getAttribute('data-' + self.data_prefix + '-parent');
        if (item)
          item = self.byName(item)[0];
      }

      var root = path.shift();
      var tree = $trees.filter(function(t) {
        return root == t.node[0];
      })[0];

      if (tree)
        tree.rebind(path);
    });
  }

  SelectTree.eachCounter = function(cb) {
    $('[data-' + this.data_prefix + '-total]').each(function() {
      cb($(this));
    });
  }

  SelectTree.setTotal = function(tree, counter) {
    var count      = (counter.data(this.data_prefix + '-total') || 0);
    var tree_total = tree.total;
    var updated    = tree.calcTotalSelected();

    if(tree_total < updated) {
      count += (updated - tree_total);
    }
    else if(tree_total > updated) {
      count += (updated - tree_total);
    }

    counter.data(this.data_prefix + '-total', count);
    counter.val(counter.val().replace(/\d+/, count));
  }

  $(function() {
    SelectTree.buildAll();

    SelectTree.eachCounter(function(c) {
      for(var i = 0; i < $trees.length; ++i) {
        $trees[i].addListener('change', function(t) {
          SelectTree.setTotal(t, c);
        });
      }
    });
  });

})();
<commit_msg>Select tree counters can now be any tag with a text()<commit_after>(function() {

  window.SelectTree = function(node, parent) {
    var self       = this;
    this.node      = node;
    this.parent    = parent;
    this.children  = [ ];
    this.linked    = null;
    this.listeners = [ ];
    this.total     = 0;

    SelectTree.byParent(this.name()).each(function() {
      self.children.push(new SelectTree($(this), self));
    });

    node.on('change', function() {
      self.onChange($(this).prop('checked'));
    });
  }

  SelectTree.prototype = {
    constructor: SelectTree,

    data: function(key) {
      return this.node[0].getAttribute('data-' + SelectTree.data_prefix + '-' + key);
    },

    name: function() {
      return this.data('name');
    },

    countTotal: function() {
      return this.data('count-total');
    },

    onChange: function(bool) {
      var linked = this.findLinked();

      this.node.prop('checked', bool);

      this.eachChild(function(child) {
        child.onChange(bool);
      });

      for(var i = 0; i < linked.length; ++i) {
        if(linked[i].node.prop('checked') != bool) {
          linked[i].onChange(bool);
        }
      }

      this.fireEvent('change', self);
    },

    addListener: function(event, listener) {
      /* only the root node has listeners */
      if(this.parent) {
        this.parent.addListener(event, listener);
      }
      else {
        this.listeners.push({ event : event, callback : listener });
      }
    },

    fireEvent: function(event, data) {
      if(this.parent) {
        this.parent.fireEvent(event, data);
      }
      else {
        var self = this;

        this.eachListener(function(l) {
          if(l.event == event) {
            l.callback(self, data);
          }
        });
      }
    },

    calcTotalSelected: function() {
      var total = 0;

      if(this.node.prop('checked') && this.countTotal()) {
        total += 1;
      }

      this.eachChild(function(c) {
        total += c.calcTotalSelected();
      });

      this.total = total;

      return this.total;
    },

    eachListener: function(cb) {
      for(var i = 0; i < this.listeners.length; ++i) {
        cb(this.listeners[i]);
      }
    },

    eachChild: function(cb) {
      for(var i = 0; i < this.children.length; ++i) {
        cb(this.children[i]);
      }
    },

    /*
     * find all nodes in the tree with the
     * specified name
     */
    findNamed: function(name) {
      if(this.parent) {
        return this.parent.findNamed(name);
      }
      else {
        return this.findNamedChildren(name);
      }
    },

    /*
     * find all child nodes with the given name
     */
    findNamedChildren: function(name) {
      var nodes =[ ];

      this.eachChild(function(child) {
        if(child.name() == name) {
          nodes.push(child);
        }
        $.merge(nodes, child.findNamedChildren(name));
      });

      return nodes;
    },

    /*
     * a linked node is a node in the same
     * tree with the same name as this node
     */
    findLinked: function() {
      if(this.linked) {
        return this.linked;
      }
      else {
        this.linked = this.findNamed(this.name());
        return this.linked;
      }
    },

    /*
     * Walks the given path in child branches looking for the tree whose node
     * is the last item, and replaces it. Meant to be used with AJAX updates.
     */
    rebind: function(path) {
      for(var i = 0; i < this.children.length; ++i) {
        var child = this.children[i];
        if (path.length == 1 && path[0].getAttribute('data-select-tree-name') == child.node[0].getAttribute('data-select-tree-name')) {
          child.node = $(path[0]);
          return true;
        }
        else if (child.node[0] == path[0]) {
          path.shift();
          return child.rebind(path);
        }
      }

      return false;
    }
  }

  SelectTree.data_prefix = 'select-tree';

  var $all, $trees;

  SelectTree.all = function() {
    if (!$all)
      $all = $('input[type="checkbox"][data-bind="' + this.data_prefix + '"]');

    return $all;
  }

  SelectTree.allRoots = function() {
    return this.byParent(null);
  }

  SelectTree.byParent = function(name) {
    var self = this;
    return this.all().filter(function() {
      return (this.getAttribute('data-' + self.data_prefix + '-parent') == name);
    });
  }

  SelectTree.byName = function(name) {
    var self = this;
    return this.all().filter(function() {
      return (this.getAttribute('data-' + self.data_prefix + '-name') == name);
    });
  }

  SelectTree.buildAll = function() {
    $trees = [ ];
    $all   = null; // Refresh

    this.allRoots().each(function() {
      var tree = new SelectTree($(this));
      $trees.push(tree);
    });
  }

  /* Given a piece of updated HTML via AJAX, looks up the select-tree boxes,
   * builds a path to the root, and then calls rebind() on it */
  SelectTree.rebind = function(html) {
    var self = this;
    $(html).find('[data-bind="' + this.data_prefix + '"]').each(function() {
      // Go up to the root
      var item = this;
      var path = [ ];

      while(item != null) {
        path.unshift(item);

        item = item.getAttribute('data-' + self.data_prefix + '-parent');
        if (item)
          item = self.byName(item)[0];
      }

      var root = path.shift();
      var tree = $trees.filter(function(t) {
        return root == t.node[0];
      })[0];

      if (tree)
        tree.rebind(path);
    });
  }

  SelectTree.eachCounter = function(cb) {
    $('[data-' + this.data_prefix + '-total]').each(function() {
      cb($(this));
    });
  }

  SelectTree.setTotal = function(tree, counter) {
    var count      = (counter.data(this.data_prefix + '-total') || 0);
    var tree_total = tree.total;
    var updated    = tree.calcTotalSelected();

    if(tree_total < updated) {
      count += (updated - tree_total);
    }
    else if(tree_total > updated) {
      count += (updated - tree_total);
    }

    counter.data(this.data_prefix + '-total', count);

    var presenter = counter.val() ? counter.val : counter.text;
    presenter.call(counter, presenter.call(counter).replace(/\d+/, count));
  }

  $(function() {
    SelectTree.buildAll();

    SelectTree.eachCounter(function(c) {
      for(var i = 0; i < $trees.length; ++i) {
        $trees[i].addListener('change', function(t) {
          SelectTree.setTotal(t, c);
        });
      }
    });
  });

})();
<|endoftext|>


<commit_before>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "he", "diff_match_patch"], function($, i18n, utils, he) {

    "use strict";

    // ATTRIBUTES

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one
 on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    // we will also save the comment html elements and their associated block
    var comments = [];

    var original_content, new_content;

    // button to show the original version
    var original_button;
    var create_original_button = function() {
        if (typeof original_button === "undefined") {
            original_button = $.htmlify(
                '<button type="button">' +
                i18n.translate("show-original") +
                '</button>'
            );
            original_button.on("click", show_original);
            original_button.style.visibility = "hidden";
        }
        return original_button;
    };

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // the block slider is used to choose which block is currently selected
    var current_position;
    (function() {
        // having a slider makes no sense with no blocks
        if (blocks === null) { return null; }

        var slider = $.htmlify('

');
        // slider position
        slider.style.left =
            ((article.getBoundingClientRect().right
              + $("#isso-thread").getBoundingClientRect().left) / 2
             - 10) + "px";
        article.insertAfter(slider);

        var cursor = $.htmlify('

');
        slider.append(cursor);
        // cursor position
        var set_cursor_position = function(y) {
            var slider_rect = slider.getBoundingClientRect();
            var slider_height = slider_rect.bottom - slider_rect.top;
            var raw_position = y - slider_rect.top - 10;
            var corrected_position =
                (raw_position < 0) ?
                0 : ((raw_position > slider_height - 20) ?
                     slider_height - 20 : raw_position);
            cursor.style.top = corrected_position + "px";
            // current_position is useful to determine the current block
            current_position = y + slider_rect.top + 10;
        };

        var first_block = blocks[0].getBoundingClientRect();
        setTimeout(function() {
            set_cursor_position((first_block.top + first_block.bottom) / 2);
        }, 0);

        // define events on slider
        var follow_mouse = function(e) {
            set_cursor_position(e.clientY);
        };
        cursor.addEventListener("mousedown", function(e) {
            document.addEventListener("mousemove", follow_mouse);
            e.preventDefault();
        });
        document.addEventListener("mouseup", function() {
            document.removeEventListener("mousemove", follow_mouse);
            show_block_comments();
        });

        // move cursor when scrolling to the top at the top or to the bottom
        // at the bottom
        // ie. when we are already at top or bottom AND scrolling had no effect
        var previous_position = window.pageYOffset;
        document.addEventListener("scroll", function() {
            var new_position = window.pageYOffset;
            if (new_position === previous_position) {
                var max = document.documentElement.scrollHeight
                          - window.innerHeight;
                if (new_position >= max) {
                    // we are at the bottom
                    alert("bottom");
                } else if (new_position <= 0) {
                    // we are at the top
                    alert("top");
                }
            }
            previous_position = new_position;
        });
    })();

    // INITIALIZE LIBRARIES

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // CKEDITOR is not required thus we must check if it is available
    if (typeof CKEDITOR !== "undefined") {
        // turn off automatic editor creation once and for all
        CKEDITOR.disableAutoInline = true;
    }
    var editor;

    // AUXILIARY FUNCTIONS

    var highlight_current_block = function() {
        for (var i = 0; i < blocks.length; i++) {
            blocks[i].style.background = "transparent";
        }
        current_block.style.background = "rgba(211,211,211,0.5)";
    };

    // content after CKEditor reformatting
    // after decoding html entities
    // and after removing extra whitespace and new lines
    var getEditorContent = function() {
        return utils.clean_html(editor.getData());
    };

    var getBlockContent = function() {
        return utils.clean_html(current_block.innerHTML);
    }

    // FUNCTIONS WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = getBlockContent();
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                if (typeof CKEDITOR !== "undefined") {
                    editor = CKEDITOR.inline(current_block);
                    editor.on("instanceReady", function() {
                        editor.dataProcessor.writer.setRules("p", {
                            ident: false,
                            breakBeforeOpen: false,
                            breakAfterOpen: false,
                            breakBeforeClose: false,
                            breakAfterClose: false
                        });
                        original_content = getEditorContent();
                    });
                    editor.on("change", maybe_article_just_changed);
                }
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_content === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = typeof CKEDITOR === "undefined" ?
                        getBlockContent() :
                        getEditorContent();
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === i18n.translate("postbox-text") ||
                comment_field.innerHTML === "") {
                current_block.blur();
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            if (typeof editor !== "undefined") {
                editor.destroy();
            }
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var save_comment = function(el, block_id) {
        comments.push({el: el, block: block_id});
    };

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        // this function is useless if there are no blocks
        if (mode == "reading" && blocks !== null) {
            // current block = block at current_position
            var i = 0;
            while (i < blocks.length &&
                   blocks[i].getBoundingClientRect().top <= current_position) {
                i++;
            }
            current_block = blocks[i - 1];
            highlight_current_block();
            // mask all comments that are not associated with the current block
            for (var i = 0 ; i < comments.length ; i++ ) {
                comments[i].el.style.display =
                    (comments[i].block === current_block.id) ?
                    "block" :
                    "none";
            }
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    var previous_block = current_block;

                    // first check that the block associated with the comment
                    // exists or that there is no associated block simply
                    // because the page has no blocks
                    if (comment.block === "") {
                        if (blocks !== null) { return; }
                    }
                    else {
                        if (blocks === null) { return; }
                        var i = 0;
                        while (
                            i < blocks.length &&
                            blocks[i].id !== comment.block
                        ) { i++; }
                        if (i === blocks.length) { return; }
                        current_block = blocks[i];
                        highlight_current_block();
                    }

                    // save original content for later if it was not already
                    if (mode === "reading") {
                        original_content = getBlockContent();
                    }
                    else if (previous_block !== current_block) {
                        // restore original content for previous block
                        previous_block.innerHTML = original_content;
                        original_content = getBlockContent();
                    }

                    mode = "reading_modification";
                    currently_showing = comment.id;

                    // print diffs
                    var array = JSON.parse(he.decode(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].classList.remove("selected");
                    }
                    el.classList.add("selected");

                    // scroll to block then to first change
                    var edit_top = $("#edit");
                    if (!edit_top.topIsVisible()) {
                        current_block.scrollIntoView();
                    }
                    if (!edit_top.topIsVisible()) {
                        edit_top.scrollIntoView();
                    }
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].classList.remove("selected");
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    // fallback if we cannot use CKEditor change event
    if (typeof CKEDITOR === "undefined") {
        article.on("keyup", maybe_article_just_changed);
    }

    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // PUBLIC METHODS

    return {
        init: init,
        new_content: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var splitted = dmp.diff_wordsToChars_(original_content, new_content);
            var diffs = dmp.diff_main(splitted.chars1, splitted.chars2);
            dmp.diff_cleanupSemantic(diffs);
            dmp.diff_charsToLines_(diffs, splitted.wordArray);
            return JSON.stringify(diffs);
        },
        block_id: function() { return current_block.id; },
        save_comment: save_comment,
        show_block_comments: show_block_comments,
        cancel: cancel,
        show: show_edit,
        original_button: create_original_button,
        show_original: show_original
    };
});

<commit_msg>Revert "start listening to scroll event"<commit_after>/* Copyright Théo Zimmermann 2014
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["app/dom", "app/i18n", "app/utils", "he", "diff_match_patch"], function($, i18n, utils, he) {

    "use strict";

    // ATTRIBUTES

    // mode can take values "reading", "reading_modification" and "commenting"
    var mode = "reading";
    // if mode is "reading_modification", currently_showing stores id of comment
    var currently_showing;

    // there must be only one
 on the page
    var article = $("article");
    // but there can be many blocks in an article
    var blocks = $(".block", article, false);
    // in the case there is no block, current_block will always represent the full article
    var current_block = article;

    // we will also save the comment html elements and their associated block
    var comments = [];

    var original_content, new_content;

    // button to show the original version
    var original_button;
    var create_original_button = function() {
        if (typeof original_button === "undefined") {
            original_button = $.htmlify(
                '<button type="button">' +
                i18n.translate("show-original") +
                '</button>'
            );
            original_button.on("click", show_original);
            original_button.style.visibility = "hidden";
        }
        return original_button;
    };

    // remember some of the DOM elements
    var cancel_button, comment_field;

    // the block slider is used to choose which block is currently selected
    var current_position;
    (function() {
        // having a slider makes no sense with no blocks
        if (blocks === null) { return null; }

        var slider = $.htmlify('

');
        // slider position
        slider.style.left =
            ((article.getBoundingClientRect().right
              + $("#isso-thread").getBoundingClientRect().left) / 2
             - 10) + "px";
        article.insertAfter(slider);

        var cursor = $.htmlify('

');
        slider.append(cursor);
        // cursor position
        var set_cursor_position = function(y) {
            var slider_rect = slider.getBoundingClientRect();
            var slider_height = slider_rect.bottom - slider_rect.top;
            var raw_position = y - slider_rect.top - 10;
            var corrected_position =
                (raw_position < 0) ?
                0 : ((raw_position > slider_height - 20) ?
                     slider_height - 20 : raw_position);
            cursor.style.top = corrected_position + "px";
            // current_position is useful to determine the current block
            current_position = y + slider_rect.top + 10;
        };

        var first_block = blocks[0].getBoundingClientRect();
        setTimeout(function() {
            set_cursor_position((first_block.top + first_block.bottom) / 2);
        }, 0);

        // define events on slider
        var follow_mouse = function(e) {
            set_cursor_position(e.clientY);
        };
        cursor.addEventListener("mousedown", function(e) {
            document.addEventListener("mousemove", follow_mouse);
            e.preventDefault();
        });
        document.addEventListener("mouseup", function() {
            document.removeEventListener("mousemove", follow_mouse);
            show_block_comments();
        });
    })();

    // INITIALIZE LIBRARIES

    // make a diff_match_patch object once and for all
    var dmp = new diff_match_patch();

    // CKEDITOR is not required thus we must check if it is available
    if (typeof CKEDITOR !== "undefined") {
        // turn off automatic editor creation once and for all
        CKEDITOR.disableAutoInline = true;
    }
    var editor;

    // AUXILIARY FUNCTIONS

    var highlight_current_block = function() {
        for (var i = 0; i < blocks.length; i++) {
            blocks[i].style.background = "transparent";
        }
        current_block.style.background = "rgba(211,211,211,0.5)";
    };

    // content after CKEditor reformatting
    // after decoding html entities
    // and after removing extra whitespace and new lines
    var getEditorContent = function() {
        return utils.clean_html(editor.getData());
    };

    var getBlockContent = function() {
        return utils.clean_html(current_block.innerHTML);
    }

    // FUNCTIONS WHICH ENABLE COMMENTING AND EDITING

    var init = function(comment_postbox) {
        comment_field = $(".textarea", comment_postbox);
        // let's curry!
        return function() {
            show_original();
            if (mode === "reading" && comment_field.innerHTML !== "") {
                mode = "commenting";
                original_content = getBlockContent();
                new_content = null;
                current_block.setAttribute("contenteditable", true);
                if (typeof CKEDITOR !== "undefined") {
                    editor = CKEDITOR.inline(current_block);
                    editor.on("instanceReady", function() {
                        editor.dataProcessor.writer.setRules("p", {
                            ident: false,
                            breakBeforeOpen: false,
                            breakAfterOpen: false,
                            breakBeforeClose: false,
                            breakAfterClose: false
                        });
                        original_content = getEditorContent();
                    });
                    editor.on("change", maybe_article_just_changed);
                }
                // first time : create cancel button and associate event
                if (!cancel_button) {
                    cancel_button = $(".post-action", comment_postbox).prepend(
                      '<input type="reset" value="' + i18n.translate("postbox-cancel") + '"></input>');
                    cancel_button.on("click", function(e) {
                        if (new_content === null ||
                            confirm(i18n.translate("postbox-confirm-cancel"))) {
                            comment_field.innerHTML = "";
                            cancel();
                        }
                    });
                }
                else {
                  cancel_button.style.display = "inline";
                }
            }
            else if (mode === "commenting" && comment_field.innerHTML === ""
                                           && new_content === null) {
                cancel();
            }
        };
    };

    var maybe_article_just_changed = function() {
        var current = typeof CKEDITOR === "undefined" ?
                        getBlockContent() :
                        getEditorContent();
        if (current !== original_content) {
            new_content = current;
        }
        else {
            new_content = null;
            if (comment_field.innerHTML === i18n.translate("postbox-text") ||
                comment_field.innerHTML === "") {
                current_block.blur();
                cancel();
            }
        }
    };

    var cancel = function() {
        if (mode === "commenting") {
            if (typeof editor !== "undefined") {
                editor.destroy();
            }
            current_block.setAttribute("contenteditable", false);
            if (new_content !== null) {
                current_block.innerHTML = original_content;
                new_content = null;
            }
            cancel_button.hide();
            mode = "reading";
        }
    };

    // FUNCTIONS TO SHOW COMMENTS / EDITS

    var save_comment = function(el, block_id) {
        comments.push({el: el, block: block_id});
    };

    var show_block_comments = function() {
        // when showing an edit or commenting, the current block is locked
        // this function is useless if there are no blocks
        if (mode == "reading" && blocks !== null) {
            // current block = block at current_position
            var i = 0;
            while (i < blocks.length &&
                   blocks[i].getBoundingClientRect().top <= current_position) {
                i++;
            }
            current_block = blocks[i - 1];
            highlight_current_block();
            // mask all comments that are not associated with the current block
            for (var i = 0 ; i < comments.length ; i++ ) {
                comments[i].el.style.display =
                    (comments[i].block === current_block.id) ?
                    "block" :
                    "none";
            }
        }
    };

    var show_edit = function(el, comment) {
        // let's curry!
        return function() {
            if (mode === "reading" || mode === "reading_modification") {
                if (currently_showing === comment.id) {
                    show_original();
                }
                else {
                    var previous_block = current_block;

                    // first check that the block associated with the comment
                    // exists or that there is no associated block simply
                    // because the page has no blocks
                    if (comment.block === "") {
                        if (blocks !== null) { return; }
                    }
                    else {
                        if (blocks === null) { return; }
                        var i = 0;
                        while (
                            i < blocks.length &&
                            blocks[i].id !== comment.block
                        ) { i++; }
                        if (i === blocks.length) { return; }
                        current_block = blocks[i];
                        highlight_current_block();
                    }

                    // save original content for later if it was not already
                    if (mode === "reading") {
                        original_content = getBlockContent();
                    }
                    else if (previous_block !== current_block) {
                        // restore original content for previous block
                        previous_block.innerHTML = original_content;
                        original_content = getBlockContent();
                    }

                    mode = "reading_modification";
                    currently_showing = comment.id;

                    // print diffs
                    var array = JSON.parse(he.decode(comment.edit));
                    var html = dmp.diff_prettyHtml(array);
                    current_block.innerHTML = html;

                    // add button to go back to standard reading mode
                    original_button.style.visibility = "visible";

                    // display selected comment in green and all others are set back to default
                    var comments = $(".isso-comment", null, false);
                    for (var i = 0; i < comments.length; i++) {
                        comments[i].classList.remove("selected");
                    }
                    el.classList.add("selected");

                    // scroll to block then to first change
                    var edit_top = $("#edit");
                    if (!edit_top.topIsVisible()) {
                        current_block.scrollIntoView();
                    }
                    if (!edit_top.topIsVisible()) {
                        edit_top.scrollIntoView();
                    }
                }
            }
        };
    };

    var show_original = function() {
        if (mode === "reading_modification") {
            // restore original display
            current_block.innerHTML = original_content;
            original_button.style.visibility = "hidden";
            var comments = $(".isso-comment", null, false);
            for (var i = 0; i < comments.length; i++) {
                comments[i].classList.remove("selected");
            }
            mode = "reading";
            currently_showing = null;
            // now show the current block like if we had just scrolled
            show_block_comments();
        }
    };

    // DEFINE EVENTS

    // fallback if we cannot use CKEditor change event
    if (typeof CKEDITOR === "undefined") {
        article.on("keyup", maybe_article_just_changed);
    }

    document.addEventListener("keydown", function(e) {
        if (e.keyCode === 27) {
            show_original();
        }
    });

    window.addEventListener("scroll", show_block_comments);

    // PUBLIC METHODS

    return {
        init: init,
        new_content: function() {
            if (new_content === null) {
                return null;
            }
            // otherwise we apply some pre-treatment before returning
            var splitted = dmp.diff_wordsToChars_(original_content, new_content);
            var diffs = dmp.diff_main(splitted.chars1, splitted.chars2);
            dmp.diff_cleanupSemantic(diffs);
            dmp.diff_charsToLines_(diffs, splitted.wordArray);
            return JSON.stringify(diffs);
        },
        block_id: function() { return current_block.id; },
        save_comment: save_comment,
        show_block_comments: show_block_comments,
        cancel: cancel,
        show: show_edit,
        original_button: create_original_button,
        show_original: show_original
    };
});

<|endoftext|>


<commit_before>var tswlairmgr = tswlairmgr || {};
tswlairmgr.turnin = tswlairmgr.turnin || {};

tswlairmgr.turnin.PickTable = function PickTable(node) {
	this.rowPrototype = null;
	this.picks = [];

	this.countOutstanding = 0;
	this.countReceived = 0;

	var self = this;

	this.el = {
		root: node,
		table: {
			root: document.getElementById("picks"),
			content: document.getElementById("picks").getElementsByTagName("tbody")[0]
		},
		counter: {
			received: document.getElementById("pick-table-count").getElementsByClassName("count-received")[0],
			outstanding: document.getElementById("pick-table-count").getElementsByClassName("count-outstanding")[0]
		},
		downloadButton: document.getElementById("download-button")
	};

	this.redrawCounts = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> redrawCounts called');
		}

		this.el['counter']['received'].innerHTML = this.countReceived;
		this.el['counter']['outstanding'].innerHTML = this.countOutstanding;
	}

	this.checkFragment = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> checkFragment called');
		}

		this.countOutstanding--;
		this.countReceived++;
		this.redrawCounts();
	};

	this.uncheckFragment = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> uncheckFragment called');
		}

		this.countOutstanding++;
		this.countReceived--;
		this.redrawCounts();
	};

	this.downloadHandler = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> downloadHandler called');
		}

		var nameColors = tswlairmgr.settings.name_colors;

		var chatScriptCode = '';
		var systemHeadingColorLight = '#ffcc00';
		var systemHeadingColorDark = '#e97f0d';
		var systemBodyColor = '#ffffff';

		var hRule = '' + (Array(32).join('-')) + '\n';

		for(var i=0; i<tswlairmgr.bossfragmentsInstance.lair.bosses.length; i++)
		{
			var missionName = tswlairmgr.bossfragmentsInstance.lair.bosses[i]['mission_name'];
			var bossName = tswlairmgr.bossfragmentsInstance.lair.bosses[i]['name'];

			var missionPicksHeader = '' + missionName + '\n' +
				'(' + bossName + ')\n';

			var missionPicksCode = '';
			for(var j=0; j<self.picks.length; j++)
			{
				var pickSet = self.picks[j];
				var pickedFragmentForMission = pickSet.picks[i];
				var fragmentName = pickedFragmentForMission.icon.el['name'].innerHTML;

				var line = '' + pickSet.name + ': ' + fragmentName + '\n';

				missionPicksCode += line;
			}

			chatScriptCode += ((i==0) ? hRule : '') +
				missionPicksHeader +
				missionPicksCode +
				hRule;
		}

		chatScriptCode += 'Generated by <a href="text://
TSW Lair Manager

http://github.com/julianrupp/tswlairmgr
" face="NORMAL">Cobin\'s TSW Lair Manager';

		var blob = new Blob([chatScriptCode], {type: "application/octet-stream;charset=utf-8"});
		saveAs(blob, "tswlairmgr");
	}

	this.update = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> update called');
		}

		var bf = tswlairmgr.bossfragmentsInstance;

		this.picks = tswlairmgr.turninparticipantsInstance.getParticipants();

		var picksByBossAndFragment = [];
		for(var i=0; i<bf.bosses.length; i++)
		{
			picksByBossAndFragment[i] = [];
			var boss = bf.bosses[i];
			for(var j=0; j<boss.fragments.length; j++)
			{
				picksByBossAndFragment[i][j] = 0;
			}
		}

		for(var i=0; i<bf.bosses.length; i++)
		{
			var boss = bf.bosses[i];
			var availablePlayers = tswlairmgr.turninparticipantsInstance.getParticipantsAvailableForMission(i);

			/* Fetch fragment counts list */
			var fragmentCounts = [];
			for(var j=0; j<boss.fragments.length; j++)
			{
				var fragment = boss.fragments[j];

				fragmentCounts[j] = fragment.controls.getCount();
			}

			/* Assign Boss fragments to people for this boss */
			for(var k=0; k<availablePlayers.length; k++)
			{
				var playerToAssign = availablePlayers[k];

				/* Find best fragment pick choice */
				var lowestFragmentCount = null;
				var lowestFragmentIndex = null;
				for(var l=0; l<fragmentCounts.length; l++)
				{
					if(lowestFragmentCount === null || fragmentCounts[l] < lowestFragmentCount)
					{
						lowestFragmentCount = fragmentCounts[l];
						lowestFragmentIndex = l;
					}
				}

				/* Pick */
				for(var m=0; m<this.picks.length; m++)
				{
					if(this.picks[m].name == playerToAssign)
					{
						this.picks[m].picks = this.picks[m].picks || [];
						this.picks[m].picks[i] = tswlairmgr.bossfragmentsInstance.bosses[i].fragments[lowestFragmentIndex];

						picksByBossAndFragment[i][lowestFragmentIndex]++;

						fragmentCounts[lowestFragmentIndex]++;

						console.log('>>> Boss '+(i+1)+': '+playerToAssign+' = '+this.picks[m].picks[i].icon.el['name'].innerHTML);
					}
				}
			}
		}

		/* Update total fragment counts in boss fragment table */
		var bf = tswlairmgr.bossfragmentsInstance;
		for(var i=0; i<bf.bosses.length; i++)
		{
			var boss = bf.bosses[i];
			var availablePlayers = tswlairmgr.turninparticipantsInstance.getParticipantsAvailableForMission(i);

			/* Fetch fragment counts list */
			var fragmentCounts = [];
			for(var j=0; j<boss.fragments.length; j++)
			{
				var fragment = boss.fragments[j];

				tswlairmgr.bossfragmentsInstance
					.bosses[i]
					.fragments[j]
					.controls.setCountAll(
						fragment.controls.getCount() + picksByBossAndFragment[i][j]
					);
			}
		}

		this.redraw();
	};

	this.redraw = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> redraw called');
		}

		/* Clear table */
		while(this.el['table']['content'].firstChild)
		{
			this.el['table']['content'].removeChild(this.el['table']['content'].firstChild);
		}
		this.countOutstanding = 0;
		this.countReceived = 0;

		for(var i=0; i<this.picks.length; i++)
		{
			var participant = this.picks[i];

			var newRowNode = this.rowPrototype.cloneNode(true); /* Deep copy */

			newRowNode.getElementsByClassName("name")[0].innerHTML = participant.name;
			for(var j=0; j<participant.picks.length; j++)
			{
				if(participant.picks[j])
				{
					var itemNode = participant.picks[j].icon.el['root'].cloneNode(true); /* Deep copy */

					itemNode.className += ' small';

					newRowNode.getElementsByClassName("fragment-checkbox")[j].appendChild(itemNode);

					this.countOutstanding++;
				}
				else
				{
					// TODO: Insert disabled empty boss fragment icon here
				}
			}

			this.el['table']['content'].appendChild(newRowNode);
		}

		this.el['counter']['received'].innerHTML = this.countReceived;
		this.el['counter']['outstanding'].innerHTML = this.countOutstanding;

		/* Enhance fragments */
		var elms = this.el['table']['content'].getElementsByClassName("fragment-checkbox");
		for(var i=0; i<elms.length; i++)
		{
			if(!elms[i].className.match(/\bdisabled\b/) && elms[i].getElementsByClassName("item").length != 0)
			{
				elms[i].style.cursor = 'pointer';
				elms[i].onclick = (function(objSelf, obj) {
					return function() {
						if(objSelf.className.match(/\bchecked\b/))
						{
							objSelf.className = 'fragment-checkbox';
							obj.uncheckFragment();
						}
						else
						{
							objSelf.className = 'fragment-checkbox checked';
							obj.checkFragment();
						}
					}
				})(elms[i], this);
			}
			else
			{
				elms[i].style.cursor = 'default';
			}
		}

		if(this.picks.length == 0)
		{
			this.el['downloadButton'].disabled = true;
		}
		else
		{
			this.el['downloadButton'].disabled = false;
		}
	};

	this.init = function() {
		/* Initialize row prototype */
		var rowPrototypeNode = this.el['table']['content'].getElementsByClassName("prototype")[0];
		this.rowPrototype = rowPrototypeNode.cloneNode(true); /* Deep copy */

		var rowPrototypeClasses = this.rowPrototype.className.split(" ");
		var prototypeClassIndex = rowPrototypeClasses.indexOf("prototype");
		if(prototypeClassIndex > -1) /* should always be true, but check for sanity */
		{
			rowPrototypeClasses.splice(prototypeClassIndex, 1);
		}
		this.rowPrototype.className = rowPrototypeClasses.join(" ");

		rowPrototypeNode.parentNode.removeChild(rowPrototypeNode);

		this.el['downloadButton'].onclick = this.downloadHandler;

		this.update();
	};

	if(tswlairmgr.settings.debug)
	{
		console.log('<tswlairmgr.turnin.PickTable> instance created');
	}

	this.init();
};<commit_msg>Fixed a bug where the TSW chat script download button would no longer work as soon as at least one person was marked as unavailable for at least one mission.<commit_after>var tswlairmgr = tswlairmgr || {};
tswlairmgr.turnin = tswlairmgr.turnin || {};

tswlairmgr.turnin.PickTable = function PickTable(node) {
	this.rowPrototype = null;
	this.picks = [];

	this.countOutstanding = 0;
	this.countReceived = 0;

	var self = this;

	this.el = {
		root: node,
		table: {
			root: document.getElementById("picks"),
			content: document.getElementById("picks").getElementsByTagName("tbody")[0]
		},
		counter: {
			received: document.getElementById("pick-table-count").getElementsByClassName("count-received")[0],
			outstanding: document.getElementById("pick-table-count").getElementsByClassName("count-outstanding")[0]
		},
		downloadButton: document.getElementById("download-button")
	};

	this.redrawCounts = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> redrawCounts called');
		}

		this.el['counter']['received'].innerHTML = this.countReceived;
		this.el['counter']['outstanding'].innerHTML = this.countOutstanding;
	}

	this.checkFragment = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> checkFragment called');
		}

		this.countOutstanding--;
		this.countReceived++;
		this.redrawCounts();
	};

	this.uncheckFragment = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> uncheckFragment called');
		}

		this.countOutstanding++;
		this.countReceived--;
		this.redrawCounts();
	};

	this.downloadHandler = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> downloadHandler called');
		}

		var nameColors = tswlairmgr.settings.name_colors;

		var chatScriptCode = '';
		var systemHeadingColorLight = '#ffcc00';
		var systemHeadingColorDark = '#e97f0d';
		var systemBodyColor = '#ffffff';

		var hRule = '' + (Array(32).join('-')) + '\n';

		for(var i=0; i<tswlairmgr.bossfragmentsInstance.lair.bosses.length; i++)
		{
			var missionName = tswlairmgr.bossfragmentsInstance.lair.bosses[i]['mission_name'];
			var bossName = tswlairmgr.bossfragmentsInstance.lair.bosses[i]['name'];

			var missionPicksHeader = '' + missionName + '\n' +
				'(' + bossName + ')\n';

			var missionPicksCode = '';
			for(var j=0; j<self.picks.length; j++)
			{
				var pickSet = self.picks[j];
				var pickedFragmentForMission = pickSet.picks[i];
				if(pickedFragmentForMission)
				{
					var fragmentName = pickedFragmentForMission.icon.el['name'].innerHTML;

					var line = '' + pickSet.name + ': ' + fragmentName + '\n';

					missionPicksCode += line;
				}
			}

			chatScriptCode += ((i==0) ? hRule : '') +
				missionPicksHeader +
				missionPicksCode +
				hRule;
		}

		chatScriptCode += 'Generated by <a href="text://
TSW Lair Manager

http://github.com/julianrupp/tswlairmgr
" face="NORMAL">Cobin\'s TSW Lair Manager';

		var blob = new Blob([chatScriptCode], {type: "application/octet-stream;charset=utf-8"});
		saveAs(blob, "tswlairmgr");
	}

	this.update = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> update called');
		}

		var bf = tswlairmgr.bossfragmentsInstance;

		this.picks = tswlairmgr.turninparticipantsInstance.getParticipants();

		var picksByBossAndFragment = [];
		for(var i=0; i<bf.bosses.length; i++)
		{
			picksByBossAndFragment[i] = [];
			var boss = bf.bosses[i];
			for(var j=0; j<boss.fragments.length; j++)
			{
				picksByBossAndFragment[i][j] = 0;
			}
		}

		for(var i=0; i<bf.bosses.length; i++)
		{
			var boss = bf.bosses[i];
			var availablePlayers = tswlairmgr.turninparticipantsInstance.getParticipantsAvailableForMission(i);

			/* Fetch fragment counts list */
			var fragmentCounts = [];
			for(var j=0; j<boss.fragments.length; j++)
			{
				var fragment = boss.fragments[j];

				fragmentCounts[j] = fragment.controls.getCount();
			}

			/* Assign Boss fragments to people for this boss */
			for(var k=0; k<availablePlayers.length; k++)
			{
				var playerToAssign = availablePlayers[k];

				/* Find best fragment pick choice */
				var lowestFragmentCount = null;
				var lowestFragmentIndex = null;
				for(var l=0; l<fragmentCounts.length; l++)
				{
					if(lowestFragmentCount === null || fragmentCounts[l] < lowestFragmentCount)
					{
						lowestFragmentCount = fragmentCounts[l];
						lowestFragmentIndex = l;
					}
				}

				/* Pick */
				for(var m=0; m<this.picks.length; m++)
				{
					if(this.picks[m].name == playerToAssign)
					{
						this.picks[m].picks = this.picks[m].picks || [];
						this.picks[m].picks[i] = tswlairmgr.bossfragmentsInstance.bosses[i].fragments[lowestFragmentIndex];

						picksByBossAndFragment[i][lowestFragmentIndex]++;

						fragmentCounts[lowestFragmentIndex]++;

						if(tswlairmgr.settings.debug)
						{
							console.log('>>> Boss '+(i+1)+': '+playerToAssign+' = '+this.picks[m].picks[i].icon.el['name'].innerHTML);
						}
					}
				}
			}
		}

		/* Update total fragment counts in boss fragment table */
		var bf = tswlairmgr.bossfragmentsInstance;
		for(var i=0; i<bf.bosses.length; i++)
		{
			var boss = bf.bosses[i];
			var availablePlayers = tswlairmgr.turninparticipantsInstance.getParticipantsAvailableForMission(i);

			/* Fetch fragment counts list */
			var fragmentCounts = [];
			for(var j=0; j<boss.fragments.length; j++)
			{
				var fragment = boss.fragments[j];

				tswlairmgr.bossfragmentsInstance
					.bosses[i]
					.fragments[j]
					.controls.setCountAll(
						fragment.controls.getCount() + picksByBossAndFragment[i][j]
					);
			}
		}

		this.redraw();
	};

	this.redraw = function() {
		if(tswlairmgr.settings.debug)
		{
			console.log('<tswlairmgr.turnin.PickTable> redraw called');
		}

		/* Clear table */
		while(this.el['table']['content'].firstChild)
		{
			this.el['table']['content'].removeChild(this.el['table']['content'].firstChild);
		}
		this.countOutstanding = 0;
		this.countReceived = 0;

		for(var i=0; i<this.picks.length; i++)
		{
			var participant = this.picks[i];

			var newRowNode = this.rowPrototype.cloneNode(true); /* Deep copy */

			newRowNode.getElementsByClassName("name")[0].innerHTML = participant.name;
			for(var j=0; j<participant.picks.length; j++)
			{
				if(participant.picks[j])
				{
					var itemNode = participant.picks[j].icon.el['root'].cloneNode(true); /* Deep copy */

					itemNode.className += ' small';

					newRowNode.getElementsByClassName("fragment-checkbox")[j].appendChild(itemNode);

					this.countOutstanding++;
				}
				else
				{
					// TODO: Insert disabled empty boss fragment icon here
				}
			}

			this.el['table']['content'].appendChild(newRowNode);
		}

		this.el['counter']['received'].innerHTML = this.countReceived;
		this.el['counter']['outstanding'].innerHTML = this.countOutstanding;

		/* Enhance fragments */
		var elms = this.el['table']['content'].getElementsByClassName("fragment-checkbox");
		for(var i=0; i<elms.length; i++)
		{
			if(!elms[i].className.match(/\bdisabled\b/) && elms[i].getElementsByClassName("item").length != 0)
			{
				elms[i].style.cursor = 'pointer';
				elms[i].onclick = (function(objSelf, obj) {
					return function() {
						if(objSelf.className.match(/\bchecked\b/))
						{
							objSelf.className = 'fragment-checkbox';
							obj.uncheckFragment();
						}
						else
						{
							objSelf.className = 'fragment-checkbox checked';
							obj.checkFragment();
						}
					}
				})(elms[i], this);
			}
			else
			{
				elms[i].style.cursor = 'default';
			}
		}

		if(this.picks.length == 0)
		{
			this.el['downloadButton'].disabled = true;
		}
		else
		{
			this.el['downloadButton'].disabled = false;
		}
	};

	this.init = function() {
		/* Initialize row prototype */
		var rowPrototypeNode = this.el['table']['content'].getElementsByClassName("prototype")[0];
		this.rowPrototype = rowPrototypeNode.cloneNode(true); /* Deep copy */

		var rowPrototypeClasses = this.rowPrototype.className.split(" ");
		var prototypeClassIndex = rowPrototypeClasses.indexOf("prototype");
		if(prototypeClassIndex > -1) /* should always be true, but check for sanity */
		{
			rowPrototypeClasses.splice(prototypeClassIndex, 1);
		}
		this.rowPrototype.className = rowPrototypeClasses.join(" ");

		rowPrototypeNode.parentNode.removeChild(rowPrototypeNode);

		this.el['downloadButton'].onclick = this.downloadHandler;

		this.update();
	};

	if(tswlairmgr.settings.debug)
	{
		console.log('<tswlairmgr.turnin.PickTable> instance created');
	}

	this.init();
};<|endoftext|>


<commit_before>var _ = require('lodash'),
	ffmpeg = require('fluent-ffmpeg');
var ShowImporter = require('../importers/ShowImporter.js');
var traktConfig = require('../../config/trakt');
var directoriesConfig = require('../../config/directories');
module.exports = function home(app, models){
	app.get('/shows', function(req, res){
		var Show = models.Show;
		if(req.isAuthenticated()){
			Show.find(function(err, shows){
				res.render('shows/index', {
					shows: shows
				});
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/show/:show', function(req, res){
		var Show = models.Show,
			Episode = models.Episode;
		if(req.isAuthenticated()){
			Show.findOne({url: req.params.show}, function(err, show){
				if(!show || show.length == 0){
					return res.render('error.html', {
						message: 'Show not found'
					});
				}
				//console.log(show)
				if(show && show.seasons){
					show.seasons = show.seasons.sort(function(a, b){
							if(a.season > b.season){
								return 1;
							}else if(a.season < b.season){
								return -1;
							}
							return 0;
					});
				}
				Episode.find({'show': show._id}, function(err, episodes){
					if(err){
						console.log(err);
					}
					//console.log('lol', episodes)
					var seasons = {};
					_.each(episodes, function (el){
						var s = el.season,
							e = el.episode;
						if(!seasons[s]){
							seasons[s] = {};
							seasons[s].num = s;
						}
						var season = seasons[s];
						if(!season.episodes){
							season.episodes = [];
						}
						if(show && show.seasons){
							if(show.seasons && show.seasons[s] && show.seasons[s].episodes){
								el = _.merge(el, show.seasons[s].episodes[e-1])
								//console.log(show.seasons[s].episodes[e])
							}
						}
						season.episodes.push(el)
					});
					seasons = _.each(seasons, function(season){
						if(season){
							season.episodes = season.episodes.sort(function(a, b){
								if(a.episode > b.episode){
									return 1;
								}else if(a.episode < b.episode){
									return -1;
								}
								return 0;
							});
						}
					});
					res.render('shows/single', {
						show: show,
						seasons: seasons
					});
				})
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/watch/:episodeId', function(req, res){
		var dir = directoriesConfig.tv,
			Episode = models.Episode;
		if(req.isAuthenticated()){
			Episode
			.findOne({'_id': req.params.episodeId})
			.populate('show')
			.exec(function(err, ep){
				console.log(ep)
				res.render('shows/episode', {
					show: {},
					ep: ep
				});
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/transcode/:episodeId', function(req, res){
		var dir = directoriesConfig.tv,
			Episode = models.Episode;
		if(req.isAuthenticated()){
			Episode
			.findOne({'_id': req.params.episodeId})
			.populate('show')
			.exec(function(err, ep){
				if(ep && ep.file){
					var options = [
						//'-threads 0',
						//'-coder 0',
						//'-flags -loop',
						//'-pix_fmt yuv420p',
						//'-subq 0',
						//'-sc_threshold 0',
						//'-keyint_min 150',
						//'-deinterlace',
						//'-maxrate 10000000',
						//'-bufsize 10000000',
						//'-acodec aac',
						'-strict experimental',
						//'-frag_duration 1000',
						'-movflags faststart+frag_keyframe+empty_moov',
						'-profile:v baseline'
					];
					// High quality, not lossless
					//options.push('-g 52', '-crf 22', '-ar 48000', '-ab 320k');
					res.contentType('video/mp4');
					console.log(ep.file)
					var proc = ffmpeg({source: dir + ep.file})
					.format('mp4')
					.audioCodec('aac')
					.addOptions(options)
					.on('start', function(commandLine) {
						console.log('Spawned Ffmpeg with command: ' + commandLine);
					})
					.on('end', function(){
						console.log('file has been converted succesfully');
					})
					.on('error', function(err){
						console.log('an error happened: ' + err.message);
					})
					.pipe(res, {end:true});

				}
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/import', function(req, res){
		var dir = directoriesConfig.tv,
			importer = new ShowImporter(traktConfig.apiKey, models);
		importer.importAll(dir, function(){});
		res.end();
	});
};<commit_msg>Uncomment options<commit_after>var _ = require('lodash'),
	ffmpeg = require('fluent-ffmpeg');
var ShowImporter = require('../importers/ShowImporter.js');
var traktConfig = require('../../config/trakt');
var directoriesConfig = require('../../config/directories');
module.exports = function home(app, models){
	app.get('/shows', function(req, res){
		var Show = models.Show;
		if(req.isAuthenticated()){
			Show.find(function(err, shows){
				res.render('shows/index', {
					shows: shows
				});
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/show/:show', function(req, res){
		var Show = models.Show,
			Episode = models.Episode;
		if(req.isAuthenticated()){
			Show.findOne({url: req.params.show}, function(err, show){
				if(!show || show.length == 0){
					return res.render('error.html', {
						message: 'Show not found'
					});
				}
				//console.log(show)
				if(show && show.seasons){
					show.seasons = show.seasons.sort(function(a, b){
							if(a.season > b.season){
								return 1;
							}else if(a.season < b.season){
								return -1;
							}
							return 0;
					});
				}
				Episode.find({'show': show._id}, function(err, episodes){
					if(err){
						console.log(err);
					}
					//console.log('lol', episodes)
					var seasons = {};
					_.each(episodes, function (el){
						var s = el.season,
							e = el.episode;
						if(!seasons[s]){
							seasons[s] = {};
							seasons[s].num = s;
						}
						var season = seasons[s];
						if(!season.episodes){
							season.episodes = [];
						}
						if(show && show.seasons){
							if(show.seasons && show.seasons[s] && show.seasons[s].episodes){
								el = _.merge(el, show.seasons[s].episodes[e-1])
								//console.log(show.seasons[s].episodes[e])
							}
						}
						season.episodes.push(el)
					});
					seasons = _.each(seasons, function(season){
						if(season){
							season.episodes = season.episodes.sort(function(a, b){
								if(a.episode > b.episode){
									return 1;
								}else if(a.episode < b.episode){
									return -1;
								}
								return 0;
							});
						}
					});
					res.render('shows/single', {
						show: show,
						seasons: seasons
					});
				})
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/watch/:episodeId', function(req, res){
		var dir = directoriesConfig.tv,
			Episode = models.Episode;
		if(req.isAuthenticated()){
			Episode
			.findOne({'_id': req.params.episodeId})
			.populate('show')
			.exec(function(err, ep){
				console.log(ep)
				res.render('shows/episode', {
					show: {},
					ep: ep
				});
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/transcode/:episodeId', function(req, res){
		var dir = directoriesConfig.tv,
			Episode = models.Episode;
		if(req.isAuthenticated()){
			Episode
			.findOne({'_id': req.params.episodeId})
			.populate('show')
			.exec(function(err, ep){
				if(ep && ep.file){
					var options = [
						'-threads 0',
						'-coder 0',
						'-flags -loop',
						'-pix_fmt yuv420p',
						'-subq 0',
						'-sc_threshold 0',
						'-keyint_min 150',
						'-deinterlace',
						'-maxrate 10000000',
						'-bufsize 10000000',
						'-acodec aac',
						'-strict experimental',
						'-frag_duration 1000',
						'-movflags +frag_keyframe+empty_moov',
						'-profile:v baseline'
					];
					// High quality, not lossless
					options.push('-g 52', '-crf 22', '-ar 48000', '-ab 320k');
					res.contentType('video/mp4');
					console.log(ep.file)
					var proc = ffmpeg({source: dir + ep.file})
					.format('libx264')
					.audioCodec('aac')
					.addOptions(options)
					.on('start', function(commandLine) {
						console.log('Spawned Ffmpeg with command: ' + commandLine);
					})
					.on('end', function(){
						console.log('file has been converted succesfully');
					})
					.on('error', function(err){
						console.log('an error happened: ' + err.message);
					})
					.pipe(res, {end:true});

				}
			});
		}else{
			res.redirect('/auth/login');
		}
	});
	app.get('/import', function(req, res){
		var dir = directoriesConfig.tv,
			importer = new ShowImporter(traktConfig.apiKey, models);
		importer.importAll(dir, function(){});
		res.end();
	});
};<|endoftext|>