<commit_before>/* global app:true */

var socket;
var currenttime;
var username='noname';

var width = 600,
	height = 1050,
	cellWidth = 80,
	cellHeight = 74, // cell size
	gapWidth = 60;
	gapHeight = 6;

var hour = d3.time.format("%I"),
	minute = d3.time.format("%M"),
	month = d3.time.format("%b"),
	weekday = d3.time.format("%a"),
	date = d3.time.format("%d"),
	ampm = d3.time.format("%p"),
	format = d3.time.format("%b/%d %H:%M%p");

(function() {
  'use strict';

	var myClock;

	function myTimer(){
		socket.emit('lookclock');
	}

  var blockdata = [];
  var clockbar = $('#clock_bar');

  var callBlocks = function(ticket){
	// +- 1 hour blocks range
	var beginT = d3.time.hour.floor(ticket);
	beginT = d3.time.hour.offset(beginT, -1);
	var endT = d3.time.hour.offset(beginT, 3);

	socket.emit('timeline', { type: 'callblocks', user:username, begintime: beginT, endtime: endT});
  }

  var draw = function(blockdata){
    d3.select("svg")
       .remove();
	var tip = d3.tip()
		.attr('class', 'd3-tip')
		.direction('e')
		.offset([0,10])
		.html(function(d) {
			return "time: "+d.time;
		});

	var svg = d3.select("#d3Area").append("svg")
		.attr("width", width)
		.attr("height", height)
		.append("g")
		.attr("transform", "translate(24, 24)");

	svg.call(tip);

	var column = svg.selectAll(".column")
		.data(blockdata)
	.enter().append("g")
		.attr("class", "column")
		.attr("transform", function (d,i)
		{ return "translate("+ (i-i%12)/12 * (cellWidth+gapWidth)+ ","+i%12 * (cellHeight+gapHeight) + ")"; })
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide);

	column.append("rect")
		.attr("class", function (d)
		{
			if (d.lock==1){
				class_name="block-locked";
			}else{
				if (d.current==1){
					class_name="block-current";
				}else{
					var class_name="block-default";
				}
			}
			return class_name;
		})
		.attr("width", cellWidth)
		.attr("height", cellHeight)
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide)
		.on('click', mouseclick);

	column.append("text")
		.attr("class", "block-name")
		.attr("x",cellWidth/2)
		.attr("y",cellHeight/2)
		.attr("dy", ".3em")
		.style("text-anchor", "middle")
		.text(function(d) {
			var h = d.time.getHours();
			var ampm = (h<12 ? "AM":"PM");
			//h=("0" + h%12).slice(-2);
			h=(h%12);
			if(h==0){h="12";}
			var m = d.time.getMinutes();
			m=("0" + m).slice(-2);
			return h+":"+m+" "+ampm;
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide)
		.on('click', mouseclick);
  }

  function mouseclick(d){
  	console.log(d.time);
  	d3.select(this).transition().duration(300)
        .style("background-color", "#333");
  }

  socket = io.connect('http://171.65.102.132:3006');

  socket.on('postblocks', function(data){
  	blockdata = [];
  	var num_ele = 9;
	for (var i=0;i<=data.length/num_ele;i++){
		var block = new Object();
		block.id = i;

		var d = new Date(0);
		d.setTime(data[i*num_ele]);
		block.time = d;

		block.lock = data[i*num_ele+1];
		block.user_id = data[i*num_ele+2];
		block.exp_id = data[i*num_ele+3];
		block.pattern_id = data[i*num_ele+4];
		block.past = data[i*num_ele+5];
		block.admin = data[i*num_ele+6];
		block.current = data[i*num_ele+7];
		block.image = data[i*num_ele+8];

		blockdata.push(block);
	}
	blockdata.length = blockdata.length-2;
	console.dir(blockdata);
	draw(blockdata);
  });

  socket.on('server_clock', function(data){
  	//console.log(data);
  	clockbar.html(""+data+"");
  });

  socket.on('message', function(msg){
	console.log(msg);
  });

  socket.on('connect', function() {
	console.log("Connected!");
	currenttime = new Date();
	callBlocks(currenttime);
	myClock=setInterval(function(){myTimer()},500);
  });

  socket.on('disconnect', function() {
	console.log('disconnected');
  });

  app = app || {};

  app.Blocks = Backbone.Model.extend({
    url: '/account/timeline/',
    defaults: {
      username: '',
      timestamp: ''
    }
  });

  app.BlocksView = Backbone.View.extend({
    el: '#blocks_nav',
    template: _.template( $('#tmpl-blocks_nav').html() ),
    events: {
      'click .btn-prev': 'reqPrev',
      'click .btn-now': 'reqNow',
      'click .btn-next': 'reqNext'
    },
    initialize: function() {
      this.model = new app.Blocks();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes));
    },
    reqPrev: function() {
      currenttime.setHours(currenttime.getHours() - 1);
      callBlocks(currenttime);
    },
    reqNow: function() {
      currenttime = new Date();
      callBlocks(currenttime);
    },
    reqNext: function() {
      currenttime.setHours(currenttime.getHours() + 1);
      callBlocks(currenttime);
    }
  });

  $(document).ready(function() {
    app.blocksView = new app.BlocksView();
  });

}());
<commit_msg>animation test<commit_after>/* global app:true */

var socket;
var currenttime;
var username='noname';

var width = 600,
	height = 1050,
	cellWidth = 80,
	cellHeight = 74, // cell size
	gapWidth = 60;
	gapHeight = 6;

var hour = d3.time.format("%I"),
	minute = d3.time.format("%M"),
	month = d3.time.format("%b"),
	weekday = d3.time.format("%a"),
	date = d3.time.format("%d"),
	ampm = d3.time.format("%p"),
	format = d3.time.format("%b/%d %H:%M%p");

(function() {
  'use strict';

	var myClock;

	function myTimer(){
		socket.emit('lookclock');
	}

  var blockdata = [];
  var clockbar = $('#clock_bar');

  var callBlocks = function(ticket){
	// +- 1 hour blocks range
	var beginT = d3.time.hour.floor(ticket);
	beginT = d3.time.hour.offset(beginT, -1);
	var endT = d3.time.hour.offset(beginT, 3);

	socket.emit('timeline', { type: 'callblocks', user:username, begintime: beginT, endtime: endT});
  }

  var draw = function(blockdata){
    d3.select("svg")
       .remove();
	var tip = d3.tip()
		.attr('class', 'd3-tip')
		.direction('e')
		.offset([0,10])
		.html(function(d) {
			return "time: "+d.time;
		});

	var svg = d3.select("#d3Area").append("svg")
		.attr("width", width)
		.attr("height", height)
		.append("g")
		.attr("transform", "translate(24, 24)");

	svg.call(tip);

	var column = svg.selectAll(".column")
		.data(blockdata)
	.enter().append("g")
		.attr("class", "column")
		.attr("transform", function (d,i)
		{ return "translate("+ (i-i%12)/12 * (cellWidth+gapWidth)+ ","+i%12 * (cellHeight+gapHeight) + ")"; })
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide);

	column.append("rect")
		.attr("class", function (d)
		{
			if (d.lock==1){
				class_name="block-locked";
			}else{
				if (d.current==1){
					class_name="block-current";
				}else{
					var class_name="block-default";
				}
			}
			return class_name;
		})
		.attr("width", cellWidth)
		.attr("height", cellHeight)
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide)
		.on('click', mouseclick);

	column.append("text")
		.attr("class", "block-name")
		.attr("x",cellWidth/2)
		.attr("y",cellHeight/2)
		.attr("dy", ".3em")
		.style("text-anchor", "middle")
		.text(function(d) {
			var h = d.time.getHours();
			var ampm = (h<12 ? "AM":"PM");
			//h=("0" + h%12).slice(-2);
			h=(h%12);
			if(h==0){h="12";}
			var m = d.time.getMinutes();
			m=("0" + m).slice(-2);
			return h+":"+m+" "+ampm;
		})
		.on('mouseover', tip.show)
		.on('mouseout', tip.hide)
		.on('click', mouseclick);
  }

  function mouseclick(d){
  	console.log(d.time);
  	d3.select(this).transition().duration(1000)
        .style("width", cellWidth*2);
  }

  socket = io.connect('http://171.65.102.132:3006');

  socket.on('postblocks', function(data){
  	blockdata = [];
  	var num_ele = 9;
	for (var i=0;i<=data.length/num_ele;i++){
		var block = new Object();
		block.id = i;

		var d = new Date(0);
		d.setTime(data[i*num_ele]);
		block.time = d;

		block.lock = data[i*num_ele+1];
		block.user_id = data[i*num_ele+2];
		block.exp_id = data[i*num_ele+3];
		block.pattern_id = data[i*num_ele+4];
		block.past = data[i*num_ele+5];
		block.admin = data[i*num_ele+6];
		block.current = data[i*num_ele+7];
		block.image = data[i*num_ele+8];

		blockdata.push(block);
	}
	blockdata.length = blockdata.length-2;
	console.dir(blockdata);
	draw(blockdata);
  });

  socket.on('server_clock', function(data){
  	//console.log(data);
  	clockbar.html(""+data+"");
  });

  socket.on('message', function(msg){
	console.log(msg);
  });

  socket.on('connect', function() {
	console.log("Connected!");
	currenttime = new Date();
	callBlocks(currenttime);
	myClock=setInterval(function(){myTimer()},500);
  });

  socket.on('disconnect', function() {
	console.log('disconnected');
  });

  app = app || {};

  app.Blocks = Backbone.Model.extend({
    url: '/account/timeline/',
    defaults: {
      username: '',
      timestamp: ''
    }
  });

  app.BlocksView = Backbone.View.extend({
    el: '#blocks_nav',
    template: _.template( $('#tmpl-blocks_nav').html() ),
    events: {
      'click .btn-prev': 'reqPrev',
      'click .btn-now': 'reqNow',
      'click .btn-next': 'reqNext'
    },
    initialize: function() {
      this.model = new app.Blocks();
      this.listenTo(this.model, 'sync', this.render);
      this.render();
    },
    render: function() {
      this.$el.html(this.template( this.model.attributes));
    },
    reqPrev: function() {
      currenttime.setHours(currenttime.getHours() - 1);
      callBlocks(currenttime);
    },
    reqNow: function() {
      currenttime = new Date();
      callBlocks(currenttime);
    },
    reqNext: function() {
      currenttime.setHours(currenttime.getHours() + 1);
      callBlocks(currenttime);
    }
  });

  $(document).ready(function() {
    app.blocksView = new app.BlocksView();
  });

}());
<|endoftext|>


