<commit_before>var app = app || {};

(function() {

	if (location.hash === '#tabletmode') {
		sessionStorage.tabletMode = 'true';
		location.hash = '/';
	}

	// this is the place the user codes
	var myCodeMirror;

	// this is a unique id assigned to the current page
	var pageInstanceUID;

	app.readyToRun = false;

	if (localStorage.uid) {
		app.uid = JSON.parse(localStorage.uid);
	} else {
		app.uid = Date.now().toString(36);
		localStorage.uid = JSON.stringify(app.uid);
	}

	app.initPage = function() {
		// get the hash key
		app.hash = app.getHashKey();

		// create code input area
		app.initCodeMirror();

		// calculate editor layout
		refreshEditorLayout();

		app.diffEngine = window.diffEngine();
		app.diffEncoder = app.diffEngine.getEncoder();
		app.diffDecoder = app.diffEngine.getDecoder();

		// run the code
		app.run();

		// ensure CodeMirror code gets properly rendered
		requestAnimationFrame(function(){
			myCodeMirror.refresh();
		});

		// we're assuming they won't visit the same page twice within one second
		pageInstanceUID = Math.floor(Date.now()/1000);
		app.fb = new Firebase('https://benjaffe.firebaseio.com/android-layout/users/' + app.uid + '/' + app.hash + '/' + pageInstanceUID);

	};

	app.getHashKey = function() {
		var hash = location.hash;
		if (hash.length > 2 && hash.substr(0,2) === '#/') {
			return hash.slice(2);
		} else {
			return '';
		}
	};

	app.initCodeMirror = function(){
		// clear pre-existing code areas
		$('.input-area').html('');

		myCodeMirror = CodeMirror(document.querySelector('.input-area'), {
			value: app.getCodeForHash(),
			mode: "android-xml",
			lineNumbers: true,
	        lineWrapping: true,
			indentUnit: 4,
			fixedGutter: true,
			viewportMargin: Infinity,
			onChange: function() {
				app.run({ autorun: true });
			}
		});
	};

	app.getCodeForHash = function() {
		// this is for testing code (#/test/...)
		if (app.hash.slice(0,4) === 'test') {
			$.get('tests/android/' + app.hash.slice(12) + '.xml', function(data){
				myCodeMirror.setValue(data);
				myCodeMirror.refresh();
				app.run({
					code: data,
					force: true
				});
			}, 'text');
			$('.test-reference-image').attr('src', 'tests/android/' + app.hash.slice(12) + '.png');
			return '';
		}

		// we have a previously-saved version
		if (localStorage['code-' + app.hash]) {
			return JSON.parse( localStorage['code-' + app.hash] );
		}

		// return the default (if there is one)
		else {
			return app.getCodeForHashDefault();
		}

		return '';
	};

	app.getCodeForHashDefault = function() {
		if (app.androidCodeDefaults) {
			if (app.androidCodeDefaults[ app.hash ]) {
				return app.androidCodeDefaults[ app.hash ];
			} else {
				return app.androidCodeDefaults[ 'default' ];
			}
		}

		return '';
	};

	app.resetCodeToHashDefault = function() {
		myCodeMirror.setValue(app.getCodeForHashDefault());
		myCodeMirror.refresh();
	};

	// this runs after code is successfully evaluated
	function runSuccess(code) {
		if (!localStorage.debug) {
			clearTimeout(app.codeEvaluationTimeout);
		}

		// save current student code
		if (app.hash.slice(0,4) !== 'test') {
			localStorage['code-' + app.hash] = JSON.stringify(code);
		}

		$('html').removeClass('invalid-code evaluating-invalid-code');
		requestAnimationFrame(function(){
			$('html').addClass('valid-code');
		});

		$('.code-saved-msg').removeClass('code-not-saved');

	}

	// this runs if the code is considered invalid or unevaluatable
	function runFail (opt) {
		var code = opt.code;
		clearTimeout(app.codeEvaluationTimeout);
		$('html').removeClass('invalid-code').addClass('evaluating-invalid-code');

		app.codeEvaluationTimeout = setTimeout(function(){
			console.log('TIMEOUT');
	 		$('html').removeClass('evaluating-invalid-code').addClass('invalid-code');
		},2000);

		if (opt.errors) {
			opt.errors.forEach(function(errorID){
				// add any errors to the error stack
				app.errors.push({
					id: errorID
				});
			});
		}

		if (!localStorage.debug) {
			$('.code-saved-msg').addClass('code-not-saved');
		} else {
			console.log('failed, but saving anyway since we\'re in debug mode');
			runSuccess(code);
		}
	}

	function updateState (newState) {
		var state = app.state || {};

		// copy over any new parameters from the previous state
		for(key in newState) {
			state[key] = newState[key];
		}

		var diff = app.diffEncoder.push(state);
		app.state = state;
		// console.log(app.diffDecoder.getState().state);
		// console.log('pushing', diff);
		app.fb.child('diffs').push(diff);
	}

	// this function evaluates code based on the mode the app is in
	app.run = function (opt) {
		opt = opt || {};

		if (!app.readyToRun && !opt.force) return false;

		var codeRaw = opt.code || myCodeMirror.getValue();
		var code;
		var elemToRender;

		updateState({
			code: codeRaw
		});

		// run the code
		var mode = 'android-layout';
		if (mode === 'android-layout') {

			if (app.hash.slice(0,4) === 'test') {
				$('html').addClass('testing-mode');
				if (app.hash === 'test/android' || app.hash === 'test/android/') {
					forwardFillTestingHistory('#/test/android/', app.tests);
				}
			} else {
				$('html').removeClass('testing-mode');
			}

			// pre-processing hook
			code = app.androidLayout.prepareCodeForParsing( codeRaw );

			// catch easy-to-detect errors (like misaligned <>'s, quotes)
			app.androidLayout.xmlSanityCheck( codeRaw );

			// if we don't have code to render, exit early rather than throwing an error
			if (codeRaw === '') {
				return false;
			}

			// parse the XML
			try {
				app.parsedXML = jQuery.parseXML( code );
			} catch (e) {
				app.parsedXML = null;
			}

			if (app.parsedXML !== null) {
				// basic parsing and styling
				elemToRender = app.androidLayout.evaluateXML(app.parsedXML);

				// calculate all the layouts
				console.debug('-------- layout pass at ' + Math.round(Date.now()/1000) + ' --------');
				app.androidLayout.evaluateXMLPass2( app.parsedXML );
				if (app.errors().length > 0) {
					runFail({
						code: codeRaw
					});
				} else {
					console.debug('woot!');
					runSuccess(codeRaw);
				}
			} else {

				runFail({
					code: codeRaw,
					errors: ['parseError']
				});

				$('html').removeClass('valid-code invalid-code')

			}
		}

		if (elemToRender) {
			$('.screen').html('').append(elemToRender);
		}

		renderErrors();

		renderHistoryLinkState();
		refreshEditorLayout();
	};

	function forwardFillTestingHistory (prefix, urls, startAtBeginning) {

		// add each test to the history
		urls.forEach(function(url){
			history.pushState({}, '', prefix + url);
		});

		// go to the first one
		if (startAtBeginning) {
			history.go((app.tests.length-1) * -1);
		}
	}

	// show the error list in the document
	function renderErrors () {
		var errors = app.errors();
		var errorStrArr = errors.map(function(error){ return error.value; });
		if (errors.length > 0) {
			$('.error-msg').show().html(errorStrArr.join('
'));
			errors.forEach(function(error){
				if (error.line) {
					$('.CodeMirror-lines > div > div:last-child > pre:nth-child('+error.line+')').addClass('highlighted-code');
				}
			});
		} else {
			$('.error-msg').hide();
			$('.highlighted-code').removeClass('highlighted-code');
			console.debug('No errors!');
		}
	}

	// undo/redo history state UI
	function renderHistoryLinkState () {
		console.debug(myCodeMirror.historySize());
		if (myCodeMirror.historySize().undo > 0) {
			$('.btn-undo').attr('disabled', false);
		} else {
			$('.btn-undo').attr('disabled', true);
		}
		if (myCodeMirror.historySize().redo > 0) {
			$('.btn-redo').attr('disabled', false);
		} else {
			$('.btn-redo').attr('disabled', true);
		}
	}

	// recalculate and resize the editor to the proper height
	function refreshEditorLayout () {
		var currentHeight = $('.CodeMirror').height();
		var containerHeight = $('.input-area-wrapper').outerHeight(true);
		var windowHeight = $(window).height();
		var wiggleRoom = 10;

		$('.CodeMirror-scroll').css('height', windowHeight - (containerHeight - currentHeight) - wiggleRoom);
		myCodeMirror.refresh();
	}

	$(window).bind('hashchange', function(e) {
		app.initPage();
	});

	// recalculate editor layout on resize
	$(window).resize(function(){
		refreshEditorLayout();
	});

	// auto-run on code mutation
	$('.code-input-area').on('input', function(){
	  app.run({ autorun: true });
	}, false);

	// manually run on Cmd-Enter / Ctrl-Enter
	$(document).on('keydown', '.code-input-area', function(e) {
	  if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
	    app.run();
	  }
	});

	// manually run when run btn is clicked
	$('.btn-run').on('click', function(){
	  app.run();
	}, false);

	// toggle checkbox states
	$('#toggle-element-outline').change(function(e){
		app.elementOutlinesEnabled = e.target.checked;
		app.run();
	});

	// reset code button
	$('.btn-reset-code').click(function(e) {
		if (!confirm('Press OK to reset your code to the default for this example.\n\nNote: This will overwrite your current code, but pressing Cmd/Ctrl Z will undo this change.')) {
			return false;
		}
		app.resetCodeToHashDefault();
	});

	// undo/redo
	$('.btn-undo').click(function(e) {
		myCodeMirror.undo();
		renderHistoryLinkState();
	});

	$('.btn-redo').click(function(e) {
		myCodeMirror.redo();
		renderHistoryLinkState();
	});

	// hooks for debugging
	if (localStorage.debug) {
		window.myCodeMirror = myCodeMirror;
	}

	// hooks for tablet mode
	if (sessionStorage.tabletMode === 'true') {
		$('#input-topbar').hide().parent().css('padding-top', '12px');
		$('.input-area').css('font-size', '120%');
		$('html').addClass('tablet-mode');
	}

	$('.input-area').mousemove(function(e){ updateMousePosition(e) });

	// report-an-issue modal event listener
	$('#issue-dialog').on('shown.bs.modal', function(e){
		// grab the code from our codeMirror instance
		$('#entry_440939498').val( myCodeMirror.getValue() );

		// grab the user's uid and path
		$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
	});

	$('#hidden_iframe').on('load', function(e){
		if (submitted) {
			$('#issue-dialog').modal('hide');
			$('#issue-submitted-dialog').modal('show');

			// clear everything
			$('#issue-dialog textarea').val('');
			$('#entry_1934743275').val('');
			$('#issue-dialog [type=radio]').prop('checked', false);

			// grab the user's uid and path
			$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
			submitted = false;
		}
	});

	var timeOfLastUpdate;
	var updateDebounceThreshold = 200;
	var lastDebouncedState = null;
	var finalStateUpdateTimeout;

	var updateMousePosition = function(e) {
		var mouse = [e.offsetX, e.offsetY];
		var state = lastDebouncedState || {};

		// I'm setting a floor of threshold/4 to give the actual state update
		// a chance to happen. Otherwise, it'd updateDebouncedState exactly on
		// time, not giving normal state updates a chance to happen (and therefore
		// resulting in stale data).
		var timeToUpdateWithFinalState = Math.max(updateDebounceThreshold / 4, updateDebounceThreshold - (Date.now() - timeOfLastUpdate));

		state.mouse = mouse;

		clearTimeout(finalStateUpdateTimeout);

		if (timeOfLastUpdate && (Date.now() - timeOfLastUpdate < updateDebounceThreshold)) {
			lastDebouncedState = state;
			finalStateUpdateTimeout = setTimeout(updateDebouncedState, timeToUpdateWithFinalState);
			return false;
		}

		timeOfLastUpdate = Date.now();
		lastDebouncedState = null;
		updateState(state);
	};

	function updateDebouncedState () {
		timeOfLastUpdate = Date.now();
		updateState(lastDebouncedState);
	}

	app.androidInit();

	app.initPage();

})();

<commit_msg>use udacity firebase<commit_after>var app = app || {};

(function() {

	if (location.hash === '#tabletmode') {
		sessionStorage.tabletMode = 'true';
		location.hash = '/';
	}

	// this is the place the user codes
	var myCodeMirror;

	// this is a unique id assigned to the current page
	var pageInstanceUID;

	app.readyToRun = false;

	if (localStorage.uid) {
		app.uid = JSON.parse(localStorage.uid);
	} else {
		app.uid = Date.now().toString(36);
		localStorage.uid = JSON.stringify(app.uid);
	}

	app.initPage = function() {
		// get the hash key
		app.hash = app.getHashKey();

		// create code input area
		app.initCodeMirror();

		// calculate editor layout
		refreshEditorLayout();

		app.diffEngine = window.diffEngine();
		app.diffEncoder = app.diffEngine.getEncoder();
		app.diffDecoder = app.diffEngine.getDecoder();

		// run the code
		app.run();

		// ensure CodeMirror code gets properly rendered
		requestAnimationFrame(function(){
			myCodeMirror.refresh();
		});

		// we're assuming they won't visit the same page twice within one second
		pageInstanceUID = Math.floor(Date.now()/1000);
		app.fb = new Firebase('https://udacity.firebaseio.com/android-layout/users/' + app.uid + '/' + app.hash + '/' + pageInstanceUID);

	};

	app.getHashKey = function() {
		var hash = location.hash;
		if (hash.length > 2 && hash.substr(0,2) === '#/') {
			return hash.slice(2);
		} else {
			return '';
		}
	};

	app.initCodeMirror = function(){
		// clear pre-existing code areas
		$('.input-area').html('');

		myCodeMirror = CodeMirror(document.querySelector('.input-area'), {
			value: app.getCodeForHash(),
			mode: "android-xml",
			lineNumbers: true,
	        lineWrapping: true,
			indentUnit: 4,
			fixedGutter: true,
			viewportMargin: Infinity,
			onChange: function() {
				app.run({ autorun: true });
			}
		});
	};

	app.getCodeForHash = function() {
		// this is for testing code (#/test/...)
		if (app.hash.slice(0,4) === 'test') {
			$.get('tests/android/' + app.hash.slice(12) + '.xml', function(data){
				myCodeMirror.setValue(data);
				myCodeMirror.refresh();
				app.run({
					code: data,
					force: true
				});
			}, 'text');
			$('.test-reference-image').attr('src', 'tests/android/' + app.hash.slice(12) + '.png');
			return '';
		}

		// we have a previously-saved version
		if (localStorage['code-' + app.hash]) {
			return JSON.parse( localStorage['code-' + app.hash] );
		}

		// return the default (if there is one)
		else {
			return app.getCodeForHashDefault();
		}

		return '';
	};

	app.getCodeForHashDefault = function() {
		if (app.androidCodeDefaults) {
			if (app.androidCodeDefaults[ app.hash ]) {
				return app.androidCodeDefaults[ app.hash ];
			} else {
				return app.androidCodeDefaults[ 'default' ];
			}
		}

		return '';
	};

	app.resetCodeToHashDefault = function() {
		myCodeMirror.setValue(app.getCodeForHashDefault());
		myCodeMirror.refresh();
	};

	// this runs after code is successfully evaluated
	function runSuccess(code) {
		if (!localStorage.debug) {
			clearTimeout(app.codeEvaluationTimeout);
		}

		// save current student code
		if (app.hash.slice(0,4) !== 'test') {
			localStorage['code-' + app.hash] = JSON.stringify(code);
		}

		$('html').removeClass('invalid-code evaluating-invalid-code');
		requestAnimationFrame(function(){
			$('html').addClass('valid-code');
		});

		$('.code-saved-msg').removeClass('code-not-saved');

	}

	// this runs if the code is considered invalid or unevaluatable
	function runFail (opt) {
		var code = opt.code;
		clearTimeout(app.codeEvaluationTimeout);
		$('html').removeClass('invalid-code').addClass('evaluating-invalid-code');

		app.codeEvaluationTimeout = setTimeout(function(){
			console.log('TIMEOUT');
	 		$('html').removeClass('evaluating-invalid-code').addClass('invalid-code');
		},2000);

		if (opt.errors) {
			opt.errors.forEach(function(errorID){
				// add any errors to the error stack
				app.errors.push({
					id: errorID
				});
			});
		}

		if (!localStorage.debug) {
			$('.code-saved-msg').addClass('code-not-saved');
		} else {
			console.log('failed, but saving anyway since we\'re in debug mode');
			runSuccess(code);
		}
	}

	function updateState (newState) {
		var state = app.state || {};

		// copy over any new parameters from the previous state
		for(key in newState) {
			state[key] = newState[key];
		}

		var diff = app.diffEncoder.push(state);
		app.state = state;
		// console.log(app.diffDecoder.getState().state);
		// console.log('pushing', diff);
		app.fb.child('diffs').push(diff);
	}

	// this function evaluates code based on the mode the app is in
	app.run = function (opt) {
		opt = opt || {};

		if (!app.readyToRun && !opt.force) return false;

		var codeRaw = opt.code || myCodeMirror.getValue();
		var code;
		var elemToRender;

		updateState({
			code: codeRaw
		});

		// run the code
		var mode = 'android-layout';
		if (mode === 'android-layout') {

			if (app.hash.slice(0,4) === 'test') {
				$('html').addClass('testing-mode');
				if (app.hash === 'test/android' || app.hash === 'test/android/') {
					forwardFillTestingHistory('#/test/android/', app.tests);
				}
			} else {
				$('html').removeClass('testing-mode');
			}

			// pre-processing hook
			code = app.androidLayout.prepareCodeForParsing( codeRaw );

			// catch easy-to-detect errors (like misaligned <>'s, quotes)
			app.androidLayout.xmlSanityCheck( codeRaw );

			// if we don't have code to render, exit early rather than throwing an error
			if (codeRaw === '') {
				return false;
			}

			// parse the XML
			try {
				app.parsedXML = jQuery.parseXML( code );
			} catch (e) {
				app.parsedXML = null;
			}

			if (app.parsedXML !== null) {
				// basic parsing and styling
				elemToRender = app.androidLayout.evaluateXML(app.parsedXML);

				// calculate all the layouts
				console.debug('-------- layout pass at ' + Math.round(Date.now()/1000) + ' --------');
				app.androidLayout.evaluateXMLPass2( app.parsedXML );
				if (app.errors().length > 0) {
					runFail({
						code: codeRaw
					});
				} else {
					console.debug('woot!');
					runSuccess(codeRaw);
				}
			} else {

				runFail({
					code: codeRaw,
					errors: ['parseError']
				});

				$('html').removeClass('valid-code invalid-code')

			}
		}

		if (elemToRender) {
			$('.screen').html('').append(elemToRender);
		}

		renderErrors();

		renderHistoryLinkState();
		refreshEditorLayout();
	};

	function forwardFillTestingHistory (prefix, urls, startAtBeginning) {

		// add each test to the history
		urls.forEach(function(url){
			history.pushState({}, '', prefix + url);
		});

		// go to the first one
		if (startAtBeginning) {
			history.go((app.tests.length-1) * -1);
		}
	}

	// show the error list in the document
	function renderErrors () {
		var errors = app.errors();
		var errorStrArr = errors.map(function(error){ return error.value; });
		if (errors.length > 0) {
			$('.error-msg').show().html(errorStrArr.join('
'));
			errors.forEach(function(error){
				if (error.line) {
					$('.CodeMirror-lines > div > div:last-child > pre:nth-child('+error.line+')').addClass('highlighted-code');
				}
			});
		} else {
			$('.error-msg').hide();
			$('.highlighted-code').removeClass('highlighted-code');
			console.debug('No errors!');
		}
	}

	// undo/redo history state UI
	function renderHistoryLinkState () {
		console.debug(myCodeMirror.historySize());
		if (myCodeMirror.historySize().undo > 0) {
			$('.btn-undo').attr('disabled', false);
		} else {
			$('.btn-undo').attr('disabled', true);
		}
		if (myCodeMirror.historySize().redo > 0) {
			$('.btn-redo').attr('disabled', false);
		} else {
			$('.btn-redo').attr('disabled', true);
		}
	}

	// recalculate and resize the editor to the proper height
	function refreshEditorLayout () {
		var currentHeight = $('.CodeMirror').height();
		var containerHeight = $('.input-area-wrapper').outerHeight(true);
		var windowHeight = $(window).height();
		var wiggleRoom = 10;

		$('.CodeMirror-scroll').css('height', windowHeight - (containerHeight - currentHeight) - wiggleRoom);
		myCodeMirror.refresh();
	}

	$(window).bind('hashchange', function(e) {
		app.initPage();
	});

	// recalculate editor layout on resize
	$(window).resize(function(){
		refreshEditorLayout();
	});

	// auto-run on code mutation
	$('.code-input-area').on('input', function(){
	  app.run({ autorun: true });
	}, false);

	// manually run on Cmd-Enter / Ctrl-Enter
	$(document).on('keydown', '.code-input-area', function(e) {
	  if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
	    app.run();
	  }
	});

	// manually run when run btn is clicked
	$('.btn-run').on('click', function(){
	  app.run();
	}, false);

	// toggle checkbox states
	$('#toggle-element-outline').change(function(e){
		app.elementOutlinesEnabled = e.target.checked;
		app.run();
	});

	// reset code button
	$('.btn-reset-code').click(function(e) {
		if (!confirm('Press OK to reset your code to the default for this example.\n\nNote: This will overwrite your current code, but pressing Cmd/Ctrl Z will undo this change.')) {
			return false;
		}
		app.resetCodeToHashDefault();
	});

	// undo/redo
	$('.btn-undo').click(function(e) {
		myCodeMirror.undo();
		renderHistoryLinkState();
	});

	$('.btn-redo').click(function(e) {
		myCodeMirror.redo();
		renderHistoryLinkState();
	});

	// hooks for debugging
	if (localStorage.debug) {
		window.myCodeMirror = myCodeMirror;
	}

	// hooks for tablet mode
	if (sessionStorage.tabletMode === 'true') {
		$('#input-topbar').hide().parent().css('padding-top', '12px');
		$('.input-area').css('font-size', '120%');
		$('html').addClass('tablet-mode');
	}

	$('.input-area').mousemove(function(e){ updateMousePosition(e) });

	// report-an-issue modal event listener
	$('#issue-dialog').on('shown.bs.modal', function(e){
		// grab the code from our codeMirror instance
		$('#entry_440939498').val( myCodeMirror.getValue() );

		// grab the user's uid and path
		$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
	});

	$('#hidden_iframe').on('load', function(e){
		if (submitted) {
			$('#issue-dialog').modal('hide');
			$('#issue-submitted-dialog').modal('show');

			// clear everything
			$('#issue-dialog textarea').val('');
			$('#entry_1934743275').val('');
			$('#issue-dialog [type=radio]').prop('checked', false);

			// grab the user's uid and path
			$('#entry_1934743275').val( JSON.parse(localStorage.uid) + '/' + app.hash + '/' + pageInstanceUID );
			submitted = false;
		}
	});

	var timeOfLastUpdate;
	var updateDebounceThreshold = 200;
	var lastDebouncedState = null;
	var finalStateUpdateTimeout;

	var updateMousePosition = function(e) {
		var mouse = [e.offsetX, e.offsetY];
		var state = lastDebouncedState || {};

		// I'm setting a floor of threshold/4 to give the actual state update
		// a chance to happen. Otherwise, it'd updateDebouncedState exactly on
		// time, not giving normal state updates a chance to happen (and therefore
		// resulting in stale data).
		var timeToUpdateWithFinalState = Math.max(updateDebounceThreshold / 4, updateDebounceThreshold - (Date.now() - timeOfLastUpdate));

		state.mouse = mouse;

		clearTimeout(finalStateUpdateTimeout);

		if (timeOfLastUpdate && (Date.now() - timeOfLastUpdate < updateDebounceThreshold)) {
			lastDebouncedState = state;
			finalStateUpdateTimeout = setTimeout(updateDebouncedState, timeToUpdateWithFinalState);
			return false;
		}

		timeOfLastUpdate = Date.now();
		lastDebouncedState = null;
		updateState(state);
	};

	function updateDebouncedState () {
		timeOfLastUpdate = Date.now();
		updateState(lastDebouncedState);
	}

	app.androidInit();

	app.initPage();

})();

<|endoftext|>


<commit_before>/*
 * e-additives.web
 * Copyright (C) 2013 VEXELON.NET Services
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

"use strict"; // jshint ;_;

require.config({
    //By default load any module IDs from js
    baseUrl: 'js',
    //To get timely, correct error triggers in IE, force a define/shim exports check.
    //enforceDefine: true,
    paths: {
        vendor: 'vendor',
        plugin: 'vendor/plugins',
        // libs
        jquery: ["vendor/jquery-1.10.1.min"], //"//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min",
        bootstrap: 'vendor/bootstrap.min',
        sammy: 'vendor/sammy-0.7.4.min',
        underscore: 'vendor/underscore-min',
        moment: 'vendor/moment_langs.min',
        mustache: 'vendor/mustache',
        footable: 'vendor/footable',
        // plugins
        typeahead: 'vendor/plugins/typeahead.min',
        ftpaginate: 'vendor/plugins/footable.paginate',
        ftfilter: 'vendor/plugins/footable.filter',
        ftsort: 'vendor/plugins/footable.sort',
        fttemplate: 'vendor/plugins/footable.plugin.template',
        i18n: 'vendor/plugins/i18n'
    },
    shim: {
        'bootstrap': ['jquery', 'typeahead', 'footable', 'ftpaginate', 'ftfilter', 'ftsort', 'fttemplate', 'moment'],
        'underscore': {
            exports: '_'
        },
        'jquery': {
            exports: '$'
        },
        'moment': {
            exports: 'moment'
        },
        'sammy': ['jquery'],
        'typeahead': ['jquery'],
        'footable': ['jquery'],
        'ftpaginate': ['footable'],
        'ftfilter': ['footable'],
        'ftsort': ['footable'],
        'fttemplate': ['footable'],
    },
    waitSeconds: 10,
    urlArgs: "bust=" + _Globals.buildnumber,
    config: {
        //Set the config for the i18n module ID
        i18n: {
            locale: _Globals.locale
        }
    }
});

require(['sammy', 'config', 'api', 'bindings', 'breadcrumbs', 'mustache', 'i18n!nls/locale', 'bootstrap',
    'plugin/sammy.mustache', 'i18n', 'plugin/domReady!'],
    function(Sammy, Config, API, Bindings, Breadcrumbs, Mustache, Locale) {

    var shortLocale = null;

    /**
     * Set datetime locale
     */
    if (_Globals.locale) {
        shortLocale = _Globals.locale.substring(0, 2).toLowerCase();
        moment.lang(shortLocale);
    }

    /**
     * Load navbar & footer
     */
    $.get('partials/navbar.ms', function(data) {
        var html = Mustache.render(data, {locale: Locale});
        $('div[role="navbar"]').html(html);
    });
    $.get('partials/footer.ms', function(data) {
        var html = Mustache.render(data, {locale: Locale});
        $('#footer').html(html);
        $('#build').html('Build: ' + _Globals.buildnumber);
    });

    var breadcrumbs = new Breadcrumbs();

    /**
     * Init client API
     */
    API.initialize(Config.serverUrl, Config.serverKey);
    if (shortLocale) {
        API.setLocale(shortLocale);
    }

    /**
     * App routes and functionality
     */
    var app = Sammy('div[role="pane"]', function() {
        this.use(Sammy.Mustache, 'ms');

        // disable Sammy template caching while in 'dev' mode
        if (Config.isDevMode) {
            this.templateCache = function() {};
        }

        var load_anim = '

';
        var searchTemplateCode = Mustache.compile('
{{code}} {{name}}
');
        var searchTemplateName = Mustache.compile('
{{name}} {{code}}
');

        // default
        this.get('#/', function() {
            this.redirect('#home');
        });
        // Main/Search page
        this.get('#home', function() {
            var self = this;
            self.swap(load_anim);

            breadcrumbs.clear();

            this.partial('partials/home.ms', {locale: Locale}, function() {
                API.getAdditives(function(err, data) {
                    if (err) {
                        console.log(err);
                        return;
                    }
                    $('.typeahead').typeahead([
                        {
                            name: 'additives-codes',
                            valueKey: 'code',
                            limit: 7,
                            local: data,
                            template: searchTemplateCode,
                            engine: Mustache,
                        },
                        {
                            name: 'additives-names',
                            valueKey: 'name',
                            limit: 7,
                            local: data,
                            template: searchTemplateName,
                            engine: Mustache,
                        }
                    ]);
                }); //eof-API
            }); //eof-this.partial
        });
        // Additives browse page
        this.get('#additives', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getAdditives(function(err, data) {
                if (err) {
                    console.log(err);
                    return;
                }
                breadcrumbs.clear().add('home').add('additives').render(self, context, function() {
                    context.data = formatAdditivesData(data);
                    context.locale = Locale;
                    context.partial('partials/additives.ms', function() {
                        $('table').footable();
                    });
                });
            });
        });
        // Search additives
        this.get('#additives/search/:query', function(context) {
            var self = this;
            self.swap(load_anim);

            API.searchAdditives(this.params['query'], function(err, data) {
                if (err) {
                    console.log(err);
                    return;
                }
                breadcrumbs.clear().add('home').add('additives').render(self, context, function() {
                    context.data = formatAdditivesData(data);
                    context.locale = Locale;
                    context.partial('partials/additives.ms');
                });
            });
        });
        // Show single additive
        this.get('#additives/:code', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getAdditive(this.params['code'], function(err, data) {
                if (err) {
                    console.log(err);
                    $(document).trigger('alert', [Locale.additives.msg_notfound]);
                    self.redirect('#additives');
                    return;
                }
                breadcrumbs.clear().add('home').add('additives').add(data.code).render(self, context, function() {
                    context.data = formatAdditivesData(data);
                    context.locale = Locale;
                    context.partial('partials/single-additive.ms');
                });
            });
        });
        // // Compare 2 additives
        // this.get('#additives/compare/:first/:second', function() {
        //     var self = this;
        //     self.swap(load_anim);

        //     // fetch first
        //     API.getAdditive(self.params['first'], function(err, dataFirst) {
        //         if (err) {
        //             console.log(err);
        //             return;
        //         }
        //         // fetch second
        //         API.getAdditive(self.params['second'], function(err, dataSecond) {
        //             if (err) {
        //                 console.log(err);
        //                 return;
        //             }

        //             self.partial('partials/compare-two.ms', {first: dataFirst, second: dataSecond});
        //         });
        //     });
        // });
        // Categories page
        this.get('#categories', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getCategories(function(err, data) {
                if (err) {
                    console.log(err);
                    return;
                }
                breadcrumbs.clear().add('home').add('categories').render(self, context, function() {
                    context.data = data;
                    context.locale = Locale;
                    context.partial('partials/categories.ms');
                });
            });
        });
        // Show single cateogry
        this.get('#categories/:id', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getCategory(this.params['id'], function(err, data) {
                if (err) {
                    console.log(err);
                    $(document).trigger('alert', [Locale.categories.msg_notfound]);
                    self.redirect('#categories');
                    return;
                }
                breadcrumbs.clear().add('home').add('categories').add(data.name).render(self, context, function() {
                    context.data = data;
                    context.locale = Locale;
                    context.partial('partials/single-category.ms');
                });
            });
        });
        // F.A.Q. page
        this.get('#faq', function(context) {
            var self = this;
            self.swap(load_anim);
            breadcrumbs.clear().add('home').add('F.A.Q.').render(self, context, function() {
                context.locale = Locale;
                context.partial('partials/faq.ms');
            });
        });
        // Legal: Privacy page
        this.get('#legal/privacy', function() {
            var self = this;
            self.swap(load_anim);
            self.partial('partials/privacy.ms');
        });
        // Legal: Terms of use page
        this.get('#legal/terms', function() {
            var self = this;
            self.swap(load_anim);
            self.partial('partials/terms.ms');
        });
        // HTTP 404
        // this.notFound = function(verb, path) {
        //     window.location = '404.html';
        // }
    });
    // start the application
    app.run('#/');
    app.clearTemplateCache();

    /**
     * Bind app events
     */
    Bindings.bindAll(app);

    /**
     * Others
     */
    function formatAdditivesData(data) {
        function _fmt(additive) {
            additive.last_update = moment(additive.last_update).format('LLL');
            return additive;
        }

        if (Object.prototype.toString.call(data) == '[object Array]') {
            var result = [];
            _.each(data, function(item) {
                result.push(_fmt(item));
            });
            return result;
        }

        return _fmt(data);
    }
});
<commit_msg>Fix: Date now show correctly in categories page.<commit_after>/*
 * e-additives.web
 * Copyright (C) 2013 VEXELON.NET Services
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

"use strict"; // jshint ;_;

require.config({
    //By default load any module IDs from js
    baseUrl: 'js',
    //To get timely, correct error triggers in IE, force a define/shim exports check.
    //enforceDefine: true,
    paths: {
        vendor: 'vendor',
        plugin: 'vendor/plugins',
        // libs
        jquery: ["vendor/jquery-1.10.1.min"], //"//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min",
        bootstrap: 'vendor/bootstrap.min',
        sammy: 'vendor/sammy-0.7.4.min',
        underscore: 'vendor/underscore-min',
        moment: 'vendor/moment_langs.min',
        mustache: 'vendor/mustache',
        footable: 'vendor/footable',
        // plugins
        typeahead: 'vendor/plugins/typeahead.min',
        ftpaginate: 'vendor/plugins/footable.paginate',
        ftfilter: 'vendor/plugins/footable.filter',
        ftsort: 'vendor/plugins/footable.sort',
        fttemplate: 'vendor/plugins/footable.plugin.template',
        i18n: 'vendor/plugins/i18n'
    },
    shim: {
        'bootstrap': ['jquery', 'typeahead', 'footable', 'ftpaginate', 'ftfilter', 'ftsort', 'fttemplate', 'moment'],
        'underscore': {
            exports: '_'
        },
        'jquery': {
            exports: '$'
        },
        'moment': {
            exports: 'moment'
        },
        'sammy': ['jquery'],
        'typeahead': ['jquery'],
        'footable': ['jquery'],
        'ftpaginate': ['footable'],
        'ftfilter': ['footable'],
        'ftsort': ['footable'],
        'fttemplate': ['footable'],
    },
    waitSeconds: 10,
    urlArgs: "bust=" + _Globals.buildnumber,
    config: {
        //Set the config for the i18n module ID
        i18n: {
            locale: _Globals.locale
        }
    }
});

require(['sammy', 'config', 'api', 'bindings', 'breadcrumbs', 'mustache', 'i18n!nls/locale', 'bootstrap',
    'plugin/sammy.mustache', 'i18n', 'plugin/domReady!'],
    function(Sammy, Config, API, Bindings, Breadcrumbs, Mustache, Locale) {

    var shortLocale = null;

    /**
     * Set datetime locale
     */
    if (_Globals.locale) {
        shortLocale = _Globals.locale.substring(0, 2).toLowerCase();
        moment.lang(shortLocale);
    }

    /**
     * Load navbar & footer
     */
    $.get('partials/navbar.ms', function(data) {
        var html = Mustache.render(data, {locale: Locale});
        $('div[role="navbar"]').html(html);
    });
    $.get('partials/footer.ms', function(data) {
        var html = Mustache.render(data, {locale: Locale});
        $('#footer').html(html);
        $('#build').html('Build: ' + _Globals.buildnumber);
    });

    var breadcrumbs = new Breadcrumbs();

    /**
     * Init client API
     */
    API.initialize(Config.serverUrl, Config.serverKey);
    if (shortLocale) {
        API.setLocale(shortLocale);
    }

    /**
     * App routes and functionality
     */
    var app = Sammy('div[role="pane"]', function() {
        this.use(Sammy.Mustache, 'ms');

        // disable Sammy template caching while in 'dev' mode
        if (Config.isDevMode) {
            this.templateCache = function() {};
        }

        var load_anim = '

';
        var searchTemplateCode = Mustache.compile('
{{code}} {{name}}
');
        var searchTemplateName = Mustache.compile('
{{name}} {{code}}
');

        // default
        this.get('#/', function() {
            this.redirect('#home');
        });
        // Main/Search page
        this.get('#home', function() {
            var self = this;
            self.swap(load_anim);

            breadcrumbs.clear();

            this.partial('partials/home.ms', {locale: Locale}, function() {
                API.getAdditives(function(err, data) {
                    if (err) {
                        console.log(err);
                        return;
                    }
                    $('.typeahead').typeahead([
                        {
                            name: 'additives-codes',
                            valueKey: 'code',
                            limit: 7,
                            local: data,
                            template: searchTemplateCode,
                            engine: Mustache,
                        },
                        {
                            name: 'additives-names',
                            valueKey: 'name',
                            limit: 7,
                            local: data,
                            template: searchTemplateName,
                            engine: Mustache,
                        }
                    ]);
                }); //eof-API
            }); //eof-this.partial
        });
        // Additives browse page
        this.get('#additives', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getAdditives(function(err, data) {
                if (err) {
                    console.log(err);
                    return;
                }
                breadcrumbs.clear().add('home').add('additives').render(self, context, function() {
                    context.data = formatAdditivesData(data);
                    context.locale = Locale;
                    context.partial('partials/additives.ms', function() {
                        $('table').footable();
                    });
                });
            });
        });
        // Search additives
        this.get('#additives/search/:query', function(context) {
            var self = this;
            self.swap(load_anim);

            API.searchAdditives(this.params['query'], function(err, data) {
                if (err) {
                    console.log(err);
                    return;
                }
                breadcrumbs.clear().add('home').add('additives').render(self, context, function() {
                    context.data = formatAdditivesData(data);
                    context.locale = Locale;
                    context.partial('partials/additives.ms');
                });
            });
        });
        // Show single additive
        this.get('#additives/:code', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getAdditive(this.params['code'], function(err, data) {
                if (err) {
                    console.log(err);
                    $(document).trigger('alert', [Locale.additives.msg_notfound]);
                    self.redirect('#additives');
                    return;
                }
                breadcrumbs.clear().add('home').add('additives').add(data.code).render(self, context, function() {
                    context.data = formatAdditivesData(data);
                    context.locale = Locale;
                    context.partial('partials/single-additive.ms');
                });
            });
        });
        // // Compare 2 additives
        // this.get('#additives/compare/:first/:second', function() {
        //     var self = this;
        //     self.swap(load_anim);

        //     // fetch first
        //     API.getAdditive(self.params['first'], function(err, dataFirst) {
        //         if (err) {
        //             console.log(err);
        //             return;
        //         }
        //         // fetch second
        //         API.getAdditive(self.params['second'], function(err, dataSecond) {
        //             if (err) {
        //                 console.log(err);
        //                 return;
        //             }

        //             self.partial('partials/compare-two.ms', {first: dataFirst, second: dataSecond});
        //         });
        //     });
        // });
        // Categories page
        this.get('#categories', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getCategories(function(err, data) {
                if (err) {
                    console.log(err);
                    return;
                }
                breadcrumbs.clear().add('home').add('categories').render(self, context, function() {
                    context.data = formatCategoriesData(data);
                    context.locale = Locale;
                    context.partial('partials/categories.ms', function() {
                        $('table').footable();
                    });
                });
            });
        });
        // Show single cateogry
        this.get('#categories/:id', function(context) {
            var self = this;
            self.swap(load_anim);

            API.getCategory(this.params['id'], function(err, data) {
                if (err) {
                    console.log(err);
                    $(document).trigger('alert', [Locale.categories.msg_notfound]);
                    self.redirect('#categories');
                    return;
                }
                breadcrumbs.clear().add('home').add('categories').add(data.name).render(self, context, function() {
                    context.data = formatCategoriesData(data);
                    context.locale = Locale;
                    context.partial('partials/single-category.ms');
                });
            });
        });
        // F.A.Q. page
        this.get('#faq', function(context) {
            var self = this;
            self.swap(load_anim);
            breadcrumbs.clear().add('home').add('F.A.Q.').render(self, context, function() {
                context.locale = Locale;
                context.partial('partials/faq.ms');
            });
        });
        // Legal: Privacy page
        this.get('#legal/privacy', function() {
            var self = this;
            self.swap(load_anim);
            self.partial('partials/privacy.ms');
        });
        // Legal: Terms of use page
        this.get('#legal/terms', function() {
            var self = this;
            self.swap(load_anim);
            self.partial('partials/terms.ms');
        });
        // HTTP 404
        // this.notFound = function(verb, path) {
        //     window.location = '404.html';
        // }
    });
    // start the application
    app.run('#/');
    app.clearTemplateCache();

    /**
     * Bind app events
     */
    Bindings.bindAll(app);

    /**
     * Others
     */
    function formatAdditivesData(data) {
        function _fmt(additive) {
            additive.last_update = moment(additive.last_update).format('LLL');
            return additive;
        }

        if (Object.prototype.toString.call(data) == '[object Array]') {
            var result = [];
            _.each(data, function(item) {
                result.push(_fmt(item));
            });
            return result;
        }

        return _fmt(data);
    }
    function formatCategoriesData(data) {
        function _fmt(category) {
            category.last_update = moment(category.last_update).format('LLL');
            return category;
        }

        if (Object.prototype.toString.call(data) == '[object Array]') {
            var result = [];
            _.each(data, function(item) {
                result.push(_fmt(item));
            });
            return result;
        }

        return _fmt(data);
    }
});
<|endoftext|>


