<commit_before>/*
	InputMagic v0.1.0
	https://github.com/ideasmashup/input-magic

	By William ANGER, ISC License, July 2014
*/

(function($, window, document, undefined){

	var $input = null;
	var firstpress = -1, lastpress = +new Date(), typespeed = -1, count = 0;
	var enable_autocomplete = false;

	// @Bobince: http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript/3561711#3561711
	function RegExp_escape(str) {
		return (str !== undefined)? str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') : '';
	}

	if (!String.prototype.trim) {
		String.prototype.trim = function (pattern) {
			if (pattern == undefined) pattern = /^\s+|\s+$/g;
			return this.replace(pattern, ''); //"\t\n\r\0\x0B."
		};
	}

	if (!String.prototype.remove) {
		String.prototype.remove = function(str) {
			var re = (typeof str == 'string')? str : new RegExp(str, 'g');
			return this.replace(re, '');
		};
	}

	if (!String.prototype.localeCompare) {
		String.prototype.localeCompare = function(str, locale, options) {
			return ((this == str) ? 0 : ((this > str) ? 1 : -1));
		};
	}

	//special post-keypress behaviors
	function after_keypress() {

		// do nothing until user types more stuff
		//if (lastpress == firstpress) return;

		var pausedelay = +new Date() - lastpress;
		//console.log('paused for '+ pausedelay);

		if (pausedelay < 500) {
			// last keypress very close : do nothing
			// because user is probably still typing stuff...

			// interrupt tasks
		}
		else if (pausedelay > 1000) {
			// last keypress was long ago
			// check email harder with a server validation request

			// indicate task in progress

			// animate avatar
			state = 'hey';
			loops = 0;
		}
		else {
			// last keypress moderately close
			// user not typing but may type again soon...
		}

		// do some basic autocompletion and checking
		email_range_autocomplete($input);
	}
	/*
		Validation state
	 */

	function state_change(state) {
		console.log('state_change = '+ state);
	}

	function input_state(name, state, completeness) {
		var $input = $('input{name='+name+']');

	}

	/*
		Form handling
	*/

	function caret($input, value) {
		var input = $input.get();
		var pos = 0;

		$input.focus();

		if (value === undefined) {
			// fetch caret position

			if (input.createTextRange) {
				var range = document.selection.createRange();
				range.moveStart('character', -$input.val().length);
				pos = range.text.length;
			}
			else if (input.selectionStart !== undefined) {
				pos = input.selectionStart;
			}

			return pos;
		}
		else {
			// set caret position
			range_create($input, value, value);
		}
	}

	function range_create($input, start, end) {
		var input = $input[0];

		if (input.createTextRange) {
			var range = input.createTextRange();
			range.collapse(true);
			range.moveStart('character', start);
			range.moveEnd('character', end);
			range.select();
		}
		else if (input.setSelectionRange) {
			input.setSelectionRange(start, end);
		}
	}

	function range_append_hint($input, hint) {
		var input = $input.get();
		var text = $input.val().trim(RegExp_escape(hint));

		$input.val(text + hint);
		$input.data('hint', hint);
		range_create($input, text.length, text.length + hint.length);
	}

	function range_autocomplete($input) {
		// complete only when caret is at value end

	}

	/*
		Email processing
	*/

	function cmp_str(a, b) {
		return a.localCompare(b);
	}

	var ADJS = ['amazing','blithesome','charismatic','decisive','excellent',
	            'fantastical','great','heroic','incredible','jolly','kickstarter',
	            'light','magical','nice','outstanding','perfect','quality',
	            'remarkable','smart','thrilling','ultimate','vibrant','wondrous','xylophone','yes_we_can','zippy'];
	var DOMS = ['hotmail','live','yahoo','gmail','orange','aol','free','numericable'];
	var EXTS = ['com','fr','eu','org','us','net','io'];

	function complete(str, suggest_arr, max_results, offset, suffix) {
		var results = [];
		if (max_results === undefined) max_results = 1;
		if (suffix === undefined) suffix = '';

		for (var i=0; i<suggest_arr.length; i++) {
			if (results < max_results) {
				if (suggest_arr[i].substring(0, str.length) == str) {
					results.push(offset? suggest_arr[i].substr(str.length) + suffix : suggest_arr[i] + suffix);
				}
			}
			else break;
		}

		// return array or single value
		if (results.length == 0) {
			// no match found
			return (max_results == 1) ? suffix : [suffix];
		}
		else {
			// found a match (or more)
			return (max_results == 1) ? results[0] : results;
		}
	}

	function email_range_autocomplete($input) {
		var value = $input.val();
		var text = value.trim(RegExp_escape($input.data('hint')));
		var len = text.length;
		var hint = '';
		var completeness = Math.min(text.length / 14, 1);

		console.log('input='+ text +' ( '+ (completeness*100) +'% )');

		if (text.length < 2) {
			// no completion yet...
			state_change('incomplete');
		}

		// complete with "best guesses" (or "motivationnal" words)
		if (text.indexOf('@') == -1) {
			if (text.length > 0) {
				hint = complete(text, ADJS, 1, true, '@');
			}
		}
		else {
			if (text.charAt(text.length - 1) != '@') {
				var parts = text.split('@', 2);
				var bef = parts[0];
				var aft = parts[1];

				if (aft.indexOf('.') == -1) {
					hint = complete(aft, DOMS, 1, true, '.');
					state_change('incomplete');
				}
				else {
					var tmp = aft.split('.', 2);
					var host = tmp[0];
					var ext = tmp[1];

					if (aft.charAt(aft.length - 1) !== '.') {
						if (ext.length > 2) {
							state_change('complete');
						}
						else {
							hint = complete(ext, EXTS, 1, true);
							state_change('partial');
						}
					}
					else {
						// no hint
					}

					// no hint
				}
			}
			else {
				// no hint
			}
		}

		if (hint.length > 0) {
			// only suggest non-empty strings
			range_append_hint($input, hint);
		}
		else {
			$input.data('hint', '');
		}
	}

	function is_email(email) {
		// Test for the minimum length the email can be
		if (email.length < 3) {
			console.log('email_too_short');
			return false;
		}

		// Test for an @ character after the first position
		if (email.indexOf('@', 1) === -1) {
			console.log('email_no_at');
			return false;
		}

		// Split out the local and domain parts
		var parts = email.split('@', 2);
		var local = parts[0];
		var domain = parts[1];

		// LOCAL PART
		// Test for invalid characters
		if (!new RegExp('^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$').test(local)) {
			console.log('local_invalid_chars');
			return false;
		}

		// DOMAIN PART
		// Test for sequences of periods
		if (new RegExp('\\.{2,}').exec(domain) !== null) {
			console.log('domain_period_sequence '+ new RegExp('\\.{2,}').exec(domain).toSource());
			return false;
		}

		// Test for leading and trailing periods and whitespace
		if (domain.trim() !== domain) {
			console.log('domain_period_limits');
			return false;
		}

		// Split the domain into subs
		var subs = domain.split('.');

		// Assume the domain will have at least two subs
		if (subs.length < 2) {
			console.log('domain_no_periods');
			return false;
		}

		// Loop through each sub
		for (sub in subs) {
			// Test for leading and trailing hyphens and whitespace
			if (sub.trim() !== sub) {
				console.log('sub_hyphen_limits');
				return false;
			}

			// Test for invalid characters
			if (!new RegExp('^[a-z0-9-]+$', 'i').test(sub)) {
				console.log('sub_invalid_chars');
				return false;
			}
		}

		// Congratulations your email made it!
		console.log('valid_email');
		return true;
	}

	function email_deep_check(str) {
		// validate and verify on server
	}

	function input_magic(name) {
		$input = $('input[name='+name+']');

		$input.keydown(function(e){
			var keycode = (e.keyCode ? e.keyCode : e.which);
			var now = +new Date();

			// typing text
			if (count++ == 0) {
				firstpress = now;
				typespeed = 3000;
			}
			else {
				lastpress = now;
				typespeed = (typespeed + (now - lastpress)) / 2;
			}

			// codes ref : http://www.quirksmode.org/js/keys.html
			console.log("pressing "+ keycode);

			if (keycode == 13) {
				// enter pressed : submit value (?)
				log.console('enter pressed... submit?');

				$input.data('hint', '');
				enable_autocomplete = false;
			}
			else if (keycode == 8 || keycode == 46) {
				// backspace or suppr : show hint again
				enable_autocomplete = false;
			}
			else if (keycode < 32) {
				// non-printable character : clear hint
				$input.data('hint', '');
				enable_autocomplete = false;
			}
			else if (keycode >= 33 && keycode <= 40) {
				// arrows keys (home, end, pgup, pgdwn, etc) : clear hint
				$input.data('hint', '');
				enable_autocomplete = true;
			}
			else {
				// printable characters : typing text so stop checking
				enable_autocomplete = true;
			}

			if (enable_autocomplete) {
				// do autocomplete
				setTimeout(function(){email_range_autocomplete($input)}, 10);
				enable_autocomplete = false;
			}
		});
	}

	window.input_magic = input_magic;
})(jQuery, window, document);
<commit_msg>(wip) more jquery "pluginization", new init() fn and $(selector).inputMagic()<commit_after>/*
	InputMagic v0.1.0
	https://github.com/ideasmashup/input-magic

	By William ANGER, ISC License, July 2014
*/

