<commit_before>(function () {

    'use strict';

    var stack        = require('callsite'),
        util         = require('util'),
        EventEmitter = require('events').EventEmitter,
        path         = require('path'),
        colorsjs     = require('colors/safe');

    /**
     * consoleOriginal
     *
     * NodeJS console object
     * @type {Object}
     */
    var consoleOriginal = console;

    /**
     * getLocation
     *
     * Get location of log.
     * ie. filename and line number
     */
    var getLocation = function () {

        var st     = stack()[2],
            result = {};

        result.filename = path.basename(st.getFileName());
        result.line = st.getLineNumber();

        return result;
    };

    /**
     * buildTime
     *
     * @param  {timestamp} timestamp
     * @return {String}                  timestamp to String
     */
    var buildTime = function (timestamp) {
        return (new Date(timestamp)).toISOString() + " ";
    };

    /**
     * buildDate
     *
     * @param  {timestamp} timestamp
     * @return {String}             timestamp to string
     */
    var buildDate = function (timestamp) {
        return (new Date(timestamp)).toDateString() + " ";
    };

    /**
     * buildTags
     *
     * @param  {Array} tags
     * @return {String}     "[tag1][tag2]"
     */
    var buildTags = function (tags) {
        return '[' + tags.join('][') + ']';
    };

    /**
     * buildFileInfos
     *
     * @param {Object} infos
     * @param {String} infos.filename
     * @param {String} infos.line
     */
    var buildFileInfos = function (infos) {
        return '[' + infos.filename + ':' + infos.line + ']';
    };

    /**
     * applyColors
     *
     * Apply style with colors.js on the console output
     * @param {String}       msg    The msg to stylize
     * @param {Array|String} colors The colors
     *
     * @return {String}
     */
    var applyColors = function (msg, colors) {

        if (!colors) {
            colors = [];
        }

        if (typeof colors === 'string') {
            colors = [colors];
        }

        colors.forEach(function (color) {
            if (typeof colorsjs[color] === 'function') {
                msg = colorsjs[color](msg);
            }
        });

        return msg;

    };

    /*
     * Console2
     *
     * @constructor
     *
     * @param {Object}       opt                     Optional default options for all loggers.
     * @param {Boolean}      opt.logInConsole        Should all loggers print to console by default ? Default true.
     * @param {Boolean}      opt.logInFile           Should all loggers saver log in file by default ? Default true.
     *
     * @param {int}          opt.contextMediumSize   Medium size of the context part of a log message.
     *                                               Used when calculating indent. Default to 45.
     * @param {int}          opt.spaceSize           Space between context part and log part. Default to 4.
     * @param {Array|String} opt.colors              Default colors output for all loggers. Default ['cyan'].
     *
     * @param {Boolean}      opt.alwaysTags          Always print tags (even without tag() ). Default false.
     * @param {Boolean}      opt.alwaysLocation      Always print location (even without file() ). Default false.
     * @param {Boolean}      opt.alwaysTime          Always print time (even without time() ). Default false.
     * @param {Boolean}      opt.alwaysDate          Always print date (even without date() ). Default false.
     */
    var Console2 = function (opt) {

        if (!opt) {
            opt = {};
        }

        /**
         * opt
         *
         * Constructor opt.
         * Setting default.
         */
        this.opt = {
            logInConsole : opt.logInConsole || true,
            logInFile    : opt.logInFile || true,

            contextMediumSize : opt.contextMediumSize || 45,
            spaceSize         : opt.spaceSize || 4,

            colors : opt.colors || "cyan",

            alwaysTags     : opt.alwaysTags || false,
            alwaysLocation : opt.alwaysLocation || false,
            alwaysTime     : opt.alwaysTime || false,
            alwaysDate     : opt.alwaysDate || false
        };

        /**
         * _tags
         *
         * Store all tags for current log
         *
         * @type {Array}
         */
        this._tags = [];

        /**
         *._time
         *
         * Log time (full date) ?
         *
         * @type {Boolean}
         */
        this._time = false;

        /**
         * _date
         *
         * Log date ?
         *
         * @type {Boolean}
         */
        this._date = false;

        /**
         * _location
         *
         * Should we log filename and line number ?
         *
         * @type {Boolean}
         */
        this._location = false;

        /**
         * _reset
         *
         * Reset properties after log
         */
        this._reset = function () {
            this._tags    = [];
            this._time    = false;
            this._date    = false;
            this.location = false;

            return this;
        };

    };

    //inherits form EventEmitter.prototype
    util.inherits(Console2, EventEmitter);

    /**
     * Console2.prototype.time
     *
     * Log the time
     */
    Console2.prototype.time = function () {
        this._time = true;

        return this;
    };

    /**
     * Console2.prototype.date
     *
     * Log the date
     */
    Console2.prototype.date = function () {
        this._date = true;

        return this;
    };

    /**
     * Console2.prototype.tag
     *
     * Add tags
     * @param  {*} tag
     */
    Console2.prototype.tag = Console2.prototype.t = function () {
        var tags = Array.prototype.slice.call(arguments, 0);
        this._tags = this._tags.concat(tags);

        return this;
    };

    /**
     * Console2.prototype.file
     *
     * Log the file name + line
     */
    Console2.prototype.file = Console2.prototype.f = function () {
        this._location = true;

        return this;
    };

    /**
     * Console2.prototype.buildMessage
     *
     * @param {Object}  log             The log object
     *
     * @param {Object}  opt             Optional options telling what to include in the message
     * @param {Boolean} opt.tags        Print Tags ? Default false.
     * @param {Boolean} opt.location    Print location ? Default false.
     * @param {Boolean} opt.time        Print time ? Default false.
     * @param {Boolean} opt.date        Print date ? Default false.
     *
     * @return {String}                 The message to print usualy.
     */
    Console2.prototype.buildMessage = function (log, opt) {

        if (!opt) {
            opt = {};
        }

        opt.tags     = opt.tags || false;
        opt.location = opt.location || false;
        opt.time     = opt.time || false;
        opt.date     = opt.date || false;

        var result = "";

        if (opt.time && log.context.time) {
            result += buildTime(log.context.time);
        }

        if (opt.date && log.context.time) {
            result += buildDate(log.context.time);
        }

        if (opt.tags && log.context.tags) {
            result += buildTags(log.context.tags);
        }

        if (opt.location && log.context.location.filename && log.context.location.line) {
            result += buildFileInfos(log.context.location);
        }

        if (result.length > 0) { //if there is context string
            //add space according to the contextMediumSize
            var offset = this.opt.contextMediumSize  - result.length;

            if (offset < 0) { //context string could be longer than medium size
                offset = 0;
            }

            result += new Array(offset + this.opt.spaceSize).join(' ');
        }

        //It's time to log the args

        var args       = Array.prototype.slice.call(log.args, 0), //transform args in an array
            msg        = "",    //the log message
            delimiter  = '\n\n',
            multiLines = false; //if the log need multiples lines (ie. object, array)

        //Process arg one by one
        args.forEach(function (arg) {

            //if arg is an object / array
            //use multiples lines
            if (arg !== null && typeof arg === 'object') {

                msg += delimiter;

                msg += JSON.stringify(arg, null, 2);

                multiLines = true;

            //for "normal" args
            } else {
                if (multiLines) {
                    msg += delimiter;
                }
                msg += arg + "";
            }
        });

        if (multiLines) {
            msg += '\n';
            msg = msg.replace(/\n/gm, '\n' + new Array(this.opt.spaceSize).join(' '));
        }

        result += msg;

        return result;

    };

    /**
     * Console2.prototype.addLogger
     *
     * Create a new logger
     * You can then use it with console.myNewLogger
     *
     * @param {String}  name                 The name of the logger.
     * @param {String}  colors               Optional. Colors of the console output. Default cyan.
     *                                       See text colors from https://github.com/Marak/colors.js
     *
     * @param {Object}  opt                  Optional options object. @see Console2 opt for default values.
     * @param {Boolean} opt.logInConsole     Should the logger print to the console ?
     * @param {Boolean} opt.logInFile        If the log should be save in file.
     * @param {Boolean} opt.alwaysTags       Always print tags (even without tag() )
     * @param {Boolean} opt.alwaysLocation   Always print location (even without file() )
     * @param {Boolean} opt.alwaysTime       Always print time (even without time() )
     * @param {Boolean} opt.alwaysDate       Always print date (even without date() )
     */
    Console2.prototype.addLogger = function (name, colors, opt) {

        if (!opt) {
            opt = {};
        }

        if (!name) {
            throw new Error("No name given at addLogger");
        }

        opt.name             = name;
        opt.colors           = colors || this.opt.colors;
        opt.type             = opt.type || opt.name;
        opt.logInConsole     = opt.logInConsole || this.opt.logInConsole;
        opt.logInFile        = opt.logInFile || this.opt.logInFile;
        opt.alwaysTags       = opt.alwaysTags || this.opt.alwaysTags;
        opt.alwaysLocation   = opt.alwaysLocation || this.opt.alwaysLocation;
        opt.alwaysTime       = opt.alwaysTime || this.opt.alwaysTime;
        opt.alwaysDate       = opt.alwaysDate || this.opt.alwaysDate;

        this[name] = function () {

            var location = getLocation();
            var time     = Date.now();

            //Let's build the log object

            var log = {
                type       : opt.type || name,
                context    : {
                    tags     : this._tags,
                    file     : this._location,
                    time     : time,
                    location : location
                },
                args       : arguments,
                argsString : util.format.apply(console, arguments), //stringify arguments
                opt        : opt
            };

            //Build the string message
            log.message = this.buildMessage(log, {
                tags     : this._tags.length > 0 || this.opt.alwaysTags,
                location : this._location || this.opt.alwaysLocation,
                time     : this._time || this.opt.alwaysTime,
                date     : this._date || this.opt.alwaysDate
            });

            //Emit events
            this.emit('new', log, log.type);
            this.emit(log.type, log);

            //If the logger should print the message
            //Print it
            if (opt.logInConsole) {
                global.console.log(applyColors(log.message, opt.colors));
            }

            this._reset();
        };

    };

    //Keep the old console
    //use also `global.console`
    Console2.prototype.Original = consoleOriginal;

    module.exports = Console2;

}());
<commit_msg>Fix all default boolean options<commit_after>(function () {

    'use strict';

    var stack        = require('callsite'),
        util         = require('util'),
        EventEmitter = require('events').EventEmitter,
        path         = require('path'),
        colorsjs     = require('colors/safe');

    /**
     * consoleOriginal
     *
     * NodeJS console object
     * @type {Object}
     */
    var consoleOriginal = console;

    /**
     * getLocation
     *
     * Get location of log.
     * ie. filename and line number
     */
    var getLocation = function () {

        var st     = stack()[2],
            result = {};

        result.filename = path.basename(st.getFileName());
        result.line = st.getLineNumber();

        return result;
    };

    /**
     * buildTime
     *
     * @param  {timestamp} timestamp
     * @return {String}                  timestamp to String
     */
    var buildTime = function (timestamp) {
        return (new Date(timestamp)).toISOString() + " ";
    };

    /**
     * buildDate
     *
     * @param  {timestamp} timestamp
     * @return {String}             timestamp to string
     */
    var buildDate = function (timestamp) {
        return (new Date(timestamp)).toDateString() + " ";
    };

    /**
     * buildTags
     *
     * @param  {Array} tags
     * @return {String}     "[tag1][tag2]"
     */
    var buildTags = function (tags) {
        return '[' + tags.join('][') + ']';
    };

    /**
     * buildFileInfos
     *
     * @param {Object} infos
     * @param {String} infos.filename
     * @param {String} infos.line
     */
    var buildFileInfos = function (infos) {
        return '[' + infos.filename + ':' + infos.line + ']';
    };

    /**
     * applyColors
     *
     * Apply style with colors.js on the console output
     * @param {String}       msg    The msg to stylize
     * @param {Array|String} colors The colors
     *
     * @return {String}
     */
    var applyColors = function (msg, colors) {

        if (!colors) {
            colors = [];
        }

        if (typeof colors === 'string') {
            colors = [colors];
        }

        colors.forEach(function (color) {
            if (typeof colorsjs[color] === 'function') {
                msg = colorsjs[color](msg);
            }
        });

        return msg;

    };

    /*
     * Console2
     *
     * @constructor
     *
     * @param {Object}       opt                     Optional default options for all loggers.
     * @param {Boolean}      opt.logInConsole        Should all loggers print to console by default ? Default true.
     * @param {Boolean}      opt.logInFile           Should all loggers saver log in file by default ? Default true.
     *
     * @param {int}          opt.contextMediumSize   Medium size of the context part of a log message.
     *                                               Used when calculating indent. Default to 45.
     * @param {int}          opt.spaceSize           Space between context part and log part. Default to 4.
     * @param {Array|String} opt.colors              Default colors output for all loggers. Default ['cyan'].
     *
     * @param {Boolean}      opt.alwaysTags          Always print tags (even without tag() ). Default false.
     * @param {Boolean}      opt.alwaysLocation      Always print location (even without file() ). Default false.
     * @param {Boolean}      opt.alwaysTime          Always print time (even without time() ). Default false.
     * @param {Boolean}      opt.alwaysDate          Always print date (even without date() ). Default false.
     */
    var Console2 = function (opt) {

        if (!opt) {
            opt = {};
        }

        /**
         * opt
         *
         * Constructor opt.
         * Setting default.
         */
        this.opt = {
            logInConsole : opt.logInConsole !== false,
            logInFile    : opt.logInFile !== false,

            contextMediumSize : opt.contextMediumSize || 45,
            spaceSize         : opt.spaceSize || 4,

            colors : opt.colors || "cyan",

            alwaysTags     : opt.alwaysTags === true,
            alwaysLocation : opt.alwaysLocation === true,
            alwaysTime     : opt.alwaysTime === true,
            alwaysDate     : opt.alwaysDate === true
        };

        /**
         * _tags
         *
         * Store all tags for current log
         *
         * @type {Array}
         */
        this._tags = [];

        /**
         *._time
         *
         * Log time (full date) ?
         *
         * @type {Boolean}
         */
        this._time = false;

        /**
         * _date
         *
         * Log date ?
         *
         * @type {Boolean}
         */
        this._date = false;

        /**
         * _location
         *
         * Should we log filename and line number ?
         *
         * @type {Boolean}
         */
        this._location = false;

        /**
         * _reset
         *
         * Reset properties after log
         */
        this._reset = function () {
            this._tags    = [];
            this._time    = false;
            this._date    = false;
            this.location = false;

            return this;
        };

    };

    //inherits form EventEmitter.prototype
    util.inherits(Console2, EventEmitter);

    /**
     * Console2.prototype.time
     *
     * Log the time
     */
    Console2.prototype.time = function () {
        this._time = true;

        return this;
    };

    /**
     * Console2.prototype.date
     *
     * Log the date
     */
    Console2.prototype.date = function () {
        this._date = true;

        return this;
    };

    /**
     * Console2.prototype.tag
     *
     * Add tags
     * @param  {*} tag
     */
    Console2.prototype.tag = Console2.prototype.t = function () {
        var tags = Array.prototype.slice.call(arguments, 0);
        this._tags = this._tags.concat(tags);

        return this;
    };

    /**
     * Console2.prototype.file
     *
     * Log the file name + line
     */
    Console2.prototype.file = Console2.prototype.f = function () {
        this._location = true;

        return this;
    };

    /**
     * Console2.prototype.buildMessage
     *
     * @param {Object}  log             The log object
     *
     * @param {Object}  opt             Optional options telling what to include in the message
     * @param {Boolean} opt.tags        Print Tags ? Default false.
     * @param {Boolean} opt.location    Print location ? Default false.
     * @param {Boolean} opt.time        Print time ? Default false.
     * @param {Boolean} opt.date        Print date ? Default false.
     *
     * @return {String}                 The message to print usualy.
     */
    Console2.prototype.buildMessage = function (log, opt) {

        if (!opt) {
            opt = {};
        }

        opt.tags     = opt.tags === true;
        opt.location = opt.location === true;
        opt.time     = opt.time === true;
        opt.date     = opt.date === true;

        var result = "";

        if (opt.time && log.context.time) {
            result += buildTime(log.context.time);
        }

        if (opt.date && log.context.time) {
            result += buildDate(log.context.time);
        }

        if (opt.tags && log.context.tags) {
            result += buildTags(log.context.tags);
        }

        if (opt.location && log.context.location.filename && log.context.location.line) {
            result += buildFileInfos(log.context.location);
        }

        if (result.length > 0) { //if there is context string
            //add space according to the contextMediumSize
            var offset = this.opt.contextMediumSize  - result.length;

            if (offset < 0) { //context string could be longer than medium size
                offset = 0;
            }

            result += new Array(offset + this.opt.spaceSize).join(' ');
        }

        //It's time to log the args

        var args       = Array.prototype.slice.call(log.args, 0), //transform args in an array
            msg        = "",    //the log message
            delimiter  = '\n\n',
            multiLines = false; //if the log need multiples lines (ie. object, array)

        //Process arg one by one
        args.forEach(function (arg) {

            //if arg is an object / array
            //use multiples lines
            if (arg !== null && typeof arg === 'object') {

                msg += delimiter;

                msg += JSON.stringify(arg, null, 2);

                multiLines = true;

            //for "normal" args
            } else {
                if (multiLines) {
                    msg += delimiter;
                }
                msg += arg + "";
            }
        });

        if (multiLines) {
            msg += '\n';
            msg = msg.replace(/\n/gm, '\n' + new Array(this.opt.spaceSize).join(' '));
        }

        result += msg;

        return result;

    };

    /**
     * Console2.prototype.addLogger
     *
     * Create a new logger
     * You can then use it with console.myNewLogger
     *
     * @param {String}  name                 The name of the logger.
     * @param {String}  colors               Optional. Colors of the console output. Default cyan.
     *                                       See text colors from https://github.com/Marak/colors.js
     *
     * @param {Object}  opt                  Optional options object. @see Console2 opt for default values.
     * @param {Boolean} opt.logInConsole     Should the logger print to the console ?
     * @param {Boolean} opt.logInFile        If the log should be save in file.
     * @param {Boolean} opt.alwaysTags       Always print tags (even without tag() )
     * @param {Boolean} opt.alwaysLocation   Always print location (even without file() )
     * @param {Boolean} opt.alwaysTime       Always print time (even without time() )
     * @param {Boolean} opt.alwaysDate       Always print date (even without date() )
     */
    Console2.prototype.addLogger = function (name, colors, opt) {

        if (!opt) {
            opt = {};
        }

        if (!name) {
            throw new Error("No name given at addLogger");
        }

        opt.name             = name;
        opt.colors           = colors || this.opt.colors;
        opt.type             = opt.type || opt.name;
        opt.logInConsole     = opt.logInConsole || this.opt.logInConsole;
        opt.logInFile        = opt.logInFile || this.opt.logInFile;
        opt.alwaysTags       = opt.alwaysTags || this.opt.alwaysTags;
        opt.alwaysLocation   = opt.alwaysLocation || this.opt.alwaysLocation;
        opt.alwaysTime       = opt.alwaysTime || this.opt.alwaysTime;
        opt.alwaysDate       = opt.alwaysDate || this.opt.alwaysDate;

        this[name] = function () {

            var location = getLocation();
            var time     = Date.now();

            //Let's build the log object

            var log = {
                type       : opt.type || name,
                context    : {
                    tags     : this._tags,
                    file     : this._location,
                    time     : time,
                    location : location
                },
                args       : arguments,
                argsString : util.format.apply(console, arguments), //stringify arguments
                opt        : opt
            };

            //Build the string message
            log.message = this.buildMessage(log, {
                tags     : this._tags.length > 0 || this.opt.alwaysTags,
                location : this._location || this.opt.alwaysLocation,
                time     : this._time || this.opt.alwaysTime,
                date     : this._date || this.opt.alwaysDate
            });

            //Emit events
            this.emit('new', log, log.type);
            this.emit(log.type, log);

            //If the logger should print the message
            //Print it
            if (opt.logInConsole) {
                global.console.log(applyColors(log.message, opt.colors));
            }

            this._reset();
        };

    };

    //Keep the old console
    //use also `global.console`
    Console2.prototype.Original = consoleOriginal;

    module.exports = Console2;

}());
<|endoftext|>