<commit_before>$.fn.random = function() {
	return this.eq(Math.floor(Math.random() * this.length));
};

Array.prototype.max = function() {
  return Math.max.apply(null, this);
};

$(document).ready(function() {
	"use strict";
	var $ = window.jQuery;
	var NProgress = window.NProgress;

	window.sliMpd = $.extend(true, window.sliMpd, {
		modules : {},

		drawFaviconTimeout : 0,

		xwax : false,

		/**
		 * adds get-paramter to url, respecting existing and not-existing params
		 * TODO: currently not compatible with urlstring that contains a #hash
		 * @param {string} urlstring
		 * @param {string} paramName
		 * @param {string} paramValue
		 */
		setGetParameter(urlstring, paramName, paramValue) {
			if (urlstring.indexOf(paramName + "=") >= 0) {
				var prefix = urlstring.substring(0, urlstring.indexOf(paramName));
				var suffix = urlstring.substring(urlstring.indexOf(paramName));
				suffix = suffix.substring(suffix.indexOf("=") + 1);
				suffix = (suffix.indexOf("&") >= 0) ? suffix.substring(suffix.indexOf("&")) : "";
				urlstring = prefix + paramName + "=" + paramValue + suffix;
			} else {
				urlstring += (urlstring.indexOf("?") < 0)
					? "?" + paramName + "=" + paramValue
					: "&" + paramName + "=" + paramValue;
			}
			return urlstring;
		},

		drawFavicon() {
			clearTimeout(window.sliMpd.drawFaviconTimeout);
			window.sliMpd.currentPlayer.drawFavicon();
			window.sliMpd.drawFaviconTimeout = setTimeout(window.sliMpd.drawFavicon, 2000);
		},

		fireRequestAndNotify(url) {
			$.get(url).done(function(response) {
				window.sliMpd.checkNotify(response);
			});
		},

		checkNotify(endcodedResponse) {
			try {
				var notifyConf = JSON.parse(endcodedResponse);
				if (typeof notifyConf.notify !== "undefined") {
					this.notify(notifyConf);
				}
			} catch(e) {
				//console.log(e + " no json response in SliMpd::checkNotify()");
			}
		},

		// TODO: respect playersize + visible xwax gui for positioning
		notify(notifyConf) {
			$.notify({
				// options
				message: notifyConf.message
			},{
				// settings
				type: (notifyConf.type || "info"),
				z_index: 10000,
				offset: {
					x: "10",
					y: "110"
				},
				placement: {
					from: "bottom",
					align: "right"
				},
			});
		},

		notifyError(errorUrl) {
			// TODO: get message from language file
			this.notify({
				message : "
OOOPS!
 something went wrong...
" + errorUrl + "",
				type : "danger"
			});
		},

		/* toggle between mpd-control and local player (jPlayer) */
		togglePlayer() {
			var TweenLite = window.TweenLite;
			var Back = window.Back;
			var Power2 = window.Power2;

			var perspective = -1000;
			var originPrev = "50% 50%";
			var originNew = "50% 50%";
			var ease = Back.easeInOut.config(1);
			var easeIn = Power2.easeIn;
			var easeOut = Power2.easeOut;
			var speed = 0.5;
			var classToRemove = window.sliMpd.conf.color.mpd.bodyclass;
			var classToAdd = window.sliMpd.conf.color.local.bodyclass;

			var tweenIn;
			var tweenOut;
			var timeScale = 0.7;

			$(".player-local,.player-mpd").removeClass("hidden");

			var transformPreviousPlayerFrom = {
				display: "block",
				transformOrigin: originPrev,
				transformPerspective: perspective,
				zIndex: 1030,
				rotationX: 0,
				y: 0,
				z:0
			};
			var transformPreviousPlayerTo = {
				display: "none",
				rotationX: 90,
				y: $(".player-mpd").height()/2,
				z: -5,
				ease: ease
			};
			var transformNewPlayerFrom = {
				transformOrigin: originNew,
				transformPerspective: perspective,
				display: "block",
				zIndex: 1029,
				rotationX: -90,
				y: -$(".player-mpd").height()/2,
				z: -5
			};
			var transformNewPlayerTo = {
				display: "block",
				rotationX: 0,
				y:0,
				z:0,
				delay:0.02,
				ease: ease
			};

			if(window.sliMpd.currentPlayer.mode === "mpd") {
				// activate local player
				window.sliMpd.currentPlayer = window.sliMpd.localPlayer;

				// reduce poll amount of inactive mpd player
				window.sliMpd.mpdPlayer.pollWorker.postMessage({
					cmd: "setMiliseconds",
					value: window.sliMpd.mpdPlayer.intervalInactive
				});

				// flip animation for both players
				tweenIn = TweenLite.fromTo($(".player-mpd"), speed, transformPreviousPlayerFrom, transformPreviousPlayerTo);
				tweenOut = TweenLite.fromTo($(".player-local"), speed, transformNewPlayerFrom, transformNewPlayerTo);

				tweenIn.timeScale(timeScale);
				tweenOut.timeScale(timeScale);

				//TweenLite.fromTo($(".permaplayer-wrapper"), speed, {rotationX: 0 }, {rotationX: 90});
			} else {
				// pause local player when switching to mpd
				window.sliMpd.currentPlayer.process({"action":"pause"});

				// activate mpd player
				window.sliMpd.currentPlayer = window.sliMpd.mpdPlayer;

				// increase poll amount as mpd player is now active
				window.sliMpd.mpdPlayer.pollWorker.postMessage({
					cmd: "setMiliseconds",
					value: window.sliMpd.mpdPlayer.intervalActive
				});
				window.sliMpd.currentPlayer.refreshInterval();

				// flip animation for both players
				tweenIn = TweenLite.fromTo($(".player-local"), speed, transformPreviousPlayerFrom, transformPreviousPlayerTo);
				tweenOut = TweenLite.fromTo($(".player-mpd"), speed, transformNewPlayerFrom, transformNewPlayerTo);

				tweenIn.timeScale(timeScale);
				tweenOut.timeScale(timeScale);

				//TweenLite.fromTo($(".permaplayer-wrapper"), speed, {rotationX: 90 }, {rotationX: 0});

				classToRemove = window.sliMpd.conf.color.local.bodyclass;
				classToAdd = window.sliMpd.conf.color.mpd.bodyclass;
			}

			// change body-class for colorizing all links in half of animation time
			// TODO: is window.setTimeout() correct or should it be on another element?
			//window.setTimeout(function (){ $("body").addClass(classToAdd).removeClass(classToRemove); }, speed/2*1000);
			$("body").addClass(classToAdd).removeClass(classToRemove);

			$.cookie("playerMode", window.sliMpd.currentPlayer.mode, { expires : 365, path: "/" });
			window.sliMpd.drawFavicon();
			window.sliMpd.currentPlayer.drawWaveform();
		}
	});

	window.sliMpd.navbar = new window.sliMpd.modules.NavbarView({
		el : "nav.main-nav"
	});
	window.sliMpd.navbar.render();

	window.sliMpd.xwax = new window.sliMpd.modules.XwaxView({
		el : ".player-xwax",
		showWaveform : true
	});
	window.sliMpd.xwax.render();

	window.sliMpd.modal = new window.sliMpd.modules.ModalView({
		el : "#global-modal .modal-content"
	});

	window.sliMpd.localPlayer = new window.sliMpd.modules.LocalPlayer({
		el : ".permaplayer.player-local"
	});
	window.sliMpd.mpdPlayer = new window.sliMpd.modules.MpdPlayer({
		el : ".permaplayer.player-mpd"
	});

	window.sliMpd.currentPlayer = ($.cookie("playerMode") === "mpd")
		? window.sliMpd.mpdPlayer
		: window.sliMpd.localPlayer;

	window.sliMpd.router = new window.sliMpd.modules.Router();

	window.Backbone.history.start({
		pushState : true
	});

	window.sliMpd.drawFavicon();

	/* toggle between display tags and display filepath */
	$(".fileModeToggle a").on("click", function(e) {
		e.preventDefault();
		$("body").toggleClass("ffn");
		$(this).find("i").toggleClass("fa-toggle-off").toggleClass("fa-toggle-on");
	});

	// delegate calls to data-toggle="lightbox"
	$(document).delegate("*[data-toggle='lightbox']", "click", function(event) {
		event.preventDefault();
		return $(this).ekkoLightbox({
			always_show_close: true,
			gallery_parent_selector: "body"
		});
	});

	$(document).on("keydown", null, "ctrl+space", function(){
		// FIXME: this does not work with open autocomplete-widget. obviously ac overrides key bindings
		$("#mainsearch").focus().select();
		return false;
	});

	$(".navbar-upper").affix({
		offset: {bottom: 200}
	});

	NProgress.configure({
		showSpinner: false,
		parent: "#nprog-container",
		speed: 100,
		trickleRate: 0.02,
		trickleSpeed: 800
	});

	// TODO: is it correct to place this here (excluded from all bootstrap-views)?
	$(function(){
		$("#top-link-block").removeClass("hidden").affix({
			// how far to scroll down before link "slides" into view
			offset: {top:100}
		});
	});
	$("#top-link-block a").on("click", function(e) {
		e.preventDefault();
		$("html,body").animate({scrollTop:0},"fast");
		return false;
	});

	/*
	 * force confirmation when user leaves sliMpd in case local audio is playing
	 * as the browser is not displaying the text there is no nedd to fetch string from language file
	 */
	window.onbeforeunload=function(){
		if(window.sliMpd.currentPlayer.mode === "local" && window.sliMpd.currentPlayer.nowPlayingState === "play") {
			return "local audio is currently playing";
		}
	}

	/*
	 * add lazy resize listener
	 */
	$(window).bind("resizeEnd", function() {
		window.sliMpd.currentPlayer.drawWaveform();
		window.sliMpd.currentPlayer.drawTimeGrid();
	});
	$(window).resize(function() {
		if(this.resizeTO) {
			clearTimeout(this.resizeTO);
		}
		this.resizeTO = setTimeout(function() {
			$(this).trigger("resizeEnd");
		}, 500);
	});

	// add some smooth animation on initial loading
	var timeScale = 1;
	var TweenLite = window.TweenLite;
	var Quint = window.Quint;
	$(window.sliMpd.localPlayer.el).css("z-index",1027);
	$(window.sliMpd.mpdPlayer.el).css("z-index",1028);
	$(window.sliMpd.currentPlayer.el).css("z-index",1030);
	TweenLite.set([$(".permaplayer"), $(".main-nav")],{opacity:1});
	TweenLite.fromTo($(".main-nav"), 0.75, { y: -$(".main-nav").height() }, { y:0, opacity:1, ease: Quint.easeOut }).timeScale(timeScale);
	TweenLite.fromTo($("#main"), 1, { scale: 0.97 }, { scale:1, opacity:1, ease: Quint.easeOut, delay: 0.15 }).timeScale(timeScale);
	TweenLite.fromTo($(".permaplayer"), 0.75, { y: $(window.sliMpd.currentPlayer.el).height() }, { y:0, opacity:1, ease: Quint.easeOut, delay: 1 }).timeScale(timeScale);
});
<commit_msg>added stagger animation tracks<commit_after>$.fn.random = function() {
	return this.eq(Math.floor(Math.random() * this.length));
};