(function($, window, document, undefined){

	var $input = null;
	var firstpress = -1, lastpress = +new Date(), typespeed = -1, count = 0;

	// Create the defaults once
	var pluginName = 'inputMagic', defaults = {
		propertyName : "value"
	};

	// The actual plugin constructor
	function Plugin(element, options) {
		this.element = element;
		this.options = $.extend({}, defaults, options);

		this._defaults = defaults;
		this._name = pluginName;

		this.init();
	}

	Plugin.prototype.init = function() {
		// Place initialization logic here
		// this.element
		// this.options

		var $elt = $(this.element);
		var enable_autocomplete = false;

		$elt.keydown(function(e){
			var keycode = (e.keyCode ? e.keyCode : e.which);
			var now = +new Date();

			// typing text
			if (count++ == 0) {
				firstpress = now;
				typespeed = 3000;
			}
			else {
				lastpress = now;
				typespeed = (typespeed + (now - lastpress)) / 2;
			}

			// codes ref : http://www.quirksmode.org/js/keys.html
			console.log("pressing "+ keycode);

			if (keycode == 13) {
				// enter pressed : submit value (?)
				log.console('enter pressed... submit?');

				$elt.data('hint', '');
				enable_autocomplete = false;
			}
			else if (keycode == 8 || keycode == 46) {
				// backspace or suppr : show hint again
				enable_autocomplete = false;
			}
			else if (keycode < 32) {
				// non-printable character : clear hint
				$elt.data('hint', '');
				enable_autocomplete = false;
			}
			else if (keycode >= 33 && keycode <= 40) {
				// arrows keys (home, end, pgup, pgdwn, etc) : clear hint
				$elt.data('hint', '');
				enable_autocomplete = true;
			}
			else {
				// printable characters : typing text so stop checking
				enable_autocomplete = true;
			}

			if (enable_autocomplete) {
				// do autocomplete
				setTimeout(function(){email_range_autocomplete($elt)}, 10);
				enable_autocomplete = false;
			}
		});
	};

	// A really lightweight plugin wrapper around the constructor,
	// preventing against multiple instantiations
	$.fn[pluginName] = function(options) {
		return this
			.each(function() {
				if (!$.data(this, 'plugin_' + pluginName)) {
					$.data(this, 'plugin_' + pluginName, new Plugin(this,
							options));
				}
			});
	}

	// @Bobince:
	// http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript/3561711#3561711
	function RegExp_escape(str) {
		return (str !== undefined)? str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') : '';
	}

	if (!String.prototype.trim) {
		String.prototype.trim = function (pattern) {
			if (pattern == undefined) pattern = /^\s+|\s+$/g;
			return this.replace(pattern, ''); //"\t\n\r\0\x0B."
		};
	}

	if (!String.prototype.remove) {
		String.prototype.remove = function(str) {
			var re = (typeof str == 'string')? str : new RegExp(str, 'g');
			return this.replace(re, '');
		};
	}

	if (!String.prototype.localeCompare) {
		String.prototype.localeCompare = function(str, locale, options) {
			return ((this == str) ? 0 : ((this > str) ? 1 : -1));
		};
	}

	//special post-keypress behaviors
	function after_keypress() {

		// do nothing until user types more stuff
		//if (lastpress == firstpress) return;

		var pausedelay = +new Date() - lastpress;
		//console.log('paused for '+ pausedelay);

		if (pausedelay < 500) {
			// last keypress very close : do nothing
			// because user is probably still typing stuff...

			// interrupt tasks
		}
		else if (pausedelay > 1000) {
			// last keypress was long ago
			// check email harder with a server validation request

			// indicate task in progress

			// animate avatar
			state = 'hey';
			loops = 0;
		}
		else {
			// last keypress moderately close
			// user not typing but may type again soon...
		}

		// do some basic autocompletion and checking
		email_range_autocomplete($input);
	}
	/*
		Validation state
	 */

	function state_change(state) {
		console.log('state_change = '+ state);
	}

	function input_state(name, state, completeness) {
		var $input = $('input{name='+name+']');

	}

	/*
		Form handling
	*/

	function caret($input, value) {
		var input = $input.get();
		var pos = 0;

		$input.focus();

		if (value === undefined) {
			// fetch caret position

			if (input.createTextRange) {
				var range = document.selection.createRange();
				range.moveStart('character', -$input.val().length);
				pos = range.text.length;
			}
			else if (input.selectionStart !== undefined) {
				pos = input.selectionStart;
			}

			return pos;
		}
		else {
			// set caret position
			range_create($input, value, value);
		}
	}

	function range_create($input, start, end) {
		var input = $input[0];

		if (input.createTextRange) {
			var range = input.createTextRange();
			range.collapse(true);
			range.moveStart('character', start);
			range.moveEnd('character', end);
			range.select();
		}
		else if (input.setSelectionRange) {
			input.setSelectionRange(start, end);
		}
	}

	function range_append_hint($input, hint) {
		var input = $input.get();
		var text = $input.val().trim(RegExp_escape(hint));

		$input.val(text + hint);
		$input.data('hint', hint);
		range_create($input, text.length, text.length + hint.length);
	}

	function range_autocomplete($input) {
		// complete only when caret is at value end

	}

	/*
		Email processing
	*/

	function cmp_str(a, b) {
		return a.localCompare(b);
	}

	var ADJS = ['amazing','blithesome','charismatic','decisive','excellent',
	            'fantastical','great','heroic','incredible','jolly','kickstarter',
	            'light','magical','nice','outstanding','perfect','quality',
	            'remarkable','smart','thrilling','ultimate','vibrant','wondrous','xylophone','yes_we_can','zippy'];
	var DOMS = ['hotmail','live','yahoo','gmail','orange','aol','free','numericable'];
	var EXTS = ['com','fr','eu','org','us','net','io'];

	function complete(str, suggest_arr, max_results, offset, suffix) {
		var results = [];
		if (max_results === undefined) max_results = 1;
		if (suffix === undefined) suffix = '';

		for (var i=0; i<suggest_arr.length; i++) {
			if (results < max_results) {
				if (suggest_arr[i].substring(0, str.length) == str) {
					results.push(offset? suggest_arr[i].substr(str.length) + suffix : suggest_arr[i] + suffix);
				}
			}
			else break;
		}

		// return array or single value
		if (results.length == 0) {
			// no match found
			return (max_results == 1) ? suffix : [suffix];
		}
		else {
			// found a match (or more)
			return (max_results == 1) ? results[0] : results;
		}
	}

	function email_range_autocomplete($input) {
		var value = $input.val();
		var text = value.trim(RegExp_escape($input.data('hint')));
		var len = text.length;
		var hint = '';
		var completeness = Math.min(text.length / 14, 1);

		console.log('input='+ text +' ( '+ (completeness*100) +'% )');

		if (text.length < 2) {
			// no completion yet...
			state_change('incomplete');
		}

		// complete with "best guesses" (or "motivationnal" words)
		if (text.indexOf('@') == -1) {
			if (text.length > 0) {
				hint = complete(text, ADJS, 1, true, '@');
			}
		}
		else {
			if (text.charAt(text.length - 1) != '@') {
				var parts = text.split('@', 2);
				var bef = parts[0];
				var aft = parts[1];

				if (aft.indexOf('.') == -1) {
					hint = complete(aft, DOMS, 1, true, '.');
					state_change('incomplete');
				}
				else {
					var tmp = aft.split('.', 2);
					var host = tmp[0];
					var ext = tmp[1];

					if (aft.charAt(aft.length - 1) !== '.') {
						if (ext.length > 2) {
							state_change('complete');
						}
						else {
							hint = complete(ext, EXTS, 1, true);
							state_change('partial');
						}
					}
					else {
						// no hint
					}

					// no hint
				}
			}
			else {
				// no hint
			}
		}

		if (hint.length > 0) {
			// only suggest non-empty strings
			range_append_hint($input, hint);
		}
		else {
			$input.data('hint', '');
		}
	}

	function is_email(email) {
		// Test for the minimum length the email can be
		if (email.length < 3) {
			console.log('email_too_short');
			return false;
		}

		// Test for an @ character after the first position
		if (email.indexOf('@', 1) === -1) {
			console.log('email_no_at');
			return false;
		}

		// Split out the local and domain parts
		var parts = email.split('@', 2);
		var local = parts[0];
		var domain = parts[1];

		// LOCAL PART
		// Test for invalid characters
		if (!new RegExp('^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$').test(local)) {
			console.log('local_invalid_chars');
			return false;
		}

		// DOMAIN PART
		// Test for sequences of periods
		if (new RegExp('\\.{2,}').exec(domain) !== null) {
			console.log('domain_period_sequence '+ new RegExp('\\.{2,}').exec(domain).toSource());
			return false;
		}

		// Test for leading and trailing periods and whitespace
		if (domain.trim() !== domain) {
			console.log('domain_period_limits');
			return false;
		}

		// Split the domain into subs
		var subs = domain.split('.');

		// Assume the domain will have at least two subs
		if (subs.length < 2) {
			console.log('domain_no_periods');
			return false;
		}

		// Loop through each sub
		for (sub in subs) {
			// Test for leading and trailing hyphens and whitespace
			if (sub.trim() !== sub) {
				console.log('sub_hyphen_limits');
				return false;
			}

			// Test for invalid characters
			if (!new RegExp('^[a-z0-9-]+$', 'i').test(sub)) {
				console.log('sub_invalid_chars');
				return false;
			}
		}

		// Congratulations your email made it!
		console.log('valid_email');
		return true;
	}

	function email_deep_check(str) {
		// validate and verify on server
	}

})(jQuery, window, document);
<|endoftext|>


<commit_before>import uniq from 'lodash/uniq';
import flatMap from 'lodash/flatMap';
import isEmpty from 'lodash/isEmpty';

const expandRegionToCountries = (iso, regions) => {
  const region = regions.find(r => r.iso_code3 === iso);
  if (!region || !region.members) return iso;
  return flatMap(region.members, expandRegionToCountries);
};

const expandRegionsToCountries = (isos, regions) =>
  uniq(flatMap(isos, iso => expandRegionToCountries(iso, regions)));

export const getMetricData = (
  year,
  column,
  metricField,
  calculationData,
  regions
) => {
  const getMetricForYearAndRegion = (y, r) =>
    metricField &&
    calculationData &&
    calculationData[y] &&
    calculationData[y][r] &&
    calculationData[y][r][metricField];
  let metricData = getMetricForYearAndRegion(year, column.iso_code3);
  // if no metric data for expandable column then use expanded regions to
  // calculate metric data
  if (!metricData && column.expandsTo && column.expandsTo.length) {
    const expandedCountries = expandRegionsToCountries(
      column.expandsTo,
      regions
    );
    metricData = expandedCountries.reduce(
      (acc, iso3) => acc + (getMetricForYearAndRegion(year, iso3) || 0),
      0
    );
  }

  // GDP is in dollars and we want to display it in million dollars
  if (metricField === 'gdp' && metricData) metricData /= 1000000;

  return metricData;
};

// some regions expands to underlying countries but also have
// their own aggregated data
export const getRegionsWithOwnData = (regions, data) => {
  if (!regions || isEmpty(data)) return [];

  const regionsISOs = regions.map(r => r.iso_code3);
  const regionsISOsWithOwnData = uniq(
    data.filter(d => regionsISOs.includes(d.iso_code3)).map(d => d.iso_code3)
  );

  return regions.filter(r => regionsISOsWithOwnData.includes(r.iso_code3));
};
<commit_msg>Fix iso param<commit_after>import uniq from 'lodash/uniq';
import flatMap from 'lodash/flatMap';
import isEmpty from 'lodash/isEmpty';

const expandRegionToCountries = (iso, regions) => {
  const region = regions.find(r => r.iso_code3 === iso);
  if (!region || !region.members) return iso;
  return flatMap(region.members, expandRegionToCountries);
};

const expandRegionsToCountries = (isos, regions) =>
  uniq(flatMap(isos, iso => expandRegionToCountries(iso, regions)));

export const getMetricData = (
  year,
  column,
  metricField,
  calculationData,
  regions
) => {
  const getMetricForYearAndRegion = (y, r) =>
    metricField &&
    calculationData &&
    calculationData[y] &&
    calculationData[y][r] &&
    calculationData[y][r][metricField];
  let metricData = getMetricForYearAndRegion(year, column.iso);
  // if no metric data for expandable column then use expanded regions to
  // calculate metric data
  if (!metricData && column.expandsTo && column.expandsTo.length) {
    const expandedCountries = expandRegionsToCountries(
      column.expandsTo,
      regions
    );
    metricData = expandedCountries.reduce(
      (acc, iso3) => acc + (getMetricForYearAndRegion(year, iso3) || 0),
      0
    );
  }

  // GDP is in dollars and we want to display it in million dollars
  if (metricField === 'gdp' && metricData) metricData /= 1000000;

  return metricData;
};

// some regions expands to underlying countries but also have
// their own aggregated data
export const getRegionsWithOwnData = (regions, data) => {
  if (!regions || isEmpty(data)) return [];

  const regionsISOs = regions.map(r => r.iso_code3);
  const regionsISOsWithOwnData = uniq(
    data.filter(d => regionsISOs.includes(d.iso_code3)).map(d => d.iso_code3)
  );

  return regions.filter(r => regionsISOsWithOwnData.includes(r.iso_code3));
};
<|endoftext|>


<commit_before>/* eslint-disable no-console */
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

const distPath = path.resolve('dist');
const files = fs
  .readdirSync(distPath)
  .filter(
    dist =>
      dist.indexOf('map') === -1 &&
      dist.indexOf('react-platform') === -1,
  );

function execPromise(cmd) {
  return new Promise(resolve => exec(cmd, resolve));
}

async function testBuilds() {
  await Promise.all[
    files.map(async file => {
      const err = await execPromise(`BUNDLE=${file} npm run test`);
      if (err) {
        console.error('\x1b[31m', `Error in ${file}`, '\x1b[30m');
        console.error(err);
        process.exit(1);
      } else {
        console.log(`${file} works as expected`);
      }
    })
  ];
}

testBuilds();
<commit_msg>refactor(lint): fix testBuilds<commit_after>/* eslint-disable no-console */
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

const distPath = path.resolve('dist');
const files = fs
  .readdirSync(distPath)
  .filter(
    dist =>
      dist.indexOf('map') === -1 &&
      dist.indexOf('react-platform') === -1,
  );