<commit_before>var supportsColor = process.env ? require('supports-color') : null;
var useColors = process.env
  ? (supportsColor || (process.env.MOCHA_COLORS !== undefined))
  : false;

var colors = {
    'pass': 90
  , 'fail': 31
  , 'bright pass': 92
  , 'bright fail': 91
  , 'bright yellow': 93
  , 'pending': 36
  , 'suite': 0
  , 'error title': 0
  , 'error message': 31
  , 'error stack': 90
  , 'checkmark': 32
  , 'fast': 90
  , 'medium': 33
  , 'slow': 31
  , 'green': 32
  , 'light': 90
  , 'diff gutter': 90
  , 'diff added': 42
  , 'diff removed': 41
};

function color(type, str) {
    if (!useColors) return String(str);
    return '\u001b[' + colors[type] + 'm' + str + '\u001b[0m';
}

var symbols = {
    pass: '✓',
    fail: '✖'
};

// With node.js on Windows: use symbols available in terminal default fonts
if ('win32' == process.platform) {
    symbols.pass = '\u221A';
    symbols.fail = '\u00D7';
}

function create(useTests) {
    var depth = 0;
    function indent() {
        return Array(depth + 2).join('  ');
    }

    var lastTitles = [];
    function printTitles(titles) {
        // Print if the titles at an index are different
        for (var i = 0; i < titles.length; i++) {
            var title = titles[i];
            var lastTitle = lastTitles[i];
            depth = i;
            if (title !== lastTitle) {
                console.log(indent() + color('suite', '%s'), title);
            }
        }
        lastTitles = titles;
        depth = titles.length;
    }

    var totalPassTime = 0;
    function printPass(test) {
        var fmt;
        if ('fast' == test.speed) {
            fmt = indent()
              + color('checkmark', symbols.pass)
              + color('pass', ' %s ');
            console.log(fmt, test.name);
        } else {
            fmt = indent()
              + color('checkmark', symbols.pass)
              + color('pass', ' %s ')
              + color(test.speed, '(%dms)');
            console.log(fmt, test.name, test.duration);
        }
        if (test.duration > 0) {
            totalPassTime += test.duration;
        }
    }

    function printInfo(result) {
        console.log('  Platform  : ' + result.platform.join(', '));
        console.log('  Report    : ' + result.url);
        console.log('  Test Page : ' + result.testPageUrl);
        console.log('  Passed    : ' + color(result.passed ? 'checkmark' : 'fail', result.passed));
        console.log();
    }

    function printFail(test) {
        var fmt;

        fmt = indent()
            + color('fail', symbols.fail + ' %s');
        console.log(fmt, test.name);

        fmt = indent()
            + color('error message', '  Error: %s');
        console.log(fmt, test.message);

        if (test.stack) {
            fmt = indent()
                + color('error stack', '    at %s');
            console.log(fmt, test.stack);
        }
    }

    function printResult(test) {
        if (test.result) {
            printPass(test);
        } else {
            printFail(test);
        }
    }

    function printFinal(result) {
        if (result.passes + result.failures + result.pending > 0) {
            console.log();
        }
        var fmt;
        if (result.passes > 0) {
            fmt = color('checkmark', '  %d passing');
            var args = [result.passes];

            if (totalPassTime > 0) {
                fmt += color('pass', ' (%dms)');
                args.push(totalPassTime);
            }

            console.log.apply(console, [fmt].concat(args));
        }
        if (result.failures > 0) {
            fmt = color('fail', '  %d failing');
            console.log(fmt, result.failures);
        }
        // Newline
        console.log();
    }

    var testResults;

    return function onTestComplete(result, callback) {
        var res = result.result || {};
        var tests = useTests && res.tests || res.reports || [];

        // Clone tests
        tests = tests.slice();

        // Newline
        console.log();

        printInfo(result);

        for (var i = 0; i < tests.length; i++) {
            var test = tests[i];
            printTitles(test.titles);
            printResult(test);
        }

        printFinal(res);
        callback(null, result.passed);
    };
}

module.exports = {
    create: create
};<commit_msg>Use duration from results rather than calculating it. Resolves #5.<commit_after>var supportsColor = process.env ? require('supports-color') : null;
var useColors = process.env
  ? (supportsColor || (process.env.MOCHA_COLORS !== undefined))
  : false;

var colors = {
    'pass': 90
  , 'fail': 31
  , 'bright pass': 92
  , 'bright fail': 91
  , 'bright yellow': 93
  , 'pending': 36
  , 'suite': 0
  , 'error title': 0
  , 'error message': 31
  , 'error stack': 90
  , 'checkmark': 32
  , 'fast': 90
  , 'medium': 33
  , 'slow': 31
  , 'green': 32
  , 'light': 90
  , 'diff gutter': 90
  , 'diff added': 42
  , 'diff removed': 41
};

function color(type, str) {
    if (!useColors) return String(str);
    return '\u001b[' + colors[type] + 'm' + str + '\u001b[0m';
}

var symbols = {
    pass: '✓',
    fail: '✖'
};

// With node.js on Windows: use symbols available in terminal default fonts
if ('win32' == process.platform) {
    symbols.pass = '\u221A';
    symbols.fail = '\u00D7';
}

function create(useTests) {
    var depth = 0;
    function indent() {
        return Array(depth + 2).join('  ');
    }

    var lastTitles = [];
    function printTitles(titles) {
        // Print if the titles at an index are different
        for (var i = 0; i < titles.length; i++) {
            var title = titles[i];
            var lastTitle = lastTitles[i];
            depth = i;
            if (title !== lastTitle) {
                console.log(indent() + color('suite', '%s'), title);
            }
        }
        lastTitles = titles;
        depth = titles.length;
    }

    function printPass(test) {
        var fmt;
        if ('fast' == test.speed) {
            fmt = indent()
              + color('checkmark', symbols.pass)
              + color('pass', ' %s ');
            console.log(fmt, test.name);
        } else {
            fmt = indent()
              + color('checkmark', symbols.pass)
              + color('pass', ' %s ')
              + color(test.speed, '(%dms)');
            console.log(fmt, test.name, test.duration);
        }
    }

    function printInfo(result) {
        console.log('  Platform  : ' + result.platform.join(', '));
        console.log('  Report    : ' + result.url);
        console.log('  Test Page : ' + result.testPageUrl);
        console.log('  Passed    : ' + color(result.passed ? 'checkmark' : 'fail', result.passed));
        console.log();
    }

    function printFail(test) {
        var fmt;

        fmt = indent()
            + color('fail', symbols.fail + ' %s');
        console.log(fmt, test.name);

        fmt = indent()
            + color('error message', '  Error: %s');
        console.log(fmt, test.message);

        if (test.stack) {
            fmt = indent()
                + color('error stack', '    at %s');
            console.log(fmt, test.stack);
        }
    }

    function printResult(test) {
        if (test.result) {
            printPass(test);
        } else {
            printFail(test);
        }
    }

    function printFinal(result) {
        if (result.passes + result.failures + result.pending > 0) {
            console.log();
        }
        var fmt;
        if (result.passes > 0) {
            fmt = color('checkmark', '  %d passing');
            var args = [result.passes];

            if (result.duration > 0) {
                fmt += color('pass', ' (%dms)');
                args.push(result.duration);
            }

            console.log.apply(console, [fmt].concat(args));
        }
        if (result.failures > 0) {
            fmt = color('fail', '  %d failing');
            console.log(fmt, result.failures);
        }
        // Newline
        console.log();
    }

    return function onTestComplete(result, callback) {
        var res = result.result || {};
        var tests = useTests && res.tests || res.reports || [];

        // Clone tests
        tests = tests.slice();

        // Newline
        console.log();

        printInfo(result);

        for (var i = 0; i < tests.length; i++) {
            var test = tests[i];
            printTitles(test.titles);
            printResult(test);
        }

        printFinal(res);
        callback(null, result.passed);
    };
}

module.exports = {
    create: create
};<|endoftext|>


<commit_before>{
    const routes = {
        "#home": { template: `<game-list></game-list>` },
        "#about": { template: `<route-about></route-about>` }
    }

    Vue.component("route-about", {
        template: `

About

            <route-link href="#home">Home</route-link>
            <route-link href="#about">About</route-link>

        `
    });

    Vue.component("route-link", {
        template: `
            <slot></slot>
        `,
        props: {
            href: String,
            required: true
        },
        methods: {
            go (e){
                e.preventDefault();
                this.$root.hash = this.href;
                window.history.pushState(null, routes[this.href], this.href);
            }
        }
    });

    new Vue({
        el: "app-router",
        data: {
            hash: location.hash,
            default: "#home"
        },
        computed: {
            currentRoute(){
                if(!routes[this.hash]){
                this.hash = this.default;
                }
                return routes[this.hash];
            }
        },
        render(h){
            return h(this.currentRoute);
        }
    });

    window.addEventListener("popstate", () => {
        app.currentRoute = location.hash;
    });

    window.router = {
        go: (hash) => {
            this.$root.hash = this.href;
            window.history.pushState(null, routes[this.href], this.href);
        }
    };
}<commit_msg>updating router again<commit_after>{
    const routes = {
        "#home": { template: `<game-list></game-list>` },
        "#about": { template: `<route-about></route-about>` }
    }

    Vue.component("route-about", {
        template: `

About

            <route-link href="#home">Home</route-link>
            <route-link href="#about">About</route-link>

        `
    });

    Vue.component("route-link", {
        template: `
            <slot></slot>
        `,
        props: {
            href: String,
            required: true
        },
        methods: {
            go (e){
                e.preventDefault();
                this.$root.hash = this.href;
                window.history.pushState(null, routes[this.href], this.href);
            }
        }
    });

    let router = new Vue({
        el: "app-router",
        data: {
            hash: location.hash
        },
        computed: {
            currentRoute(){
                if(!routes[this.hash]){
                    let defaultHash = this.$el.getAttribute("default-route");
                    this.hash = defaultHash;
                    window.history.pushState(null, routes[this.hash], this.hash);
                }
                return routes[this.hash];
            }
        },
        methods: {
            go (hash){
                this.hash = hash;
                window.history.pushState(null, routes[hash], hash);
            }
        },
        render(h){
            return h(this.currentRoute);
        }
    });

    window.addEventListener("popstate", () => {
        router.currentRoute = location.hash;
    });

    window.router = router;
}<|endoftext|>