Array.prototype.max = function() {
  return Math.max.apply(null, this);
};

$(document).ready(function() {
	"use strict";
	var $ = window.jQuery;
	var NProgress = window.NProgress;

	window.sliMpd = $.extend(true, window.sliMpd, {
		modules : {},

		drawFaviconTimeout : 0,

		xwax : false,

		/**
		 * adds get-paramter to url, respecting existing and not-existing params
		 * TODO: currently not compatible with urlstring that contains a #hash
		 * @param {string} urlstring
		 * @param {string} paramName
		 * @param {string} paramValue
		 */
		setGetParameter(urlstring, paramName, paramValue) {
			if (urlstring.indexOf(paramName + "=") >= 0) {
				var prefix = urlstring.substring(0, urlstring.indexOf(paramName));
				var suffix = urlstring.substring(urlstring.indexOf(paramName));
				suffix = suffix.substring(suffix.indexOf("=") + 1);
				suffix = (suffix.indexOf("&") >= 0) ? suffix.substring(suffix.indexOf("&")) : "";
				urlstring = prefix + paramName + "=" + paramValue + suffix;
			} else {
				urlstring += (urlstring.indexOf("?") < 0)
					? "?" + paramName + "=" + paramValue
					: "&" + paramName + "=" + paramValue;
			}
			return urlstring;
		},

		drawFavicon() {
			clearTimeout(window.sliMpd.drawFaviconTimeout);
			window.sliMpd.currentPlayer.drawFavicon();
			window.sliMpd.drawFaviconTimeout = setTimeout(window.sliMpd.drawFavicon, 2000);
		},

		fireRequestAndNotify(url) {
			$.get(url).done(function(response) {
				window.sliMpd.checkNotify(response);
			});
		},

		checkNotify(endcodedResponse) {
			try {
				var notifyConf = JSON.parse(endcodedResponse);
				if (typeof notifyConf.notify !== "undefined") {
					this.notify(notifyConf);
				}
			} catch(e) {
				//console.log(e + " no json response in SliMpd::checkNotify()");
			}
		},

		// TODO: respect playersize + visible xwax gui for positioning
		notify(notifyConf) {
			$.notify({
				// options
				message: notifyConf.message
			},{
				// settings
				type: (notifyConf.type || "info"),
				z_index: 10000,
				offset: {
					x: "10",
					y: "110"
				},
				placement: {
					from: "bottom",
					align: "right"
				},
			});
		},

		notifyError(errorUrl) {
			// TODO: get message from language file
			this.notify({
				message : "
OOOPS!
 something went wrong...
" + errorUrl + "",
				type : "danger"
			});
		},

		/* toggle between mpd-control and local player (jPlayer) */
		togglePlayer() {
			var TweenLite = window.TweenLite;
			var Back = window.Back;
			var Power2 = window.Power2;

			var perspective = -1000;
			var originPrev = "50% 50%";
			var originNew = "50% 50%";
			var ease = Back.easeInOut.config(1);
			var easeIn = Power2.easeIn;
			var easeOut = Power2.easeOut;
			var speed = 0.5;
			var classToRemove = window.sliMpd.conf.color.mpd.bodyclass;
			var classToAdd = window.sliMpd.conf.color.local.bodyclass;

			var tweenIn;
			var tweenOut;
			var timeScale = 0.7;

			$(".player-local,.player-mpd").removeClass("hidden");

			var transformPreviousPlayerFrom = {
				display: "block",
				transformOrigin: originPrev,
				transformPerspective: perspective,
				zIndex: 1030,
				rotationX: 0,
				y: 0,
				z:0
			};
			var transformPreviousPlayerTo = {
				display: "none",
				rotationX: 90,
				y: $(".player-mpd").height()/2,
				z: -5,
				ease: ease
			};
			var transformNewPlayerFrom = {
				transformOrigin: originNew,
				transformPerspective: perspective,
				display: "block",
				zIndex: 1029,
				rotationX: -90,
				y: -$(".player-mpd").height()/2,
				z: -5
			};
			var transformNewPlayerTo = {
				display: "block",
				rotationX: 0,
				y:0,
				z:0,
				delay:0.02,
				ease: ease
			};

			if(window.sliMpd.currentPlayer.mode === "mpd") {
				// activate local player
				window.sliMpd.currentPlayer = window.sliMpd.localPlayer;

				// reduce poll amount of inactive mpd player
				window.sliMpd.mpdPlayer.pollWorker.postMessage({
					cmd: "setMiliseconds",
					value: window.sliMpd.mpdPlayer.intervalInactive
				});

				// flip animation for both players
				tweenIn = TweenLite.fromTo($(".player-mpd"), speed, transformPreviousPlayerFrom, transformPreviousPlayerTo);
				tweenOut = TweenLite.fromTo($(".player-local"), speed, transformNewPlayerFrom, transformNewPlayerTo);

				tweenIn.timeScale(timeScale);
				tweenOut.timeScale(timeScale);

				//TweenLite.fromTo($(".permaplayer-wrapper"), speed, {rotationX: 0 }, {rotationX: 90});
			} else {
				// pause local player when switching to mpd
				window.sliMpd.currentPlayer.process({"action":"pause"});

				// activate mpd player
				window.sliMpd.currentPlayer = window.sliMpd.mpdPlayer;

				// increase poll amount as mpd player is now active
				window.sliMpd.mpdPlayer.pollWorker.postMessage({
					cmd: "setMiliseconds",
					value: window.sliMpd.mpdPlayer.intervalActive
				});
				window.sliMpd.currentPlayer.refreshInterval();

				// flip animation for both players
				tweenIn = TweenLite.fromTo($(".player-local"), speed, transformPreviousPlayerFrom, transformPreviousPlayerTo);
				tweenOut = TweenLite.fromTo($(".player-mpd"), speed, transformNewPlayerFrom, transformNewPlayerTo);

				tweenIn.timeScale(timeScale);
				tweenOut.timeScale(timeScale);

				//TweenLite.fromTo($(".permaplayer-wrapper"), speed, {rotationX: 90 }, {rotationX: 0});

				classToRemove = window.sliMpd.conf.color.local.bodyclass;
				classToAdd = window.sliMpd.conf.color.mpd.bodyclass;
			}

			// change body-class for colorizing all links in half of animation time
			// TODO: is window.setTimeout() correct or should it be on another element?
			//window.setTimeout(function (){ $("body").addClass(classToAdd).removeClass(classToRemove); }, speed/2*1000);
			$("body").addClass(classToAdd).removeClass(classToRemove);

			$.cookie("playerMode", window.sliMpd.currentPlayer.mode, { expires : 365, path: "/" });
			window.sliMpd.drawFavicon();
			window.sliMpd.currentPlayer.drawWaveform();
		}
	});

	window.sliMpd.navbar = new window.sliMpd.modules.NavbarView({
		el : "nav.main-nav"
	});
	window.sliMpd.navbar.render();

	window.sliMpd.xwax = new window.sliMpd.modules.XwaxView({
		el : ".player-xwax",
		showWaveform : true
	});
	window.sliMpd.xwax.render();

	window.sliMpd.modal = new window.sliMpd.modules.ModalView({
		el : "#global-modal .modal-content"
	});

	window.sliMpd.localPlayer = new window.sliMpd.modules.LocalPlayer({
		el : ".permaplayer.player-local"
	});
	window.sliMpd.mpdPlayer = new window.sliMpd.modules.MpdPlayer({
		el : ".permaplayer.player-mpd"
	});

	window.sliMpd.currentPlayer = ($.cookie("playerMode") === "mpd")
		? window.sliMpd.mpdPlayer
		: window.sliMpd.localPlayer;

	window.sliMpd.router = new window.sliMpd.modules.Router();

	window.Backbone.history.start({
		pushState : true
	});

	window.sliMpd.drawFavicon();

	/* toggle between display tags and display filepath */
	$(".fileModeToggle a").on("click", function(e) {
		e.preventDefault();
		$("body").toggleClass("ffn");
		$(this).find("i").toggleClass("fa-toggle-off").toggleClass("fa-toggle-on");
	});

	// delegate calls to data-toggle="lightbox"
	$(document).delegate("*[data-toggle='lightbox']", "click", function(event) {
		event.preventDefault();
		return $(this).ekkoLightbox({
			always_show_close: true,
			gallery_parent_selector: "body"
		});
	});

	$(document).on("keydown", null, "ctrl+space", function(){
		// FIXME: this does not work with open autocomplete-widget. obviously ac overrides key bindings
		$("#mainsearch").focus().select();
		return false;
	});

	$(".navbar-upper").affix({
		offset: {bottom: 200}
	});

	NProgress.configure({
		showSpinner: false,
		parent: "#nprog-container",
		speed: 100,
		trickleRate: 0.02,
		trickleSpeed: 800
	});

	// TODO: is it correct to place this here (excluded from all bootstrap-views)?
	$(function(){
		$("#top-link-block").removeClass("hidden").affix({
			// how far to scroll down before link "slides" into view
			offset: {top:100}
		});
	});
	$("#top-link-block a").on("click", function(e) {
		e.preventDefault();
		$("html,body").animate({scrollTop:0},"fast");
		return false;
	});

	/*
	 * force confirmation when user leaves sliMpd in case local audio is playing
	 * as the browser is not displaying the text there is no nedd to fetch string from language file
	 */
	window.onbeforeunload=function(){
		if(window.sliMpd.currentPlayer.mode === "local" && window.sliMpd.currentPlayer.nowPlayingState === "play") {
			return "local audio is currently playing";
		}
	}

	/*
	 * add lazy resize listener
	 */
	$(window).bind("resizeEnd", function() {
		window.sliMpd.currentPlayer.drawWaveform();
		window.sliMpd.currentPlayer.drawTimeGrid();
	});
	$(window).resize(function() {
		if(this.resizeTO) {
			clearTimeout(this.resizeTO);
		}
		this.resizeTO = setTimeout(function() {
			$(this).trigger("resizeEnd");
		}, 500);
	});

	// add some smooth animation on initial loading
	var timeScale = 1;
	var TweenLite = window.TweenLite;
	var Quint = window.Quint;
	$(window.sliMpd.localPlayer.el).css("z-index",1027);
	$(window.sliMpd.mpdPlayer.el).css("z-index",1028);
	$(window.sliMpd.currentPlayer.el).css("z-index",1030);
	TweenLite.set([$(".permaplayer"), $(".main-nav")],{opacity:1});
	TweenLite.fromTo($(".main-nav"), 0.75, { y: -$(".main-nav").height() }, { y:0, opacity:1, ease: Quint.easeOut }).timeScale(timeScale);
	TweenLite.fromTo($("#main"), 1, { scale: 0.97 }, { scale:1, opacity:1, ease: Quint.easeOut, delay: 0.15 }).timeScale(timeScale);
	TweenMax.staggerFrom($(".track-row"),2, { y: -30, opacity:0, ease: Quint.easeOut, delay: 0.15 }, 0.2).timeScale(timeScale);
	TweenLite.fromTo($(".permaplayer"), 0.75, { y: $(window.sliMpd.currentPlayer.el).height() }, { y:0, opacity:1, ease: Quint.easeOut, delay: 1 }).timeScale(timeScale);
});
<|endoftext|>