function execPromise(cmd) {
  return new Promise(resolve => exec(cmd, resolve));
}

async function testBuilds() {
  // eslint-disable-next-line no-restricted-syntax
  for (const file of files) {
    // eslint-disable-next-line no-await-in-loop
    const err = await execPromise(`BUNDLE=${file} npm run test`);
    if (err) {
      console.error('\x1b[31m', `Error in ${file}`, '\x1b[30m');
      console.error(err);
      process.exit(1);
    } else {
      console.log(`${file} works as expected`);
    }
  }
}

testBuilds();
<|endoftext|>


<commit_before>/**
 * Rich Text Editor
 */
'use strict';

(function (document, CKEDITOR) {
    const cfg = {
        customConfig: '',
        disableNativeSpellChecker: true,
        extraAllowedContent: 'article section(*)',
        filebrowserBrowseUrl: '/file/browser',
        format_tags: 'p;h2;h3',
        height: '30rem',
        removeButtons: 'Cut,Copy,Paste,Undo,Redo,Anchor,Strike,Subscript,Superscript,Indent,Outdent',
        removeDialogTabs: 'link:advanced;link:target',
        stylesSet: false,
        toolbarGroups: [
            {name: 'document', groups: ['mode', 'document', 'doctools']},
            {name: 'clipboard', groups: ['clipboard', 'undo']},
            {name: 'editing', groups: ['find', 'selection', 'spellchecker']},
            {name: 'forms'},
            {name: 'styles'},
            {name: 'basicstyles', groups: ['basicstyles', 'cleanup']},
            {name: 'links'},
            {name: 'paragraph', groups: ['list', 'blocks', 'indent', 'align', 'bidi']},
            {name: 'insert'},
            {name: 'colors'},
            {name: 'tools'},
            {name: 'others'},
            {name: 'about'}
        ]
    };

    document.addEventListener('DOMContentLoaded', function () {
        Array.prototype.forEach.call(document.querySelectorAll('textarea[data-type=rte]'), function (item) {
            CKEDITOR.replace(item, cfg);
        });
    });
})(document, CKEDITOR);
<commit_msg>Reorder toolbar<commit_after>/**
 * Rich Text Editor
 */
'use strict';

(function (document, CKEDITOR) {
    const cfg = {
        customConfig: '',
        disableNativeSpellChecker: true,
        extraAllowedContent: 'article section(*)',
        filebrowserBrowseUrl: '/file/browser',
        format_tags: 'p;h2;h3',
        height: '30rem',
        removeDialogTabs: 'link:advanced;link:target',
        stylesSet: false,
        toolbar: [
            {name: 'clipboard', items: ['Undo', 'Redo']},
            {name: 'styles', items: ['Format']},
            {name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'RemoveFormat']},
            {name: 'links', items: ['Link', 'Unlink']},
            {name: 'paragraph', items: ['BulletedList', 'NumberedList', 'Blockquote']},
            {name: 'insert', items: ['Detail', 'Media', 'Table', 'HorizontalRule']},
            {name: 'tools', items: ['ShowBlocks']}
        ]
    };

    document.addEventListener('DOMContentLoaded', function () {
        Array.prototype.forEach.call(document.querySelectorAll('textarea[data-type=rte]'), function (item) {
            CKEDITOR.replace(item, cfg);
        });
    });
})(document, CKEDITOR);
<|endoftext|>


<commit_before>const gulp = require('gulp');
const gutil = require("gulp-util");
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const webpackConfig = require('./webpack.config.js');
const WebpackDevServer = require("webpack-dev-server");
const connect = require('gulp-connect');

gulp.task('riot', () => {
  return gulp.src('ui/index.js')
    .pipe(webpackStream(webpackConfig))
    .pipe(gulp.dest('ui/dist/'))
    .pipe(connect.reload());
});

gulp.task('riot:watch', ()=>{
  return gulp.watch(['ui/**/*.tag','ui/index.js','ui/router.js','ui/services/**/*.js'], ['riot']);
})

gulp.task('connect', function() {
  connect.server({
    root: 'ui',
    livereload: true
  });
});

gulp.task('dev', ['connect','riot:watch'], function() {
	gutil.log('done');
});
<commit_msg>fix gulp dev task<commit_after>const gulp = require('gulp');
const gutil = require("gulp-util");
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const webpackConfig = require('./webpack.config.js');
const WebpackDevServer = require("webpack-dev-server");
const connect = require('gulp-connect');

gulp.task('riot', () => {
  return gulp.src('ui/index.js')
    .pipe(webpackStream(webpackConfig))
    .pipe(gulp.dest('ui/dist/'))
    .pipe(connect.reload());
});

gulp.task('riot:watch', ()=>{
  return gulp.watch(['ui/**/*.tag','ui/index.js','ui/router.js','ui/services/**/*.js'], ['riot']);
})

gulp.task('connect', function() {
  connect.server({
    root: 'ui',
    livereload: true
  });
});

gulp.task('dev', ['riot','connect','riot:watch'], function() {
	gutil.log('done');
});
<|endoftext|>


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

  function addPropertyTo(target, methodName, value) {
    Object.defineProperty(target, methodName, {
      enumerable: false,
      configurable: false,
      writable: false,
      value: value
    });
  }

  function banProperty(target, methodName) {
    addPropertyTo(target, methodName, function() {
      throw new ImmutableError("The " + methodName +
        " method cannot be invoked on an ImmutableArray.");
    });
  }

  var immutabilityTag = "__immutable_invariants_hold";

  function addImmutabilityTag(target) {
    addPropertyTo(target, immutabilityTag, true);
  }

  function isImmutable(target) {
    if (typeof target === "object") {
      return target === null || target.hasOwnProperty(immutabilityTag);
    } else {
      // Only objects are even potentially mutable.
      return true;
    }
  }

  var mutatingObjectMethods = [
    "setPrototypeOf"
  ];

  var nonMutatingObjectMethods = [
    "keys"
  ];

  var mutatingArrayMethods = mutatingObjectMethods.concat([
    "push", "pop", "sort", "splice", "shift", "unshift", "reverse"
  ]);

  var nonMutatingArrayMethods = nonMutatingObjectMethods.concat([
    "map", "filter", "slice", "concat", "reduce", "reduceRight"
  ]);

  function ImmutableError() {}
  ImmutableError.prototype = Error.prototype;

  function makeImmutable(obj, bannedMethods) {
    // Make all mutating methods throw exceptions.
    for (var index in bannedMethods) {
      banProperty(obj, bannedMethods[index]);
    }

    // Tag it so we can quickly tell it's immutable later.
    addImmutabilityTag(obj);

    // Freeze it and return it.
    Object.freeze(obj);

    return obj;
  }

  function makeMethodReturnImmutable(obj, methodName) {
    var currentMethod = obj[methodName];

    addPropertyTo(obj, methodName, function() {
      return Immutable(currentMethod.apply(obj, arguments));
    })
  }

  function makeImmutableArray() {
    var result = [];

    // Populate the array before it gets frozen.
    for (var index in arguments) {
      result.push(Immutable(arguments[index]));
    }

    // Don't change their implementations, but wrap these functions to make sure
    // they always return an immutable value.
    for (var index in nonMutatingArrayMethods) {
      var methodName = nonMutatingArrayMethods[index];
      makeMethodReturnImmutable(result, methodName);
    }

    return makeImmutable(result, mutatingArrayMethods);
  }

  function makeImmutableObject(obj) {
    var result = {};

    // Populate the object before it gets frozen.
    switch (typeof obj) {
      case "object":
        if (obj !== null) {
          for (var key in obj) {
            result[key] = Immutable(obj[key]);
          }
        }
        break;
      case "undefined":
        // We're making an empty ImmutableMap. No problem.
        break;
      default:
        throw new TypeError(
          "ImmutableMap constructor does not accept an argument of type " +
          (typeof obj) + ".")
    }

    return makeImmutable(result, mutatingObjectMethods);
  }

  function Immutable(obj) {
    // If the user passes multiple arguments, assume what they want is an array.
    if (arguments.length > 1) {
      return makeImmutableArray.apply(makeImmutableArray, arguments);
    } else if (isImmutable(obj)) {
      return obj;
    } else if (obj instanceof Array) {
      return makeImmutableArray.apply(makeImmutableArray, obj);
    } else {
      return makeImmutableObject(obj);
    }
  }

  // Export the library
  Immutable.isImmutable    = isImmutable;
  Immutable.ImmutableError = ImmutableError;

  Object.freeze(Immutable);

  if (typeof module === "object") {
    module.exports = Immutable;
  } else if (typeof exports === "object") {
    exports.Immutable = Immutable;
  } else if (typeof window === "object") {
    window.Immutable = Immutable;
  } else if (typeof global === "object") {
    global.Immutable = Immutable;
  }
})();<commit_msg>Implement ImmutableObject#merge<commit_after>(function(){
  "use strict";

  function addPropertyTo(target, methodName, value) {
    Object.defineProperty(target, methodName, {
      enumerable: false,
      configurable: false,
      writable: false,
      value: value
    });
  }

  function banProperty(target, methodName) {
    addPropertyTo(target, methodName, function() {
      throw new ImmutableError("The " + methodName +
        " method cannot be invoked on an ImmutableArray.");
    });
  }

  var immutabilityTag = "__immutable_invariants_hold";

  function addImmutabilityTag(target) {
    addPropertyTo(target, immutabilityTag, true);
  }

  function isImmutable(target) {
    if (typeof target === "object") {
      return target === null || target.hasOwnProperty(immutabilityTag);
    } else {
      // Only objects are even potentially mutable.
      return true;
    }
  }

  var mutatingObjectMethods = [
    "setPrototypeOf"
  ];

  var nonMutatingObjectMethods = [
    "keys"
  ];

  var mutatingArrayMethods = mutatingObjectMethods.concat([
    "push", "pop", "sort", "splice", "shift", "unshift", "reverse"
  ]);

  var nonMutatingArrayMethods = nonMutatingObjectMethods.concat([
    "map", "filter", "slice", "concat", "reduce", "reduceRight"
  ]);

  function ImmutableError() {}
  ImmutableError.prototype = Error.prototype;

  function makeImmutable(obj, bannedMethods) {
    // Make all mutating methods throw exceptions.
    for (var index in bannedMethods) {
      banProperty(obj, bannedMethods[index]);
    }

    // Tag it so we can quickly tell it's immutable later.
    addImmutabilityTag(obj);

    // Freeze it and return it.
    Object.freeze(obj);

    return obj;
  }

  function makeMethodReturnImmutable(obj, methodName) {
    var currentMethod = obj[methodName];

    addPropertyTo(obj, methodName, function() {
      return Immutable(currentMethod.apply(obj, arguments));
    })
  }

  function makeImmutableArray() {
    var result = [];

    // Populate the array before it gets frozen.
    for (var index in arguments) {
      result.push(Immutable(arguments[index]));
    }

    // Don't change their implementations, but wrap these functions to make sure
    // they always return an immutable value.
    for (var index in nonMutatingArrayMethods) {
      var methodName = nonMutatingArrayMethods[index];
      makeMethodReturnImmutable(result, methodName);
    }

    return makeImmutable(result, mutatingArrayMethods);
  }

  function merge(other) {
    if (arguments.length > 0) {
      var merged = {};

      for (var key in this) {
        merged[key] = this[key];
      }

      // Prioritize the other objects in the order in which they were passed.
      for (var index in arguments) {
        var other = arguments[index];

        for (var key in other) {
          merged[key] = other[key];
        }
      }

      return makeImmutableObject(merged);
    } else {
      // Calling .merge() with no arguments is a no-op. Don't bother cloning.
      return this;
    }
  };

  // Finalizes an object with immutable methods, freezes it, and returns it.
  function makeImmutableObject(obj) {
    addPropertyTo(obj, "merge", merge);

    return makeImmutable(obj, mutatingObjectMethods);
  }

  function Immutable(obj) {
    // If the user passes multiple arguments, assume what they want is an array.
    if (arguments.length > 1) {
      return makeImmutableArray.apply(makeImmutableArray, arguments);
    } else if (isImmutable(obj)) {
      return obj;
    } else if (obj instanceof Array) {
      return makeImmutableArray.apply(makeImmutableArray, obj);
    } else {
      // Don't freeze the object we were given; make a clone and use that.
      var clone = {};

      if (obj !== null && obj !== undefined) {
        for (var key in obj) {
          clone[key] = Immutable(obj[key]);
        }
      }

      return makeImmutableObject(clone);
    }
  }

  // Export the library
  Immutable.isImmutable    = isImmutable;
  Immutable.ImmutableError = ImmutableError;

  Object.freeze(Immutable);

  if (typeof module === "object") {
    module.exports = Immutable;
  } else if (typeof exports === "object") {
    exports.Immutable = Immutable;
  } else if (typeof window === "object") {
    window.Immutable = Immutable;
  } else if (typeof global === "object") {
    global.Immutable = Immutable;
  }
})();<|endoftext|>