<commit_before>
(function() {

	var ans = document.getElementById('answer-output'),
			form = document.getElementById('formula-output'),
			nums = document.getElementsByClassName('num'),
			ops = document.getElementsByClassName('op'),
			numsInputted = [],
			val1 = '',
			val2 = '',
			val, currentOp;

	function storeNum() {

		// check if last click was equals button. If so, clear out
		// all values before storing current number click
		if(ans.innerHTML === val1 && currentOp === '') {
			fullClear();
		}
		// display input in equation field and store individual nums
		// into an array
		form.insertAdjacentHTML('beforeend', this.innerHTML);
		numsInputted.push(this.innerHTML);

	}

	// called only when an operator is clicked (+,-,*,/,^)
	function operation() {

		// check if previous click was an operator and not a number
		// if so, proceed to next block
		if( !/[+\-*\/^]$/.test(form.innerHTML) ) {

			if(numsInputted.length) {

				// if nums array is populated, store values in val,
				// clear array, and show current op in equation display
				val = numsInputted.join('');
				numsInputted = [];
				form.insertAdjacentHTML('beforeend', this.innerHTML);

				// if val1 contains a value, val2 gets last input and
				// compute is called, else val1 is assigned the input
				// this will dynamically show the answer each time an
				// op is clicked
				if(val1 !== '') {
					val2 = val;
					compute();
				} else {
					val1 = val;
				}

				// this will be true when an op is clicked after equals
			} else if(ans.innerHTML === val1) {

				// and so the previous answer and current op will be
				// displayed in equation field
				form.insertAdjacentHTML('beforeend', val1 + this.innerHTML);

			} else {

				// when no numbers have yet been
				// entered, 0 is used as first val
				val1 = 0;
				form.insertAdjacentHTML('beforeend', '0' + this.innerHTML);

			}

			// store currently selected op
			currentOp = this.innerHTML;

			// if minus is clicked as a negator after *, /, or ^
		} else if( this.innerHTML === '-' && /[*\/^]$/.test(form.innerHTML) ) {

			// add it to display, push to nums array, and keep currentOp as is
			form.insertAdjacentHTML('beforeend', this.innerHTML);
			numsInputted.push(this.innerHTML);

			// finally check if last two chars in equation field are any op
			// followed by a minus (as a negator to a future num input)
			// if this is not the case, overwrite previous op with current op
			// the prevents overwriting a minus acting as a negator with the
			// current op
		} else if( !/[+\-*\/^][\-]$/.test(form.innerHTML) ) {

			// replace last char in equation field and update currentOp
			form.innerHTML = form.innerHTML.slice(0, -1) + this.innerHTML;
			currentOp = this.innerHTML;

		}

	}

	function compute() {

		// perform proper calculation based on currentOp then store the
		// result in val1 in case next calculation is chained
		currentOp === '^' ?
				ans.innerHTML = Math.pow(val1, val2) :
				ans.innerHTML = eval(val1 + currentOp + val2);

		val1 = ans.innerHTML;

	}

	function fullClear() {

		// clears out all stored values
		semiClear();
		ans.innerHTML = '0';
		val1 = '';

	}

	function semiClear() {

		// keeps val1 and doesn't wipe answer display
		form.innerHTML = '';
		numsInputted = [];
		currentOp = '';
		val2 = '';

	}

	// add handlers to numbered inputs
	for(var i=0; i<nums.length; i++) {
		nums[i].addEventListener('click', storeNum);
	}

	// add handlers to operation inputs
	for (var j=0; j<ops.length; j++) {
		ops[j].addEventListener('click', operation);
	}

	document.getElementById('clear').addEventListener('click', function() {

		fullClear();

	});

	document.getElementById('equals').addEventListener('click', function() {

		// store second value, perform calculation, then call semiClear in
		// case next input is an op
		val2 = numsInputted.join('');
		compute();
		semiClear();

	});

	document.getElementById('delete').addEventListener('click', function() {

		// remove last value in nums array and last char in equation display
		// but only if nums array is not empty (input is only removed to last op)
		if(numsInputted.length) {
			numsInputted.pop();
			form.innerHTML = form.innerHTML.slice(0, -1);
		}

	});

	document.getElementById('decimal').addEventListener('click', function() {

		// only store decimal if not already in nums array (no double decimals!)
		if(numsInputted.indexOf('.') === -1) {
			storeNum.apply(this);
		}

	});

})();
<commit_msg>fixed typo<commit_after>
(function() {

	var ans = document.getElementById('answer-output'),
			form = document.getElementById('formula-output'),
			nums = document.getElementsByClassName('num'),
			ops = document.getElementsByClassName('op'),
			numsInputted = [],
			val1 = '',
			val2 = '',
			val, currentOp;

	function storeNum() {

		// check if last click was equals button. If so, clear out
		// all values before storing current number click
		if(ans.innerHTML === val1 && currentOp === '') {
			fullClear();
		}
		// display input in equation field and store individual nums
		// into an array
		form.insertAdjacentHTML('beforeend', this.innerHTML);
		numsInputted.push(this.innerHTML);

	}

	// called only when an operator is clicked (+,-,*,/,^)
	function operation() {

		// check if previous click was an operator and not a number
		// if so, proceed to next block
		if( !/[+\-*\/^]$/.test(form.innerHTML) ) {

			if(numsInputted.length) {

				// if nums array is populated, store values in val,
				// clear array, and show current op in equation display
				val = numsInputted.join('');
				numsInputted = [];
				form.insertAdjacentHTML('beforeend', this.innerHTML);

				// if val1 contains a value, val2 gets last input and
				// compute is called, else val1 is assigned the input
				// this will dynamically show the answer each time an
				// op is clicked
				if(val1 !== '') {
					val2 = val;
					compute();
				} else {
					val1 = val;
				}

				// this will be true when an op is clicked after equals
			} else if(ans.innerHTML === val1) {

				// and so the previous answer and current op will be
				// displayed in equation field
				form.insertAdjacentHTML('beforeend', val1 + this.innerHTML);

			} else {

				// when no numbers have yet been
				// entered, 0 is used as first val
				val1 = 0;
				form.insertAdjacentHTML('beforeend', '0' + this.innerHTML);

			}

			// store currently selected op
			currentOp = this.innerHTML;

			// if minus is clicked as a negator after *, /, or ^
		} else if( this.innerHTML === '-' && /[*\/^]$/.test(form.innerHTML) ) {

			// add it to display, push to nums array, and keep currentOp as is
			form.insertAdjacentHTML('beforeend', this.innerHTML);
			numsInputted.push(this.innerHTML);

			// finally check if last two chars in equation field are any op
			// followed by a minus (as a negator to a future num input)
			// if this is not the case, overwrite previous op with current op
			// this prevents overwriting a minus acting as a negator with the
			// current op
		} else if( !/[+\-*\/^][\-]$/.test(form.innerHTML) ) {

			// replace last char in equation field and update currentOp
			form.innerHTML = form.innerHTML.slice(0, -1) + this.innerHTML;
			currentOp = this.innerHTML;

		}

	}

	function compute() {

		// perform proper calculation based on currentOp then store the
		// result in val1 in case next calculation is chained
		currentOp === '^' ?
				ans.innerHTML = Math.pow(val1, val2) :
				ans.innerHTML = eval(val1 + currentOp + val2);

		val1 = ans.innerHTML;

	}

	function fullClear() {

		// clears out all stored values
		semiClear();
		ans.innerHTML = '0';
		val1 = '';

	}

	function semiClear() {

		// keeps val1 and doesn't wipe answer display
		form.innerHTML = '';
		numsInputted = [];
		currentOp = '';
		val2 = '';

	}

	// add handlers to numbered inputs
	for(var i=0; i<nums.length; i++) {
		nums[i].addEventListener('click', storeNum);
	}

	// add handlers to operation inputs
	for (var j=0; j<ops.length; j++) {
		ops[j].addEventListener('click', operation);
	}

	document.getElementById('clear').addEventListener('click', function() {

		fullClear();

	});

	document.getElementById('equals').addEventListener('click', function() {

		// store second value, perform calculation, then call semiClear in
		// case next input is an op
		val2 = numsInputted.join('');
		compute();
		semiClear();

	});

	document.getElementById('delete').addEventListener('click', function() {

		// remove last value in nums array and last char in equation display
		// but only if nums array is not empty (input is only removed to last op)
		if(numsInputted.length) {
			numsInputted.pop();
			form.innerHTML = form.innerHTML.slice(0, -1);
		}

	});

	document.getElementById('decimal').addEventListener('click', function() {

		// only store decimal if not already in nums array (no double decimals!)
		if(numsInputted.indexOf('.') === -1) {
			storeNum.apply(this);
		}

	});

})();
<|endoftext|>


<commit_before>import Config from 'react-native-config';
import tracker from 'helpers/googleAnalytics';
import CONSTANTS from 'config/constants';
import { LOGOUT_REQUEST } from 'redux-modules/user';
import { getActionsTodoCount } from 'helpers/sync';
import omit from 'lodash/omit';

import { SAVE_AREA_COMMIT, GET_AREAS_COMMIT } from 'redux-modules/areas';

// Actions