<commit_before>$.getJSON("logic.json", function(logic){

	//globals
	var oldpop;
	function closepop(){
		if(oldpop){
			oldpop.popover('hide');
			oldpop = null;
		}
	}

	//escape button
	$(document).keydown(function(e){
		if(e.which == 27){
			closepop();
		}
	});

	//survey sortable
	$(".panel-group").sortable({
		handle: ".panel-heading",
		update: writexml,
		start: closepop
	});

	//create new surveys
	$("#new_survey_button").click(function(e){
		e.preventDefault();
		this.blur();
		var el = $("#surveytemplate .survey_content").clone();
		var id = el.children(".panel-collapse").uniqueId()[0].id;
		el.find("h4.panel-title a").attr("href", "#" + id);
		el.find(".list-group").sortable({
			update: writexml,
			start: closepop
		});
		el.find(".dropdown-menu a").click(function(e){
			e.preventDefault();
			var prompt_type = $(this).data("type");
			add_prompt(prompt_type, el)
		});
		el.find(".remove_survey_button").click(function(e){
			e.preventDefault();
			bootbox.confirm({
				title : "Delete Survey",
				message : "Do you want to remove this survey from the campaign?",
				callback : function(result){
					if(!result) return;
					el.hide(function(){
						el.remove()
						writexml();
					})
				}
			});
		});
		$("#surveygroup").append(el);
		$("#surveygroup").find(".collapse").collapse('hide');
		el.find(".collapse").collapse('show');

		//update view
		el.find(".survey_id_field").on("keyup", function(){
			var urn = urnify($(this).val())
			$(this).val(urn)
			el.find("h4.panel-title a").text("Survey: " + urn)
		})

		//update xml
		el.find("input,textarea").change(writexml).keyup(writexml);
		writexml();
	});

	//create new prompt
	function add_prompt(prompt_type, el){
		el.find(".survey_prompt_list").append(function(){
			var a = $(Mustache.render(templates.promptlink, {
				prompt_type : prompt_type,
				icon : logic.icons[prompt_type]
			})).data("prompt_type", prompt_type);
			a.popover({
				html: true,
				//placement: "top",
				//trigger: "hover",
				title : prompt_type + ' prompt', // ',
				content: popover_content(prompt_type, a)
			}).click(function(e){
				e.preventDefault();
			}).on("show.bs.popover", function(){
				if(oldpop != a){
					closepop();
				}
				oldpop = a;
			})
			return a;
		})
		writexml();
	}

	//initiate the prompt popover
	function popover_content(prompt_type, a){
		var templates = window.templates;
		var fields = logic.prompttypes[prompt_type];
		var el = $("#prompttemplate").children().clone();
		var form = el.find("form");

		// Other fields get dynamically
		$.each(fields, function(index, fieldname){
			var field = logic.fields[fieldname];
			var output = Mustache.render(templates[field.type], {
				field : fieldname,
				label : field.label || toTitleCase(fieldname),
				placeholder : field.placeholder || "Please enter " + fieldname.toLowerCase()
			});
			var input = form.append(output).find("input");

			//force number fields to be numbers.
			if(field.type == "number"){
				input.on("blur", function(){
					$(this).val($(this).val());
				})
			}

			//update view
			if(fieldname == "id"){
				var prompttext = a.find(".prompt_id_text");
				input.on("keyup", function(){
					var urn = urnify($(this).val())
					$(this).val(urn)
					prompttext.text(urn || "___")
				})
			}
		});

		a.find(".remove_prompt_button").click(function(e){
			e.preventDefault()
			e.stopPropagation();
			closepop();
			a.hide(function(){
				a.popover('destroy');
				a.remove();
				writexml();
			})
		});

		el.find(".choice_values").tagit({
			afterTagAdded : writexml,
			afterTagRemoved : writexml
		})

		el.find("input,textarea").change(writexml).keyup(writexml);

		return el;
	}

	/* Convert Form to XML. Should rewrite this in proper MVC */
	function form2xml(){
		var xml = $("<root/>")
		var campaign = $("<campaign/>").appendTo(xml);
		var surveys = $("<surveys/>").appendTo(campaign);

		$("#surveygroup .survey_form").each(function(){

			/* create node */
			var form = $(this);
			var survey = $("<survey/>").appendTo(surveys);

			/* survey fields */
			$("<id/>").text(form.find(".survey_id_field").val()).appendTo(survey);
			$("<title/>").text(form.find(".survey_title_field").val()).appendTo(survey);
			$("<description/>").text(form.find(".survey_description_field").val()).appendTo(survey);
			$("<submitText/>").text(form.find(".survey_submit_field").val()).appendTo(survey);
			$("<anytime/>").text(form.find(".survey_anytime_field").is(":checked")).appendTo(survey);

			/* find prompts */
			var contents = $("<contentList/>").appendTo(survey)
			form.find(".survey_prompt_list .prompt_link").each(function(){

				var prompt_link = $(this);
				var prompt_type = prompt_link.data("prompt_type");

				if(prompt_type == "message"){
					var prompt = $("<message/>").appendTo(contents)
				} else {
					var prompt = $("<prompt/>").appendTo(contents)
					$("<promptType>").text(prompt_link.data("prompt_type")).appendTo(prompt)
				}

				var popover = prompt_link.data("bs.popover").$tip;
				var fields = $(popover).find(".prompt_field")
				var properties = {};

				fields.each(function(){
					var field = $(this);
					var name = field.data("field")
					var value = field.is("input[type=checkbox]") ? field.is(':checked') : field.val();

					//some fields have to be put in the xml as 'properties'
					if(logic.fields[name].property){
						if(field.is("ol")){
							$.each(field.tagit("assignedTags"), function(i, val){
								//we start counting from 1 because that is how OL are displayed
								properties[i + 1] = val
							});
						} else {
							properties[name] = value;
						}
					} else {
						$("<"+name+"/>").text(value).appendTo(prompt)
					}

					//ohmage apparently has no default for this
					if(name == "skippable" && value == true){
						$("<skipLabel/>").text("Skip").appendTo(prompt)
					}
				})

				//append properties
				if(Object.keys(properties).length){
					var props = $("<properties>").appendTo(prompt)
					$.each(properties, function(key, val){
						var prop = $("<property>").appendTo(props)
						$("<key/>").text(key).appendTo(prop)
						$("").text(val).appendTo(prop)
					})
				}
			})
		});
		return xml
	}

	function writexml(){
		var xmltext = vkbeautify.xml('<?xml version="1.0" encoding="UTF-8"?>\n' + form2xml().html());
		$("code").text(xmltext)
		return xmltext;
	}

	function toTitleCase(str){
		return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
	}

	function urnify(str){
		return str.replace(/[^a-z0-9]/gi,'').substr(0, 20)
	}

	$("#download_xml_button").click(function(e){
		$(this).attr("download", "campaign.xml")
		$(this).attr("href", "data:application/xml," + encodeURIComponent(writexml()))
	})

	//init page
	writexml();

}).fail(function(){
	alert("Downloading logic.json failed.")
});
<commit_msg>XML tags are case sensitive arghhhh<commit_after>$.getJSON("logic.json", function(logic){

	//globals
	var oldpop;
	var parse = (function(parser, jQuery){
		return function(str) {
			return jQuery(parser.parseFromString(str, "text/xml").documentElement)
		}
	})(new DOMParser(), jQuery)

	function closepop(){
		if(oldpop){
			oldpop.popover('hide');
			oldpop = null;
		}
	}

	//escape button
	$(document).keydown(function(e){
		if(e.which == 27){
			closepop();
		}
	});

	//survey sortable
	$(".panel-group").sortable({
		handle: ".panel-heading",
		update: writexml,
		start: closepop
	});

	//create new surveys
	$("#new_survey_button").click(function(e){
		e.preventDefault();
		this.blur();
		var el = $("#surveytemplate .survey_content").clone();
		var id = el.children(".panel-collapse").uniqueId()[0].id;
		el.find("h4.panel-title a").attr("href", "#" + id);
		el.find(".list-group").sortable({
			update: writexml,
			start: closepop
		});
		el.find(".dropdown-menu a").click(function(e){
			e.preventDefault();
			var prompt_type = $(this).data("type");
			add_prompt(prompt_type, el)
		});
		el.find(".remove_survey_button").click(function(e){
			e.preventDefault();
			bootbox.confirm({
				title : "Delete Survey",
				message : "Do you want to remove this survey from the campaign?",
				callback : function(result){
					if(!result) return;
					el.hide(function(){
						el.remove()
						writexml();
					})
				}
			});
		});
		$("#surveygroup").append(el);
		$("#surveygroup").find(".collapse").collapse('hide');
		el.find(".collapse").collapse('show');

		//update view
		el.find(".survey_id_field").on("keyup", function(){
			var urn = urnify($(this).val())
			$(this).val(urn)
			el.find("h4.panel-title a").text("Survey: " + urn)
		})

		//update xml
		el.find("input,textarea").change(writexml).keyup(writexml);
		writexml();
	});

	//create new prompt
	function add_prompt(prompt_type, el){
		el.find(".survey_prompt_list").append(function(){
			var a = $(Mustache.render(templates.promptlink, {
				prompt_type : prompt_type,
				icon : logic.icons[prompt_type]
			})).data("prompt_type", prompt_type);
			a.popover({
				html: true,
				//placement: "top",
				//trigger: "hover",
				title : prompt_type + ' prompt', // ',
				content: popover_content(prompt_type, a)
			}).click(function(e){
				e.preventDefault();
			}).on("show.bs.popover", function(){
				if(oldpop != a){
					closepop();
				}
				oldpop = a;
			})
			return a;
		})
		writexml();
	}

	//initiate the prompt popover
	function popover_content(prompt_type, a){
		var templates = window.templates;
		var fields = logic.prompttypes[prompt_type];
		var el = $("#prompttemplate").children().clone();
		var form = el.find("form");

		// Other fields get dynamically
		$.each(fields, function(index, fieldname){
			var field = logic.fields[fieldname];
			var output = Mustache.render(templates[field.type], {
				field : fieldname,
				label : field.label || toTitleCase(fieldname),
				placeholder : field.placeholder || "Please enter " + fieldname.toLowerCase()
			});
			var input = form.append(output).find("input");

			//force number fields to be numbers.
			if(field.type == "number"){
				input.on("blur", function(){
					$(this).val($(this).val());
				})
			}

			//update view
			if(fieldname == "id"){
				var prompttext = a.find(".prompt_id_text");
				input.on("keyup", function(){
					var urn = urnify($(this).val())
					$(this).val(urn)
					prompttext.text(urn || "___")
				})
			}
		});

		a.find(".remove_prompt_button").click(function(e){
			e.preventDefault()
			e.stopPropagation();
			closepop();
			a.hide(function(){
				a.popover('destroy');
				a.remove();
				writexml();
			})
		});

		el.find(".choice_values").tagit({
			afterTagAdded : writexml,
			afterTagRemoved : writexml
		})

		el.find("input,textarea").change(writexml).keyup(writexml);

		return el;
	}

	/* Convert Form to XML. Should rewrite this in proper MVC */
	function form2xml(){
		var xml = $("<root/>")
		var campaign = $("<campaign/>").appendTo(xml);
		var surveys = $("<surveys/>").appendTo(campaign);

		$("#surveygroup .survey_form").each(function(){

			/* create node */
			var form = $(this);
			var survey = parse("<survey/>").appendTo(surveys);

			/* survey fields */
			parse("<id/>").text(form.find(".survey_id_field").val()).appendTo(survey);
			parse("<title/>").text(form.find(".survey_title_field").val()).appendTo(survey);
			parse("<description/>").text(form.find(".survey_description_field").val()).appendTo(survey);
			parse("<submitText/>").text(form.find(".survey_submit_field").val()).appendTo(survey);
			parse("<anytime/>").text(form.find(".survey_anytime_field").is(":checked")).appendTo(survey);

			/* find prompts */
			var contents = $("<contentList/>").appendTo(survey)
			form.find(".survey_prompt_list .prompt_link").each(function(){

				var prompt_link = $(this);
				var prompt_type = prompt_link.data("prompt_type");

				if(prompt_type == "message"){
					var prompt = parse("<message/>").appendTo(contents)
				} else {
					var prompt = $("<prompt/>").appendTo(contents)
					parse("<promptType>").text(prompt_link.data("prompt_type")).appendTo(prompt)
				}

				var popover = prompt_link.data("bs.popover").$tip;
				var fields = $(popover).find(".prompt_field")
				var properties = {};

				fields.each(function(){
					var field = $(this);
					var name = field.data("field")
					var value = field.is("input[type=checkbox]") ? field.is(':checked') : field.val();

					//some fields have to be put in the xml as 'properties'
					if(logic.fields[name].property){
						if(field.is("ol")){
							$.each(field.tagit("assignedTags"), function(i, val){
								//we start counting from 1 because that is how OL are displayed
								properties[i + 1] = val
							});
						} else {
							properties[name] = value;
						}
					} else {
						parse("<"+name+"/>").text(value).appendTo(prompt)
					}

					//ohmage apparently has no default for this
					if(name == "skippable" && value == true){
						parse("<skipLabel/>").text("Skip").appendTo(prompt)
					}
				})

				//append properties
				if(Object.keys(properties).length){
					var props = parse("<properties>").appendTo(prompt)
					$.each(properties, function(key, val){
						var prop = parse("<property>").appendTo(props)
						parse("<key/>").text(key).appendTo(prop)
						parse("").text(val).appendTo(prop)
					})
				}
			})
		});
		return xml
	}

	function writexml(){
		var xmltext = vkbeautify.xml('<?xml version="1.0" encoding="UTF-8"?>\n' + form2xml().html());
		$("code").text(xmltext)
		return xmltext;
	}

	function toTitleCase(str){
		return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
	}

	function urnify(str){
		return str.replace(/[^a-z0-9]/gi,'').substr(0, 20)
	}

	$("#download_xml_button").click(function(e){
		$(this).attr("download", "campaign.xml")
		$(this).attr("href", "data:application/xml," + encodeURIComponent(writexml()))
	})

	//init page
	writexml();

}).fail(function(){
	alert("Downloading logic.json failed.")
});
<|endoftext|>