<commit_before>"use strict";

function chartFailure(chart, title) {
  var $chartDiv = $(chart.renderTo);
  var $chartWrapper = $chartDiv.parents('.chart-wrapper');

  $chartWrapper.addClass('alert alert-warning');
  $chartWrapper.html(`<h3>${title} chart</h3>`)
}

function chartSuccess(chartConfig, chartData, chart) {

  var $chartDiv = $(chart.renderTo);
  var chartType = chartData.chart1_type;
  var seriesData = chartData.series_data;
  var noAdvice = chartConfig.no_advice;

  var $chartWrapper = $chartDiv.parents('.chart-wrapper');

  var titleH3 = $chartWrapper.find('h3');
  var titleH5 = $chartWrapper.find('h5');

  titleH3.text(chartData.title);

  if (chartData.subtitle) {
    titleH5.text(chartData.subtitle);
  } else {
    titleH5.hide();
  }

  if (! noAdvice) {

    var adviceHeader = chartData.advice_header;
    var adviceFooter = chartData.advice_footer;

    if (adviceHeader) {
      $chartWrapper.find('.advice-header').html(adviceHeader);
    }

    if (adviceFooter) {
      $chartWrapper.find('.advice-footer').html(adviceFooter);
    }
  }

  if (chartType == 'bar' || chartType == 'column' || chartType == 'line') {

    barColumnLine(chartData, chart, seriesData, chartConfig);

  // Scatter
  } else if (chartType == 'scatter') {
    scatter(chartData, chart, seriesData);

  // Pie
  } else if (chartType == 'pie') {
    pie(chartData, chart, seriesData, $chartDiv);
  }

  if(chartData.allowed_operations){
    processAnalysisOperations(chartConfig, chart, chartData.allowed_operations, chartData.drilldown_available, chartData.parent_timescale_description)
  }

  if(chartData.annotations){
    var xAxis = chart.xAxis[0];

    var xAxisCategories = xAxis.categories;
    if(chartData.annotations == 'weekly'){
      var data = {
        date_grouping: chartData.annotations,
        x_axis_categories: xAxisCategories
      };
    } else {
      var data = {
        date_grouping: chartData.annotations,
        x_axis_start: xAxisCategories[0],
        x_axis_end: xAxisCategories.slice(-1)[0]
      };
    }

    $.ajax({
      type: 'GET',
      dataType: "json",
      url: chartConfig.annotations,
      data: data,
      success: function (returnedData) {
        processAnnotations(returnedData, chart)
      }
    });
  }

  $chartDiv.attr( "maxYvalue", chart.yAxis[0].max );

  // Activate any popovers
  $('[data-toggle="popover"]').popover();

  chart.hideLoading();
}

function processAnalysisCharts(){
  if ($("div.analysis-chart").length ) {
    $("div.analysis-chart").each(function(){
      var chartConfig = $(this).data('chart-config');
      processAnalysisChart(this, chartConfig);
      setupAnalysisControls(this, chartConfig);
    });
  }
}

function processAnalysisChart(chartContainer, chartConfig){
  var thisId = chartContainer.id;
  var thisChart = Highcharts.chart(thisId, commonChartOptions(function(event){processChartClick(chartConfig, chartContainer, event)}));
  var chartType = chartConfig.type;
  var yAxisUnits = chartConfig.y_axis_units;
  var mpanMprn = chartConfig.mpan_mprn;
  var seriesBreakdown = chartConfig.series_breakdown;
  var dateRanges = chartConfig.date_ranges;
  var dataPath = chartConfig.jsonUrl;
  var chartData = chartConfig.jsonData;
  var transformations = chartConfig.transformations;

  if (dataPath !== undefined && dataPath.length) {
    var requestData = {
      chart_type: chartType,
      chart_y_axis_units: yAxisUnits,
      mpan_mprn: mpanMprn,
      transformations: transformations,
      series_breakdown: seriesBreakdown,
      date_ranges: dateRanges
    };

    thisChart.showLoading();

    $.ajax({
      type: 'GET',
      async: true,
      dataType: "json",
      url: dataPath,
      data: requestData,
      success: function (returnedData) {
        var thisChartData = returnedData.charts[0];
        if (thisChartData == undefined) {
          chartFailure(thisChart, "We do not have enough data at the moment to display this ");
        } else if (thisChartData.series_data == null) {
          chartFailure(thisChart, thisChartData.title);
        } else {
          chartSuccess(chartConfig, thisChartData, thisChart);
        }
      },
      error: function(broken) {
        chartFailure(thisChart, "We do not have enough data at the moment to display this ");
      }
    });
  } else {
    chartSuccess(chartConfig, chartData, thisChart);
  }
}

function processAnnotations(loaded_annotations, chart){
  var xAxis = chart.xAxis[0];
  var xAxisCategories = xAxis.categories;

  var annotations = loaded_annotations.map(function(annotation){
    var categoryIndex = xAxisCategories.indexOf(annotation.x_axis_category);
    var date = new Date(annotation.date);
    var point = xAxis.series[0].getValidPoints()[categoryIndex];
    var date = new Date(annotation.date);
    if(xAxis.series[0].stackKey){
      var y = point.total;
    } else {
      var y = point.y;
    }
    return {
      point: {
        x: categoryIndex,
        y: y,
        xAxis: 0,
        yAxis: 0,
      },
      text: '',
    };
  });
  chart.addAnnotation({
    labelOptions:{
      useHTML: true,
      style: {
        fontSize: '15px'
      }
    },
    labels: annotations
  }, true);
  $('.highcharts-annotation [data-toggle="tooltip"]').tooltip()
}

function setupAnalysisControls(chartContainer, chartConfig){
  var controls = $(chartContainer).parent().find('.analysis_controls');
  if(controls.length){
    controls.find('.move_back').hide().on('click', function(event){
      event.preventDefault();
      pushTransformation(chartConfig, chartContainer, 'move', -1);
    });
    controls.find('.move_forward').hide().on('click', function(event){
      event.preventDefault();
      pushTransformation(chartConfig, chartContainer, 'move', 1);
    });

    controls.find('.drillup').hide();
    controls.find('.drillup').on('click', function(event){
      event.preventDefault();

      var transformations = chartConfig.transformations;
      var inDrilldown = transformations.some(isDrilldownTransformation);
      var lastDrilldownIndex = transformations.reverse().findIndex(isDrilldownTransformation);
      var sliceTo = transformations.length - lastDrilldownIndex - 1;
      var newTransformtions = transformations.reverse().slice(0, sliceTo);

      chartConfig.transformations = newTransformtions;
      processAnalysisChart(chartContainer, chartConfig);
    });
  }
}

function processAnalysisOperations(chartConfig, chart, operations, drilldownAvailable, parentTimescaleDescription){
  var chartContainer = $(chart.renderTo);
  var controls = $(chartContainer).parent().find('.analysis_controls');
  if(controls.length){
    $.each(operations, function(operation, config ) {
      $.each(config.directions, function(direction, enabled ) {
        var control = controls.find(`.${operation}_${direction}`);
        if(enabled){
          control.show();
        } else {
          control.hide();
        }
        control.find('span.period').html(config.timescale_description);
      });
    });

   chartConfig.drilldown_available =  drilldownAvailable;

    if(drilldownAvailable){
      chart.update({subtitle: {text: 'Click on the chart to explore the data'}});
    }

    var transformations = chartConfig.transformations;
    var inDrilldown = transformations.some(isDrilldownTransformation);
    var drillup = controls.find('.drillup');
    if(inDrilldown){
      drillup.find('span.period').html(parentTimescaleDescription);
      drillup.show();
    } else {
      drillup.hide();
    }
  }
}

function pushTransformation(chartConfig, chartContainer, transformation_type, transformation_value){
  var transformations = chartConfig.transformations;
  var last_transformation = transformations[transformations.length -1];

  if(transformation_type != 'drilldown' && last_transformation && last_transformation[0] == transformation_type){
    var new_transformation_value = last_transformation[1] + transformation_value;
    transformations.pop();
    if(new_transformation_value != 0){
      transformations.push([transformation_type, last_transformation[1] + transformation_value]);
    }
  } else {
    transformations.push([transformation_type, transformation_value]);
  }
  chartConfig.transformations = transformations;
  processAnalysisChart(chartContainer, chartConfig);
}

function processChartClick(chartConfig, chartContainer, event){
  var controls = $(chartContainer).parent().find('.analysis_controls');
  if(controls.length){
    if(chartConfig.drilldown_available){
      pushTransformation(chartConfig, chartContainer, 'drilldown', event.point.index)
    }
  }
}

function isDrilldownTransformation(transformation){
  return transformation[0] == 'drilldown';
}

$(document).ready(processAnalysisCharts);

<commit_msg>Refactor the JS a little<commit_after>"use strict";

function chartFailure(chart, title) {
  var $chartDiv = $(chart.renderTo);
  var $chartWrapper = $chartDiv.parents('.chart-wrapper');

  $chartWrapper.addClass('alert alert-warning');
  $chartWrapper.html(`<h3>${title} chart</h3>`)
}

function chartSuccess(chartConfig, chartData, chart) {

  var $chartDiv = $(chart.renderTo);
  var chartType = chartData.chart1_type;
  var seriesData = chartData.series_data;
  var noAdvice = chartConfig.no_advice;

  var $chartWrapper = $chartDiv.parents('.chart-wrapper');

  var titleH3 = $chartWrapper.find('h3');
  var titleH5 = $chartWrapper.find('h5');

  titleH3.text(chartData.title);

  if (chartData.subtitle) {
    titleH5.text(chartData.subtitle);
  } else {
    titleH5.hide();
  }

  if (! noAdvice) {

    var adviceHeader = chartData.advice_header;
    var adviceFooter = chartData.advice_footer;

    if (adviceHeader) {
      $chartWrapper.find('.advice-header').html(adviceHeader);
    }

    if (adviceFooter) {
      $chartWrapper.find('.advice-footer').html(adviceFooter);
    }
  }

  if (chartType == 'bar' || chartType == 'column' || chartType == 'line') {

    barColumnLine(chartData, chart, seriesData, chartConfig);

  // Scatter
  } else if (chartType == 'scatter') {
    scatter(chartData, chart, seriesData);

  // Pie
  } else if (chartType == 'pie') {
    pie(chartData, chart, seriesData, $chartDiv);
  }

  if(chartData.allowed_operations){
    processAnalysisOperations(chartConfig, chart, chartData.allowed_operations, chartData.drilldown_available, chartData.parent_timescale_description)
  }

  if(chartData.annotations){
    var xAxis = chart.xAxis[0];

    var xAxisCategories = xAxis.categories;
    if(chartData.annotations == 'weekly'){
      var data = {
        date_grouping: chartData.annotations,
        x_axis_categories: xAxisCategories
      };
    } else {
      var data = {
        date_grouping: chartData.annotations,
        x_axis_start: xAxisCategories[0],
        x_axis_end: xAxisCategories.slice(-1)[0]
      };
    }

    $.ajax({
      type: 'GET',
      dataType: "json",
      url: chartConfig.annotations,
      data: data,
      success: function (returnedData) {
        processAnnotations(returnedData, chart)
      }
    });
  }

  $chartDiv.attr( "maxYvalue", chart.yAxis[0].max );

  // Activate any popovers
  $('[data-toggle="popover"]').popover();

  chart.hideLoading();
}