const GET_DEFAULT_TEMPLATE_REQUEST = 'report/GET_DEFAULT_TEMPLATE_REQUEST';
const GET_DEFAULT_TEMPLATE_COMMIT = 'report/GET_DEFAULT_TEMPLATE_COMMIT';
const GET_DEFAULT_TEMPLATE_ROLLBACK = 'report/GET_DEFAULT_TEMPLATE_ROLLBACK';
const GET_REPORT_TEMPLATE_REQUEST = 'report/GET_REPORT_TEMPLATE_REQUEST';
const GET_REPORT_TEMPLATE_COMMIT = 'report/GET_REPORT_TEMPLATE_COMMIT';
const GET_REPORT_TEMPLATE_ROLLBACK = 'report/GET_REPORT_TEMPLATE_ROLLBACK';
const CREATE_REPORT = 'report/CREATE_REPORT';
const UPDATE_REPORT = 'report/UPDATE_REPORT';
const UPLOAD_REPORT_REQUEST = 'report/UPLOAD_REPORT_REQUEST';
export const UPLOAD_REPORT_COMMIT = 'report/UPLOAD_REPORT_COMMIT';
const UPLOAD_REPORT_ROLLBACK = 'report/UPLOAD_REPORT_ROLLBACK';

// Reducer
const initialState = {
  templates: {},
  list: {},
  synced: false,
  syncing: false,
  pendingData: {
    templates: {}
  }
};

function orderQuestions(questions) {
  if (!questions || !questions.length) return [];
  return questions.sort((a, b) => parseInt(a.order, 10) - parseInt(b.order, 10));
}

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case GET_DEFAULT_TEMPLATE_REQUEST:
      return { ...state, synced: false, syncing: true };
    case GET_DEFAULT_TEMPLATE_COMMIT: {
      const template = action.payload || {};
      template.questions = orderQuestions(template.questions);
      const templates = {
        ...state.templates,
        default: template
      };
      return { ...state, templates, synced: true, syncing: false };
    }
    case GET_DEFAULT_TEMPLATE_ROLLBACK:
      return { ...state, syncing: false };
    case GET_REPORT_TEMPLATE_REQUEST: {
      const templateId = action.payload;

      const pendingData = {
        ...state.pendingData,
        templates: {
          ...state.pendingData.templates,
          [templateId]: true
        }
      };
      return { ...state, pendingData };
    }
    case GET_REPORT_TEMPLATE_COMMIT: {
      const template = action.payload || {};
      template.questions = orderQuestions(template.questions);
      const templates = {
        ...state.templates,
        [template.id]: template
      };
      const pendingData = {
        ...state.pendingData,
        templates: omit(state.pendingData.templates, [template.id])
      };
      return { ...state, templates, pendingData };
    }
    case GET_REPORT_TEMPLATE_ROLLBACK: {
      const { templateId } = action.meta;

      const pendingData = {
        ...state.pendingData,
        templates: {
          ...state.pendingData.templates,
          [templateId]: false
        }
      };
      return { ...state, pendingData };
    }
    case GET_AREAS_COMMIT: {
      const data = [...action.payload];
      let pendingData = state.pendingData;
      data.forEach((area) => {
        if (area.templateId && !state.templates[area.templateId]) {
          pendingData = {
            templates: { ...pendingData.templates, [area.templateId]: false }
          };
        }
      });
      return { ...state, pendingData };
    }
    case SAVE_AREA_COMMIT: {
      const area = action.payload;
      let pendingData = { ...state.pendingData };
      if (area && area.templateId) {
        pendingData = {
          templates: { ...pendingData.templates, [area.templateId]: false }
        };
      }
      return { ...state, pendingData };
    }
    case CREATE_REPORT: {
      const reports = { ...state.list, ...action.payload };
      return Object.assign({}, state, { list: reports });
    }
    case UPDATE_REPORT: {
      const list = Object.assign({}, state.list);
      list[action.payload.name] = Object.assign({}, state.list[action.payload.name], action.payload.data);
      return Object.assign({}, state, { list });
    }
    case UPLOAD_REPORT_REQUEST: {
      const { name, status } = action.payload;
      const report = state.list[name];
      const list = { ...state.list, [name]: { ...report, status } };
      return { ...state, list, synced: false, syncing: true };
    }
    case UPLOAD_REPORT_COMMIT: {
      const { name, status } = action.meta.report;
      const report = state.list[name];
      const list = { ...state.list, [name]: { ...report, status } };
      return { ...state, list, synced: true, syncing: false };
    }
    case UPLOAD_REPORT_ROLLBACK: {
      return { ...state, syncing: false };
    }
    case LOGOUT_REQUEST: {
      return initialState;
    }
    default: {
      return state;
    }
  }
}

// Action Creators
export function getDefaultReport() {
  const template = Config.REPORT_ID;
  const url = `${Config.API_URL}/reports/${template}`;

  return {
    type: GET_DEFAULT_TEMPLATE_REQUEST,
    meta: {
      offline: {
        effect: { url },
        commit: { type: GET_DEFAULT_TEMPLATE_COMMIT },
        rollback: { type: GET_DEFAULT_TEMPLATE_ROLLBACK }
      }
    }
  };
}

export function getReportTemplate(templateId) {
  const url = `${Config.API_URL}/reports/${templateId}`;

  return {
    type: GET_REPORT_TEMPLATE_REQUEST,
    payload: templateId,
    meta: {
      offline: {
        effect: { url },
        commit: { type: GET_REPORT_TEMPLATE_COMMIT },
        rollback: { type: GET_REPORT_TEMPLATE_ROLLBACK, meta: { templateId } }
      }
    }
  };
}

export function createReport({ name, userPosition, clickedPosition, area }) {
  return {
    type: CREATE_REPORT,
    payload: {
      [name]: {
        area,
        userPosition,
        clickedPosition,
        index: 0,
        status: CONSTANTS.status.draft,
        date: new Date().toISOString()
      }
    }
  };
}

export function saveReport(name, data) {
  return {
    type: UPDATE_REPORT,
    payload: { name, data }
  };
}

export function uploadReport({ reportName, fields }) {
  tracker.trackEvent('Report', 'Complete Report', { label: 'Click Done', value: 0 });
  return (dispatch, state) => {
    const reportValues = state().form[reportName].values;
    const user = state().user;
    const userName = (user && user.data && user.data.fullName) || 'Guest user';
    const organization = (user && user.data && user.data.organization) || 'None';
    const report = state().reports.list[reportName];
    const language = state().app.language;
    const area = report.area;
    const dataset = area.dataset || {};
    const form = new FormData();
    const defaultTemplate = state().reports.templates.default;
    const templateId = report.area.templateId || defaultTemplate.id;

    form.append('report', templateId);
    form.append('areaOfInterest', area.id);
    form.append('startDate', dataset.startDate);
    form.append('endDate', dataset.endDate);
    form.append('layer', dataset.slug);
    form.append('language', language);
    form.append('username', userName);
    form.append('organization', organization);
    form.append('date', report && report.date);
    form.append('clickedPosition', report && report.clickedPosition.toString());
    form.append('userPosition', report && report.userPosition.toString());

    Object.keys(reportValues).forEach((key) => {
      if (fields.includes(key)) {
        if (typeof reportValues[key] === 'string' && reportValues[key].indexOf('jpg') >= 0) { // TODO: improve this
          const image = {
            uri: reportValues[key],
            type: 'image/jpg',
            name: `${reportName}-image-${key}.jpg`
          };
          form.append(key, image);
        } else {
          form.append(key, reportValues[key].toString());
        }
      }
    });

    const requestPayload = {
      name: reportName,
      status: CONSTANTS.status.complete
    };
    const commitPayload = {
      name: reportName,
      status: CONSTANTS.status.uploaded,
      alerts: JSON.parse(report.clickedPosition)
    };
    const url = `${Config.API_URL}/reports/${Config.REPORT_ID}/answers`;
    const headers = { 'content-type': 'multipart/form-data' };
    dispatch({
      type: UPLOAD_REPORT_REQUEST,
      payload: requestPayload,
      meta: {
        offline: {
          effect: { url, body: form, method: 'POST', headers },
          commit: { type: UPLOAD_REPORT_COMMIT, meta: { report: commitPayload } },
          rollback: { type: UPLOAD_REPORT_ROLLBACK }
        }
      }
    });
  };
}

export function syncReports() {
  return (dispatch, state) => {
    const { reports } = state();
    if (!reports.synced && !reports.syncing) dispatch(getDefaultReport());
    const { pendingData } = state().reports;
    if (getActionsTodoCount(pendingData) > 0) {
      Object.keys(pendingData).forEach((type) => {
        const syncingReportsData = pendingData[type];
        const canDispatch = id => (typeof syncingReportsData[id] !== 'undefined' && syncingReportsData[id] === false);
        Object.keys(syncingReportsData).forEach(id => {
          if (canDispatch(id)) {
            dispatch(getReportTemplate(id));
          }
        });
      });
    }
  };
}
<commit_msg>Don't save unpublish reports<commit_after>import Config from 'react-native-config';
import tracker from 'helpers/googleAnalytics';
import CONSTANTS from 'config/constants';
import { LOGOUT_REQUEST } from 'redux-modules/user';
import { getActionsTodoCount } from 'helpers/sync';
import omit from 'lodash/omit';

import { SAVE_AREA_COMMIT, GET_AREAS_COMMIT } from 'redux-modules/areas';

// Actions

const GET_DEFAULT_TEMPLATE_REQUEST = 'report/GET_DEFAULT_TEMPLATE_REQUEST';
const GET_DEFAULT_TEMPLATE_COMMIT = 'report/GET_DEFAULT_TEMPLATE_COMMIT';
const GET_DEFAULT_TEMPLATE_ROLLBACK = 'report/GET_DEFAULT_TEMPLATE_ROLLBACK';
const GET_REPORT_TEMPLATE_REQUEST = 'report/GET_REPORT_TEMPLATE_REQUEST';
const GET_REPORT_TEMPLATE_COMMIT = 'report/GET_REPORT_TEMPLATE_COMMIT';
const GET_REPORT_TEMPLATE_ROLLBACK = 'report/GET_REPORT_TEMPLATE_ROLLBACK';
const CREATE_REPORT = 'report/CREATE_REPORT';
const UPDATE_REPORT = 'report/UPDATE_REPORT';
const UPLOAD_REPORT_REQUEST = 'report/UPLOAD_REPORT_REQUEST';
export const UPLOAD_REPORT_COMMIT = 'report/UPLOAD_REPORT_COMMIT';
const UPLOAD_REPORT_ROLLBACK = 'report/UPLOAD_REPORT_ROLLBACK';