<commit_before>// display modal window
function displayModal() {
  document.getElementById('modal1').style.display = "block"; // this worked!!!!!!
  console.log("Donate button clicked");
}

// close modal window
function closeModal(){
  document.getElementById("modal1").style.display = "none";
  console.log("Close button clicked");

}

// Getting all records and stuff from the database

    $.getJSON("https://spreadsheets.google.com/feeds/list/1mFtnlk9MjHz9smP07SG2uPJ8rkv8dt2_eDR5wqLkilg/1/public/values?alt=json", function(data) {

      // create a card
      var newCard = ' ';
      for (var i = 0; i < data.feed.entry.length; i++) {

        // variables
        var userName = (data.feed.entry[i]["gsx$enteryourfullname"]['$t']); // this works
        var urlLink = (data.feed.entry[i]["gsx$personalwebsiteurl"]['$t']); // this works
        var about = (data.feed.entry[i]["gsx$tellusaboutyourself"]['$t']); // this works
        var userImg = (data.feed.entry[i]["gsx$addaprofilepicture"]['$t']); // this works
        var twitterHandle = (data.feed.entry[i]["gsx$linktotwitteraccount"]['$t']); // this works
        var userRole = (data.feed.entry[i]["gsx$whatdoyou"]['$t']);
        var userLoc = (data.feed.entry[i]["gsx$whereareyoulocated"]['$t']);

        // Card template
        newCard += '
';
        newCard += '
';
        newCard += '
';
        newCard += '';
        newCard += '
';
        newCard += '
';
        newCard += '
' + userName + '
'; // this works
        newCard += '
'+ userRole +'
';
        newCard += '
' + about + '
'; // this works
        newCard += '
' + userLoc + '
'; // this works
        newCard += '
';
        newCard += '
';
        newCard += '';
        newCard += 'open_in_new'; // this works
        newCard += '
';
        newCard += '
';
        newCard += '
';

          // I want to know when a records field is false, then

          if (userRole == false) {
            console.log(twitterHandle);
          };

          // remove twitter icon if no value

          var twitterIcon1 = document.getElementsByClassName('twitterIcon');

                  if (twitterHandle == false) {
                    console.log(twitterHandle);

                    //document.getElementsByClassName("card-title").style.color = "#ff00ff";
                    //document.getElementById('demo').style.color = "#ff00ff";
                    //twitterIcon1.style.display = "none";
                    //document.getElementsByClassName('twitterIcon').style.visibility = "hidden";

                  }

      }; // End of Loop

      document.getElementById('rightColContent').innerHTML = newCard;

    }); // End Get Json