function processAnalysisCharts(){
  if ($("div.analysis-chart").length ) {
    $("div.analysis-chart").each(function(){
      var chartConfig = $(this).data('chart-config');
      processAnalysisChart(this, chartConfig);
      setupAnalysisControls(this, chartConfig);
    });
  }
}

function processAnalysisChartAjax(chartId, chartConfig, highchartsChart) {
  var chartType = chartConfig.type;
  var yAxisUnits = chartConfig.y_axis_units;
  var mpanMprn = chartConfig.mpan_mprn;
  var seriesBreakdown = chartConfig.series_breakdown;
  var dateRanges = chartConfig.date_ranges;
  var dataPath = chartConfig.jsonUrl;
  var transformations = chartConfig.transformations;
  var requestData = {
    chart_type: chartType,
    chart_y_axis_units: yAxisUnits,
    mpan_mprn: mpanMprn,
    transformations: transformations,
    series_breakdown: seriesBreakdown,
    date_ranges: dateRanges
  };

  highchartsChart.showLoading();

  $.ajax({
    type: 'GET',
    async: true,
    dataType: "json",
    url: dataPath,
    data: requestData,
    success: function (returnedData) {
      var thisChartData = returnedData.charts[0];
      if (thisChartData == undefined) {
        chartFailure(highchartsChart, "We do not have enough data at the moment to display this ");
      } else if (thisChartData.series_data == null) {
        chartFailure(highchartsChart, thisChartData.title);
      } else {
        chartSuccess(chartConfig, thisChartData, highchartsChart);
      }
    },
    error: function(broken) {
      chartFailure(highchartsChart, "We do not have enough data at the moment to display this ");
    }
  });
}

function processAnalysisChart(chartContainer, chartConfig){
  var thisId = chartContainer.id;
  var thisChart = Highcharts.chart(thisId, commonChartOptions(function(event){processChartClick(chartConfig, chartContainer, event)}));
  var chartData = chartConfig.jsonData;

  if (chartData !== undefined) {
    chartSuccess(chartConfig, chartData, thisChart);
  } else {
    processAnalysisChartAjax(thisId, chartConfig, thisChart)
  }
}

function processAnnotations(loaded_annotations, chart){
  var xAxis = chart.xAxis[0];
  var xAxisCategories = xAxis.categories;

  var annotations = loaded_annotations.map(function(annotation){
    var categoryIndex = xAxisCategories.indexOf(annotation.x_axis_category);
    var date = new Date(annotation.date);
    var point = xAxis.series[0].getValidPoints()[categoryIndex];
    var date = new Date(annotation.date);
    if(xAxis.series[0].stackKey){
      var y = point.total;
    } else {
      var y = point.y;
    }
    return {
      point: {
        x: categoryIndex,
        y: y,
        xAxis: 0,
        yAxis: 0,
      },
      text: '',
    };
  });
  chart.addAnnotation({
    labelOptions:{
      useHTML: true,
      style: {
        fontSize: '15px'
      }
    },
    labels: annotations
  }, true);
  $('.highcharts-annotation [data-toggle="tooltip"]').tooltip()
}

function setupAnalysisControls(chartContainer, chartConfig){
  var controls = $(chartContainer).parent().find('.analysis_controls');
  if(controls.length){
    controls.find('.move_back').hide().on('click', function(event){
      event.preventDefault();
      pushTransformation(chartConfig, chartContainer, 'move', -1);
    });
    controls.find('.move_forward').hide().on('click', function(event){
      event.preventDefault();
      pushTransformation(chartConfig, chartContainer, 'move', 1);
    });

    controls.find('.drillup').hide();
    controls.find('.drillup').on('click', function(event){
      event.preventDefault();

      var transformations = chartConfig.transformations;
      var inDrilldown = transformations.some(isDrilldownTransformation);
      var lastDrilldownIndex = transformations.reverse().findIndex(isDrilldownTransformation);
      var sliceTo = transformations.length - lastDrilldownIndex - 1;
      var newTransformtions = transformations.reverse().slice(0, sliceTo);

      chartConfig.transformations = newTransformtions;
      processAnalysisChart(chartContainer, chartConfig);
    });
  }
}

function processAnalysisOperations(chartConfig, chart, operations, drilldownAvailable, parentTimescaleDescription){
  var chartContainer = $(chart.renderTo);
  var controls = $(chartContainer).parent().find('.analysis_controls');
  if(controls.length){
    $.each(operations, function(operation, config ) {
      $.each(config.directions, function(direction, enabled ) {
        var control = controls.find(`.${operation}_${direction}`);
        if(enabled){
          control.show();
        } else {
          control.hide();
        }
        control.find('span.period').html(config.timescale_description);
      });
    });

   chartConfig.drilldown_available =  drilldownAvailable;

    if(drilldownAvailable){
      chart.update({subtitle: {text: 'Click on the chart to explore the data'}});
    }

    var transformations = chartConfig.transformations;
    var inDrilldown = transformations.some(isDrilldownTransformation);
    var drillup = controls.find('.drillup');
    if(inDrilldown){
      drillup.find('span.period').html(parentTimescaleDescription);
      drillup.show();
    } else {
      drillup.hide();
    }
  }
}

function pushTransformation(chartConfig, chartContainer, transformation_type, transformation_value){
  var transformations = chartConfig.transformations;
  var last_transformation = transformations[transformations.length -1];

  if(transformation_type != 'drilldown' && last_transformation && last_transformation[0] == transformation_type){
    var new_transformation_value = last_transformation[1] + transformation_value;
    transformations.pop();
    if(new_transformation_value != 0){
      transformations.push([transformation_type, last_transformation[1] + transformation_value]);
    }
  } else {
    transformations.push([transformation_type, transformation_value]);
  }
  chartConfig.transformations = transformations;
  processAnalysisChart(chartContainer, chartConfig);
}

function processChartClick(chartConfig, chartContainer, event){
  var controls = $(chartContainer).parent().find('.analysis_controls');
  if(controls.length){
    if(chartConfig.drilldown_available){
      pushTransformation(chartConfig, chartContainer, 'drilldown', event.point.index)
    }
  }
}

function isDrilldownTransformation(transformation){
  return transformation[0] == 'drilldown';
}

$(document).ready(processAnalysisCharts);

<|endoftext|>


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

  function addMethodTo(target, methodName, implementation) {
    Object.defineProperty(target, methodName, {
      enumerable: false,
      configurable: false,
      writable: false,
      value: implementation
    });
  }

  var privateArrayMethods = [
    "push", "sort", "splice", "shift", "unshift", "reverse"
  ];

  function ImmutableError(message) {
    this.name    = "ImmutableError";
    this.message = (message || "");
  }

  ImmutableError.prototype = Error.prototype;

  function makeImmutableArray() {
    var result = [];

    // Fill the array while it still supports push().
    result.push.apply(result, arguments);

    // Make all mutating methods throw exceptions.
    for (var index in privateArrayMethods) {
      (function(methodName) {
        addMethodTo(result, methodName, function() {
          throw new ImmutableError("The " + methodName +
            " method cannot be invoked on an ImmutableArray.");
        });
      })(privateArrayMethods[index]);
    }

    // Freeze it and return it.
    Object.freeze(result);
    return result;
  }

  // TODO: make it immutable
  function makeImmutableMap(obj) {
    return obj;
  }

  // Export the library

  var Immutable = {
    Array:          makeImmutableArray,
    Map:            makeImmutableMap,
    ImmutableError: ImmutableError
  };

  Object.freeze(Immutable);

  if (typeof module === "object") {
    module.exports = Immutable;
  } else if (typeof exports === "object") {
    exports.Immutable = Immutable;
  } else if (typeof window === "object") {
    window.Immutable = Immutable;
  } else if (typeof global === "object") {
    global.Immutable = Immutable;
  }
})();<commit_msg>Implement immutability tag.<commit_after>(function(){
  "use strict";

  function addPropertyTo(target, methodName, value) {
    Object.defineProperty(target, methodName, {
      enumerable: false,
      configurable: false,
      writable: false,
      value: value
    });
  }

  function addImmutabilityTag(target) {
    addPropertyTo(target, "__immutable_invariants_hold", true);
  }

  var privateArrayMethods = [
    "push", "sort", "splice", "shift", "unshift", "reverse"
  ];

  function ImmutableError(message) {
    this.name    = "ImmutableError";
    this.message = (message || "");
  }

  ImmutableError.prototype = Error.prototype;

  function makeImmutableArray() {
    var result = [];

    // Fill the array while it still supports push().
    result.push.apply(result, arguments);

    // Make all mutating methods throw exceptions.
    for (var index in privateArrayMethods) {
      (function(methodName) {
        addPropertyTo(result, methodName, function() {
          throw new ImmutableError("The " + methodName +
            " method cannot be invoked on an ImmutableArray.");
        });
      })(privateArrayMethods[index]);
    }

    // Tag it so we can quickly tell it's immutable later.
    addImmutabilityTag(result);

    // Freeze it and return it.
    Object.freeze(result);
    return result;
  }

  // TODO: make it immutable
  function makeImmutableMap(obj) {
    return obj;
  }

  // Export the library

  var Immutable = {
    Array:          makeImmutableArray,
    Map:            makeImmutableMap,
    ImmutableError: ImmutableError
  };

  Object.freeze(Immutable);

  if (typeof module === "object") {
    module.exports = Immutable;
  } else if (typeof exports === "object") {
    exports.Immutable = Immutable;
  } else if (typeof window === "object") {
    window.Immutable = Immutable;
  } else if (typeof global === "object") {
    global.Immutable = Immutable;
  }
})();<|endoftext|>