<commit_before>'use strict';

var eLevels = [];
var tLevels = [];
var chartDates = [];

function DataPoint (date, prescription, dosage, tLevel, eLevel, logEntry){
  this.date = date;
  this.prescription = prescription;
  this.dosage = dosage;
  this.tLevel = tLevel;
  this.eLevel = eLevel;
  this.logEntry = logEntry;
};

function loadLocalStorage (){
  DataPoint.tempData = JSON.parse(localStorage.dataPoints);
  DataPoint.tempData.forEach(function (input){
  eLevels.push(input.eLevel);
  tLevels.push(input.tLevel);
  chartDates.push(input.date);
  });
};

function renderLogs(){
      var template = Handlebars.compile($('#entry-template').html());
      DataPoint.tempData.forEach(function(data){$('#user-log-info').append(template(data));});
};

$('#submit-button').on('click', function(e){
  e.preventDefault();
  var obj = new DataPoint($('#date').val(), $('#prescription').val(), parseInt($('#dosage').val()), parseInt($('#tLevel').val()), parseInt($('#eLevel').val()), $('#entry-form').val());
  if(!localStorage.dataPoints) localStorage.dataPoints = JSON.stringify([]);
  console.log(localStorage.dataPoints);
  DataPoint.tempData = JSON.parse(localStorage.dataPoints);
  DataPoint.tempData.push(obj);
  localStorage.dataPoints = JSON.stringify(DataPoint.tempData);
  renderLogs();
  renderChart();
  $.post('/submit', obj).then(console.log('post complete')).catch(console.error);
});
<commit_msg>just merged rowen's changes for the chart<commit_after>'use strict';