// Reducer
const initialState = {
  templates: {},
  list: {},
  synced: false,
  syncing: false,
  pendingData: {
    templates: {}
  }
};

function orderQuestions(questions) {
  if (!questions || !questions.length) return [];
  return questions.sort((a, b) => parseInt(a.order, 10) - parseInt(b.order, 10));
}

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case GET_DEFAULT_TEMPLATE_REQUEST:
      return { ...state, synced: false, syncing: true };
    case GET_DEFAULT_TEMPLATE_COMMIT: {
      const template = action.payload || {};
      template.questions = orderQuestions(template.questions);
      const templates = {
        ...state.templates,
        default: template
      };
      return { ...state, templates, synced: true, syncing: false };
    }
    case GET_DEFAULT_TEMPLATE_ROLLBACK:
      return { ...state, syncing: false };
    case GET_REPORT_TEMPLATE_REQUEST: {
      const templateId = action.payload;

      const pendingData = {
        ...state.pendingData,
        templates: {
          ...state.pendingData.templates,
          [templateId]: true
        }
      };
      return { ...state, pendingData };
    }
    case GET_REPORT_TEMPLATE_COMMIT: {
      const template = action.payload || {};
      template.questions = orderQuestions(template.questions);
      let templates = { ...state.templates };
      if (template.status !== 'unpublished') {
        templates = {
          ...templates,
          [template.id]: template
        };
      }
      const pendingData = {
        ...state.pendingData,
        templates: omit(state.pendingData.templates, [template.id])
      };
      return { ...state, templates, pendingData };
    }
    case GET_REPORT_TEMPLATE_ROLLBACK: {
      const { templateId } = action.meta;

      const pendingData = {
        ...state.pendingData,
        templates: {
          ...state.pendingData.templates,
          [templateId]: false
        }
      };
      return { ...state, pendingData };
    }
    case GET_AREAS_COMMIT: {
      const data = [...action.payload];
      let pendingData = state.pendingData;
      data.forEach((area) => {
        if (area.templateId && !state.templates[area.templateId]) {
          pendingData = {
            templates: { ...pendingData.templates, [area.templateId]: false }
          };
        }
      });
      return { ...state, pendingData };
    }
    case SAVE_AREA_COMMIT: {
      const area = action.payload;
      let pendingData = { ...state.pendingData };
      if (area && area.templateId) {
        pendingData = {
          templates: { ...pendingData.templates, [area.templateId]: false }
        };
      }
      return { ...state, pendingData };
    }
    case CREATE_REPORT: {
      const reports = { ...state.list, ...action.payload };
      return Object.assign({}, state, { list: reports });
    }
    case UPDATE_REPORT: {
      const list = Object.assign({}, state.list);
      list[action.payload.name] = Object.assign({}, state.list[action.payload.name], action.payload.data);
      return Object.assign({}, state, { list });
    }
    case UPLOAD_REPORT_REQUEST: {
      const { name, status } = action.payload;
      const report = state.list[name];
      const list = { ...state.list, [name]: { ...report, status } };
      return { ...state, list, synced: false, syncing: true };
    }
    case UPLOAD_REPORT_COMMIT: {
      const { name, status } = action.meta.report;
      const report = state.list[name];
      const list = { ...state.list, [name]: { ...report, status } };
      return { ...state, list, synced: true, syncing: false };
    }
    case UPLOAD_REPORT_ROLLBACK: {
      return { ...state, syncing: false };
    }
    case LOGOUT_REQUEST: {
      return initialState;
    }
    default: {
      return state;
    }
  }
}

// Action Creators
export function getDefaultReport() {
  const template = Config.REPORT_ID;
  const url = `${Config.API_URL}/reports/${template}`;

  return {
    type: GET_DEFAULT_TEMPLATE_REQUEST,
    meta: {
      offline: {
        effect: { url },
        commit: { type: GET_DEFAULT_TEMPLATE_COMMIT },
        rollback: { type: GET_DEFAULT_TEMPLATE_ROLLBACK }
      }
    }
  };
}

export function getReportTemplate(templateId) {
  const url = `${Config.API_URL}/reports/${templateId}`;

  return {
    type: GET_REPORT_TEMPLATE_REQUEST,
    payload: templateId,
    meta: {
      offline: {
        effect: { url },
        commit: { type: GET_REPORT_TEMPLATE_COMMIT },
        rollback: { type: GET_REPORT_TEMPLATE_ROLLBACK, meta: { templateId } }
      }
    }
  };
}

export function createReport({ name, userPosition, clickedPosition, area }) {
  return {
    type: CREATE_REPORT,
    payload: {
      [name]: {
        area,
        userPosition,
        clickedPosition,
        index: 0,
        status: CONSTANTS.status.draft,
        date: new Date().toISOString()
      }
    }
  };
}

export function saveReport(name, data) {
  return {
    type: UPDATE_REPORT,
    payload: { name, data }
  };
}

export function uploadReport({ reportName, fields }) {
  tracker.trackEvent('Report', 'Complete Report', { label: 'Click Done', value: 0 });
  return (dispatch, state) => {
    const reportValues = state().form[reportName].values;
    const user = state().user;
    const userName = (user && user.data && user.data.fullName) || 'Guest user';
    const organization = (user && user.data && user.data.organization) || 'None';
    const report = state().reports.list[reportName];
    const language = state().app.language;
    const area = report.area;
    const dataset = area.dataset || {};
    const form = new FormData();
    const defaultTemplate = state().reports.templates.default;
    const templateId = report.area.templateId || defaultTemplate.id;

    form.append('report', templateId);
    form.append('areaOfInterest', area.id);
    form.append('startDate', dataset.startDate);
    form.append('endDate', dataset.endDate);
    form.append('layer', dataset.slug);
    form.append('language', language);
    form.append('username', userName);
    form.append('organization', organization);
    form.append('date', report && report.date);
    form.append('clickedPosition', report && report.clickedPosition.toString());
    form.append('userPosition', report && report.userPosition.toString());

    Object.keys(reportValues).forEach((key) => {
      if (fields.includes(key)) {
        if (typeof reportValues[key] === 'string' && reportValues[key].indexOf('jpg') >= 0) { // TODO: improve this
          const image = {
            uri: reportValues[key],
            type: 'image/jpg',
            name: `${reportName}-image-${key}.jpg`
          };
          form.append(key, image);
        } else {
          form.append(key, reportValues[key].toString());
        }
      }
    });

    const requestPayload = {
      name: reportName,
      status: CONSTANTS.status.complete
    };
    const commitPayload = {
      name: reportName,
      status: CONSTANTS.status.uploaded,
      alerts: JSON.parse(report.clickedPosition)
    };
    const url = `${Config.API_URL}/reports/${Config.REPORT_ID}/answers`;
    const headers = { 'content-type': 'multipart/form-data' };
    dispatch({
      type: UPLOAD_REPORT_REQUEST,
      payload: requestPayload,
      meta: {
        offline: {
          effect: { url, body: form, method: 'POST', headers },
          commit: { type: UPLOAD_REPORT_COMMIT, meta: { report: commitPayload } },
          rollback: { type: UPLOAD_REPORT_ROLLBACK }
        }
      }
    });
  };
}

export function syncReports() {
  return (dispatch, state) => {
    const { reports } = state();
    if (!reports.synced && !reports.syncing) dispatch(getDefaultReport());
    const { pendingData } = state().reports;
    if (getActionsTodoCount(pendingData) > 0) {
      Object.keys(pendingData).forEach((type) => {
        const syncingReportsData = pendingData[type];
        const canDispatch = id => (typeof syncingReportsData[id] !== 'undefined' && syncingReportsData[id] === false);
        Object.keys(syncingReportsData).forEach(id => {
          if (canDispatch(id)) {
            dispatch(getReportTemplate(id));
          }
        });
      });
    }
  };
}
<|endoftext|>


<commit_before>/**
 * generated by alinw
 */

(function() {
    var root = this;
    var isDev = false;
    if (typeof root.ALINW === "object" && root.ALINW.isDev) {
        isDev = root.ALINW.isDev;
    }

    var config = {
        base: null,

        alias: {
            $: 'alinw/jquery/1.8.3/jquery',
            "$-debug": 'alinw/jquery/1.8.3/jquery-debug',
            handlebars: typeof root.process === "undefined" ? 'gallery/handlebars/1.0.2/handlebars' : 'gallery/handlebars/1.0.2/runtime',
            _: "gallery/underscore/1.6.0/underscore",
            less: 'alinw/less/1.9.0/less',
            moment: "gallery/moment/2.3.1/moment"
        },
        paths: {},
        comboSyntax: ["??", ","],
        comboMaxLength: 500,
        preload: [
            "$"
        ],
        map: [],
        charset: 'utf-8',
        timeout: 20000,
        debug: true
    };

    // base
    if (root.ALINW && root.ALINW.cdnPath) {
        config.base = root.ALINW.cdnPath;
    }
    if (root.ALINW && root.ALINW.cdnVersion) {
        config.base += '/' + root.ALINW.cdnVersion;
    }

    var isHttps = false;
    if (root.location && root.location.protocol && root.location.protocol.indexOf("https") >= 0) {
        isHttps = true;
    }
    if (typeof root.process === "undefined") {
        config.paths.gallery = isHttps ? "https://a.alipayobjects.com/gallery" : 'http://assets.spmjs.org/gallery';
        config.paths.arale = isHttps ? "https://a.alipayobjects.com/arale" : 'http://assets.spmjs.org/arale';
        config.paths.platform = isDev ? "http://g.assets.daily.taobao.net/platform" : 'https://s.tbcdn.cn/g/platform';
        config.paths.alinw = isDev ? "http://g.assets.daily.taobao.net/alinw" : 'https://s.tbcdn.cn/g/alinw';
    }

    if (root.seajs) {
        root.seajs.config(config);
    }
    return config;
}).call(this);<commit_msg>刚才提交的有bug<commit_after>/**
 * generated by alinw
 */