<commit_before>$(document).ready(function(){
  // todos for this file
  // make it OO

  function draw(response) {
      // Chart size
  var w = window.innerWidth,
      h = 450,
      // Date variables
      days = [ 'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday' ],
      monthNames = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
        "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ],
      abbreviatedMonthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ],
      // d3 variables
      maxDataPointsForDots = 500,
      transitionDuration = 1000,
      svg = null,
      yAxisGroup = null,
      xAxisGroup = null,
      dataCirclesGroup = null,
      dataLinesGroup = null;

    var data = response,
    violations = 0;
    // add usefull properties to the data objects
    data.forEach(function(obj){
      obj.date = new Date(obj.created_at);
      obj.isDay = obj.date.getHours() >= 6 && obj.date.getHours() <= 22;
      if(obj.violation){ violations += 1; }
    });
    var margin = 40;
    var max = d3.max(data, function(d) { return d.temp }) + 1;
    var min = d3.min(data, function(d) { return d.outdoor_temp }) - 5;
    var pointRadius = 4;
    var x = d3.time.scale().range([0, w - margin * 2]).domain([data[0].date, data[data.length - 1].date]);
    var y = d3.scale.linear().range([h - margin * 2, 0]).domain([min, max]);
    var xAxis = d3.svg.axis().scale(x).tickSize(h - margin * 2).tickPadding(0).ticks(data.length);
    var yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + margin * 2).tickPadding(0).ticks(7);
    var t = null,
    strokeWidth = w / data.length;

    svg = d3.select('#d3-chart').select('svg').select('g');
    if (svg.empty()) {
      svg = d3.select('#d3-chart')
        .append('svg:svg')
        .attr('width', w)
        .attr('height', h)
        .attr('class', 'viz')
        .append('svg:g')
        .attr('transform', 'translate(' + margin + ',' + margin + ')');
    }

    t = svg.transition().duration(transitionDuration);

    function addLineStlyingToXTicks(){
      var $lines = $(".xTick .tick line"),
          length = data.length,
          date,
          newText,
          $textEl;

      for(var i = 0; i < length; i++){
        if(data[i].isDay === false){
          $($lines[i]).attr(
            { 'stroke-width': strokeWidth, 'stroke': '#90ABB0' }
          );
          if(i === 0){
            $($lines[i]).attr({ 'stroke-width': strokeWidth * 1.9 });
          }
        }
        else {
          if (i === 8 || i === 32 || i === 56 || i === 80 || i === 104 || i === 128 || i === 154 ) {
            date = data[i].date;
            newText = abbreviatedMonthNames[date.getMonth()] + " "
              + date.getDate() + ", " + (date.getYear() + 1900);
            $textEl = $($(".xTick .tick text")[i]);
            $textEl.text(newText);
            $textEl.show();
            $textEl.attr({"x": 20, "y": 380});
          }
        }
      }
    }

// x ticks and labels gets placed first
    // x ticks and labels
    if (!xAxisGroup) {
      xAxisGroup = svg.append('svg:g')
        .attr('class', 'xTick')
        .call(xAxis);
      addLineStlyingToXTicks();
    }
    else {
      t.select('.xTick').call(xAxis);
    }

// y ticks and labels gets placed second
    // y ticks and labels
    if (!yAxisGroup) {
      yAxisGroup = svg.append('svg:g')
        .attr('class', 'yTick')
        .call(yAxis);
    }
    else {
      t.select('.yTick').call(yAxis);
    }
    // fixes x value for text
    $(".yTick .tick text").attr("x", "-5")

// y ticks and labels gets placed third
    // Draw the lines
    if (!dataLinesGroup) {
      dataLinesGroup = svg.append('svg:g');
    }

    var dataLines = dataLinesGroup.selectAll('.data-line').data([data]);

    var line = d3.svg.line()
      // assign the X function to plot our line as we wish
      .x(function(d,i) {
        // verbose logging to show what's actually being done
        //console.log('Plotting X temp for date: ' + d.date + ' using index: ' + i + ' to be at: ' + x(d.date) + ' using our xScale.');
        // return the X coordinate where we want to plot this datapoint
        //return x(i);
        return x(d.date);
      })
      .y(function(d) {
        // verbose logging to show what's actually being done
        //console.log('Plotting Y temp for data temp: ' + d.temp + ' to be at: ' + y(d.temp) + " using our yScale.");
        // return the Y coordinate where we want to plot this datapoint
        //return y(d);
        return y(d.temp);
      })
      .interpolate("linear");

    var garea = d3.svg.area()
      .interpolate("linear")
      .x(function(d) {
        // verbose logging to show what's actually being done
        return x(d.date);
      })
      .y0(h - margin * 2)
      .y1(function(d) {
        // verbose logging to show what's actually being done
        return y(d.outdoor_temp);
      });

    dataLines
      .enter()
      .append('svg:path')
      .attr("class", "area");
      // .attr("d", garea(data));

    dataLines.enter().append('path')
      .attr('class', 'data-line')
      .style('opacity', 0.3)
      .attr("d", line(data))
      .transition()
      .delay(transitionDuration / 2)
      .duration(transitionDuration)
      .style('opacity', 1);
      // .attr('x1', function(d, i) { return (i > 0) ? xScale(data[i - 1].date) : xScale(d.date); })
      // .attr('y1', function(d, i) { return (i > 0) ? yScale(data[i - 1].temp) : yScale(d.temp); })
      // .attr('x2', function(d) { return xScale(d.date); })
      // .attr('y2', function(d) { return yScale(d.temp); });

    // dataLines.transition()
    //   .attr("d", line)
    //   .duration(transitionDuration)
    //   .style('opacity', 1)
    //   .attr("transform", function(d) {
    //     return "translate(" + x(d.date) + "," + y(d.temp) + ")";
    //   });

    dataLines.exit()
      .transition()
      .attr("d", line)
      .duration(transitionDuration)
      .attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(0) + ")"; })
      .style('opacity', 1e-6)
      .remove();

    d3.selectAll(".area").transition()
      .duration(transitionDuration)
      .attr("d", garea(data));

    // move the area to the back of the graph
    var fillArea = $(".area")
    $("#d3-chart svg > g").prepend(fillArea)

    $("#violations span").text($("#violations span").text().replace(/#/, violations));

    // Draw the points
    if (!dataCirclesGroup) {
      dataCirclesGroup = svg.append('svg:g');
    }

    var circles = dataCirclesGroup.selectAll('.data-point').data(data);

    circles.enter()
      .append('svg:circle')
      .attr('class', 'data-point')
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function() { return y(0) })
      .attr('r', function(d) {
        return d.violation ? pointRadius : 0;
      })
      .transition()
      .duration(transitionDuration)
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function(d) { return y(d.temp) });

    // circles
    //   .transition()
    //   .duration(transitionDuration)
    //   .attr('cx', function(d) { return x(d.date) })
    //   .attr('cy', function(d) { return y(d.temp) })
    //   .attr('r', function(d) {
    //     return d.violation ? pointRadius : null
    //   })
    //   .style('opacity', 1);

    circles
      .exit()
      .transition()
      .duration(transitionDuration)
      // Leave the cx transition off. Allowing the points to fall where they lie is best.
      //.attr('cx', function(d, i) { return xScale(i) })
      .attr('cy', function() { return y(0) })
      .style("opacity", 1e-6)
      .remove();

    function legalMinimumFor(reading){
      if(reading.isDay === true){
        return '68';
      }else{
        return '55';
      }
    }

    function getCivilianTime(reading){
      if (reading.getHours() > 12){
        return (reading.getHours() - 12) + ":"
          + (reading.getMinutes() >= 10 ?
            reading.getMinutes() : "0" + reading.getMinutes())
          + " PM";
      }else{
        return reading.getHours() + ":"
          + (reading.getMinutes() >= 10 ?
            reading.getMinutes() : "0" + reading.getMinutes())
          + " AM";
      }
    }

    $('svg circle').tipsy({
      gravity: 's',
      html: true,
      topOffset: 2.8,
      leftOffset: 3.8,
      opacity: 1,
      title: function() {
        var d = this.__data__;
        var pDate = d.date;
        return pDate.getDate() + ' '
          + monthNames[pDate.getMonth()] + ' '
          + pDate.getFullYear() + '
'
          + days[ pDate.getDay() ] + ' at '
          + getCivilianTime(pDate) + '
'
          + 'Temperature in Violation
'
          + '
Temperature in Apt: ' + d.temp + '°'
          + '
Temperature Outside: ' + d.outdoor_temp + '°'
          + '
Legal minimum: ' + legalMinimumFor(d) + '°';
      }
    });
  }

  function drawChartBasedOnScreenSize(chartData){
    if (window.innerWidth < 450) {
      var quarterReadings = chartData.slice(151, 199);
      $("#d3-chart").html("")
      draw(quarterReadings);
    }else if(window.innerWidth < 720){
      var halfReadings = chartData.slice(103, 199);
      $("#d3-chart").html("")
      draw(halfReadings);
    }else if(window.innerWidth < 1080){
      var threeQuarterReadings = chartData.slice(48, 199);
      $("#d3-chart").html("")
      draw(threeQuarterReadings);
    }else{
      $("#d3-chart").html("")
      draw(chartData);
    }
  }

  if($("#d3-chart").length > 0){
    if(/collaborations/.test(document.URL)){
      var URL = /\/users\/\d+\/collaborations\/\d+/.exec(document.URL)[0];
    }else{
      var URL = /\/users\/\d+/.exec(document.URL)[0];
    }
    $.ajax({
      url: URL,
      dataType: "JSON",
      success: function(response){
        if(response.length > 0){
          drawChartBasedOnScreenSize(response);
          var resizeTimer = 0;
          window.onresize = function(){
            if (resizeTimer){
              clearTimeout(resizeTimer);
            }
            resizeTimer = setTimeout(function(){
              drawChartBasedOnScreenSize(response);
            }, 50);
          };
        }
      },
      error: function(response){
        console.log("error");
        console.log(response);
      }
    });
  }

});<commit_msg>changes x value to 0<commit_after>$(document).ready(function(){
  // todos for this file
  // make it OO

  function draw(response) {
      // Chart size
  var w = window.innerWidth,
      h = 450,
      // Date variables
      days = [ 'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday' ],
      monthNames = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
        "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ],
      abbreviatedMonthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ],
      // d3 variables
      maxDataPointsForDots = 500,
      transitionDuration = 1000,
      svg = null,
      yAxisGroup = null,
      xAxisGroup = null,
      dataCirclesGroup = null,
      dataLinesGroup = null;

    var data = response,
    violations = 0;
    // add usefull properties to the data objects
    data.forEach(function(obj){
      obj.date = new Date(obj.created_at);
      obj.isDay = obj.date.getHours() >= 6 && obj.date.getHours() <= 22;
      if(obj.violation){ violations += 1; }
    });
    var margin = 40;
    var max = d3.max(data, function(d) { return d.temp }) + 1;
    var min = d3.min(data, function(d) { return d.outdoor_temp }) - 5;
    var pointRadius = 4;
    var x = d3.time.scale().range([0, w - margin * 2]).domain([data[0].date, data[data.length - 1].date]);
    var y = d3.scale.linear().range([h - margin * 2, 0]).domain([min, max]);
    var xAxis = d3.svg.axis().scale(x).tickSize(h - margin * 2).tickPadding(0).ticks(data.length);
    var yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + margin * 2).tickPadding(0).ticks(7);
    var t = null,
    strokeWidth = w / data.length;

    svg = d3.select('#d3-chart').select('svg').select('g');
    if (svg.empty()) {
      svg = d3.select('#d3-chart')
        .append('svg:svg')
        .attr('width', w)
        .attr('height', h)
        .attr('class', 'viz')
        .append('svg:g')
        .attr('transform', 'translate(' + margin + ',' + margin + ')');
    }

    t = svg.transition().duration(transitionDuration);

    function addLineStlyingToXTicks(){
      var $lines = $(".xTick .tick line"),
          length = data.length,
          date,
          newText,
          $textEl;

      for(var i = 0; i < length; i++){
        if(data[i].isDay === false){
          $($lines[i]).attr(
            { 'stroke-width': strokeWidth, 'stroke': '#90ABB0' }
          );
          if(i === 0){
            $($lines[i]).attr({ 'stroke-width': strokeWidth * 1.9 });
          }
        }
        else {
          if (i === 8 || i === 32 || i === 56 || i === 80 || i === 104 || i === 128 || i === 154 ) {
            date = data[i].date;
            newText = abbreviatedMonthNames[date.getMonth()] + " "
              + date.getDate() + ", " + (date.getYear() + 1900);
            $textEl = $($(".xTick .tick text")[i]);
            $textEl.text(newText);
            $textEl.show();
            $textEl.attr({"x": 0, "y": 380});
          }
        }
      }
    }

// x ticks and labels gets placed first
    // x ticks and labels
    if (!xAxisGroup) {
      xAxisGroup = svg.append('svg:g')
        .attr('class', 'xTick')
        .call(xAxis);
      addLineStlyingToXTicks();
    }
    else {
      t.select('.xTick').call(xAxis);
    }

// y ticks and labels gets placed second
    // y ticks and labels
    if (!yAxisGroup) {
      yAxisGroup = svg.append('svg:g')
        .attr('class', 'yTick')
        .call(yAxis);
    }
    else {
      t.select('.yTick').call(yAxis);
    }
    // fixes x value for text
    $(".yTick .tick text").attr("x", "-5")

// y ticks and labels gets placed third
    // Draw the lines
    if (!dataLinesGroup) {
      dataLinesGroup = svg.append('svg:g');
    }

    var dataLines = dataLinesGroup.selectAll('.data-line').data([data]);

    var line = d3.svg.line()
      // assign the X function to plot our line as we wish
      .x(function(d,i) {
        // verbose logging to show what's actually being done
        //console.log('Plotting X temp for date: ' + d.date + ' using index: ' + i + ' to be at: ' + x(d.date) + ' using our xScale.');
        // return the X coordinate where we want to plot this datapoint
        //return x(i);
        return x(d.date);
      })
      .y(function(d) {
        // verbose logging to show what's actually being done
        //console.log('Plotting Y temp for data temp: ' + d.temp + ' to be at: ' + y(d.temp) + " using our yScale.");
        // return the Y coordinate where we want to plot this datapoint
        //return y(d);
        return y(d.temp);
      })
      .interpolate("linear");

    var garea = d3.svg.area()
      .interpolate("linear")
      .x(function(d) {
        // verbose logging to show what's actually being done
        return x(d.date);
      })
      .y0(h - margin * 2)
      .y1(function(d) {
        // verbose logging to show what's actually being done
        return y(d.outdoor_temp);
      });

    dataLines
      .enter()
      .append('svg:path')
      .attr("class", "area");
      // .attr("d", garea(data));

    dataLines.enter().append('path')
      .attr('class', 'data-line')
      .style('opacity', 0.3)
      .attr("d", line(data))
      .transition()
      .delay(transitionDuration / 2)
      .duration(transitionDuration)
      .style('opacity', 1);
      // .attr('x1', function(d, i) { return (i > 0) ? xScale(data[i - 1].date) : xScale(d.date); })
      // .attr('y1', function(d, i) { return (i > 0) ? yScale(data[i - 1].temp) : yScale(d.temp); })
      // .attr('x2', function(d) { return xScale(d.date); })
      // .attr('y2', function(d) { return yScale(d.temp); });

    // dataLines.transition()
    //   .attr("d", line)
    //   .duration(transitionDuration)
    //   .style('opacity', 1)
    //   .attr("transform", function(d) {
    //     return "translate(" + x(d.date) + "," + y(d.temp) + ")";
    //   });

    dataLines.exit()
      .transition()
      .attr("d", line)
      .duration(transitionDuration)
      .attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(0) + ")"; })
      .style('opacity', 1e-6)
      .remove();

    d3.selectAll(".area").transition()
      .duration(transitionDuration)
      .attr("d", garea(data));

    // move the area to the back of the graph
    var fillArea = $(".area")
    $("#d3-chart svg > g").prepend(fillArea)

    $("#violations span").text($("#violations span").text().replace(/#/, violations));

    // Draw the points
    if (!dataCirclesGroup) {
      dataCirclesGroup = svg.append('svg:g');
    }

    var circles = dataCirclesGroup.selectAll('.data-point').data(data);

    circles.enter()
      .append('svg:circle')
      .attr('class', 'data-point')
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function() { return y(0) })
      .attr('r', function(d) {
        return d.violation ? pointRadius : 0;
      })
      .transition()
      .duration(transitionDuration)
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function(d) { return y(d.temp) });

    // circles
    //   .transition()
    //   .duration(transitionDuration)
    //   .attr('cx', function(d) { return x(d.date) })
    //   .attr('cy', function(d) { return y(d.temp) })
    //   .attr('r', function(d) {
    //     return d.violation ? pointRadius : null
    //   })
    //   .style('opacity', 1);

    circles
      .exit()
      .transition()
      .duration(transitionDuration)
      // Leave the cx transition off. Allowing the points to fall where they lie is best.
      //.attr('cx', function(d, i) { return xScale(i) })
      .attr('cy', function() { return y(0) })
      .style("opacity", 1e-6)
      .remove();

    function legalMinimumFor(reading){
      if(reading.isDay === true){
        return '68';
      }else{
        return '55';
      }
    }

    function getCivilianTime(reading){
      if (reading.getHours() > 12){
        return (reading.getHours() - 12) + ":"
          + (reading.getMinutes() >= 10 ?
            reading.getMinutes() : "0" + reading.getMinutes())
          + " PM";
      }else{
        return reading.getHours() + ":"
          + (reading.getMinutes() >= 10 ?
            reading.getMinutes() : "0" + reading.getMinutes())
          + " AM";
      }
    }

    $('svg circle').tipsy({
      gravity: 's',
      html: true,
      topOffset: 2.8,
      leftOffset: 3.8,
      opacity: 1,
      title: function() {
        var d = this.__data__;
        var pDate = d.date;
        return pDate.getDate() + ' '
          + monthNames[pDate.getMonth()] + ' '
          + pDate.getFullYear() + '
'
          + days[ pDate.getDay() ] + ' at '
          + getCivilianTime(pDate) + '
'
          + 'Temperature in Violation
'
          + '
Temperature in Apt: ' + d.temp + '°'
          + '
Temperature Outside: ' + d.outdoor_temp + '°'
          + '
Legal minimum: ' + legalMinimumFor(d) + '°';
      }
    });
  }

  function drawChartBasedOnScreenSize(chartData){
    if (window.innerWidth < 450) {
      var quarterReadings = chartData.slice(151, 199);
      $("#d3-chart").html("")
      draw(quarterReadings);
    }else if(window.innerWidth < 720){
      var halfReadings = chartData.slice(103, 199);
      $("#d3-chart").html("")
      draw(halfReadings);
    }else if(window.innerWidth < 1080){
      var threeQuarterReadings = chartData.slice(48, 199);
      $("#d3-chart").html("")
      draw(threeQuarterReadings);
    }else{
      $("#d3-chart").html("")
      draw(chartData);
    }
  }

  if($("#d3-chart").length > 0){
    if(/collaborations/.test(document.URL)){
      var URL = /\/users\/\d+\/collaborations\/\d+/.exec(document.URL)[0];
    }else{
      var URL = /\/users\/\d+/.exec(document.URL)[0];
    }
    $.ajax({
      url: URL,
      dataType: "JSON",
      success: function(response){
        if(response.length > 0){
          drawChartBasedOnScreenSize(response);
          var resizeTimer = 0;
          window.onresize = function(){
            if (resizeTimer){
              clearTimeout(resizeTimer);
            }
            resizeTimer = setTimeout(function(){
              drawChartBasedOnScreenSize(response);
            }, 50);
          };
        }
      },
      error: function(response){
        console.log("error");
        console.log(response);
      }
    });
  }

});<|endoftext|>