var eLevels = [];
var tLevels = [];
var chartDates = [];

function DataPoint (date, prescription, dosage, tLevel, eLevel, logEntry){
  this.date = date;
  this.prescription = prescription;
  this.dosage = dosage;
  this.tLevel = tLevel;
  this.eLevel = eLevel;
  this.logEntry = logEntry;
};

function loadLocalStorage (){
  DataPoint.tempData = JSON.parse(localStorage.dataPoints);
  DataPoint.tempData.forEach(function (input){
    eLevels.push(input.eLevel);
    tLevels.push(input.tLevel);
    chartDates.push(input.date);
  });
};

function renderLogs(){
  var template = Handlebars.compile($('#entry-template').html());
  DataPoint.tempData.forEach(function(data){$('#user-log-info').append(template(data));});
};

$('#submit-button').on('click', function(e){
  e.preventDefault();
  var obj = new DataPoint($('#date').val(), $('#prescription').val(), parseInt($('#dosage').val()), parseInt($('#tLevel').val()), parseInt($('#eLevel').val()), $('#entry-form').val());
  if(!localStorage.dataPoints) localStorage.dataPoints = JSON.stringify([]);
  console.log(localStorage.dataPoints);
  DataPoint.tempData = JSON.parse(localStorage.dataPoints);
  DataPoint.tempData.push(obj);
  localStorage.dataPoints = JSON.stringify(DataPoint.tempData);
  renderLogs();
  renderChart();
  $.post('/submit', obj).then(console.log('post complete')).catch(console.error);
});
<|endoftext|>


<commit_before>var user;

$(setup)

function setup() {
  user = parseUserCookie()
  $.fn.select2.defaults.formatNoMatches = 'Ei tuloksia'
  $.fn.select2.defaults.formatSearching = 'Haetaan...'
  $.fn.select2.defaults.adaptDropdownCssClass = function(c) {  return c == 'required' ? c : null }

  var login = loginPage()
  var error = errorDialog()

  $.ajaxSetup({ dataType: 'json', processData: false, contentType: 'application/json' })

  $(document).ajaxError(function(e, req) {
    if (req.status == 403) {
      login.show()
    } else {
      error.show()
    }
  })

  $('#overlay').on('click', closeDialog)

  $('body').on('click', '.dialog', stopPropagation)

  var navigation = navi()
  searchPage()
  programDetails()
  buyerPage()
  billingPage()
  navigation.start()
}

function errorDialog() {
  var $overlay = $('#error-overlay')
  var $dialog = $('#error-dialog')
  $dialog.find('a').click(function(e) { e.preventDefault(); location.reload() })
  return { show: function() { $dialog.add($overlay).show() } }
}