(function() {
    var root = this;
    var isDev = false;
    if (typeof root.ALINW === "object" && root.ALINW.isDev) {
        isDev = root.ALINW.isDev;
    }

    var config = {
        base: null,

        alias: {
            $: 'alinw/jquery/1.8.3/jquery',
            "$-debug": 'alinw/jquery/1.8.3/jquery-debug',
            handlebars: typeof root.process === "undefined" ? 'gallery/handlebars/1.0.2/handlebars' : 'gallery/handlebars/1.0.2/runtime',
            _: "gallery/underscore/1.6.0/underscore",
            less: 'alinw/less/1.9.0/less',
            moment: "gallery/moment/2.3.1/moment"
        },
        paths: {
            demoPath: 'apps/demo'
        },
        comboSyntax: ["??", ","],
        comboMaxLength: 500,
        preload: [
            "$"
        ],
        map: [],
        charset: 'utf-8',
        timeout: 20000,
        debug: true
    };

    // base
    if (root.ALINW && root.ALINW.cdnPath) {
        config.base = root.ALINW.cdnPath;
    }
    if (root.ALINW && root.ALINW.cdnVersion) {
        config.base += '/' + root.ALINW.cdnVersion;
    }

    var isHttps = false;
    if (root.location && root.location.protocol && root.location.protocol.indexOf("https") >= 0) {
        isHttps = true;
    }
    if (typeof root.process === "undefined") {
        config.paths.gallery = isHttps ? "https://a.alipayobjects.com/gallery" : 'http://assets.spmjs.org/gallery';
        config.paths.arale = isHttps ? "https://a.alipayobjects.com/arale" : 'http://assets.spmjs.org/arale';
        config.paths.platform = isDev ? "http://g.assets.daily.taobao.net/platform" : 'https://s.tbcdn.cn/g/platform';
        config.paths.alinw = isDev ? "http://g.assets.daily.taobao.net/alinw" : 'https://s.tbcdn.cn/g/alinw';
    }

    if (root.seajs) {
        root.seajs.config(config);
    }
    return config;
}).call(this);
<|endoftext|>


<commit_before>// Here's the problem with modal views: you can't re-render them.
// Because when they have an internal state (background fade), and rendering twice means that you won't be able to close your modal, or it won't render at all.
// I'm not sure I understand it completely, but... I had problems with that.
//
// Also, separating modal view logic is a Good Thing in any case. This view can become 'pp.View.Modal' in the future.
pp.views.UserSettingsBox = pp.View.Common.extend({
    events: {
        'click .btn-primary': 'submit'
    },

    t: 'user-settings-box',

    subviews: {
        '.settings-subview': function () {
            return new pp.views.UserSettings({ model: this.model });
        }
    },

    afterInitialize: function() {
        this.setElement($('#user-settings')); // settings-box is a singleton
    },

    start: function () {
        this.render();
        this.$('.modal').modal('show');
        this.model.fetch();
    },

    submit: function() {
        var that = this;
        this.userSettings.save({
            success: function() {
                that.$('.modal').modal('hide');
            },
            failure: function() {
                alert('modal submit failed!');
            }
        });
    },
});
<commit_msg>bugfix in settings-box - use subview()<commit_after>// Here's the problem with modal views: you can't re-render them.
// Because when they have an internal state (background fade), and rendering twice means that you won't be able to close your modal, or it won't render at all.
// I'm not sure I understand it completely, but... I had problems with that.
//
// Also, separating modal view logic is a Good Thing in any case. This view can become 'pp.View.Modal' in the future.
pp.views.UserSettingsBox = pp.View.Common.extend({
    events: {
        'click .btn-primary': 'submit'
    },

    t: 'user-settings-box',

    subviews: {
        '.settings-subview': function () {
            return new pp.views.UserSettings({ model: this.model });
        }
    },

    afterInitialize: function() {
        this.setElement($('#user-settings')); // settings-box is a singleton
    },

    start: function () {
        this.render();
        this.$('.modal').modal('show');
        this.model.fetch();
    },

    submit: function() {
        var that = this;
        this.subview('.settings-subview').save({
            success: function() {
                that.$('.modal').modal('hide');
            },
            failure: function() {
                alert('modal submit failed!');
            }
        });
    },
});
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React, { Component, Fragment } from 'react'
import Modal from 'components/Modal'
import Button from 'components/Button'
import CheckListGroup from 'components/CheckListGroup'
import {
  loadMorePlaylistListAsync,
  changePinnedPlaylists
} from 'redux/actions/PlaylistActions'
import FilterBar from 'components/FilterBar'
import Banner from 'components/Banner'
import SearchInput from 'components/Texts/SearchInput'
import request from 'axios'
import { URL } from 'constants/URL'
import { connect } from 'react-redux'

class SelectPlaylistsToPinModal extends Component {
  static propTypes = {
    changePinnedPlaylists: PropTypes.func.isRequired,
    loadMoreButton: PropTypes.bool.isRequired,
    loadMorePlaylist: PropTypes.func.isRequired,
    onHide: PropTypes.func.isRequired,
    playlistsToPin: PropTypes.array.isRequired,
    pinnedPlaylists: PropTypes.array.isRequired,
    selectedPlaylists: PropTypes.array.isRequired
  }

  state = {
    selectTabActive: true,
    selectedPlaylists: [],
    searchedPlaylists: [],
    searchText: '',
    playlistObjects: {}
  }