<commit_msg>Update js/app.js<commit_after>// display modal window
function displayModal() {
  document.getElementById('modal1').style.display = "block"; // this worked!!!!!!
  console.log("Donate button clicked");
}

// close modal window
function closeModal(){
  document.getElementById("modal1").style.display = "none";
  console.log("Close button clicked");

}

// Getting all records and stuff from the database

    $.getJSON("https://spreadsheets.google.com/feeds/list//1vBxh-IOal5mR833bAwnvH9kZ7Xe5o4eEe57ve5a1m1o/1/public/values?alt=json", function(data) {

      // create a card
      var newCard = ' ';
      for (var i = 0; i < data.feed.entry.length; i++) {

        // variables
        var userName = (data.feed.entry[i]["gsx$enteryourfullname"]['$t']); // this works
        var urlLink = (data.feed.entry[i]["gsx$personalwebsiteurl"]['$t']); // this works
        var about = (data.feed.entry[i]["gsx$tellusaboutyourself"]['$t']); // this works
        var userImg = (data.feed.entry[i]["gsx$addaprofilepicture"]['$t']); // this works
        var twitterHandle = (data.feed.entry[i]["gsx$linktotwitteraccount"]['$t']); // this works
        var userRole = (data.feed.entry[i]["gsx$whatdoyou"]['$t']);
        var userLoc = (data.feed.entry[i]["gsx$whereareyoulocated"]['$t']);

        // Card template
        newCard += '
';
        newCard += '
';
        newCard += '
';
        newCard += '';
        newCard += '
';
        newCard += '
';
        newCard += '
' + userName + '
'; // this works
        newCard += '
'+ userRole +'
';
        newCard += '
' + about + '
'; // this works
        newCard += '
' + userLoc + '
'; // this works
        newCard += '
';
        newCard += '
';
        newCard += '';
        newCard += 'open_in_new'; // this works
        newCard += '
';
        newCard += '
';
        newCard += '
';

          // I want to know when a records field is false, then

          if (userRole == false) {
            console.log(twitterHandle);
          };

          // remove twitter icon if no value

          var twitterIcon1 = document.getElementsByClassName('twitterIcon');

                  if (twitterHandle == false) {
                    console.log(twitterHandle);

                    //document.getElementsByClassName("card-title").style.color = "#ff00ff";
                    //document.getElementById('demo').style.color = "#ff00ff";
                    //twitterIcon1.style.display = "none";
                    //document.getElementsByClassName('twitterIcon').style.visibility = "hidden";

                  }

      }; // End of Loop

      document.getElementById('rightColContent').innerHTML = newCard;

    }); // End Get Json