function loginPage() {
  var $overlay = $('#login-overlay')
  var $form = $('#login').submit(function(e) { e.preventDefault() })
  var $username = $form.find('input[name="username"]').on('input', checkInput)
  var $password = $form.find('input[name="password"]').on('input', checkInput)
  var $feedback = $form.find('.feedback')
  var $button = $form.find('button')
  var $info = $('#header .user-info').toggle(!!user)
  $info.find('.name').text(user ? user.name : '')

  $info.find('.logout').click(function() {
    $.post('/logout').done(function() { location.reload() })
  })

  $form.on('validate', function() {
    var invalid = $username.hasClass('invalid') || $password.hasClass('invalid')
    $button.prop('disabled', invalid? 'disabled' : '')
    $feedback.slideUp()
  })

  $button.click(function() {
    $.post('/login', JSON.stringify({ username: $username.val(), password: $password.val() }))
      .done(function() { location.reload() })
      .fail(function(jqXHR) {
        if (jqXHR.status == 403) {
          $password.val('').trigger('input').focus()
          $feedback.slideDown()
        }
      })
  })

  return { show: show }

  function show() {
    $form.add($overlay).show()
    $username.focus()
  }
  function checkInput() {
    $(this).toggleClass('invalid', $(this).val() === '').trigger('validate')
  }
}

function navi() {
  var $navi = $('#header .navi')

  $navi.find('a').on('click', function(e) {
    e.preventDefault()
    show($(this)).trigger('show')
  })

  function start() {
    var hash = location.hash
    if (hash == '') {
      $navi.find('a:first').click()
    } else {
      var parts = hash.split('/').map(decodeURIComponent)
      var $a = $navi.find('a[href='+parts.shift()+']')
      show($a).trigger('show', parts)
    }
  }

  function show($a) {
    $navi.find('a.active').removeClass('active')
    $a.addClass('active')
    $('body').children('.page').hide()
    return $($a.data('href')).show()
  }

  return { start: start }
}

function buyerPage() { $('#buyer-page').on('show', function() { location.hash = '#tilaajat' }) }
function billingPage() { $('#billing-page').on('show', function() { location.hash = '#laskutus'}) }

function stopPropagation(e) { e.stopPropagation() }

function isNotEmpty(val) {
  return (val.trim().length) > 0
}