<commit_before>//=require prototype
//=require effects
//=require dragdrop
//=require rails
//
<commit_msg>railmail only requires prototype, not everything else<commit_after>//=require prototype
//
<|endoftext|>


<commit_before>function inviteToShareOnTwitter() {
  $('.fb_share.btn').hide();
  $('.fb_popup_btn.btn-primary').hide();
  $('.fb_request_btn').hide();
  $('.fb_share_message').hide();
  $('.tweet').show();
  $('.sharing-message').text("You shared on Facebook! How about Twitter?");
  //  Add this to get facebook button to change to twitter when fb is clicked
  //if ($('.img_plus_fb_ribbon').length) {
  //  $('.img_plus_fb_ribbon').addClass('tw');
  //}
  //if ($('.thanks_with_share_sidebar').length) {
  //  $('.share_box').addClass('tw');
  //}
  // $('.fb_popup_btn').hide();
  // $('.tw a').css('display', 'block');
}

function trackFacebookStatus(facebookStatus) {
  $.ajax({
    url: VK.social_tracking_url,
    data: {facebook_action: "status", facebook_status: facebookStatus.status}
  });
}

function initFacebookApp() {
  var appId = $('meta[property="fb:app_id"]').attr('content');
  FB.init({
    appId: appId,
    status: true, // check login status
    cookie: true, // enable cookies to allow the server to access the session
    xfbml: true,  // parse XFBML
    frictionless: true // for facebook request dialog
  });

  FB.getLoginStatus(trackFacebookStatus);
  if (VK.facebook_sharing_type == "facebook_wall") {
    FB.Event.subscribe('auth.statusChange', function (facebookStatus) {
      if (VK.fb_action_instance_id !== "" && facebookStatus.status === "connected") {
        FB.api(VK.fb_action_instance_id, 'get', function (response) {
          if (VK.fb_action_instance_id === response.id)  {
            inviteToShareOnTwitter();
          }
        });
      }
    });
  }
}

function setUpParamsForSocialTracking(facebook_action, action_id, request_id, request_to_ids) {
  var params = {petition_id: VK.petition_id, facebook_action: facebook_action};
  if (VK.signature_id !== "") {
    params = $.extend(params, {signature_id: VK.signature_id});
  }
  if (action_id !== "") {
    params = $.extend(params, {action_id: action_id});
  }
  if (request_id !== "") {
    params = $.extend(params, {request_id: request_id});
    params = $.extend(params, {friend_ids: request_to_ids});
  }

  return params;
}

function setupSocialTrackingControllerRequest(facebook_action, action_id, request_id, request_to_ids) {
    $.ajax({
      url: VK.social_tracking_url,
      data: setUpParamsForSocialTracking(facebook_action, action_id, request_id, request_to_ids)
    });
}

function setupSocialTracking() {
  try {
    if (FB && FB.Event && FB.Event.subscribe) {
      FB.Event.subscribe('edge.create', function (targetUrl) {
        _gaq.push(['_trackSocial', 'facebook', 'like', targetUrl]);
        //Google doesn't export social event data yet, so we have to track social actions as events too
        _gaq.push(['_trackEvent', 'facebook', 'like', targetUrl]);
        setupSocialTrackingControllerRequest('like');
        inviteToShareOnTwitter();
      });
      FB.Event.subscribe('edge.remove', function (targetUrl) {
        _gaq.push(['_trackSocial', 'facebook', 'unlike', targetUrl]);
        _gaq.push(['_trackEvent', 'facebook', 'unlike', targetUrl]);
      });
    }
  } catch (e) {
  }
}

function submitFacebookAction() {
  FB.login(function (response) {
    if (response.authResponse) {
      FB.api(
        '/me/watchdognet:sign',
        'post',
        {
          petition: $('meta[property="og:url"]').attr("content")
        },
        function (response) {
          if (!response || response.error) {
            $('.fb_share_message').text("Please try again.");
          } else {
            setupSocialTrackingControllerRequest('share', response.id, '', '');
            inviteToShareOnTwitter();
          }
        }
      );
    } else {
      $('.fb_share_message').hide();
    }
  }, {scope: 'publish_actions'});
}

function setupShareFacebookButton() {
  var shareButton = $('.fb_share.btn');
  shareButton.click(function (event) {
    $('.fb_share_message').text("Connecting to Facebook...");
    $('.fb_share_message').show();
    submitFacebookAction();
  });
}

function preventWhitespaceOn(input) {
  $(input).change(function () {
    this.value = this.value.replace(/ /g, '');
  });
}

function EmailSuggestions() {
  var self = this;
  var $email = $('#signature_email');
  var $hint = $("#hint");

  this.init = function () {
    $('.suggested_email').live("click", function () {
      $email.val($(this).html());
      $hint.css('display', 'none');
      return false;
    });
  };

  this.mailCheckSuggestions = function (event) {
    $hint.css('display', 'none');
    $email.mailcheck({
      //annoyingly, mailcheck doesn't let you add to their default list of domains, so we have to duplicate them all here.
      domains:["yahoo.com", "google.com", "hotmail.com", "gmail.com", "me.com", "aol.com", "mac.com",
        "live.com", "comcast.net", "googlemail.com", "msn.com", "hotmail.co.uk", "yahoo.co.uk",
        "facebook.com", "verizon.net", "sbcglobal.net", "att.net", "gmx.com", "mail.com", "q.com"],
      suggested:function (element, suggestion) {
        event.go = true;
        if (!$hint.html()) {
          var suggestionFragment = 'Did you mean ' + suggestion.full + "?" +
            "
Click the '" + $("#sign_petition").val() + "' button again if your address is correct";
          $hint.html(suggestionFragment).fadeIn(150);
          event.go = false;
        }
      }
    });
  };
}