  componentDidMount() {
    const { pinnedPlaylists, playlistsToPin, selectedPlaylists } = this.props
    this.setState({
      selectedPlaylists,
      playlistObjects: {
        ...pinnedPlaylists.reduce(
          (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
          {}
        ),
        ...playlistsToPin.reduce(
          (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
          {}
        )
      }
    })
  }

  componentDidUpdate(prevProps) {
    if (prevProps.playlistsToPin !== this.props.playlistsToPin) {
      this.setState(state => ({
        playlistObjects: {
          ...state.playlistObjects,
          ...this.props.playlistsToPin.reduce(
            (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
            {}
          )
        }
      }))
    }
  }

  render() {
    const {
      playlistObjects,
      searchText,
      selectedPlaylists,
      selectTabActive
    } = this.state
    const { loadMoreButton, playlistsToPin } = this.props
    const lastPlaylistId = playlistsToPin[playlistsToPin.length - 1].id
    return (
      <Modal onHide={this.props.onHide}>
        Select up to 5 playlists

          {selectedPlaylists.length > 5 && (
            <Banner love>Please limit your selection to 5 playlists</Banner>
          )}
          <FilterBar>
             this.setState({ selectTabActive: true })}
              style={{ cursor: 'pointer' }}
            >
              Select

             this.setState({ selectTabActive: false })}
              style={{ cursor: 'pointer' }}
            >
              Selected

          </FilterBar>

            {selectTabActive && (
              <Fragment>
                <SearchInput
                  autoFocus
                  placeholder="Search for playlists to pin"
                  value={searchText}
                  onChange={this.onPlaylistSearchInput}
                />
                <CheckListGroup
                  style={{ marginTop: '1rem' }}
                  inputType="checkbox"
                  onSelect={this.onSelect}
                  listItems={this.renderListItems()}
                />
                {loadMoreButton && (
                  <Button
                    style={{ marginTop: '2rem', width: '100%' }}
                    transparent
                    onClick={() => this.loadMorePlaylists(lastPlaylistId)}
                  >
                    Load More
                  </Button>
                )}
                {playlistsToPin.length === 0 && (

No Playlists

                )}
              </Fragment>
            )}
            {!selectTabActive && (
              <Fragment>
                <CheckListGroup
                  inputType="checkbox"
                  onSelect={this.onDeselect}
                  listItems={selectedPlaylists.map(playlistId => ({
                    label: playlistObjects[playlistId],
                    checked: true
                  }))}
                />
                {selectedPlaylists.length === 0 && (

No Playlist Selected

                )}
              </Fragment>
            )}

          <Button
            primary
            onClick={this.onSubmit}
            disabled={selectedPlaylists.length > 5}
          >
            Done
          </Button>
          <Button
            transparent
            style={{ marginRight: '1rem' }}
            onClick={this.props.onHide}
          >
            Cancel
          </Button>

      </Modal>
    )
  }

  loadMorePlaylists = lastPlaylistId => {
    this.props.loadMorePlaylist(lastPlaylistId)
  }

  onPlaylistSearchInput = async text => {
    this.setState({ searchText: text })
    const { data } = await request.get(
      `${URL}/playlist/search/toPin?query=${text}`
    )
    this.setState(state => ({
      searchedPlaylists: data,
      playlistObjects: {
        ...state.playlistObjects,
        ...data.reduce(
          (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
          {}
        )
      }
    }))
  }

  onSelect = index => {
    const { searchText, searchedPlaylists } = this.state
    const { playlistsToPin } = this.props
    const playlists = searchText ? searchedPlaylists : playlistsToPin
    let playlistId = playlists[index].id
    this.setState(state => ({
      selectedPlaylists:
        state.selectedPlaylists.indexOf(playlistId) === -1
          ? [playlistId].concat(state.selectedPlaylists)
          : state.selectedPlaylists.filter(id => id !== playlistId)
    }))
  }

  onDeselect = index => {
    const { selectedPlaylists } = this.state
    let playlistIndex = 0
    const newSelectedPlaylists = selectedPlaylists.filter(playlist => {
      return playlistIndex++ !== index
    })
    this.setState({ selectedPlaylists: newSelectedPlaylists })
  }

  onSubmit = () => {
    const { changePinnedPlaylists, onHide } = this.props
    const { selectedPlaylists } = this.state
    return changePinnedPlaylists(selectedPlaylists).then(() => onHide())
  }

  renderListItems = () => {
    const { playlistsToPin } = this.props
    const { searchText, searchedPlaylists, selectedPlaylists } = this.state
    const playlists = searchText ? searchedPlaylists : playlistsToPin
    return playlists.map(playlist => {
      return {
        label: playlist.title,
        checked: selectedPlaylists.indexOf(playlist.id) !== -1
      }
    })
  }
}

export default connect(null, {
  loadMorePlaylist: loadMorePlaylistListAsync,
  changePinnedPlaylists: changePinnedPlaylists
})(SelectPlaylistsToPinModal)
<commit_msg>no loadmore button for pin playlist modal when search text exist<commit_after>import PropTypes from 'prop-types'
import React, { Component, Fragment } from 'react'
import Modal from 'components/Modal'
import Button from 'components/Button'
import CheckListGroup from 'components/CheckListGroup'
import {
  loadMorePlaylistListAsync,
  changePinnedPlaylists
} from 'redux/actions/PlaylistActions'
import FilterBar from 'components/FilterBar'
import Banner from 'components/Banner'
import SearchInput from 'components/Texts/SearchInput'
import request from 'axios'
import { URL } from 'constants/URL'
import { connect } from 'react-redux'

class SelectPlaylistsToPinModal extends Component {
  static propTypes = {
    changePinnedPlaylists: PropTypes.func.isRequired,
    loadMoreButton: PropTypes.bool.isRequired,
    loadMorePlaylist: PropTypes.func.isRequired,
    onHide: PropTypes.func.isRequired,
    playlistsToPin: PropTypes.array.isRequired,
    pinnedPlaylists: PropTypes.array.isRequired,
    selectedPlaylists: PropTypes.array.isRequired
  }

  state = {
    selectTabActive: true,
    selectedPlaylists: [],
    searchedPlaylists: [],
    searchText: '',
    playlistObjects: {}
  }

  componentDidMount() {
    const { pinnedPlaylists, playlistsToPin, selectedPlaylists } = this.props
    this.setState({
      selectedPlaylists,
      playlistObjects: {
        ...pinnedPlaylists.reduce(
          (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
          {}
        ),
        ...playlistsToPin.reduce(
          (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
          {}
        )
      }
    })
  }

  componentDidUpdate(prevProps) {
    if (prevProps.playlistsToPin !== this.props.playlistsToPin) {
      this.setState(state => ({
        playlistObjects: {
          ...state.playlistObjects,
          ...this.props.playlistsToPin.reduce(
            (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
            {}
          )
        }
      }))
    }
  }

  render() {
    const {
      playlistObjects,
      searchText,
      selectedPlaylists,
      selectTabActive
    } = this.state
    const { loadMoreButton, playlistsToPin } = this.props
    const lastPlaylistId = playlistsToPin[playlistsToPin.length - 1].id
    return (
      <Modal onHide={this.props.onHide}>
        Select up to 5 playlists

          {selectedPlaylists.length > 5 && (
            <Banner love>Please limit your selection to 5 playlists</Banner>
          )}
          <FilterBar>
             this.setState({ selectTabActive: true })}
              style={{ cursor: 'pointer' }}
            >
              Select

             this.setState({ selectTabActive: false })}
              style={{ cursor: 'pointer' }}
            >
              Selected

          </FilterBar>

            {selectTabActive && (
              <Fragment>
                <SearchInput
                  autoFocus
                  placeholder="Search for playlists to pin"
                  value={searchText}
                  onChange={this.onPlaylistSearchInput}
                />
                <CheckListGroup
                  style={{ marginTop: '1rem' }}
                  inputType="checkbox"
                  onSelect={this.onSelect}
                  listItems={this.renderListItems()}
                />
                {loadMoreButton && !searchText && (
                  <Button
                    style={{ marginTop: '2rem', width: '100%' }}
                    transparent
                    onClick={() => this.loadMorePlaylists(lastPlaylistId)}
                  >
                    Load More
                  </Button>
                )}
                {playlistsToPin.length === 0 && (

No Playlists

                )}
              </Fragment>
            )}
            {!selectTabActive && (
              <Fragment>
                <CheckListGroup
                  inputType="checkbox"
                  onSelect={this.onDeselect}
                  listItems={selectedPlaylists.map(playlistId => ({
                    label: playlistObjects[playlistId],
                    checked: true
                  }))}
                />
                {selectedPlaylists.length === 0 && (

No Playlist Selected

                )}
              </Fragment>
            )}

          <Button
            primary
            onClick={this.onSubmit}
            disabled={selectedPlaylists.length > 5}
          >
            Done
          </Button>
          <Button
            transparent
            style={{ marginRight: '1rem' }}
            onClick={this.props.onHide}
          >
            Cancel
          </Button>

      </Modal>
    )
  }

  loadMorePlaylists = lastPlaylistId => {
    this.props.loadMorePlaylist(lastPlaylistId)
  }

  onPlaylistSearchInput = async text => {
    this.setState({ searchText: text })
    const { data } = await request.get(
      `${URL}/playlist/search/toPin?query=${text}`
    )
    this.setState(state => ({
      searchedPlaylists: data,
      playlistObjects: {
        ...state.playlistObjects,
        ...data.reduce(
          (prev, playlist) => ({ ...prev, [playlist.id]: playlist.title }),
          {}
        )
      }
    }))
  }

  onSelect = index => {
    const { searchText, searchedPlaylists } = this.state
    const { playlistsToPin } = this.props
    const playlists = searchText ? searchedPlaylists : playlistsToPin
    let playlistId = playlists[index].id
    this.setState(state => ({
      selectedPlaylists:
        state.selectedPlaylists.indexOf(playlistId) === -1
          ? [playlistId].concat(state.selectedPlaylists)
          : state.selectedPlaylists.filter(id => id !== playlistId)
    }))
  }

  onDeselect = index => {
    const { selectedPlaylists } = this.state
    let playlistIndex = 0
    const newSelectedPlaylists = selectedPlaylists.filter(playlist => {
      return playlistIndex++ !== index
    })
    this.setState({ selectedPlaylists: newSelectedPlaylists })
  }

  onSubmit = () => {
    const { changePinnedPlaylists, onHide } = this.props
    const { selectedPlaylists } = this.state
    return changePinnedPlaylists(selectedPlaylists).then(() => onHide())
  }

  renderListItems = () => {
    const { playlistsToPin } = this.props
    const { searchText, searchedPlaylists, selectedPlaylists } = this.state
    const playlists = searchText ? searchedPlaylists : playlistsToPin
    return playlists.map(playlist => {
      return {
        label: playlist.title,
        checked: selectedPlaylists.indexOf(playlist.id) !== -1
      }
    })
  }
}

export default connect(null, {
  loadMorePlaylist: loadMorePlaylistListAsync,
  changePinnedPlaylists: changePinnedPlaylists
})(SelectPlaylistsToPinModal)
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
mongeese;

module.exports = mongeese = {
  // Our list of current connections
  connections: {},

  // Closing an existing connection
  closeConnection: function (name) {
    if (name !== undefined) {
      mongeese.connections[name].base.disconnect();
    } else { throw new Error('Connection name required.'); }
  },

  // Get all current connections
  getAllConnections: function () {
    return mongeese.connections;
  },

  // Getting an already established connection
  getConnection: function (name) {
    if (name !== undefined) {
      return mongeese.connections[name];
    } else { throw new Error('Connection name required.'); }
  },

  // Check for connection existence
  connectionExists: function (name) {
    if (name !== undefined) {
      return mongeese.connections[name] != null;
    } else { throw new Error('Connection name required.'); }
  },

  // Creating and returning a new connection
  createConnection: function (name, uri, options) {
    if (name !== undefined) {
      mongeese.connections[name] = mongoose.createConnection(uri || 'mongodb://localhost/test', options || {});
      return mongeese.connections[name];
    } else { throw new Error('Connection name required.'); }
  },

  // Remove connection from pool
  removeConnection: function (name) {
    if (name !== undefined) {
      if (delete mongeese.connections[name]) {
        return true;
      } else { return false; }
    } else { throw new Error('Connection name required.'); }
  },

  // Close all current connections
  closeAllConnections: function () {
    try {
      for (var connection in mongoose.connections) {
        mongeese.connections[connection].base.disconnect();
      }
      return true;
    } catch (err) { throw new Error('Unable to close connections: ' + err); }
  }
};
<commit_msg>Misc work -- bug fixes, new method, better return values<commit_after>'use strict';

var mongoose = require('mongoose'),
    mongeese;

function getObjectSize (obj) {
  var size = 0;

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) size++;
  }

  return size;
}

module.exports = mongeese = {
  connections: {},

  connectionExists: function (name) {
    if (name !== undefined) {
      return mongeese.connections[name] != null;
    } else { throw new Error('Connection name required.'); }
  },

  closeAllConnections: function () {
    try {
      for (var connection in mongeese.connections) {
        mongeese.connections[connection].base.disconnect();
      }
    } catch (err) { throw new Error('Unable to close connections: ' + err); }
  },

  closeConnection: function (name) {
    if (name !== undefined) {
      try {
        mongeese.connections[name].base.disconnect();
      } catch (err) { throw new Error('Unable to close connection: ' + err); }
    } else { throw new Error('Connection name required.'); }
  },

  createConnection: function (name, uri, options) {
    if (name !== undefined) {
      mongeese.connections[name] = mongoose.createConnection(uri || 'mongodb://localhost/test', options || {});
      return mongeese.connections[name];
    } else { throw new Error('Connection name required.'); }
  },

  getAllConnections: function () {
    return mongeese.connections;
  },

  getConnection: function (name) {
    if (name !== undefined) {
      return mongeese.connections[name];
    } else { throw new Error('Connection name required.'); }
  },

  getConnectionCount: function () {
    return getObjectSize(mongeese.connections);
  },

  removeAllConnections: function () {
    try {
      for (var connection in mongeese.connections) {
        delete mongeese.connections[connection];
      }
    } catch (err) { throw new Error('Unable to remove connections: ' + err); }
  },

  removeConnection: function (name) {
    if (name !== undefined) {
      return (delete mongeese.connections[name]) ? true : false;
    } else { throw new Error('Connection name required.'); }
  }
};
<|endoftext|>


<commit_before>// Import React
import React from "react";
import mapValues from "lodash/mapValues";

// Import Spectacle Core tags
import {
  Appear,
  //BlockQuote,
  //Cite,
  CodePane,
  Deck,
  //Fill,
  Heading,
  Image,
  Layout,
  Link,
  List,
  ListItem,
  //Markdown,
  //Quote,
  Slide,
  Table,
  TableRow,
  TableHeaderItem,
  TableItem
  //Text
} from "spectacle";

import Counter from './counter_01';

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");
require("./custom.css");

const slideTransition = ["slide"];
const images = mapValues({
  lifecycle: require("../images/lifecycle.png"),
  survivejs: require("../images/survivejs.png")
}, (v) => v.replace("/", ""));

preloader(images);

const theme = createTheme({
  primary: "white",
  secondary: "black",
  tertiary: "#09b5c4",
  quartenary: "rgba(255, 219, 169, 0.43)"
});

export default class Presentation extends React.Component {
  render() {
    return (
      <Deck transition={slideTransition} transitionDuration={500} theme={theme}>
        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={1} fit caps lineHeight={1} textColor="tertiary">
            React Components
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            React Philosophy
          </Heading>
          <List>
            <Appear><ListItem>Model your application as a component hierarchy</ListItem></Appear>
            <Appear><ListItem>Each component can have props and state</ListItem></Appear>
            <Appear><ListItem>Escape hatches through lifecycle methods and refs</ListItem></Appear>
            <Appear><ListItem>React forces you to think about state (good thing)</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Components
          </Heading>
          <Layout>

                <TableRow>
                  <TableHeaderItem />
                  <TableHeaderItem>createClass</TableHeaderItem>
                  <TableHeaderItem>extends Component</TableHeaderItem>
                  <TableHeaderItem>Functions</TableHeaderItem>
                </TableRow>

                <TableRow>
                  <TableItem>props</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem>context</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem>refs</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>(X)</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem>state</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem />
                </TableRow>
                <TableRow>
                  <TableItem>Lifecycle methods</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem />
                </TableRow>
                <TableRow>
                  <TableItem>Notes</TableItem>
                  <TableItem>Deprecated!</TableItem>
                  <TableItem />
                  <TableItem>Good default</TableItem>
                </TableRow>

          </Layout>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            React.Component
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Cat Counter
          </Heading>
          <Counter />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_01.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            No JSX
          </Heading>
          <CodePane
            lang="js"
            source={require("raw-loader!content!./counter_no_jsx.js")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component with <Link href="https://github.com/tc39/proposal-class-public-fields">public fields (stage 2)</Link>
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_02.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component with Function Style setState
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_03.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component with Function Style setState Extracted
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_04.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Copy the last cat counter example to <Link href="https://codesandbox.io/">CodeSandbox</Link></ListItem></Appear>
            <Appear><ListItem>Make it possible to add two cats at once</ListItem></Appear>
            <Appear><ListItem>*Add a reset button to restore the count to zero</ListItem></Appear>
            <Appear><ListItem>**Add multiple options. Hint: [1, 2, 4].map(...). Look up React <Link href="https://facebook.github.io/react/docs/reconciliation.html">key</Link>. Why is it needed?</ListItem></Appear>
            <Appear><ListItem>***Try this.setState(..., cb)</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            refs and Lifecycle Methods
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            React.Component with a Ref
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_09.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Lifecycle Methods
          </Heading>
          <Image src={images.lifecycle} margin="40px auto" height="324px" />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Implement a lifecycle method and see when it gets triggered</ListItem></Appear>
            <Appear><ListItem>*Implement App that contains multiple CatCounters</ListItem></Appear>
            <Appear><ListItem>**Push counter state management to App</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Stateless Functions
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Stateless Functions
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_01.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Stateless Functions with a Shorthand
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_02.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Stateless Functions Destructured
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_03.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
        <Heading size={4}>
          Stateless Functions Destructured and Formatted for Readability (parens!)
        </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_04.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Refactor the application into function style where possible</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Higher-Order Components
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            Why Higher-Order Components?
          </Heading>
          <List>
            <Appear><ListItem>Encapsulate a specific concern</ListItem></Appear>
            <Appear><ListItem>Examples: authenticated route, connect (pass state)</ListItem></Appear>
            <Appear><ListItem>Smaller slices to test</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Refactor state management into a stateful HOC that contains setState</ListItem></Appear>
            <Appear><ListItem>Implement Provider and connect pair to pass state through hierarchy (hint: see Redux for basic API)*</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Link href="https://www.survivejs.com/">
            <Heading size={1}>
              SurviveJS
            </Heading>
          </Link>
          <Image src={images.survivejs} margin="0px auto 40px" height="524px"/>
        </Slide>

        <Slide transition={slideTransition} bgColor="tertiary">
          <Heading size={1} caps fit textColor="primary">
            Made in Finland by
          </Heading>
          <Link href="https://twitter.com/bebraw">
            <Heading caps fit size={2} textColor="secondary">
              Juho Vepsäläinen
            </Heading>
          </Link>
        </Slide>
      </Deck>
    );
  }
}
<commit_msg>Improve wording<commit_after>// Import React
import React from "react";
import mapValues from "lodash/mapValues";

// Import Spectacle Core tags
import {
  Appear,
  //BlockQuote,
  //Cite,
  CodePane,
  Deck,
  //Fill,
  Heading,
  Image,
  Layout,
  Link,
  List,
  ListItem,
  //Markdown,
  //Quote,
  Slide,
  Table,
  TableRow,
  TableHeaderItem,
  TableItem
  //Text
} from "spectacle";

import Counter from './counter_01';

// Import image preloader util
import preloader from "spectacle/lib/utils/preloader";

// Import theme
import createTheme from "spectacle/lib/themes/default";

// Require CSS
require("normalize.css");
require("spectacle/lib/themes/default/index.css");
require("./custom.css");

const slideTransition = ["slide"];
const images = mapValues({
  lifecycle: require("../images/lifecycle.png"),
  survivejs: require("../images/survivejs.png")
}, (v) => v.replace("/", ""));

preloader(images);

const theme = createTheme({
  primary: "white",
  secondary: "black",
  tertiary: "#09b5c4",
  quartenary: "rgba(255, 219, 169, 0.43)"
});

export default class Presentation extends React.Component {
  render() {
    return (
      <Deck transition={slideTransition} transitionDuration={500} theme={theme}>
        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={1} fit caps lineHeight={1} textColor="tertiary">
            React Components
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            React Philosophy
          </Heading>
          <List>
            <Appear><ListItem>Model your application as a component hierarchy</ListItem></Appear>
            <Appear><ListItem>Each component can have props and state</ListItem></Appear>
            <Appear><ListItem>Escape hatches through lifecycle methods and refs</ListItem></Appear>
            <Appear><ListItem>React forces you to think about state (a good thing!)</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Components
          </Heading>
          <Layout>

                <TableRow>
                  <TableHeaderItem />
                  <TableHeaderItem>createClass</TableHeaderItem>
                  <TableHeaderItem>extends Component</TableHeaderItem>
                  <TableHeaderItem>Functions</TableHeaderItem>
                </TableRow>

                <TableRow>
                  <TableItem>props</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem>context</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem>refs</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>(X)</TableItem>
                </TableRow>
                <TableRow>
                  <TableItem>state</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem />
                </TableRow>
                <TableRow>
                  <TableItem>Lifecycle methods</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem>X</TableItem>
                  <TableItem />
                </TableRow>
                <TableRow>
                  <TableItem>Notes</TableItem>
                  <TableItem>Deprecated!</TableItem>
                  <TableItem />
                  <TableItem>Good default</TableItem>
                </TableRow>

          </Layout>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            React.Component
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Cat Counter
          </Heading>
          <Counter />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_01.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            No JSX
          </Heading>
          <CodePane
            lang="js"
            source={require("raw-loader!content!./counter_no_jsx.js")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component with <Link href="https://github.com/tc39/proposal-class-public-fields">public fields (stage 2)</Link>
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_02.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component with Function Style setState
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_03.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            React.Component with Function Style setState Extracted
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!content!./counter_04.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Copy the last cat counter example to <Link href="https://codesandbox.io/">CodeSandbox</Link></ListItem></Appear>
            <Appear><ListItem>Make it possible to add two cats at once</ListItem></Appear>
            <Appear><ListItem>*Add a reset button to restore the count to zero</ListItem></Appear>
            <Appear><ListItem>**Add multiple options. Hint: [1, 2, 4].map(...). Look up React <Link href="https://facebook.github.io/react/docs/reconciliation.html">key</Link>. Why is it needed?</ListItem></Appear>
            <Appear><ListItem>***Try this.setState(..., cb)</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            refs and Lifecycle Methods
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            React.Component with a Ref
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_09.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Lifecycle Methods
          </Heading>
          <Image src={images.lifecycle} margin="40px auto" height="324px" />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Implement a lifecycle method and see when it gets triggered</ListItem></Appear>
            <Appear><ListItem>*Implement App that contains multiple CatCounters</ListItem></Appear>
            <Appear><ListItem>**Push counter state management to App</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Stateless Functions
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Stateless Functions
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_01.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Stateless Functions with a Shorthand
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_02.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={4}>
            Stateless Functions Destructured
          </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_03.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
        <Heading size={4}>
          Stateless Functions Destructured and Formatted for Readability (parens!)
        </Heading>
          <CodePane
            lang="jsx"
            source={require("raw-loader!../examples/component_04.jsx")}
            margin="20px auto"
          />
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Refactor the application into function style where possible</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition} bgColor="secondary">
          <Heading size={2} textColor="tertiary">
            Higher-Order Components
          </Heading>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1} fit>
            Why Higher-Order Components?
          </Heading>
          <List>
            <Appear><ListItem>Encapsulate a specific concern</ListItem></Appear>
            <Appear><ListItem>Examples: authenticated route, connect (pass state)</ListItem></Appear>
            <Appear><ListItem>Smaller slices to test</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Heading size={1}>
            Exercises
          </Heading>
          <List>
            <Appear><ListItem>Refactor state management into a stateful HOC that contains setState</ListItem></Appear>
            <Appear><ListItem>Implement Provider and connect pair to pass state through hierarchy (hint: see Redux for basic API)*</ListItem></Appear>
          </List>
        </Slide>

        <Slide transition={slideTransition}>
          <Link href="https://www.survivejs.com/">
            <Heading size={1}>
              SurviveJS
            </Heading>
          </Link>
          <Image src={images.survivejs} margin="0px auto 40px" height="524px"/>
        </Slide>

        <Slide transition={slideTransition} bgColor="tertiary">
          <Heading size={1} caps fit textColor="primary">
            Made in Finland by
          </Heading>
          <Link href="https://twitter.com/bebraw">
            <Heading caps fit size={2} textColor="secondary">
              Juho Vepsäläinen
            </Heading>
          </Link>
        </Slide>
      </Deck>
    );
  }
}
<|endoftext|>