function isEmail(txt) {
  var regexp = /^([A-Za-z0-9\x27\x2f!#$%&*+=?^_`{|}~-]+(\.[A-Za-z0-9\x27\x2f!#$%&*+=?^_`{|}~-]+)*)@(([a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]|[a-zA-Z0-9]{1,63})(\.([a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]|[a-zA-Z0-9]{1,63}))*\.[a-zA-Z0-9]{2,63})$/
  return regexp.test(txt)
}

function validate(f) {
  return function() {
    $(this).toggleClass('invalid', !f($(this).val())).trigger('validation')
  }
}

function validateTextChange($el, validatorFn) {
  var validator = validate(validatorFn)
  $el.on('input change validate', validator).on('blur', function() { $(this).addClass('touched') })
}

function requiredCheckboxGroup($el) {
  $el.on('change validate', 'input:checkbox', function() {
    $el.toggleClass('invalid', $el.find('input:checkbox:checked').length == 0).trigger('validation')
  })
}

function showDialog($html) {
  $('#overlay').show()
  $('#dialog').show().append($html)
}

function closeDialog() {
  $('#dialog').empty().hide()
  $('#overlay').hide()
}

$.fn.throttledInput = function(fn) {
  return $(this).each(function() {
    var prev = undefined
    var timeout = null
    var $input = $(this).on('keyup', function() {
      var txt = $input.val()
      var that = this
      if (timeout) clearTimeout(timeout)
      timeout = setTimeout(function() {
        if (prev == txt) return
        prev = txt
        fn.call(that, txt)
      }, 400)
    })
    $input.on('reset', reset)
    $input.on('fire', function() {
      reset()
      fn.call(this, prev)
    })

    function reset() {
      if (timeout) clearTimeout(timeout)
      prev = $input.val()
    }
  })
}

function ageLimitIcon(summary) {
  return summary.pegi
    ? 'images/pegi-'+summary.age.toString().toLowerCase()+'.png'
    : 'images/agelimit-'+summary.age.toString().toLowerCase()+'.png'
}
function warningIcons(summary) {
  return summary.pegi
    ? summary.warnings.map(function(w) { return $('<span>', { class:'warning pegi-' + w.category.toLowerCase() }) })
    : summary.warnings.map(function(w) { return $('<span>', { class:'warning ' + w.category }) })
}

function notIn(arr, el) {
  return _.indexOf(arr, el) === -1
}

function parseUserCookie() {
  var cookie = $.cookie('user')
  if (!cookie) return null
  return JSON.parse(cookie.substring(4, cookie.lastIndexOf('.')))
}

function hasRole(role) {
  var roles = ['root', 'kavi', 'user']
  if (!user) return false
  return roles.indexOf(role) >= roles.indexOf(user.role)
}<commit_msg>Fix showing pegi-games. Summary structure is a bit complicated now...<commit_after>var user;

$(setup)

function setup() {
  user = parseUserCookie()
  $.fn.select2.defaults.formatNoMatches = 'Ei tuloksia'
  $.fn.select2.defaults.formatSearching = 'Haetaan...'
  $.fn.select2.defaults.adaptDropdownCssClass = function(c) {  return c == 'required' ? c : null }

  var login = loginPage()
  var error = errorDialog()

  $.ajaxSetup({ dataType: 'json', processData: false, contentType: 'application/json' })

  $(document).ajaxError(function(e, req) {
    if (req.status == 403) {
      login.show()
    } else {
      error.show()
    }
  })

  $('#overlay').on('click', closeDialog)

  $('body').on('click', '.dialog', stopPropagation)

  var navigation = navi()
  searchPage()
  programDetails()
  buyerPage()
  billingPage()
  navigation.start()
}

function errorDialog() {
  var $overlay = $('#error-overlay')
  var $dialog = $('#error-dialog')
  $dialog.find('a').click(function(e) { e.preventDefault(); location.reload() })
  return { show: function() { $dialog.add($overlay).show() } }
}

function loginPage() {
  var $overlay = $('#login-overlay')
  var $form = $('#login').submit(function(e) { e.preventDefault() })
  var $username = $form.find('input[name="username"]').on('input', checkInput)
  var $password = $form.find('input[name="password"]').on('input', checkInput)
  var $feedback = $form.find('.feedback')
  var $button = $form.find('button')
  var $info = $('#header .user-info').toggle(!!user)
  $info.find('.name').text(user ? user.name : '')

  $info.find('.logout').click(function() {
    $.post('/logout').done(function() { location.reload() })
  })

  $form.on('validate', function() {
    var invalid = $username.hasClass('invalid') || $password.hasClass('invalid')
    $button.prop('disabled', invalid? 'disabled' : '')
    $feedback.slideUp()
  })

  $button.click(function() {
    $.post('/login', JSON.stringify({ username: $username.val(), password: $password.val() }))
      .done(function() { location.reload() })
      .fail(function(jqXHR) {
        if (jqXHR.status == 403) {
          $password.val('').trigger('input').focus()
          $feedback.slideDown()
        }
      })
  })

  return { show: show }

  function show() {
    $form.add($overlay).show()
    $username.focus()
  }
  function checkInput() {
    $(this).toggleClass('invalid', $(this).val() === '').trigger('validate')
  }
}

function navi() {
  var $navi = $('#header .navi')

  $navi.find('a').on('click', function(e) {
    e.preventDefault()
    show($(this)).trigger('show')
  })

  function start() {
    var hash = location.hash
    if (hash == '') {
      $navi.find('a:first').click()
    } else {
      var parts = hash.split('/').map(decodeURIComponent)
      var $a = $navi.find('a[href='+parts.shift()+']')
      show($a).trigger('show', parts)
    }
  }

  function show($a) {
    $navi.find('a.active').removeClass('active')
    $a.addClass('active')
    $('body').children('.page').hide()
    return $($a.data('href')).show()
  }

  return { start: start }
}

function buyerPage() { $('#buyer-page').on('show', function() { location.hash = '#tilaajat' }) }
function billingPage() { $('#billing-page').on('show', function() { location.hash = '#laskutus'}) }

function stopPropagation(e) { e.stopPropagation() }

function isNotEmpty(val) {
  return (val.trim().length) > 0
}

function isEmail(txt) {
  var regexp = /^([A-Za-z0-9\x27\x2f!#$%&*+=?^_`{|}~-]+(\.[A-Za-z0-9\x27\x2f!#$%&*+=?^_`{|}~-]+)*)@(([a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]|[a-zA-Z0-9]{1,63})(\.([a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]|[a-zA-Z0-9]{1,63}))*\.[a-zA-Z0-9]{2,63})$/
  return regexp.test(txt)
}

function validate(f) {
  return function() {
    $(this).toggleClass('invalid', !f($(this).val())).trigger('validation')
  }
}

function validateTextChange($el, validatorFn) {
  var validator = validate(validatorFn)
  $el.on('input change validate', validator).on('blur', function() { $(this).addClass('touched') })
}

function requiredCheckboxGroup($el) {
  $el.on('change validate', 'input:checkbox', function() {
    $el.toggleClass('invalid', $el.find('input:checkbox:checked').length == 0).trigger('validation')
  })
}

function showDialog($html) {
  $('#overlay').show()
  $('#dialog').show().append($html)
}

function closeDialog() {
  $('#dialog').empty().hide()
  $('#overlay').hide()
}

$.fn.throttledInput = function(fn) {
  return $(this).each(function() {
    var prev = undefined
    var timeout = null
    var $input = $(this).on('keyup', function() {
      var txt = $input.val()
      var that = this
      if (timeout) clearTimeout(timeout)
      timeout = setTimeout(function() {
        if (prev == txt) return
        prev = txt
        fn.call(that, txt)
      }, 400)
    })
    $input.on('reset', reset)
    $input.on('fire', function() {
      reset()
      fn.call(this, prev)
    })

    function reset() {
      if (timeout) clearTimeout(timeout)
      prev = $input.val()
    }
  })
}

function ageLimitIcon(summary) {
  return summary.pegi
    ? 'images/pegi-'+summary.age.toString().toLowerCase()+'.png'
    : 'images/agelimit-'+summary.age.toString().toLowerCase()+'.png'
}
function warningIcons(summary) {
  return summary.pegi
    ? summary.warnings.map(function(w) { return $('<span>', { class:'warning pegi-' + w.toLowerCase() }) })
    : summary.warnings.map(function(w) { return $('<span>', { class:'warning ' + w.category }) })
}

function notIn(arr, el) {
  return _.indexOf(arr, el) === -1
}

function parseUserCookie() {
  var cookie = $.cookie('user')
  if (!cookie) return null
  return JSON.parse(cookie.substring(4, cookie.lastIndexOf('.')))
}

function hasRole(role) {
  var roles = ['root', 'kavi', 'user']
  if (!user) return false
  return roles.indexOf(role) >= roles.indexOf(user.role)
}<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const path = require('path');
const ms = require('ms');

const DIST_DIR = path.join(__dirname, '../../dist');
const UNIVERSAL_RENDERER_PATH = path.join(DIST_DIR, 'server.js');
const CLIENT_STATS_PATH = path.join(DIST_DIR, 'stats.json');
const router = express.Router();

let universalRenderer;
let stats;

try {
    universalRenderer = require(UNIVERSAL_RENDERER_PATH).default;
} catch (ex) {
    throw new Error('Server bundle not found. Try running `npm run build`');
}

try {
    stats = require(CLIENT_STATS_PATH);
} catch (ex) {
    throw new Error('Client bundle stats.json not found. Try running `npm run build`');
}

router.use(express.static(DIST_DIR, {
    maxAge: ms(process.env.BROWSER_CACHE || 0)
}));

router.use(universalRenderer(stats));

module.exports = router;
<commit_msg>Rename universalRenderer to serverRenderer (#71)<commit_after>'use strict';

const express = require('express');
const path = require('path');
const ms = require('ms');

const DIST_DIR = path.join(__dirname, '../../dist');
const SERVER_RENDERER_PATH = path.join(DIST_DIR, 'server.js');
const CLIENT_STATS_PATH = path.join(DIST_DIR, 'stats.json');
const router = express.Router();

let serverRenderer;
let stats;

try {
    serverRenderer = require(SERVER_RENDERER_PATH).default;
} catch (ex) {
    throw new Error('Server bundle not found. Try running `npm run build`');
}

try {
    stats = require(CLIENT_STATS_PATH);
} catch (ex) {
    throw new Error('Client bundle stats.json not found. Try running `npm run build`');
}

router.use(express.static(DIST_DIR, {
    maxAge: ms(process.env.BROWSER_CACHE || 0)
}));

router.use(serverRenderer(stats));

module.exports = router;
<|endoftext|>


<commit_before>/*global $*/
define([ "dialog/dialog", "util/lang", "text!layouts/header.html", "text!layouts/tutorial-list.html","text!layouts/tutorial-view.html", "ui/widget/textbox", "ui/widget/tooltip", "make-api", "json!/api/butterconfig" ],
  function( Dialog, Lang, HEADER_TEMPLATE, TUTORIAL_LIST_TEMPLATE, TUTORIAL_VIEW_TEMPLATE, TextBoxWrapper, ToolTip, Make, config ) {

  return function( butter, options ){

    options = options || {};

    // this is terrible templating and needs to be replaced ASAP
    HEADER_TEMPLATE = HEADER_TEMPLATE.replace( /\{\{user_bar\}\}/g, config.user_bar )
                                     .replace( /\{\{audience\}\}/g, config.audience );

    var TOOLTIP_NAME = "name-error-header-tooltip";

    var _this = this,
        _rootElement = Lang.domFragment( HEADER_TEMPLATE, ".butter-header" ),
        _bodyWrapper = document.querySelector( ".body-wrapper" ),
        _tutorialButtonContainer = document.querySelector( ".butter-tutorial-container" ),
        _saveButton = _rootElement.querySelector( ".butter-save-btn" ),
        _projectTitle = _rootElement.querySelector( ".butter-project-title" ),
        _projectName = _projectTitle.querySelector( ".butter-project-name" ),
        _clearEvents = _rootElement.querySelector( ".butter-clear-events-btn" ),
        _previewBtn = _rootElement.querySelector( ".butter-preview-btn" ),
        _projectBtn = _rootElement.querySelector( ".butter-project-btn" ),
        _projectMenu = _rootElement.querySelector( ".butter-project-menu" ),
        _projectMenuControl = _rootElement.querySelector( ".butter-project-menu-control" ),
        _projectMenuList = _projectMenu.querySelector( ".butter-btn-menu" ),
        _noProjectNameToolTip,
        _projectTitlePlaceHolderText = _projectName.innerHTML,
        _toolTip, _loginTooltip;

    // create a tooltip for the plrojectName element
    _toolTip = ToolTip.create({
      title: "header-title-tooltip",
      message: "Change the name of your project",
      element: _projectTitle,
      top: "60px"
    });

    // Default state
    _toolTip.hidden = true;

    _loginTooltip = ToolTip.create({
      title: "header-title-tooltip",
      message: "Login to save your project!",
      element: _projectTitle,
      top: "60px"
    });

    var make = new Make({
      apiURL: config.make_endpoint
    });

    _this.element = _rootElement;

    ToolTip.apply( _projectTitle );

    function showErrorDialog( message ) {
      var dialog = Dialog.spawn( "error-message", {
        data: message,
        events: {
          cancel: function() {
            dialog.close();
          }
        }
      });
      dialog.open();
    }

    function saveProject() {
      function afterSave() {
        butter.editor.openEditor( "project-editor" );
        togglePreviewButton( true );
        toggleProjectNameListeners( true );
      }

      if ( butter.project.isSaved ) {
        return;
      } else if ( !checkProjectName( butter.project.name ) ) {
        nameError();
      } else {
        if ( !butter.project.isSaved ) {
          toggleSaveButton( false );

          butter.project.save(function( e ) {
            if ( e.error === "okay" ) {
              afterSave();
              return;
            } else {
              toggleSaveButton( true );
              togglePreviewButton( false );
              toggleProjectNameListeners( true );
              showErrorDialog(  "There was a problem saving your project, so it was backed up to your browser's storage" +
                                " (i.e., you can close or reload this page and it will be recovered). Please try again." );
            }
          });
        } else {
          afterSave();
        }
      }
    }

    function openProjectEditor() {
      butter.editor.openEditor( "project-editor" );
    }

    function toggleProjectButton( on ) {
      if ( on ) {
        _projectBtn.classList.remove( "butter-disabled" );
        _projectBtn.addEventListener( "click", openProjectEditor, false );
      } else {
        _projectBtn.classList.add( "butter-disabled" );
        _projectBtn.removeEventListener( "click", openProjectEditor, false );
      }
    }

    function toggleSaveButton( on ) {
      if ( on ) {
        _saveButton.classList.remove( "butter-disabled" );
        _saveButton.addEventListener( "click", saveProject, false );
      } else {
        _saveButton.classList.add( "butter-disabled" );
        _saveButton.removeEventListener( "click", saveProject, false );
      }
    }

    function togglePreviewButton( on ) {
      if ( on ) {
        _previewBtn.classList.remove( "butter-disabled" );
        _previewBtn.href = butter.project.publishUrl;
        _previewBtn.onclick = function() {
          return true;
        };
      } else {
        _previewBtn.classList.add( "butter-disabled" );
        _previewBtn.href = "";
        _previewBtn.onclick = function() {
          return false;
        };
      }
    }

    function toggleClearButton( on ) {
      if ( on ) {
        _clearEvents.classList.remove( "butter-disabled" );
        _clearEvents.addEventListener( "click", clearEventsClick, false );
      } else {
        _clearEvents.classList.add( "butter-disabled" );
        _clearEvents.removeEventListener( "click", clearEventsClick, false );
      }
    }

    function toggleProjectNameListeners( state, tooltipIgnore ) {
      if ( state ) {
        _projectTitle.addEventListener( "click", projectNameClick, false );
        _projectName.classList.remove( "butter-disabled" );
        _projectName.addEventListener( "click", projectNameClick, false );
      } else {
        _projectTitle.removeEventListener( "click", projectNameClick, false );
        _projectName.removeEventListener( "click", projectNameClick, false );
        _projectName.classList.add( "butter-disabled" );
      }

      if ( !tooltipIgnore ) {
        _loginTooltip.hidden = state;
        _toolTip.hidden = !state;
      }
    }

    function projectNameClick() {
      var input = document.createElement( "input" );

      input.type = "text";

      input.placeholder = _projectTitlePlaceHolderText;
      input.classList.add( "butter-project-name" );
      input.value = _projectName.textContent !== _projectTitlePlaceHolderText ? _projectName.textContent : "";
      TextBoxWrapper.applyTo( input );
      _projectTitle.replaceChild( input, _projectName );
      toggleProjectNameListeners( false, true );
      input.focus();
      input.addEventListener( "blur", onBlur, false );
      input.addEventListener( "keypress", onKeyPress, false );
    }

    function clearEventsClick() {
      var dialog;
      if ( butter.currentMedia && butter.currentMedia.hasTrackEvents() ) {
        dialog = Dialog.spawn( "delete-track-events", {
          data: butter
        });
        dialog.open();
      }
    }

    this.views = {
      dirty: function() {
        togglePreviewButton( false );
        toggleSaveButton( true );
        toggleProjectButton( false );
      },
      clean: function() {
        togglePreviewButton( true );
        toggleSaveButton( false );
        toggleProjectButton( true );
      },
      login: function() {
        var isSaved = butter.project.isSaved;

        toggleProjectNameListeners( butter.cornfield.authenticated() );
        togglePreviewButton( isSaved );
        toggleSaveButton( !isSaved && butter.cornfield.authenticated() );
        toggleProjectButton( isSaved );
      },
      logout: function() {
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleProjectButton( false );
        toggleProjectNameListeners( false );
      }
    };

    // Set up the project menu
    _projectMenuControl.addEventListener( "click", function() {
      if ( butter.currentMedia.hasTrackEvents() ) {
        toggleClearButton( true );
      } else {
        toggleClearButton( false );
      }
      _projectMenu.classList.toggle( "butter-btn-menu-expanded" );
    }, false );

    _projectMenuList.addEventListener( "click", function( e ) {
      if ( e.target.classList.contains( "butter-disabled" ) ) {
        return;
      }
      _projectMenu.classList.remove( "butter-btn-menu-expanded" );
    }, true );

    function destroyToolTip() {
      if ( _noProjectNameToolTip && !_noProjectNameToolTip.destroyed ) {
        _projectTitle.removeEventListener( "mouseover", destroyToolTip, false );
        _noProjectNameToolTip.destroy();
      }
    }

    function onKeyPress( e ) {
      var node = _projectTitle.querySelector( ".butter-project-name" );

      // if this wasn't the 'enter' key, return early
      if ( e.keyCode !== 13 ) {
        return;
      }

      node.blur();
      node.removeEventListener( "keypress", onKeyPress, false );
    }

    /*
     * Function: checkProjectName
     *
     * Checks whether the current projects name is a valid one or not.
     * @returns boolean value representing whether or not the current project name is valid
     */
    function checkProjectName( name ) {
      return !!name && name !== _projectTitlePlaceHolderText;
    }

    function nameError() {
      destroyToolTip();

      _projectTitle.addEventListener( "mouseover", destroyToolTip, false );

      ToolTip.create({
        name: TOOLTIP_NAME,
        message: "Please give your project a name before saving",
        hidden: false,
        element: _projectTitle,
        top: "50px",
        error: true
      });

      _noProjectNameToolTip = ToolTip.get( TOOLTIP_NAME );
    }

    function onBlur() {
      var node = _projectTitle.querySelector( ".butter-project-name" );
      node.removeEventListener( "blur", onBlur, false );

      _projectName.textContent = node.value || _projectTitlePlaceHolderText;
      if( checkProjectName( _projectName.textContent ) ) {
        butter.project.name = _projectName.textContent;
        saveProject();
      } else {
        nameError();
        toggleProjectNameListeners( true );
      }

      _projectTitle.replaceChild( _projectName, node );
    }

    this.attachToDOM = function() {
      document.body.classList.add( "butter-header-spacing" );
      document.body.insertBefore( _rootElement, document.body.firstChild );

      loadDashboard();
    };

    butter.listen( "authenticated", _this.views.login, false );
    butter.listen( "logout", _this.views.logout, false );

    butter.listen( "projectsaved", function() {
      // Disable "Save" button
      _this.views.clean();
      _projectName.textContent = butter.project.name;
    });

    butter.listen( "projectchanged", function() {
      // Re-enable "Save" button to indicate things are not saved
      _this.views.dirty();
    });

    function loadTutorials() {
      var tutorialUrl;

      if ( butter.project.publishUrl ) {
        tutorialUrl = butter.project.publishUrl;
      } else if ( butter.project.remixedFromUrl ) {
        tutorialUrl = butter.project.remixedFromUrl;
      }

      make.tags( "tutorial-" + escape( tutorialUrl ) ).then( function( err, results ) {
        var tutorialView = Lang.domFragment( TUTORIAL_VIEW_TEMPLATE, ".tutorial-view" ),
            tutorialTemplate = Lang.domFragment( TUTORIAL_LIST_TEMPLATE, ".tutorial-template" ),
            iframeCover = tutorialView.querySelector( ".tutorial-iframe-cover" ),
            iframe = tutorialView.querySelector( ".tutorial-iframe" ),
            closeButton = tutorialView.querySelector( ".tutorial-close-button" ),
            viewTitle = tutorialView.querySelector( ".tutorial-view-title" ),
            tutorialList = document.querySelector( ".tutorial-list" ),
            tutorialBtn = document.querySelector( ".tutorial-btn" );

        if ( err || !results.length ) {
          return;
        }

        tutorialBtn.classList.remove( "hidden" );

        var onCoverMouseUp = function() {
          iframeCover.style.display = "none";
          tutorialView.addEventListener( "mousedown", onCoverMouseDown, false );
          document.removeEventListener( "mouseup", onCoverMouseUp, false );
        };

        var onCoverMouseDown = function() {
          iframeCover.style.display = "block";
          tutorialView.removeEventListener( "mousedown", onCoverMouseDown, false );
          document.addEventListener( "mouseup", onCoverMouseUp, false );
        };

        var createTutorialItem = function( item ) {
          var tutorialElement = document.createElement( "div" );
          tutorialElement.classList.add( "tutorial-list-item" );
          tutorialElement.addEventListener( "click", function() {
            iframe.src = item.url;
            viewTitle.innerHTML = "Tutorial: " + item.title;
            tutorialView.classList.remove( "closed" );
            tutorialView.style.height = "";
            tutorialView.style.width = "";
          }, false );
          tutorialElement.innerHTML = item.title;
          tutorialList.appendChild( tutorialElement );
        };

        tutorialView.addEventListener( "mousedown", onCoverMouseDown, false );

        closeButton.userSelect = "none";
        document.body.appendChild( tutorialView );

        closeButton.addEventListener( "click", function() {
          tutorialView.classList.add( "closed" );
          tutorialView.style.height = 0;
          tutorialView.style.width = 0;
        }, false );

        tutorialBtn.addEventListener( "click", function() {
          tutorialList.classList.toggle( "open" );
        }, false );

        $( tutorialView ).draggable({
          cancel: "iframe"
        });
        $( tutorialView ).resizable();

        for ( var i = 0; i < results.length; i++ ) {
          createTutorialItem( results[ i ] );
        }
      });
    }

    function loadDashboard() {
      var myProjectsButton = document.querySelector( ".user-info > .makes" ),
          container = document.querySelector( ".my-projects-container" ),
          iframe = document.querySelector( ".my-projects-iframe" );

     function close() {
        myProjectsButton.addEventListener( "click", open, false );
        myProjectsButton.removeEventListener( "click", close, false );

        container.style.zIndex = "";
        container.style.position = "";
        iframe.style.height = "";
      }

      function open() {
        myProjectsButton.addEventListener( "click", close, false );
        myProjectsButton.removeEventListener( "click", open, false );

        container.style.zIndex = 5;
        container.style.position = "relative";
        iframe.style.height = "300px";

        iframe.src = "/dashboard";
      }

      myProjectsButton.addEventListener( "click", open, false );
    }

    butter.listen( "ready", function() {
      if ( butter.project.name ) {
        _projectName.textContent = butter.project.name;
      }

      if ( !butter.cornfield.authenticated() ) {
        toggleProjectNameListeners( false );
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleProjectButton( false );
      }

      if ( butter.project.publishUrl ||
           butter.project.remixedFromUrl ) {
        loadTutorials();
      }
    });
  };
});
<commit_msg>[#882688] Do not let project be saved while not logged in.<commit_after>/*global $*/
define([ "dialog/dialog", "util/lang", "text!layouts/header.html", "text!layouts/tutorial-list.html","text!layouts/tutorial-view.html", "ui/widget/textbox", "ui/widget/tooltip", "make-api", "json!/api/butterconfig" ],
  function( Dialog, Lang, HEADER_TEMPLATE, TUTORIAL_LIST_TEMPLATE, TUTORIAL_VIEW_TEMPLATE, TextBoxWrapper, ToolTip, Make, config ) {

  return function( butter, options ){

    options = options || {};

    // this is terrible templating and needs to be replaced ASAP
    HEADER_TEMPLATE = HEADER_TEMPLATE.replace( /\{\{user_bar\}\}/g, config.user_bar )
                                     .replace( /\{\{audience\}\}/g, config.audience );

    var TOOLTIP_NAME = "name-error-header-tooltip";

    var _this = this,
        _rootElement = Lang.domFragment( HEADER_TEMPLATE, ".butter-header" ),
        _bodyWrapper = document.querySelector( ".body-wrapper" ),
        _tutorialButtonContainer = document.querySelector( ".butter-tutorial-container" ),
        _saveButton = _rootElement.querySelector( ".butter-save-btn" ),
        _projectTitle = _rootElement.querySelector( ".butter-project-title" ),
        _projectName = _projectTitle.querySelector( ".butter-project-name" ),
        _clearEvents = _rootElement.querySelector( ".butter-clear-events-btn" ),
        _previewBtn = _rootElement.querySelector( ".butter-preview-btn" ),
        _projectBtn = _rootElement.querySelector( ".butter-project-btn" ),
        _projectMenu = _rootElement.querySelector( ".butter-project-menu" ),
        _projectMenuControl = _rootElement.querySelector( ".butter-project-menu-control" ),
        _projectMenuList = _projectMenu.querySelector( ".butter-btn-menu" ),
        _noProjectNameToolTip,
        _projectTitlePlaceHolderText = _projectName.innerHTML,
        _toolTip, _loginTooltip;

    // create a tooltip for the plrojectName element
    _toolTip = ToolTip.create({
      title: "header-title-tooltip",
      message: "Change the name of your project",
      element: _projectTitle,
      top: "60px"
    });

    // Default state
    _toolTip.hidden = true;

    _loginTooltip = ToolTip.create({
      title: "header-title-tooltip",
      message: "Login to save your project!",
      element: _projectTitle,
      top: "60px"
    });

    var make = new Make({
      apiURL: config.make_endpoint
    });

    _this.element = _rootElement;

    ToolTip.apply( _projectTitle );

    function showErrorDialog( message ) {
      var dialog = Dialog.spawn( "error-message", {
        data: message,
        events: {
          cancel: function() {
            dialog.close();
          }
        }
      });
      dialog.open();
    }

    function saveProject() {
      function afterSave() {
        butter.editor.openEditor( "project-editor" );
        togglePreviewButton( true );
        toggleProjectNameListeners( true );
      }

      if ( butter.project.isSaved ) {
        return;
      } else if ( !checkProjectName( butter.project.name ) ) {
        nameError();
      } else {
        if ( !butter.project.isSaved ) {
          toggleSaveButton( false );

          butter.project.save(function( e ) {
            if ( e.error === "okay" ) {
              afterSave();
              return;
            } else {
              toggleSaveButton( true );
              togglePreviewButton( false );
              toggleProjectNameListeners( true );
              showErrorDialog(  "There was a problem saving your project, so it was backed up to your browser's storage" +
                                " (i.e., you can close or reload this page and it will be recovered). Please try again." );
            }
          });
        } else {
          afterSave();
        }
      }
    }

    function openProjectEditor() {
      butter.editor.openEditor( "project-editor" );
    }

    function toggleProjectButton( on ) {
      if ( on ) {
        _projectBtn.classList.remove( "butter-disabled" );
        _projectBtn.addEventListener( "click", openProjectEditor, false );
      } else {
        _projectBtn.classList.add( "butter-disabled" );
        _projectBtn.removeEventListener( "click", openProjectEditor, false );
      }
    }

    function toggleSaveButton( on ) {
      if ( on ) {
        _saveButton.classList.remove( "butter-disabled" );
        _saveButton.addEventListener( "click", saveProject, false );
      } else {
        _saveButton.classList.add( "butter-disabled" );
        _saveButton.removeEventListener( "click", saveProject, false );
      }
    }

    function togglePreviewButton( on ) {
      if ( on ) {
        _previewBtn.classList.remove( "butter-disabled" );
        _previewBtn.href = butter.project.publishUrl;
        _previewBtn.onclick = function() {
          return true;
        };
      } else {
        _previewBtn.classList.add( "butter-disabled" );
        _previewBtn.href = "";
        _previewBtn.onclick = function() {
          return false;
        };
      }
    }

    function toggleClearButton( on ) {
      if ( on ) {
        _clearEvents.classList.remove( "butter-disabled" );
        _clearEvents.addEventListener( "click", clearEventsClick, false );
      } else {
        _clearEvents.classList.add( "butter-disabled" );
        _clearEvents.removeEventListener( "click", clearEventsClick, false );
      }
    }

    function toggleProjectNameListeners( state, tooltipIgnore ) {
      if ( state ) {
        _projectTitle.addEventListener( "click", projectNameClick, false );
        _projectName.classList.remove( "butter-disabled" );
        _projectName.addEventListener( "click", projectNameClick, false );
      } else {
        _projectTitle.removeEventListener( "click", projectNameClick, false );
        _projectName.removeEventListener( "click", projectNameClick, false );
        _projectName.classList.add( "butter-disabled" );
      }

      if ( !tooltipIgnore ) {
        _loginTooltip.hidden = state;
        _toolTip.hidden = !state;
      }
    }

    function projectNameClick() {
      var input = document.createElement( "input" );

      input.type = "text";

      input.placeholder = _projectTitlePlaceHolderText;
      input.classList.add( "butter-project-name" );
      input.value = _projectName.textContent !== _projectTitlePlaceHolderText ? _projectName.textContent : "";
      TextBoxWrapper.applyTo( input );
      _projectTitle.replaceChild( input, _projectName );
      toggleProjectNameListeners( false, true );
      input.focus();
      input.addEventListener( "blur", onBlur, false );
      input.addEventListener( "keypress", onKeyPress, false );
    }

    function clearEventsClick() {
      var dialog;
      if ( butter.currentMedia && butter.currentMedia.hasTrackEvents() ) {
        dialog = Dialog.spawn( "delete-track-events", {
          data: butter
        });
        dialog.open();
      }
    }

    this.views = {
      dirty: function() {
        togglePreviewButton( false );
        toggleSaveButton( butter.cornfield.authenticated() );
        toggleProjectButton( false );
      },
      clean: function() {
        togglePreviewButton( true );
        toggleSaveButton( false );
        toggleProjectButton( true );
      },
      login: function() {
        var isSaved = butter.project.isSaved;

        toggleProjectNameListeners( butter.cornfield.authenticated() );
        togglePreviewButton( isSaved );
        toggleSaveButton( !isSaved && butter.cornfield.authenticated() );
        toggleProjectButton( isSaved );
      },
      logout: function() {
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleProjectButton( false );
        toggleProjectNameListeners( false );
      }
    };

    // Set up the project menu
    _projectMenuControl.addEventListener( "click", function() {
      if ( butter.currentMedia.hasTrackEvents() ) {
        toggleClearButton( true );
      } else {
        toggleClearButton( false );
      }
      _projectMenu.classList.toggle( "butter-btn-menu-expanded" );
    }, false );

    _projectMenuList.addEventListener( "click", function( e ) {
      if ( e.target.classList.contains( "butter-disabled" ) ) {
        return;
      }
      _projectMenu.classList.remove( "butter-btn-menu-expanded" );
    }, true );

    function destroyToolTip() {
      if ( _noProjectNameToolTip && !_noProjectNameToolTip.destroyed ) {
        _projectTitle.removeEventListener( "mouseover", destroyToolTip, false );
        _noProjectNameToolTip.destroy();
      }
    }

    function onKeyPress( e ) {
      var node = _projectTitle.querySelector( ".butter-project-name" );

      // if this wasn't the 'enter' key, return early
      if ( e.keyCode !== 13 ) {
        return;
      }

      node.blur();
      node.removeEventListener( "keypress", onKeyPress, false );
    }

    /*
     * Function: checkProjectName
     *
     * Checks whether the current projects name is a valid one or not.
     * @returns boolean value representing whether or not the current project name is valid
     */
    function checkProjectName( name ) {
      return !!name && name !== _projectTitlePlaceHolderText;
    }

    function nameError() {
      destroyToolTip();

      _projectTitle.addEventListener( "mouseover", destroyToolTip, false );

      ToolTip.create({
        name: TOOLTIP_NAME,
        message: "Please give your project a name before saving",
        hidden: false,
        element: _projectTitle,
        top: "50px",
        error: true
      });

      _noProjectNameToolTip = ToolTip.get( TOOLTIP_NAME );
    }

    function onBlur() {
      var node = _projectTitle.querySelector( ".butter-project-name" );
      node.removeEventListener( "blur", onBlur, false );

      _projectName.textContent = node.value || _projectTitlePlaceHolderText;
      if( checkProjectName( _projectName.textContent ) ) {
        butter.project.name = _projectName.textContent;
        saveProject();
      } else {
        nameError();
        toggleProjectNameListeners( true );
      }

      _projectTitle.replaceChild( _projectName, node );
    }

    this.attachToDOM = function() {
      document.body.classList.add( "butter-header-spacing" );
      document.body.insertBefore( _rootElement, document.body.firstChild );

      loadDashboard();
    };

    butter.listen( "authenticated", _this.views.login, false );
    butter.listen( "logout", _this.views.logout, false );

    butter.listen( "projectsaved", function() {
      // Disable "Save" button
      _this.views.clean();
      _projectName.textContent = butter.project.name;
    });

    butter.listen( "projectchanged", function() {
      // Re-enable "Save" button to indicate things are not saved
      _this.views.dirty();
    });

    function loadTutorials() {
      var tutorialUrl;

      if ( butter.project.publishUrl ) {
        tutorialUrl = butter.project.publishUrl;
      } else if ( butter.project.remixedFromUrl ) {
        tutorialUrl = butter.project.remixedFromUrl;
      }

      make.tags( "tutorial-" + escape( tutorialUrl ) ).then( function( err, results ) {
        var tutorialView = Lang.domFragment( TUTORIAL_VIEW_TEMPLATE, ".tutorial-view" ),
            tutorialTemplate = Lang.domFragment( TUTORIAL_LIST_TEMPLATE, ".tutorial-template" ),
            iframeCover = tutorialView.querySelector( ".tutorial-iframe-cover" ),
            iframe = tutorialView.querySelector( ".tutorial-iframe" ),
            closeButton = tutorialView.querySelector( ".tutorial-close-button" ),
            viewTitle = tutorialView.querySelector( ".tutorial-view-title" ),
            tutorialList = document.querySelector( ".tutorial-list" ),
            tutorialBtn = document.querySelector( ".tutorial-btn" );

        if ( err || !results.length ) {
          return;
        }

        tutorialBtn.classList.remove( "hidden" );

        var onCoverMouseUp = function() {
          iframeCover.style.display = "none";
          tutorialView.addEventListener( "mousedown", onCoverMouseDown, false );
          document.removeEventListener( "mouseup", onCoverMouseUp, false );
        };

        var onCoverMouseDown = function() {
          iframeCover.style.display = "block";
          tutorialView.removeEventListener( "mousedown", onCoverMouseDown, false );
          document.addEventListener( "mouseup", onCoverMouseUp, false );
        };

        var createTutorialItem = function( item ) {
          var tutorialElement = document.createElement( "div" );
          tutorialElement.classList.add( "tutorial-list-item" );
          tutorialElement.addEventListener( "click", function() {
            iframe.src = item.url;
            viewTitle.innerHTML = "Tutorial: " + item.title;
            tutorialView.classList.remove( "closed" );
            tutorialView.style.height = "";
            tutorialView.style.width = "";
          }, false );
          tutorialElement.innerHTML = item.title;
          tutorialList.appendChild( tutorialElement );
        };

        tutorialView.addEventListener( "mousedown", onCoverMouseDown, false );

        closeButton.userSelect = "none";
        document.body.appendChild( tutorialView );

        closeButton.addEventListener( "click", function() {
          tutorialView.classList.add( "closed" );
          tutorialView.style.height = 0;
          tutorialView.style.width = 0;
        }, false );

        tutorialBtn.addEventListener( "click", function() {
          tutorialList.classList.toggle( "open" );
        }, false );

        $( tutorialView ).draggable({
          cancel: "iframe"
        });
        $( tutorialView ).resizable();

        for ( var i = 0; i < results.length; i++ ) {
          createTutorialItem( results[ i ] );
        }
      });
    }

    function loadDashboard() {
      var myProjectsButton = document.querySelector( ".user-info > .makes" ),
          container = document.querySelector( ".my-projects-container" ),
          iframe = document.querySelector( ".my-projects-iframe" );

     function close() {
        myProjectsButton.addEventListener( "click", open, false );
        myProjectsButton.removeEventListener( "click", close, false );

        container.style.zIndex = "";
        container.style.position = "";
        iframe.style.height = "";
      }

      function open() {
        myProjectsButton.addEventListener( "click", close, false );
        myProjectsButton.removeEventListener( "click", open, false );

        container.style.zIndex = 5;
        container.style.position = "relative";
        iframe.style.height = "300px";

        iframe.src = "/dashboard";
      }

      myProjectsButton.addEventListener( "click", open, false );
    }

    butter.listen( "ready", function() {
      if ( butter.project.name ) {
        _projectName.textContent = butter.project.name;
      }

      if ( !butter.cornfield.authenticated() ) {
        toggleProjectNameListeners( false );
        togglePreviewButton( false );
        toggleSaveButton( false );
        toggleProjectButton( false );
      }

      if ( butter.project.publishUrl ||
           butter.project.remixedFromUrl ) {
        loadTutorials();
      }
    });
  };
});
<|endoftext|>