<|endoftext|>


<commit_before> // Responsive navigation settings
var nav = responsiveNav(".nav-collapse", {
  customToggle: "nav-toggle",
  closeOnNavClick: true,
  openPos: "static"
});

// Hook up and configure responsive slides plugin

$(".rslides").responsiveSlides({
  auto: false,             // Boolean: Animate automatically, true or false
  // speed: 500,            // Integer: Speed of the transition, in milliseconds
  // timeout: 4000,          // Integer: Time between slide transitions, in milliseconds
  pager: true,           // Boolean: Show pager, true or false
  nav: false,             // Boolean: Show navigation, true or false
  random: false,          // Boolean: Randomize the order of the slides, true or false
  pause: false,           // Boolean: Pause on hover, true or false
  pauseControls: true,    // Boolean: Pause when hovering controls, true or false
  prevText: "Previous",   // String: Text for the "previous" button
  nextText: "Next",       // String: Text for the "next" button
  maxwidth: "",           // Integer: Max-width of the slideshow, in pixels
  navContainer: "",       // Selector: Where controls should be appended to, default is after the 'ul'
  manualControls: "",     // Selector: Declare custom pager navigation
  namespace: "rslides",   // String: Change the default namespace used
  before: function(){},   // Function: Before callback
  after: function(){}     // Function: After callback
});