function initTwitter() {
  var js, fjs = document.getElementsByTagName("script")[0];
  if (!document.getElementById("twitter-wjs")) {
    js = document.createElement("script");
    js.id = "twitter-wjs";
    js.src = "//platform.twitter.com/widgets.js";
    fjs.parentNode.insertBefore(js, fjs);
  }
}

function bindFacebookPopupButton() {

  function openPopup() {
    var sharer = "https://www.facebook.com/sharer/sharer.php?u=";
    var domain = location.href.replace(/\?.*/,"");
    var memberHash = VK.current_member_hash;
    var url = [sharer, domain, '?share_ref=', memberHash].join('');
    window.open(url , 'sharer', 'width=626,height=436');
  }

  $('.fb_popup_btn').click(function() {
    openPopup();
    setupSocialTrackingControllerRequest('popup');
    inviteToShareOnTwitter();
    $('.giantbox').hide();
  });
}

function bindFacebookWidgetButton() {

  function openWidget() {
    var element = $('.facebook-share-widget');
    $('#thanksModal').modal('hide');
    $('#facebookFriendsModal').modal('toggle');
    var domain = location.href.replace(/\?.*/,"");
    var options = {
      base_path: '/widget',
      template:  { 'link': domain + '?wall=' + VK.current_member_hash }
    };
    if (VK.fbWallLoaded) { return; }
    var widget = new FacebookShareWidget(element, options);
    VK.fbWallLoaded = true;
    $('.facebook-share-widget .search-text').get(0).focus();
  }

  function performLoginAndOpenWidget() {
    setupSocialTrackingControllerRequest('wall');
    FB.login(function (response) {
      if (response.authResponse) {
        openWidget();
       }
    }, {scope: 'publish_stream'});
  }

  $('.fb_widget_btn').click(performLoginAndOpenWidget);
}

function bindFacebookRequestButton() {

  function requestCallbackForSendRequest(response) {
    if(response && response.request) {
      setupSocialTrackingControllerRequest('request', '', response.request, response.to);
    }
    inviteToShareOnTwitter();
  }

  function sendRequestViaMultiFriendSelector() {
    FB.ui({method: 'apprequests',
      message: VK.petition_title
    }, requestCallbackForSendRequest);
  }

  $('.fb_request_btn').click(sendRequestViaMultiFriendSelector);
}

function drawModalAfterSigning() {
  if (screen.width > 480 && $('#thanksModal').length) {
    $('#thanksModal').modal('toggle');
  }
}

function initShowPetition() {
  preventWhitespaceOn('#signature_email');
  setupSocialTracking();

  $('form').on("submit", function (event) {
    if (!VK.signing_from_email) {
      var emailSuggestor = new EmailSuggestions();
      emailSuggestor.init();
      emailSuggestor.mailCheckSuggestions(event);
    }
    return event.go;
  });
}

function initSharePetition() {
  initTwitter();
  initFacebookApp();
  setupSocialTracking();
  setupShareFacebookButton();
  bindFacebookPopupButton();
  bindFacebookWidgetButton();
  bindFacebookRequestButton();
  drawModalAfterSigning();
}
<commit_msg>don't crash all JS when Facebook doesn't load (e.g. on localhost)<commit_after>function inviteToShareOnTwitter() {
  $('.fb_share.btn').hide();
  $('.fb_popup_btn.btn-primary').hide();
  $('.fb_request_btn').hide();
  $('.fb_share_message').hide();
  $('.tweet').show();
  $('.sharing-message').text("You shared on Facebook! How about Twitter?");
  //  Add this to get facebook button to change to twitter when fb is clicked
  //if ($('.img_plus_fb_ribbon').length) {
  //  $('.img_plus_fb_ribbon').addClass('tw');
  //}
  //if ($('.thanks_with_share_sidebar').length) {
  //  $('.share_box').addClass('tw');
  //}
  // $('.fb_popup_btn').hide();
  // $('.tw a').css('display', 'block');
}

function trackFacebookStatus(facebookStatus) {
  $.ajax({
    url: VK.social_tracking_url,
    data: {facebook_action: "status", facebook_status: facebookStatus.status}
  });
}

function initFacebookApp() {
  var appId = $('meta[property="fb:app_id"]').attr('content');
  FB.init({
    appId: appId,
    status: true, // check login status
    cookie: true, // enable cookies to allow the server to access the session
    xfbml: true,  // parse XFBML
    frictionless: true // for facebook request dialog
  });

  if (FB.getLoginStatus) { FB.getLoginStatus(trackFacebookStatus); }
  if (VK.facebook_sharing_type == "facebook_wall") {
    FB.Event.subscribe('auth.statusChange', function (facebookStatus) {
      if (VK.fb_action_instance_id !== "" && facebookStatus.status === "connected") {
        FB.api(VK.fb_action_instance_id, 'get', function (response) {
          if (VK.fb_action_instance_id === response.id)  {
            inviteToShareOnTwitter();
          }
        });
      }
    });
  }
}

function setUpParamsForSocialTracking(facebook_action, action_id, request_id, request_to_ids) {
  var params = {petition_id: VK.petition_id, facebook_action: facebook_action};
  if (VK.signature_id !== "") {
    params = $.extend(params, {signature_id: VK.signature_id});
  }
  if (action_id !== "") {
    params = $.extend(params, {action_id: action_id});
  }
  if (request_id !== "") {
    params = $.extend(params, {request_id: request_id});
    params = $.extend(params, {friend_ids: request_to_ids});
  }

  return params;
}

function setupSocialTrackingControllerRequest(facebook_action, action_id, request_id, request_to_ids) {
    $.ajax({
      url: VK.social_tracking_url,
      data: setUpParamsForSocialTracking(facebook_action, action_id, request_id, request_to_ids)
    });
}

function setupSocialTracking() {
  try {
    if (FB && FB.Event && FB.Event.subscribe) {
      FB.Event.subscribe('edge.create', function (targetUrl) {
        _gaq.push(['_trackSocial', 'facebook', 'like', targetUrl]);
        //Google doesn't export social event data yet, so we have to track social actions as events too
        _gaq.push(['_trackEvent', 'facebook', 'like', targetUrl]);
        setupSocialTrackingControllerRequest('like');
        inviteToShareOnTwitter();
      });
      FB.Event.subscribe('edge.remove', function (targetUrl) {
        _gaq.push(['_trackSocial', 'facebook', 'unlike', targetUrl]);
        _gaq.push(['_trackEvent', 'facebook', 'unlike', targetUrl]);
      });
    }
  } catch (e) {
  }
}

function submitFacebookAction() {
  FB.login(function (response) {
    if (response.authResponse) {
      FB.api(
        '/me/watchdognet:sign',
        'post',
        {
          petition: $('meta[property="og:url"]').attr("content")
        },
        function (response) {
          if (!response || response.error) {
            $('.fb_share_message').text("Please try again.");
          } else {
            setupSocialTrackingControllerRequest('share', response.id, '', '');
            inviteToShareOnTwitter();
          }
        }
      );
    } else {
      $('.fb_share_message').hide();
    }
  }, {scope: 'publish_actions'});
}

function setupShareFacebookButton() {
  var shareButton = $('.fb_share.btn');
  shareButton.click(function (event) {
    $('.fb_share_message').text("Connecting to Facebook...");
    $('.fb_share_message').show();
    submitFacebookAction();
  });
}

function preventWhitespaceOn(input) {
  $(input).change(function () {
    this.value = this.value.replace(/ /g, '');
  });
}

function EmailSuggestions() {
  var self = this;
  var $email = $('#signature_email');
  var $hint = $("#hint");

  this.init = function () {
    $('.suggested_email').live("click", function () {
      $email.val($(this).html());
      $hint.css('display', 'none');
      return false;
    });
  };

  this.mailCheckSuggestions = function (event) {
    $hint.css('display', 'none');
    $email.mailcheck({
      //annoyingly, mailcheck doesn't let you add to their default list of domains, so we have to duplicate them all here.
      domains:["yahoo.com", "google.com", "hotmail.com", "gmail.com", "me.com", "aol.com", "mac.com",
        "live.com", "comcast.net", "googlemail.com", "msn.com", "hotmail.co.uk", "yahoo.co.uk",
        "facebook.com", "verizon.net", "sbcglobal.net", "att.net", "gmx.com", "mail.com", "q.com"],
      suggested:function (element, suggestion) {
        event.go = true;
        if (!$hint.html()) {
          var suggestionFragment = 'Did you mean ' + suggestion.full + "?" +
            "
Click the '" + $("#sign_petition").val() + "' button again if your address is correct";
          $hint.html(suggestionFragment).fadeIn(150);
          event.go = false;
        }
      }
    });
  };
}

function initTwitter() {
  var js, fjs = document.getElementsByTagName("script")[0];
  if (!document.getElementById("twitter-wjs")) {
    js = document.createElement("script");
    js.id = "twitter-wjs";
    js.src = "//platform.twitter.com/widgets.js";
    fjs.parentNode.insertBefore(js, fjs);
  }
}

function bindFacebookPopupButton() {

  function openPopup() {
    var sharer = "https://www.facebook.com/sharer/sharer.php?u=";
    var domain = location.href.replace(/\?.*/,"");
    var memberHash = VK.current_member_hash;
    var url = [sharer, domain, '?share_ref=', memberHash].join('');
    window.open(url , 'sharer', 'width=626,height=436');
  }

  $('.fb_popup_btn').click(function() {
    openPopup();
    setupSocialTrackingControllerRequest('popup');
    inviteToShareOnTwitter();
    $('.giantbox').hide();
  });
}

function bindFacebookWidgetButton() {

  function openWidget() {
    var element = $('.facebook-share-widget');
    $('#thanksModal').modal('hide');
    $('#facebookFriendsModal').modal('toggle');
    var domain = location.href.replace(/\?.*/,"");
    var options = {
      base_path: '/widget',
      template:  { 'link': domain + '?wall=' + VK.current_member_hash }
    };
    if (VK.fbWallLoaded) { return; }
    var widget = new FacebookShareWidget(element, options);
    VK.fbWallLoaded = true;
    $('.facebook-share-widget .search-text').get(0).focus();
  }

  function performLoginAndOpenWidget() {
    setupSocialTrackingControllerRequest('wall');
    FB.login(function (response) {
      if (response.authResponse) {
        openWidget();
       }
    }, {scope: 'publish_stream'});
  }

  $('.fb_widget_btn').click(performLoginAndOpenWidget);
}

function bindFacebookRequestButton() {

  function requestCallbackForSendRequest(response) {
    if(response && response.request) {
      setupSocialTrackingControllerRequest('request', '', response.request, response.to);
    }
    inviteToShareOnTwitter();
  }

  function sendRequestViaMultiFriendSelector() {
    FB.ui({method: 'apprequests',
      message: VK.petition_title
    }, requestCallbackForSendRequest);
  }

  $('.fb_request_btn').click(sendRequestViaMultiFriendSelector);
}

function drawModalAfterSigning() {
  if (screen.width > 480 && $('#thanksModal').length) {
    $('#thanksModal').modal('toggle');
  }
}

function initShowPetition() {
  preventWhitespaceOn('#signature_email');
  setupSocialTracking();

  $('form').on("submit", function (event) {
    if (!VK.signing_from_email) {
      var emailSuggestor = new EmailSuggestions();
      emailSuggestor.init();
      emailSuggestor.mailCheckSuggestions(event);
    }
    return event.go;
  });
}

function initSharePetition() {
  initTwitter();
  initFacebookApp();
  setupSocialTracking();
  setupShareFacebookButton();
  bindFacebookPopupButton();
  bindFacebookWidgetButton();
  bindFacebookRequestButton();
  drawModalAfterSigning();
}
<|endoftext|>