// FAQ-related js
$('.js-faq-trigger').click(function(e) {
  // Grab current anchor value
  var currentAttrValue = $(this).attr('href');
  // Open up the hidden content panel
  $(currentAttrValue).toggleClass('display-none');

  e.preventDefault();
});

// Snipcart-related js

// Show button to continue shopping
Snipcart.api.configure('show_continue_shopping', true);

// Display shipping options based on customer address

var euCountries = [ "AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE",
  "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "GB" ]

function setSnipcartShippingMethods(address) {
  if (address.country == "DE") {
    Snipcart.api.configure('allowed_shipping_methods', ['germany']);
  }
  else if ($.inArray(address.country, euCountries) > -1) {
    Snipcart.api.configure('allowed_shipping_methods', ['eu']);
  }
  else {
    Snipcart.api.configure('allowed_shipping_methods', ['worldwide']);
  }
}

Snipcart.subscribe('billingaddress.changed', function (address) {
  if (address.shippingSameAsBilling) {
    setSnipcartShippingMethods(address);
  }
});

Snipcart.subscribe('shippingaddress.changed', function (address) {
  setSnipcartShippingMethods(address);
});

Snipcart.subscribe('cart.ready', function (cart) {
  if (cart.order) {
    setSnipcartShippingMethods(cart.order.shippingAddress);
  }
});
<commit_msg>Use slideToggle instead of toggleClass<commit_after> // Responsive navigation settings
var nav = responsiveNav(".nav-collapse", {
  customToggle: "nav-toggle",
  closeOnNavClick: true,
  openPos: "static"
});

// Hook up and configure responsive slides plugin

$(".rslides").responsiveSlides({
  auto: false,             // Boolean: Animate automatically, true or false
  // speed: 500,            // Integer: Speed of the transition, in milliseconds
  // timeout: 4000,          // Integer: Time between slide transitions, in milliseconds
  pager: true,           // Boolean: Show pager, true or false
  nav: false,             // Boolean: Show navigation, true or false
  random: false,          // Boolean: Randomize the order of the slides, true or false
  pause: false,           // Boolean: Pause on hover, true or false
  pauseControls: true,    // Boolean: Pause when hovering controls, true or false
  prevText: "Previous",   // String: Text for the "previous" button
  nextText: "Next",       // String: Text for the "next" button
  maxwidth: "",           // Integer: Max-width of the slideshow, in pixels
  navContainer: "",       // Selector: Where controls should be appended to, default is after the 'ul'
  manualControls: "",     // Selector: Declare custom pager navigation
  namespace: "rslides",   // String: Change the default namespace used
  before: function(){},   // Function: Before callback
  after: function(){}     // Function: After callback
});

// FAQ-related js
$('.js-faq-trigger').click(function(e) {
  // Grab current anchor value
  var currentAttrValue = $(this).attr('href');
  // Open up the hidden content panel
  $(currentAttrValue).slideToggle('fast');
  e.preventDefault();
});

// Snipcart-related js

// Show button to continue shopping
Snipcart.api.configure('show_continue_shopping', true);

// Display shipping options based on customer address

var euCountries = [ "AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE",
  "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE", "GB" ]

function setSnipcartShippingMethods(address) {
  if (address.country == "DE") {
    Snipcart.api.configure('allowed_shipping_methods', ['germany']);
  }
  else if ($.inArray(address.country, euCountries) > -1) {
    Snipcart.api.configure('allowed_shipping_methods', ['eu']);
  }
  else {
    Snipcart.api.configure('allowed_shipping_methods', ['worldwide']);
  }
}

Snipcart.subscribe('billingaddress.changed', function (address) {
  if (address.shippingSameAsBilling) {
    setSnipcartShippingMethods(address);
  }
});

Snipcart.subscribe('shippingaddress.changed', function (address) {
  setSnipcartShippingMethods(address);
});

Snipcart.subscribe('cart.ready', function (cart) {
  if (cart.order) {
    setSnipcartShippingMethods(cart.order.shippingAddress);
  }
});
<|endoftext|>


<commit_before>(function () {
  'use strict';

  var SPACE_PRESSED;
  var body = document.body;
  var startButton = document.querySelector('.startButton');
  var placeholder = document.querySelectorAll('.hackered');

  var enableFullscreen = function (element) {
    if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen();
    }
  };

  var enterHackerMode = function () {
    enableFullscreen(document.documentElement);
    startButton.classList.add('hidden');
    body.classList.add('hacker-mode');

    Array.prototype.forEach.call(placeholder, function (element) {
      var text = element.dataset.text.split('');

      setTimeout(function () {
        element.classList.remove('hidden');
        startTyping(0, element, text);
      }, 3000);
    });
  };

  var startTyping = function (index, placeholder, text) {
    if (index < text.length) {

      var writeLetter = function () {
        if (text[index] === '\n') {
          placeholder.innerHTML += '

';
          index++;
        } else {
          placeholder.innerHTML += text[index++];
        }

        startTyping(index, placeholder, text);
      };

      if (SPACE_PRESSED === true) {
        window.clearTimeout(addLetter);
        window.addLetter = setTimeout(writeLetter, randomizeTimeout(50, 100));
      } else if (SPACE_PRESSED === false) {
        window.clearTimeout(addLetter);
        window.addLetter = setTimeout(writeLetter, randomizeTimeout(10, 20));
      } else {
        window.addLetter = setTimeout(writeLetter, randomizeTimeout(50, 100));
      }
    } else {
      body.classList.add('typing-ended');
    }
  };

  var randomizeTimeout = function (minValue, maxValue) {
    return Math.floor(Math.random() * (maxValue - minValue + 1) + minValue);
  };

  document.addEventListener('keydown', function(event) {
    if (event.keyCode === 32) {
      SPACE_PRESSED = false;
    }
  });

  document.addEventListener('keyup', function(event) {
    if (event.keyCode === 32) {
      SPACE_PRESSED = true;
    }
  });

  startButton.addEventListener('click', enterHackerMode);

})();<commit_msg>Unnecessary equal to true<commit_after>(function () {
  'use strict';

  var SPACE_PRESSED;
  var body = document.body;
  var startButton = document.querySelector('.startButton');
  var placeholder = document.querySelectorAll('.hackered');

  var enableFullscreen = function (element) {
    if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen();
    }
  };

  var enterHackerMode = function () {
    enableFullscreen(document.documentElement);
    startButton.classList.add('hidden');
    body.classList.add('hacker-mode');

    Array.prototype.forEach.call(placeholder, function (element) {
      var text = element.dataset.text.split('');

      setTimeout(function () {
        element.classList.remove('hidden');
        startTyping(0, element, text);
      }, 3000);
    });
  };

  var startTyping = function (index, placeholder, text) {
    if (index < text.length) {

      var writeLetter = function () {
        if (text[index] === '\n') {
          placeholder.innerHTML += '

';
          index++;
        } else {
          placeholder.innerHTML += text[index++];
        }

        startTyping(index, placeholder, text);
      };

      if (SPACE_PRESSED) {
        window.clearTimeout(addLetter);
        window.addLetter = setTimeout(writeLetter, randomizeTimeout(50, 100));
      } else if (SPACE_PRESSED === false) {
        window.clearTimeout(addLetter);
        window.addLetter = setTimeout(writeLetter, randomizeTimeout(10, 20));
      } else {
        window.addLetter = setTimeout(writeLetter, randomizeTimeout(50, 100));
      }
    } else {
      body.classList.add('typing-ended');
    }
  };

  var randomizeTimeout = function (minValue, maxValue) {
    return Math.floor(Math.random() * (maxValue - minValue + 1) + minValue);
  };

  document.addEventListener('keydown', function(event) {
    if (event.keyCode === 32) {
      SPACE_PRESSED = false;
    }
  });

  document.addEventListener('keyup', function(event) {
    if (event.keyCode === 32) {
      SPACE_PRESSED = true;
    }
  });

  startButton.addEventListener('click', enterHackerMode);

})();<|endoftext|>


<commit_before>'use strict';

var tube = angular.module("tube", ['ngRoute', 'ab-base64']);

tube.config(function($routeProvider, $httpProvider) {
  $routeProvider.when('/devices', { templateUrl: 'templates/devices/index.html', controller:'DeviceCtrl'});
  $routeProvider.when('/devices/:udid', { templateUrl: 'templates/devices/show.html', controller:'DeviceDetailCtrl' });
  $routeProvider.otherwise({redirectTo: '/devices'});

  // $httpProvider.defaults.useXDomain = true;
  // delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

// Config constant
tube.constant('servicesConfig', (function(){
  return {
    demoService: "http://qcasting.qgenius.com",
    playerPath : "../player/sewise.player.min.js"
  }
})());<commit_msg>Change player path<commit_after>'use strict';

var tube = angular.module("tube", ['ngRoute', 'ab-base64']);

tube.config(function($routeProvider, $httpProvider) {
  $routeProvider.when('/devices', { templateUrl: 'templates/devices/index.html', controller:'DeviceCtrl'});
  $routeProvider.when('/devices/:udid', { templateUrl: 'templates/devices/show.html', controller:'DeviceDetailCtrl' });
  $routeProvider.otherwise({redirectTo: '/devices'});

  // $httpProvider.defaults.useXDomain = true;
  // delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

// Config constant
tube.constant('servicesConfig', (function(){
  return {
    demoService: "http://qcasting.qgenius.com",
    playerPath : "/qcasting/player/sewise.player.min.js"
  }
})());<|endoftext|>


<commit_before>import Em from 'ember';
import { defaultValue } from 'llama-table/computed';
var makeArray = Em.makeArray;
var computed = Em.computed;
var alias = computed.alias;
var reads = computed.reads;

/**
 * Adds some extra properties to row definitions.
 * @module controllers
 * @constructor
 * @class RowController
 * @extends Ember.ObjectProxy
 */
var RowController = Em.ObjectProxy.extend({
	contentIndex: computed('parentController.[]', function () {
		var array = this.get('parentController');
		var content = this;
		var index = makeArray(array).indexOf(content);
		return index;
	}),
	isExpanded: false,
	height: defaultValue('content.height', 30),
	subcontentHeight: reads('height')
});

export default RowController;
<commit_msg>Re-aliased row content to model<commit_after>import Em from 'ember';
import { defaultValue } from 'llama-table/computed';
var makeArray = Em.makeArray;
var computed = Em.computed;
var alias = computed.alias;
var reads = computed.reads;

/**
 * Adds some extra properties to row definitions.
 * @module controllers
 * @constructor
 * @class RowController
 * @extends Ember.ObjectProxy
 */
var RowController = Em.ObjectProxy.extend({
	content: alias('model'),
	contentIndex: computed('parentController.[]', function () {
		var array = this.get('parentController');
		var content = this;
		var index = makeArray(array).indexOf(content);
		return index;
	}),
	isExpanded: false,
	height: defaultValue('content.height', 30),
	subcontentHeight: reads('height')
});

export default RowController;
<|endoftext|>