<commit_before>/*
* DOMElement
* Visit http://createjs.com/ for documentation, updates and examples.
*
* Copyright (c) 2010 gskinner.com, inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

(function(ns) {
// TODO: fix problems with rotation.
// TODO: exclude from getObjectsUnderPoint

/**
 * This class is still experimental, and more advanced use is likely to be buggy. Please report bugs.

* A DOMElement allows you to associate a HTMLElement with the display list. It will be transformed
* within the DOM as though it is child of the Container it is added to. However, it is not rendered
* to canvas, and as such will retain whatever z-index it has relative to the canvas (ie. it will be
* drawn in front of or behind the canvas).

* The position of a DOMElement is relative to their parent node in the DOM. It is recommended that
* the DOM Object be added to a div that also contains the canvas so that they share the same position
* on the page.

* DOMElement is useful for positioning HTML elements over top of canvas content, and for elements
* that you want to display outside the bounds of the canvas. For example, a tooltip with rich HTML
* content.

* DOMElement instances are not full EaselJS display objects, and do not participate in EaselJS mouse
* events or support methods like hitTest.
* @class DOMElement
* @extends DisplayObject
* @constructor
* @param {HTMLElement} htmlElement A reference or id for the DOM element to manage.
**/
var DOMElement = function(htmlElement) {
  this.initialize(htmlElement);
}
var p = DOMElement.prototype = new ns.DisplayObject();

// public properties:
	/**
	 * The DOM object to manage.
	 * @property htmlElement
	 * @type HTMLElement
	 **/
	p.htmlElement = null;

// private properties:
	/**
	 * @property _style
	 * @protected
	 **/
	p._style = null;

// constructor:
	/**
	 * @property DisplayObject_initialize
	 * @type Function
   * @private
	 **/
	p.DisplayObject_initialize = p.initialize;

	/**
	 * Initialization method.
	 * @method initialize
	 * @protected
	*/
	p.initialize = function(htmlElement) {
		if (typeof(htmlElement)=="string") { htmlElement = document.getElementById(htmlElement); }
		this.DisplayObject_initialize();
		this.mouseEnabled = false;
		this.htmlElement = htmlElement;
		if (htmlElement) {
			this._style = htmlElement.style;
			this._style.position = "absolute";
			this._style.transformOrigin = this._style.webkitTransformOrigin = this._style.msTransformOrigin = this._style.MozTransformOrigin = this._style.OTransformOrigin = "0% 0%";
		}
	}

// public methods:
	// TODO: fix this. Right now it's used internally to determine if it should be drawn, but DOMElement always needs to be drawn.
	/**
	 * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
	 * This does not account for whether it would be visible within the boundaries of the stage.
	 * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
	 * @method isVisible
	 * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
	 **/
	p.isVisible = function() {
		return this.htmlElement != null;
	}

	/**
	 * Draws the display object into the specified context ignoring it's visible, alpha, shadow, and transform.
	 * Returns true if the draw was handled (useful for overriding functionality).
	 * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
	 * @method draw
	 * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
	 * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
	 * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
	 * into itself).
	 **/
	p.draw = function(ctx, ignoreCache) {
		// TODO: possibly save out previous matrix values, to compare against new ones (so layout doesn't need to fire if there is no change)
		if (this.htmlElement == null) { return; }
		var mtx = this.getConcatenatedMatrix(this._matrix);

		var o = this.htmlElement;
		o.style.opacity = ""+mtx.alpha;
		// this relies on the _tick method because draw isn't called if a parent is not visible.
		o.style.visibility = this.visible ? "visible" : "hidden";
		o.style.transform = o.style.webkitTransform = o.style.OTransform =  o.style.msTransform = ["matrix("+mtx.a,mtx.b,mtx.c,mtx.d,(mtx.tx+0.5|0),(mtx.ty+0.5|0)+")"].join(",");
		o.style.MozTransform = ["matrix("+mtx.a,mtx.b,mtx.c,mtx.d,(mtx.tx+0.5|0)+"px",(mtx.ty+0.5|0)+"px)"].join(",");
		return true;
	}

	/**
	 * Not applicable to DOMElement.
	 * @method cache
	 */
	p.cache = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method uncache
	 */
	p.uncache = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method updateCache
	 */
	p.updateCache = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method updateCache
	 */
	p.hitTest = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method localToGlobal
	 */
	p.localToGlobal = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method globalToLocal
	 */
	p.globalToLocal = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method localToLocal
	 */
	p.localToLocal = function() {}

	/**
	 * This presently clones the DOMElement instance, but not the associated HTMLElement.
	 * @method clone
	 * @return {DOMElement} a clone of the DOMElement instance.
	 **/
	p.clone = function() {
		var o = new DOMElement();
		this.cloneProps(o);
		return o;
	}

	/**
	 * Returns a string representation of this object.
	 * @method toString
	 * @return {String} a string representation of the instance.
	 **/
	p.toString = function() {
		return "[DOMElement (name="+  this.name +")]";
	}

// private methods:
	p._tick = function(data) {
		if (this.htmlElement == null) { return; }
		this.htmlElement.style.visibility = "hidden";
		if (this.onTick) { this.onTick(data); }
	}

	/* Not needed with current setup:
	p._calculateVisible = function() {
		var p = this;
		while (p) {
			if (!p.visible) { return false; }
			p = p.parent;
		}
		return true;
	}
	*/
ns.DOMElement = DOMElement;
}(createjs||(createjs={})));
var createjs;<commit_msg>webkit to Webkit in DOMElement<commit_after>/*
* DOMElement
* Visit http://createjs.com/ for documentation, updates and examples.
*
* Copyright (c) 2010 gskinner.com, inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

(function(ns) {
// TODO: fix problems with rotation.
// TODO: exclude from getObjectsUnderPoint

/**
 * This class is still experimental, and more advanced use is likely to be buggy. Please report bugs.

* A DOMElement allows you to associate a HTMLElement with the display list. It will be transformed
* within the DOM as though it is child of the Container it is added to. However, it is not rendered
* to canvas, and as such will retain whatever z-index it has relative to the canvas (ie. it will be
* drawn in front of or behind the canvas).

* The position of a DOMElement is relative to their parent node in the DOM. It is recommended that
* the DOM Object be added to a div that also contains the canvas so that they share the same position
* on the page.

* DOMElement is useful for positioning HTML elements over top of canvas content, and for elements
* that you want to display outside the bounds of the canvas. For example, a tooltip with rich HTML
* content.

* DOMElement instances are not full EaselJS display objects, and do not participate in EaselJS mouse
* events or support methods like hitTest.
* @class DOMElement
* @extends DisplayObject
* @constructor
* @param {HTMLElement} htmlElement A reference or id for the DOM element to manage.
**/
var DOMElement = function(htmlElement) {
  this.initialize(htmlElement);
}
var p = DOMElement.prototype = new ns.DisplayObject();

// public properties:
	/**
	 * The DOM object to manage.
	 * @property htmlElement
	 * @type HTMLElement
	 **/
	p.htmlElement = null;

// private properties:
	/**
	 * @property _style
	 * @protected
	 **/
	p._style = null;

// constructor:
	/**
	 * @property DisplayObject_initialize
	 * @type Function
   * @private
	 **/
	p.DisplayObject_initialize = p.initialize;

	/**
	 * Initialization method.
	 * @method initialize
	 * @protected
	*/
	p.initialize = function(htmlElement) {
		if (typeof(htmlElement)=="string") { htmlElement = document.getElementById(htmlElement); }
		this.DisplayObject_initialize();
		this.mouseEnabled = false;
		this.htmlElement = htmlElement;
		if (htmlElement) {
			this._style = htmlElement.style;
			this._style.position = "absolute";
			this._style.transformOrigin = this._style.WebkitTransformOrigin = this._style.msTransformOrigin = this._style.MozTransformOrigin = this._style.OTransformOrigin = "0% 0%";
		}
	}

// public methods:
	// TODO: fix this. Right now it's used internally to determine if it should be drawn, but DOMElement always needs to be drawn.
	/**
	 * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
	 * This does not account for whether it would be visible within the boundaries of the stage.
	 * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
	 * @method isVisible
	 * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
	 **/
	p.isVisible = function() {
		return this.htmlElement != null;
	}

	/**
	 * Draws the display object into the specified context ignoring it's visible, alpha, shadow, and transform.
	 * Returns true if the draw was handled (useful for overriding functionality).
	 * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
	 * @method draw
	 * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
	 * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
	 * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
	 * into itself).
	 **/
	p.draw = function(ctx, ignoreCache) {
		// TODO: possibly save out previous matrix values, to compare against new ones (so layout doesn't need to fire if there is no change)
		if (this.htmlElement == null) { return; }
		var mtx = this.getConcatenatedMatrix(this._matrix);

		var o = this.htmlElement;
		o.style.opacity = ""+mtx.alpha;
		// this relies on the _tick method because draw isn't called if a parent is not visible.
		o.style.visibility = this.visible ? "visible" : "hidden";
		o.style.transform = o.style.WebkitTransform = o.style.OTransform =  o.style.msTransform = ["matrix("+mtx.a,mtx.b,mtx.c,mtx.d,(mtx.tx+0.5|0),(mtx.ty+0.5|0)+")"].join(",");
		o.style.MozTransform = ["matrix("+mtx.a,mtx.b,mtx.c,mtx.d,(mtx.tx+0.5|0)+"px",(mtx.ty+0.5|0)+"px)"].join(",");
		return true;
	}

	/**
	 * Not applicable to DOMElement.
	 * @method cache
	 */
	p.cache = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method uncache
	 */
	p.uncache = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method updateCache
	 */
	p.updateCache = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method updateCache
	 */
	p.hitTest = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method localToGlobal
	 */
	p.localToGlobal = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method globalToLocal
	 */
	p.globalToLocal = function() {}

	/**
	 * Not applicable to DOMElement.
	 * @method localToLocal
	 */
	p.localToLocal = function() {}

	/**
	 * This presently clones the DOMElement instance, but not the associated HTMLElement.
	 * @method clone
	 * @return {DOMElement} a clone of the DOMElement instance.
	 **/
	p.clone = function() {
		var o = new DOMElement();
		this.cloneProps(o);
		return o;
	}

	/**
	 * Returns a string representation of this object.
	 * @method toString
	 * @return {String} a string representation of the instance.
	 **/
	p.toString = function() {
		return "[DOMElement (name="+  this.name +")]";
	}

// private methods:
	p._tick = function(data) {
		if (this.htmlElement == null) { return; }
		this.htmlElement.style.visibility = "hidden";
		if (this.onTick) { this.onTick(data); }
	}

	/* Not needed with current setup:
	p._calculateVisible = function() {
		var p = this;
		while (p) {
			if (!p.visible) { return false; }
			p = p.parent;
		}
		return true;
	}
	*/
ns.DOMElement = DOMElement;
}(createjs||(createjs={})));
var createjs;<|endoftext|>


<commit_before>//
// Inject into GitHub.com
//
function icRun() {
  var target = document.querySelector('.js-calendar-graph');

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.type === 'childList') {
        var days     = $('#calendar-graph rect');
        var bestDay  = "";
        var maxCount = 0;
        d3.selectAll(days).attr("data-contrib-count", function(d, i) {
          if (d[1] > maxCount) {
            bestDay  = d[0];
            maxCount = d[1];
          }
          return d[1];
        });
        observer.disconnect();
        target.setAttribute("data-max-contributions", maxCount);
        target.setAttribute("data-best-day", bestDay);
      }
    });
  });

  observer.observe(target, { attributes: true, childList: true, characterData: true});
}
var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ icRun +')();'));
document.documentElement.appendChild(script);

//
// The actual extension
//

$(function() {
  var target = document.querySelector('.js-calendar-graph');

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.attributeName === 'data-max-contributions') {
        // We're loaded and ready!
        observer.disconnect();
        renderIsometricChart();
        initUI();
      }
    });
  });

  debugger;
  if ($('.js-calendar-graph').data("max-contributions") !== undefined) {
    renderIsometricChart();
    initUI();
  }
  else {
    observer.observe(target, { attributes: true, childList: true, characterData: true});
  }

});

function renderIsometricChart() {
  $('

').insertBefore('#contributions-calendar');
  $('<canvas id="isometric-contributions" width="728" height="470"></canvas>').appendTo('.ic-contributions-wrapper');

  var SIZE       = 12;
  var GH_OFFSET  = 13;
  var MAX_HEIGHT = 100;

  var canvas = document.getElementById('isometric-contributions');

  // create pixel view container in point
  var point = new obelisk.Point(87, 100);
  var pixelView = new obelisk.PixelView(canvas, point);

  var maxContributions = $('.js-calendar-graph').data("max-contributions");
  var contribCount;

  $('#calendar-graph g > g').each(function(g) {
    var x = parseInt($(this).attr('transform').match(/(\d+)/)[0] / GH_OFFSET);
    $(this).find('rect').each(function(r) {
      var r            = $(this).get(0);
      var y            = parseInt($(this).attr('y') / GH_OFFSET);
      var style        = $(this).attr('style');
      var contribCount = parseInt($(this).data("contrib-count"));

      var dimension = new obelisk.CubeDimension(SIZE, SIZE, parseInt(MAX_HEIGHT/maxContributions * contribCount) + 3);

      var color = getSquareColor(style);
      var cube  = new obelisk.Cube(dimension, color, false);
      var p3d   = new obelisk.Point3D(SIZE * x, SIZE * y, 0);
      pixelView.renderObject(cube, p3d);
    });
  });
}

function initUI() {
  var contributionsBox = $('#contributions-calendar').closest('.box').find('.box-body');
  var insertLocation   = $('#contributions-calendar').closest('.box').find('.box-header .box-title');

  // Inject toggle
  $('').insertBefore(insertLocation);

  // Observe toggle
  $('.ic-toggle-option').click(function(e) {
    e.preventDefault();
    var option = $(this).data("ic-option");
    if (option === "squares") {
      contributionsBox.removeClass('ic-cubes').addClass('ic-squares');
    }
    else {
      contributionsBox.removeClass('ic-squares').addClass('ic-cubes');
    }
    $('.ic-toggle-option').removeClass('active');
    $(this).addClass('active');

    chrome.storage.local.set({'toggleSetting': option});
  });

  // Check for user preference
  chrome.storage.local.get('toggleSetting', function (result) {
    if (result.toggleSetting !== undefined) {
      $('.ic-toggle-option.'+result.toggleSetting).addClass('active');
      contributionsBox.addClass('ic-'+result.toggleSetting);
    }
    else {
      $('.ic-toggle-option.cubes').addClass('active');
      contributionsBox.removeClass('ic-squares').addClass('ic-cubes');
    }
  });

  // Inject footer w/ toggle for showing 2D chart
  $('Show normal chart below ▾').appendTo($('.ic-contributions-wrapper'));

  $('.ic-2d-toggle').click(function(e) {
    e.preventDefault();
    if (contributionsBox.hasClass('show-2d')) {
      $(this).text('Show normal chart below ▾');
      contributionsBox.removeClass('show-2d');
    }
    else {
      $(this).text('Hide normal chart below ▴');
      contributionsBox.addClass('show-2d');
    }
  });

  loadStats();
}

function loadStats() {
  // Year total
  var str        = $('.contrib-day').html();
  var html       = $.parseHTML(str);
  var countTotal = html[1].innerText.match(/(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?/)[0];
  var datesTotal = $.trim(html[2].nodeValue);

  // Best day
  var countBest = $('.js-calendar-graph').data('max-contributions');
  var dateParts = $('.js-calendar-graph').data('best-day').split(" ");
  var dateBest  = dateParts[1] + " " + dateParts[2] + " " + dateParts[3];

  $('
1 year total' + countTotal + 'contributions' + datesTotal + 'Busiest day' + countBest + 'contributions' + dateBest + '
').appendTo($('.ic-contributions-wrapper'));

  // Longest streak
  var str          = $('.contrib-streak').html();
  var html         = $.parseHTML(str);
  var countLongest = html[1].innerText.match(/(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?/)[0];
  var datesLongest = $.trim(html[2].nodeValue);

  // Current streak
  var str          = $('.contrib-streak-current').html();
  var html         = $.parseHTML(str);
  var countCurrent = html[1].innerText.match(/(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?/)[0];
  var datesCurrent = $.trim(html[2].nodeValue);

  $('
Longest streak' + countLongest + 'days' + datesLongest + 'Current streak' + countCurrent + 'days' + datesCurrent + '
').appendTo($('.ic-contributions-wrapper'));
}

function getSquareColor(style) {
  var color;
  var color0 = new obelisk.CubeColor().getByHorizontalColor(0xeeeeee);
  var color1 = new obelisk.CubeColor().getByHorizontalColor(0xd6e685);
  var color2 = new obelisk.CubeColor().getByHorizontalColor(0x8cc665);
  var color3 = new obelisk.CubeColor().getByHorizontalColor(0x44a340);
  var color4 = new obelisk.CubeColor().getByHorizontalColor(0x1e6823);

  if      (style == 'fill: rgb(238, 238, 238);' || style == 'fill: #eeeeee;') color = color0;
  else if (style == 'fill: rgb(214, 230, 133);' || style == 'fill: #d6e685;')  color = color1;
  else if (style == 'fill: rgb(140, 198, 101);' || style == 'fill: #8cc665;')  color = color2;
  else if (style == 'fill: rgb(68, 163, 64);'   || style == 'fill: #44a340;')  color = color3;
  else if (style == 'fill: rgb(30, 104, 35);'   || style == 'fill: #1e6823;')  color = color4;

  return color;
}

<commit_msg>handle display of busiest day w/ 0 contributions<commit_after>//
// Inject into GitHub.com
//
function icRun() {
  var target = document.querySelector('.js-calendar-graph');

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.type === 'childList') {
        var days     = $('#calendar-graph rect');
        var bestDay  = "";
        var maxCount = 0;
        d3.selectAll(days).attr("data-contrib-count", function(d, i) {
          if (d[1] > maxCount) {
            bestDay  = d[0];
            maxCount = d[1];
          }
          return d[1];
        });
        observer.disconnect();
        target.setAttribute("data-max-contributions", maxCount);
        target.setAttribute("data-best-day", bestDay);
      }
    });
  });

  observer.observe(target, { attributes: true, childList: true, characterData: true});
}
var script = document.createElement('script');
script.appendChild(document.createTextNode('('+ icRun +')();'));
document.documentElement.appendChild(script);

//
// The actual extension
//

$(function() {
  var target = document.querySelector('.js-calendar-graph');

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.attributeName === 'data-max-contributions') {
        // We're loaded and ready!
        observer.disconnect();
        renderIsometricChart();
        initUI();
      }
    });
  });

  if ($('.js-calendar-graph').data("max-contributions") !== undefined) {
    renderIsometricChart();
    initUI();
  }
  else {
    observer.observe(target, { attributes: true, childList: true, characterData: true});
  }

});

function renderIsometricChart() {
  $('

').insertBefore('#contributions-calendar');
  $('<canvas id="isometric-contributions" width="728" height="470"></canvas>').appendTo('.ic-contributions-wrapper');

  var SIZE       = 12;
  var GH_OFFSET  = 13;
  var MAX_HEIGHT = 100;

  var canvas = document.getElementById('isometric-contributions');

  // create pixel view container in point
  var point = new obelisk.Point(87, 100);
  var pixelView = new obelisk.PixelView(canvas, point);

  var maxContributions = $('.js-calendar-graph').data("max-contributions");
  var contribCount;

  $('#calendar-graph g > g').each(function(g) {
    var x = parseInt($(this).attr('transform').match(/(\d+)/)[0] / GH_OFFSET);
    $(this).find('rect').each(function(r) {
      var r            = $(this).get(0);
      var y            = parseInt($(this).attr('y') / GH_OFFSET);
      var style        = $(this).attr('style');
      var contribCount = parseInt($(this).data("contrib-count"));

      var dimension = new obelisk.CubeDimension(SIZE, SIZE, parseInt(MAX_HEIGHT/maxContributions * contribCount) + 3);

      var color = getSquareColor(style);
      var cube  = new obelisk.Cube(dimension, color, false);
      var p3d   = new obelisk.Point3D(SIZE * x, SIZE * y, 0);
      pixelView.renderObject(cube, p3d);
    });
  });
}

function initUI() {
  var contributionsBox = $('#contributions-calendar').closest('.box').find('.box-body');
  var insertLocation   = $('#contributions-calendar').closest('.box').find('.box-header .box-title');

  // Inject toggle
  $('').insertBefore(insertLocation);

  // Observe toggle
  $('.ic-toggle-option').click(function(e) {
    e.preventDefault();
    var option = $(this).data("ic-option");
    if (option === "squares") {
      contributionsBox.removeClass('ic-cubes').addClass('ic-squares');
    }
    else {
      contributionsBox.removeClass('ic-squares').addClass('ic-cubes');
    }
    $('.ic-toggle-option').removeClass('active');
    $(this).addClass('active');

    chrome.storage.local.set({'toggleSetting': option});
  });

  // Check for user preference
  chrome.storage.local.get('toggleSetting', function (result) {
    if (result.toggleSetting !== undefined) {
      $('.ic-toggle-option.'+result.toggleSetting).addClass('active');
      contributionsBox.addClass('ic-'+result.toggleSetting);
    }
    else {
      $('.ic-toggle-option.cubes').addClass('active');
      contributionsBox.removeClass('ic-squares').addClass('ic-cubes');
    }
  });

  // Inject footer w/ toggle for showing 2D chart
  $('Show normal chart below ▾').appendTo($('.ic-contributions-wrapper'));

  $('.ic-2d-toggle').click(function(e) {
    e.preventDefault();
    if (contributionsBox.hasClass('show-2d')) {
      $(this).text('Show normal chart below ▾');
      contributionsBox.removeClass('show-2d');
    }
    else {
      $(this).text('Hide normal chart below ▴');
      contributionsBox.addClass('show-2d');
    }
  });

  loadStats();
}

function loadStats() {
  // Year total
  var str        = $('.contrib-day').html();
  var html       = $.parseHTML(str);
  var countTotal = html[1].innerText.match(/(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?/)[0];
  var datesTotal = $.trim(html[2].nodeValue);

  // Best day
  var countBest = $('.js-calendar-graph').data('max-contributions');
  var dateParts = $('.js-calendar-graph').data('best-day').split(" ");
  var dateBest  = "Not so busy after all.";
  if (dateParts[1] !== undefined) {
    dateBest  = dateParts[1] + " " + dateParts[2] + " " + dateParts[3];
  }

  $('
1 year total' + countTotal + 'contributions' + datesTotal + 'Busiest day' + countBest + 'contributions' + dateBest + '
').appendTo($('.ic-contributions-wrapper'));

  // Longest streak
  var str          = $('.contrib-streak').html();
  var html         = $.parseHTML(str);
  var countLongest = html[1].innerText.match(/(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?/)[0];
  var datesLongest = $.trim(html[2].nodeValue);

  // Current streak
  var str          = $('.contrib-streak-current').html();
  var html         = $.parseHTML(str);
  var countCurrent = html[1].innerText.match(/(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?/)[0];
  var datesCurrent = $.trim(html[2].nodeValue);

  $('
Longest streak' + countLongest + 'days' + datesLongest + 'Current streak' + countCurrent + 'days' + datesCurrent + '
').appendTo($('.ic-contributions-wrapper'));
}

function getSquareColor(style) {
  var color;
  var color0 = new obelisk.CubeColor().getByHorizontalColor(0xeeeeee);
  var color1 = new obelisk.CubeColor().getByHorizontalColor(0xd6e685);
  var color2 = new obelisk.CubeColor().getByHorizontalColor(0x8cc665);
  var color3 = new obelisk.CubeColor().getByHorizontalColor(0x44a340);
  var color4 = new obelisk.CubeColor().getByHorizontalColor(0x1e6823);

  if      (style == 'fill: rgb(238, 238, 238);' || style == 'fill: #eeeeee;') color = color0;
  else if (style == 'fill: rgb(214, 230, 133);' || style == 'fill: #d6e685;')  color = color1;
  else if (style == 'fill: rgb(140, 198, 101);' || style == 'fill: #8cc665;')  color = color2;
  else if (style == 'fill: rgb(68, 163, 64);'   || style == 'fill: #44a340;')  color = color3;
  else if (style == 'fill: rgb(30, 104, 35);'   || style == 'fill: #1e6823;')  color = color4;

  return color;
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 Alex Grant (@localnerve), LocalNerve LLC
 * Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
 *
 */
'use strict';

var debug = require('debug')('Example:Utils:Transformers');

// This will be a hash of all the availble actions that can be defined
var actions = {
  example: require('../actions/example')
};

/*
 * Transforms from json routes to fluxible routes.
 */
function toFluxibleRoutes(routes) {
  debug('Transforming json to fluxible routes');
  var fluxibleRoutes = {};

  Object.keys(routes).forEach(function(route) {
    var transformed = routes[route];

    debug('transforming "'+transformed.action.name+'" to '+
      (actions[transformed.action.name].name || 'undefined'));

    if (!actions[transformed.action.name]) {
      throw new Error('action "'+transformed.action.name+'"" not found');
    }

    transformed.action = (function(action, actionParams) {
      return function (context, payload, done) {
        context.executeAction(action, actionParams, done);
      };
    }(actions[transformed.action.name], transformed.action.params));

    fluxibleRoutes[route] = transformed;
  });

  return fluxibleRoutes;
}

module.exports = {
  toFluxibleRoutes: toFluxibleRoutes
};<commit_msg>fixed error check order<commit_after>/**
 * Copyright (c) 2015 Alex Grant (@localnerve), LocalNerve LLC
 * Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
 *
 */
'use strict';

var debug = require('debug')('Example:Utils:Transformers');

// This will be a hash of all the availble actions that can be defined
var actions = {
  example: require('../actions/example')
};

/*
 * Transforms from json routes to fluxible routes.
 */
function toFluxibleRoutes(routes) {
  debug('Transforming json to fluxible routes');
  var fluxibleRoutes = {};

  Object.keys(routes).forEach(function(route) {
    var transformed = routes[route];

    if (!actions[transformed.action.name]) {
      throw new Error('action "'+transformed.action.name+'"" not found');
    }

    debug('transforming "'+transformed.action.name+'" to '+
      (actions[transformed.action.name].name || 'undefined'));

    transformed.action = (function(action, actionParams) {
      return function (context, payload, done) {
        context.executeAction(action, actionParams, done);
      };
    }(actions[transformed.action.name], transformed.action.params));

    fluxibleRoutes[route] = transformed;
  });

  return fluxibleRoutes;
}

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


<commit_before>// Install any necessary polyfills into global, such as es6, stage/3, stage/4, etc. as needed
//
require('../styles/app.scss');

import 'core-js/es6';

// Seems like importing 'react-dom' is not enough, we need to import 'react' as well.
import React from 'react';
import ReactDOM from 'react-dom';

import uuid from 'uuid';
import $ from 'jquery';
import 'arrive';
import { scrape, scrapeUserData } from './scrape';

import config from './config';
import hub from './hub';
import { getTimeISO8601 } from './utils';
import { registerHandlers } from './handlers/index';

import StartButton from './components/startButton';

function boot () {
    console.log(`Fbtrex version ${config.VERSION} build ${config.BUILD} loading.`);

    // Source handlers so they can process events
    registerHandlers(hub);

    render();
    timeline();
    prefeed();
    watch();
    flush();
};

function timeline () {
    processTimeline();
    document.arrive('#feedx_container', processTimeline);
}

function prefeed () {
    document.querySelectorAll('.userContentWrapper').forEach(processPost);
};

function watch () {
    document.arrive('.userContentWrapper', function () { processPost(this); });
};

function render () {
    const rootElement = $('<div />', { 'id': 'fbtrex--root' });
    const basicInfo = scrapeUserData($('body'));

    hub.event('user', basicInfo);

    $('body').append(rootElement);
    ReactDOM.render((<StartButton userId={basicInfo.id} />), document.getElementById('fbtrex--root'));
};

function flush () {
    window.addEventListener('beforeunload', (e) => {
        hub.event('windowUnload');
    });
}

function processPost (elem) {
    if (window.location.href !== 'https://www.facebook.com/') {
        console.debug('Skip post, not in main feed');
        return;
    }

    const $elem = $(elem).parent();
    const data = scrape($elem);

    if (data) {
        hub.event('newPost', { element: $elem, data: data });
    }
};

function processTimeline () {
    hub.event('newTimeline', { uuid: uuid.v4(), dt: getTimeISO8601() });
}

boot();
<commit_msg>Process only posts in the main column (no ticker)<commit_after>// Install any necessary polyfills into global, such as es6, stage/3, stage/4, etc. as needed
//
require('../styles/app.scss');

import 'core-js/es6';

// Seems like importing 'react-dom' is not enough, we need to import 'react' as well.
import React from 'react';
import ReactDOM from 'react-dom';

import uuid from 'uuid';
import $ from 'jquery';
import 'arrive';
import { scrape, scrapeUserData } from './scrape';

import config from './config';
import hub from './hub';
import { getTimeISO8601 } from './utils';
import { registerHandlers } from './handlers/index';

import StartButton from './components/startButton';

function boot () {
    console.log(`Fbtrex version ${config.VERSION} build ${config.BUILD} loading.`);

    // Source handlers so they can process events
    registerHandlers(hub);

    render();
    timeline();
    prefeed();
    watch();
    flush();
};

function timeline () {
    processTimeline();
    document.arrive('#feedx_container', processTimeline);
}

function prefeed () {
    document.querySelectorAll('#contentCol .userContentWrapper').forEach(processPost);
};

function watch () {
    document.arrive('#contentCol .userContentWrapper', function () { processPost(this); });
};

function render () {
    const rootElement = $('<div />', { 'id': 'fbtrex--root' });
    const basicInfo = scrapeUserData($('body'));

    hub.event('user', basicInfo);

    $('body').append(rootElement);
    ReactDOM.render((<StartButton userId={basicInfo.id} />), document.getElementById('fbtrex--root'));
};

function flush () {
    window.addEventListener('beforeunload', (e) => {
        hub.event('windowUnload');
    });
}

function processPost (elem) {
    if (window.location.href !== 'https://www.facebook.com/') {
        console.debug('Skip post, not in main feed');
        return;
    }

    const $elem = $(elem).parent();
    const data = scrape($elem);

    if (data) {
        hub.event('newPost', { element: $elem, data: data });
    }
};

function processTimeline () {
    hub.event('newTimeline', { uuid: uuid.v4(), dt: getTimeISO8601() });
}

boot();
<|endoftext|>


<commit_before>(function (Handsontable) {
  var AutocompleteEditor = Handsontable.editors.HandsontableEditor.prototype.extend();

  AutocompleteEditor.prototype.init = function () {
    Handsontable.editors.HandsontableEditor.prototype.init.apply(this, arguments);
    this.$htContainer.handsontable('updateSettings', {height: this.getDropdownHeight()});

    this.query = null;
    this.choices = [];
  };

  AutocompleteEditor.prototype.createElements = function(){
    Handsontable.editors.HandsontableEditor.prototype.createElements.apply(this, arguments);

    this.$htContainer.addClass('autocompleteEditor');

  };

  AutocompleteEditor.prototype.bindEvents = function(){
    var that = this;

    this.$textarea.on('keydown.autocompleteEditor', function(event){

      if(!Handsontable.helper.isMetaKey(event.keyCode) || [Handsontable.helper.keyCode.BACKSPACE, Handsontable.helper.keyCode.DELETE].indexOf(event.keyCode) != -1){
        setTimeout(function () {
          that.queryChoices(that.$textarea.val());
        });
      } else if (event.keyCode == Handsontable.helper.keyCode.ENTER && that.cellProperties.strict !== true){
        that.$htContainer.handsontable('deselectCell');
      }

    });

    this.$htContainer.on('mouseleave', function () {
      if(that.cellProperties.strict === true){
        that.highlightBestMatchingChoice();
      }
    });

    this.$htContainer.on('mouseenter', function () {
      that.$htContainer.handsontable('deselectCell');
    });

    Handsontable.editors.HandsontableEditor.prototype.bindEvents.apply(this, arguments);

  };

  var onBeforeKeyDownInner;

  AutocompleteEditor.prototype.open = function () {

    Handsontable.editors.HandsontableEditor.prototype.open.apply(this, arguments);

    this.$textarea[0].style.visibility = 'visible';
    this.focus();

    var choicesListHot =  this.$htContainer.handsontable('getInstance');
    var that = this;

    choicesListHot.updateSettings({
      'colWidths': [Handsontable.Dom.outerWidth(this.TEXTAREA) - 2],
      afterRenderer: function (TD, row, col, prop, value) {
        var caseSensitive = this.getCellMeta(row, col).filteringCaseSensitive === true;
        var indexOfMatch =  caseSensitive ? value.indexOf(this.query) : value.toLowerCase().indexOf(that.query.toLowerCase());

        if(indexOfMatch != -1){
          var match = value.substr(indexOfMatch, that.query.length);
          TD.innerHTML = value.replace(match, '' + match + '');
        }
      }
    });

    onBeforeKeyDownInner = function (event) {
      var instance = this;

      if (event.keyCode == Handsontable.helper.keyCode.ARROW_UP){
        if (instance.getSelected() && instance.getSelected()[0] == 0){

          if(!parent.cellProperties.strict){
            instance.deselectCell();
          }

          parent.instance.listen();
          parent.focus();
          event.preventDefault();
          event.stopImmediatePropagation();
        }
      }

    };

    choicesListHot.addHook('beforeKeyDown', onBeforeKeyDownInner);

    this.queryChoices(this.TEXTAREA.value);

  };

  AutocompleteEditor.prototype.close = function () {

    this.$htContainer.handsontable('getInstance').removeHook('beforeKeyDown', onBeforeKeyDownInner);

    Handsontable.editors.HandsontableEditor.prototype.close.apply(this, arguments);
  };

  AutocompleteEditor.prototype.queryChoices = function(query){
    this.query = query;

    if (typeof this.cellProperties.source == 'function'){
      var that = this;

      this.cellProperties.source(query, function(choices){
        that.updateChoicesList(choices)
      });

    } else if (Handsontable.helper.isArray(this.cellProperties.source)) {

      var choices;

      if(!query || this.cellProperties.filter === false){
        choices = this.cellProperties.source;
      } else {

        var filteringCaseSensitive = this.cellProperties.filteringCaseSensitive === true;
        var lowerCaseQuery = query.toLowerCase();

        choices = this.cellProperties.source.filter(function(choice){

          if (filteringCaseSensitive) {
            return choice.indexOf(query) != -1;
          } else {
            return choice.toLowerCase().indexOf(lowerCaseQuery) != -1;
          }

        });
      }

      this.updateChoicesList(choices)

    } else {
      this.updateChoicesList([]);
    }

  };

  AutocompleteEditor.prototype.updateChoicesList = function (choices) {

     this.choices = choices;

    this.$htContainer.handsontable('loadData', Handsontable.helper.pivot([choices]));

    if(this.cellProperties.strict === true){
      this.highlightBestMatchingChoice();
    }

    //this.focus(); // this override textEditor events ie. ctrl combinations
    // Can't highlight text in the cell with ctrl+a in autocomplete demo #1590
  };

  AutocompleteEditor.prototype.highlightBestMatchingChoice = function () {
    var bestMatchingChoice = this.findBestMatchingChoice();

    if ( typeof bestMatchingChoice == 'undefined' && this.cellProperties.allowInvalid === false){
      bestMatchingChoice = 0;
    }

    if(typeof bestMatchingChoice == 'undefined'){
      this.$htContainer.handsontable('deselectCell');
    } else {
      this.$htContainer.handsontable('selectCell', bestMatchingChoice, 0);
    }

  };

  AutocompleteEditor.prototype.findBestMatchingChoice = function(){
    var bestMatch = {};
    var valueLength = this.getValue().length;
    var currentItem;
    var indexOfValue;
    var charsLeft;

    for(var i = 0, len = this.choices.length; i < len; i++){
      currentItem = this.choices[i];

      if(valueLength > 0){
        indexOfValue = currentItem.indexOf(this.getValue())
      } else {
        indexOfValue = currentItem === this.getValue() ? 0 : -1;
      }

      if(indexOfValue == -1) continue;

      charsLeft =  currentItem.length - indexOfValue - valueLength;

      if( typeof bestMatch.indexOfValue == 'undefined'
        || bestMatch.indexOfValue > indexOfValue
        || ( bestMatch.indexOfValue == indexOfValue && bestMatch.charsLeft > charsLeft ) ){

        bestMatch.indexOfValue = indexOfValue;
        bestMatch.charsLeft = charsLeft;
        bestMatch.index = i;

      }

    }

    return bestMatch.index;
  };

  AutocompleteEditor.prototype.getDropdownHeight = function(){
    //return 10 * this.$htContainer.handsontable('getInstance').getRowHeight(0);
    //sorry, we can't measure row height before it was rendered. Let's use fixed height for now
    return 230;
  };

  Handsontable.editors.AutocompleteEditor = AutocompleteEditor;
  Handsontable.editors.registerEditor('autocomplete', AutocompleteEditor);

})(Handsontable);
<commit_msg>Editing autocomplete selection, cursor goes to the end of selected string<commit_after>(function (Handsontable) {
  var AutocompleteEditor = Handsontable.editors.HandsontableEditor.prototype.extend();

  AutocompleteEditor.prototype.init = function () {
    Handsontable.editors.HandsontableEditor.prototype.init.apply(this, arguments);
    this.$htContainer.handsontable('updateSettings', {height: this.getDropdownHeight()});

    this.query = null;
    this.choices = [];
  };

  AutocompleteEditor.prototype.createElements = function(){
    Handsontable.editors.HandsontableEditor.prototype.createElements.apply(this, arguments);

    this.$htContainer.addClass('autocompleteEditor');

  };

  AutocompleteEditor.prototype.bindEvents = function(){
    var that = this;

    this.$textarea.on('keydown.autocompleteEditor', function(event){

      if(!Handsontable.helper.isMetaKey(event.keyCode) || [Handsontable.helper.keyCode.BACKSPACE, Handsontable.helper.keyCode.DELETE].indexOf(event.keyCode) != -1){
        setTimeout(function () {
          that.queryChoices(that.$textarea.val());
        });
      } else if (event.keyCode == Handsontable.helper.keyCode.ENTER && that.cellProperties.strict !== true){
        that.$htContainer.handsontable('deselectCell');
      }

    });

    this.$htContainer.on('mouseleave', function () {
      if(that.cellProperties.strict === true){
        that.highlightBestMatchingChoice();
      }
    });

    this.$htContainer.on('mouseenter', function () {
      that.$htContainer.handsontable('deselectCell');
    });

    Handsontable.editors.HandsontableEditor.prototype.bindEvents.apply(this, arguments);

  };

  var onBeforeKeyDownInner;

  AutocompleteEditor.prototype.open = function () {

    Handsontable.editors.HandsontableEditor.prototype.open.apply(this, arguments);

    this.$textarea[0].style.visibility = 'visible';
    this.focus();

    var choicesListHot =  this.$htContainer.handsontable('getInstance');
    var that = this;

    choicesListHot.updateSettings({
      'colWidths': [Handsontable.Dom.outerWidth(this.TEXTAREA) - 2],
      afterRenderer: function (TD, row, col, prop, value) {
        var caseSensitive = this.getCellMeta(row, col).filteringCaseSensitive === true;
        var indexOfMatch =  caseSensitive ? value.indexOf(this.query) : value.toLowerCase().indexOf(that.query.toLowerCase());

        if(indexOfMatch != -1){
          var match = value.substr(indexOfMatch, that.query.length);
          TD.innerHTML = value.replace(match, '' + match + '');
        }
      }
    });

    onBeforeKeyDownInner = function (event) {
      var instance = this;

      if (event.keyCode == Handsontable.helper.keyCode.ARROW_UP){
        if (instance.getSelected() && instance.getSelected()[0] == 0){

          if(!parent.cellProperties.strict){
            instance.deselectCell();
          }

          parent.instance.listen();
          parent.focus();
          event.preventDefault();
          event.stopImmediatePropagation();
        }
      }

    };

    choicesListHot.addHook('beforeKeyDown', onBeforeKeyDownInner);

    this.queryChoices(this.TEXTAREA.value);

  };

  AutocompleteEditor.prototype.close = function () {

    this.$htContainer.handsontable('getInstance').removeHook('beforeKeyDown', onBeforeKeyDownInner);

    Handsontable.editors.HandsontableEditor.prototype.close.apply(this, arguments);
  };

  AutocompleteEditor.prototype.queryChoices = function(query){
    this.query = query;

    if (typeof this.cellProperties.source == 'function'){
      var that = this;

      this.cellProperties.source(query, function(choices){
        that.updateChoicesList(choices)
      });

    } else if (Handsontable.helper.isArray(this.cellProperties.source)) {

      var choices;

      if(!query || this.cellProperties.filter === false){
        choices = this.cellProperties.source;
      } else {

        var filteringCaseSensitive = this.cellProperties.filteringCaseSensitive === true;
        var lowerCaseQuery = query.toLowerCase();

        choices = this.cellProperties.source.filter(function(choice){

          if (filteringCaseSensitive) {
            return choice.indexOf(query) != -1;
          } else {
            return choice.toLowerCase().indexOf(lowerCaseQuery) != -1;
          }

        });
      }

      this.updateChoicesList(choices)

    } else {
      this.updateChoicesList([]);
    }

  };

  AutocompleteEditor.prototype.updateChoicesList = function (choices) {

     this.choices = choices;

    this.$htContainer.handsontable('loadData', Handsontable.helper.pivot([choices]));

    if(this.cellProperties.strict === true){
      this.highlightBestMatchingChoice();
    }

    //this.focus(); // this override textEditor events ie. ctrl combinations
    // Can't highlight text in the cell with ctrl+a in autocomplete demo #1590
    // Editing autocomplete selection, cursor goes to the end of selected string. #1610
  };

  AutocompleteEditor.prototype.highlightBestMatchingChoice = function () {
    var bestMatchingChoice = this.findBestMatchingChoice();

    if ( typeof bestMatchingChoice == 'undefined' && this.cellProperties.allowInvalid === false){
      bestMatchingChoice = 0;
    }

    if(typeof bestMatchingChoice == 'undefined'){
      this.$htContainer.handsontable('deselectCell');
    } else {
      this.$htContainer.handsontable('selectCell', bestMatchingChoice, 0);
    }

  };

  AutocompleteEditor.prototype.findBestMatchingChoice = function(){
    var bestMatch = {};
    var valueLength = this.getValue().length;
    var currentItem;
    var indexOfValue;
    var charsLeft;

    for(var i = 0, len = this.choices.length; i < len; i++){
      currentItem = this.choices[i];

      if(valueLength > 0){
        indexOfValue = currentItem.indexOf(this.getValue())
      } else {
        indexOfValue = currentItem === this.getValue() ? 0 : -1;
      }

      if(indexOfValue == -1) continue;

      charsLeft =  currentItem.length - indexOfValue - valueLength;

      if( typeof bestMatch.indexOfValue == 'undefined'
        || bestMatch.indexOfValue > indexOfValue
        || ( bestMatch.indexOfValue == indexOfValue && bestMatch.charsLeft > charsLeft ) ){

        bestMatch.indexOfValue = indexOfValue;
        bestMatch.charsLeft = charsLeft;
        bestMatch.index = i;

      }

    }

    return bestMatch.index;
  };

  AutocompleteEditor.prototype.getDropdownHeight = function(){
    //return 10 * this.$htContainer.handsontable('getInstance').getRowHeight(0);
    //sorry, we can't measure row height before it was rendered. Let's use fixed height for now
    return 230;
  };

  Handsontable.editors.AutocompleteEditor = AutocompleteEditor;
  Handsontable.editors.registerEditor('autocomplete', AutocompleteEditor);

})(Handsontable);
<|endoftext|>


<commit_before>function FeedbackControl($scope, FeedbackControlService, FeedbackSignal) {

    $scope.selected = [];
    $scope.checkboxes = $("input[type=checkbox][name=feedid]");

    var update_selected = function(action, id) {

        if (action == 'add' && $scope.selected.indexOf(id) == -1) {
            $scope.selected.push(id);
        }

        if (action == 'remove' && $scope.selected.indexOf(id) != -1) {
            $scope.selected.splice($scope.selected.indexOf(id), 1);
        }

    }

    var highlight = function(entity) {
        if(entity.checked) {
            $(entity).parents('.dashboard-feedback').css({'background-color': '#F1F1f1'});
        } else {
            $(entity).parents('.dashboard-feedback').css({'background-color': '#FFF'});
        }
    }

    $scope.feedback_status = function(id, feed_status) {
        console.log(feed_status + " id: " + id);

        FeedbackSignal.set_status_message(feed_status)
        FeedbackSignal.set_feed_id(id);

        FeedbackControlService.change_status(id, feed_status);
    }

    $scope.reply_feedback = function(id) {
        console.log("reply id:" + id);
    }

    $scope.update_selection = function($event, feed) {

        var checkbox = $event.target;
        var action = (checkbox.checked ? 'add' : 'remove');

        update_selected(action, feed);
        highlight(checkbox);
        /*
        if(checkbox.checked) {
            $(checkbox).parents('.dashboard-feedback').css({'background-color': '#F1F1f1'});
        } else {
            $(checkbox).parents('.dashboard-feedback').css({'background-color': '#FFF'});
        }
        */
    }

    $scope.select_all = function($event) {

        var checkbox = $event.target;
        var action = (checkbox.checked ? 'add' : 'remove');

        for(var i=0; i < $scope.checkboxes.length; i++) {
            var entity = $($scope.checkboxes[i]);

            if(action == "add") {
                entity.prop("checked", true);
            } else {
                entity.prop("checked", false);
            }

            update_selected(action, parseInt(entity.val(), 10));
            highlight(entity);
        }
    }
}

function CheckyBox($scope, FeedbackSignal) {

    $scope.status_selection;
    var feed_id;

    $scope.undo = function() {
        console.log("Undo ID: " + feed_id);
    }

    $scope.$on('checkFeedbackStatus', function() {
        $scope.status_selection = FeedbackSignal.feed_status;
        feed_id = FeedbackSignal.feed_id;
    });
}
<commit_msg>oh yes<commit_after>function FeedbackControl($scope, FeedbackControlService, FeedbackSignal) {

    $scope.selected = [];
    $scope.checkboxes = $("input[type=checkbox][name=feedid]");

    var update_selected = function(action, id) {

        if (action == 'add' && $scope.selected.indexOf(id) == -1) {
            $scope.selected.push(id);
        }

        if (action == 'remove' && $scope.selected.indexOf(id) != -1) {
            $scope.selected.splice($scope.selected.indexOf(id), 1);
        }

    }

    var highlight = function(entity) {
        if(entity.checked) {
            $(entity).parents('.dashboard-feedback').css({'background-color': '#F1F1f1'});
        } else {
            $(entity).parents('.dashboard-feedback').css({'background-color': '#FFF'});
        }
    }

    $scope.feedback_status = function(id, feed_status) {
        console.log(feed_status + " id: " + id);

        FeedbackSignal.set_status_message(feed_status)
        FeedbackSignal.set_feed_id(id);

        FeedbackControlService.change_status(id, feed_status);
    }

    $scope.reply_feedback = function(id) {
        console.log("reply id:" + id);
    }

    $scope.update_selection = function($event, feed) {

        var checkbox = $event.target;
        var action = (checkbox.checked ? 'add' : 'remove');

        update_selected(action, feed);
        highlight(checkbox);
        /*
        if(checkbox.checked) {
            $(checkbox).parents('.dashboard-feedback').css({'background-color': '#F1F1f1'});
        } else {
            $(checkbox).parents('.dashboard-feedback').css({'background-color': '#FFF'});
        }
        */
    }

    $scope.select_all = function($event) {

        var checkbox = $event.target;
        var action = (checkbox.checked ? 'add' : 'remove');

        for(var i=0; i < $scope.checkboxes.length; i++) {
            var entity = $($scope.checkboxes[i]);

            if(action == "add") {
                entity.prop("checked", true);
            } else {
                entity.prop("checked", false);
            }

            update_selected(action, parseInt(entity.val(), 10));
            //highlight(checkbox);
            console.log(entity);
        }
    }
}

function CheckyBox($scope, FeedbackSignal) {

    $scope.status_selection;
    var feed_id;

    $scope.undo = function() {
        console.log("Undo ID: " + feed_id);
    }

    $scope.$on('checkFeedbackStatus', function() {
        $scope.status_selection = FeedbackSignal.feed_status;
        feed_id = FeedbackSignal.feed_id;
    });
}
<|endoftext|>


<commit_before>(function(){
  var pluginName = 'qqvideo';
  CKEDITOR.plugins.add(pluginName, {
    lang:'zh-cn',
    onLoad: function(){
    },
    beforeInit: function(editor){
    },
    init: function(editor) {
            editor.addCommand(pluginName, new CKEDITOR.dialogCommand(pluginName));
            editor.ui.addButton(pluginName, {
              label: lang.button.label,
              command: pluginName,
              icon: this.path + 'images/icon.png'
            });
            CKEDITOR.dialog.add(pluginName, this.path + 'dialogs/qqvideo.js');
    },
    afterInit: function(editor){

    }
  });
})();<commit_msg>fix a bug<commit_after>(function(){
  var pluginName = 'qqvideo';
  CKEDITOR.plugins.add(pluginName, {
    lang:'zh-cn',
    onLoad: function(){
    },
    beforeInit: function(editor){
    },
    init: function(editor) {
      var lang = editor.lang[pluginName];
      editor.addCommand(pluginName, new CKEDITOR.dialogCommand(pluginName));
      editor.ui.addButton(pluginName, {
        label: lang.button.label,
        command: pluginName,
        icon: this.path + 'images/icon.png'
      });
      CKEDITOR.dialog.add(pluginName, this.path + 'dialogs/qqvideo.js');
    },
    afterInit: function(editor){

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


<commit_before>/**
*
*	Full Calendar callback methods.
*
*/

function scheduleRefetchEvents() {
    $("#schedule_calendar").fullCalendar( 'refetchEvents' );
}

function openAddShowForm() {

     if(($("#add-show-form").length == 1) && ($("#add-show-form").css('display')=='none')) {
        $("#add-show-form").show();
        var y = $("#schedule_calendar").width();
        var z = $("#schedule-add-show").width();
        $("#schedule_calendar").width(y-z-50);
        $("#schedule_calendar").fullCalendar('render');
    }
}

function makeAddShowButton(){
    $('.fc-header-left')
        .append('')
        .append('Show')
        .find('span.fc-button:last > a')
            .click(function(){
                openAddShowForm();

                var span = $(this).parent();
                $(span).prev().remove();
                $(span).remove();
            });
}

function beginEditShow(data){
    //alert (data.entries);

    $("#add-show-form")
        .empty()
        .append(data.newForm);

    setAddShowEvents();
    openAddShowForm();
}

function makeTimeStamp(date){
	var sy, sm, sd, h, m, s, timestamp;
	sy = date.getFullYear();
	sm = date.getMonth() + 1;
	sd = date.getDate();
	h = date.getHours();
	m = date.getMinutes();
	s = date.getSeconds();

	timestamp = sy+"-"+ sm +"-"+ sd +" "+ h +":"+ m +":"+ s;
	return timestamp;
}

function dayClick(date, allDay, jsEvent, view) {
    var now, today, selected, chosenDate, chosenTime;

    now = new Date();

    if(view.name === "month") {
        today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
        selected = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    }
    else {
        today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes());
        selected = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
    }

    if(selected >= today) {
        var addShow = $('.add-button');

        //remove the +show button if it exists.
        if(addShow.length == 1){
             var span = $(addShow).parent();
            $(span).prev().remove();
            $(span).remove();
        }

        chosenDate = selected.getFullYear();

        var month = selected.getMonth() + 1;
        if(month < 10) {
            chosenDate = chosenDate+'-0'+month;
        }
        else {
            chosenDate = chosenDate+'-'+month;
        }

        var day = selected.getDate();
        if(day < 10) {
            chosenDate = chosenDate+'-0'+day;
        }
        else {
            chosenDate = chosenDate+'-'+day;
        }

        var min = selected.getMinutes();
        var hours = selected.getHours();
        if(min < 10){
            chosenTime = hours+":0"+min;
        }
        else {
            chosenTime = hours+":"+min;
        }

        $("#add_show_start_date").val(chosenDate);
        $("#add_show_end_date").datepicker("option", "minDate", chosenDate);
        $("#add_show_end_date").val(chosenDate);
        $("#add_show_start_time").val(chosenTime);
        $("#schedule-show-when").show();

	    openAddShowForm();
    }
}

function viewDisplay( view ) {

    if(view.name === 'agendaDay' || view.name === 'agendaWeek') {

        var calendarEl = this;

        var select = $('<select class="schedule_change_slots input_select"/>')
            .append('<option value="1">1m</option>')
            .append('<option value="5">5m</option>')
            .append('<option value="10">10m</option>')
            .append('<option value="15">15m</option>')
            .append('<option value="30">30m</option>')
            .append('<option value="60">60m</option>')
            .change(function(){
                var slotMin = $(this).val();
                var opt = view.calendar.options;
                var date = $(calendarEl).fullCalendar('getDate');

                opt.slotMinutes = parseInt(slotMin);
                opt.events = getFullCalendarEvents;
                opt.defaultView = view.name;

                //re-initialize calendar with new slotmin options
                $(calendarEl)
                    .fullCalendar('destroy')
                    .fullCalendar(opt)
                    .fullCalendar( 'gotoDate', date );
            });

        var topLeft = $(view.element).find("table.fc-agenda-days > thead th:first");

        select.width(topLeft.width())
            .height(topLeft.height());

        topLeft.empty()
            .append(select);

        var slotMin = view.calendar.options.slotMinutes;
        $('.schedule_change_slots option[value="'+slotMin+'"]').attr('selected', 'selected');
    }

    if(($("#add-show-form").length == 1) && ($("#add-show-form").css('display')=='none') && ($('.fc-header-left > span').length == 5)) {
        makeAddShowButton();
    }
}

function eventRender(event, element, view) {

    //only put progress bar on shows that aren't being recorded.
	if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.record === 0) {
		var div = $('
');
		div
			.height('5px')
			.width('95%')
			.css('margin-top', '5px')
            .css('margin-left', 'auto')
            .css('margin-right', 'auto')
			.progressbar({
				value: event.percent
			});

		$(element).find(".fc-event-content").append(div);
	}

    //add the record/rebroadcast icons if needed.

    //record icon (only if not on soundcloud, will always be true for future events)
    if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.record === 1 && event.soundcloud_id === -1) {

		$(element).find(".fc-event-time").before('');
	}
    if(view.name === 'month' && event.record === 1 && event.soundcloud_id === -1) {

		$(element).find(".fc-event-title").after('');
	}
    //rebroadcast icon
    if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.rebroadcast === 1) {

		$(element).find(".fc-event-time").before('');
	}
    if(view.name === 'month' && event.rebroadcast === 1) {

		$(element).find(".fc-event-title").after('');
	}
    //soundcloud icon
    if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.soundcloud_id !== -1 && event.record === 1) {

		$(element).find(".fc-event-time").before('');
	}
    if(view.name === 'month' && event.soundcloud_id !== -1 && event.record === 1) {

		$(element).find(".fc-event-title").after('');
	}
}

function eventAfterRender( event, element, view ) {

    $(element)
		.jjmenu("click",
			[{get:"/Schedule/make-context-menu/format/json/id/#id#"}],
			{id: event.id},
			{xposition: "mouse", yposition: "mouse"});
}

function eventDrop(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
	var url;

	url = '/Schedule/move-show/format/json';

	$.post(url,
		{day: dayDelta, min: minuteDelta, showInstanceId: event.id},
		function(json){
			if(json.error) {
                alert(json.error);
				revertFunc();
			}
		});
}

function eventResize( event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view ) {
	var url;

	url = '/Schedule/resize-show/format/json';

	$.post(url,
		{day: dayDelta, min: minuteDelta, showInstanceId: event.id},
		function(json){
			if(json.error) {
                alert(json.error);
				revertFunc();
			}

            scheduleRefetchEvents();
		});
}

function getFullCalendarEvents(start, end, callback) {
	var url, start_date, end_date;

	start_date = makeTimeStamp(start);
	end_date = makeTimeStamp(end);

	url = '/Schedule/event-feed';

	var d = new Date();

	$.post(url, {format: "json", start: start_date, end: end_date, cachep: d.getTime()}, function(json){
		callback(json.events);
	});
}
<commit_msg>nudge progress bar up a bit for new css.<commit_after>/**
*
*	Full Calendar callback methods.
*
*/

function scheduleRefetchEvents() {
    $("#schedule_calendar").fullCalendar( 'refetchEvents' );
}

function openAddShowForm() {

     if(($("#add-show-form").length == 1) && ($("#add-show-form").css('display')=='none')) {
        $("#add-show-form").show();
        var y = $("#schedule_calendar").width();
        var z = $("#schedule-add-show").width();
        $("#schedule_calendar").width(y-z-50);
        $("#schedule_calendar").fullCalendar('render');
    }
}

function makeAddShowButton(){
    $('.fc-header-left')
        .append('')
        .append('Show')
        .find('span.fc-button:last > a')
            .click(function(){
                openAddShowForm();

                var span = $(this).parent();
                $(span).prev().remove();
                $(span).remove();
            });
}

function beginEditShow(data){
    //alert (data.entries);

    $("#add-show-form")
        .empty()
        .append(data.newForm);

    setAddShowEvents();
    openAddShowForm();
}

function makeTimeStamp(date){
	var sy, sm, sd, h, m, s, timestamp;
	sy = date.getFullYear();
	sm = date.getMonth() + 1;
	sd = date.getDate();
	h = date.getHours();
	m = date.getMinutes();
	s = date.getSeconds();

	timestamp = sy+"-"+ sm +"-"+ sd +" "+ h +":"+ m +":"+ s;
	return timestamp;
}

function dayClick(date, allDay, jsEvent, view) {
    var now, today, selected, chosenDate, chosenTime;

    now = new Date();

    if(view.name === "month") {
        today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
        selected = new Date(date.getFullYear(), date.getMonth(), date.getDate());
    }
    else {
        today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes());
        selected = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
    }

    if(selected >= today) {
        var addShow = $('.add-button');

        //remove the +show button if it exists.
        if(addShow.length == 1){
             var span = $(addShow).parent();
            $(span).prev().remove();
            $(span).remove();
        }

        chosenDate = selected.getFullYear();

        var month = selected.getMonth() + 1;
        if(month < 10) {
            chosenDate = chosenDate+'-0'+month;
        }
        else {
            chosenDate = chosenDate+'-'+month;
        }

        var day = selected.getDate();
        if(day < 10) {
            chosenDate = chosenDate+'-0'+day;
        }
        else {
            chosenDate = chosenDate+'-'+day;
        }

        var min = selected.getMinutes();
        var hours = selected.getHours();
        if(min < 10){
            chosenTime = hours+":0"+min;
        }
        else {
            chosenTime = hours+":"+min;
        }

        $("#add_show_start_date").val(chosenDate);
        $("#add_show_end_date").datepicker("option", "minDate", chosenDate);
        $("#add_show_end_date").val(chosenDate);
        $("#add_show_start_time").val(chosenTime);
        $("#schedule-show-when").show();

	    openAddShowForm();
    }
}

function viewDisplay( view ) {

    if(view.name === 'agendaDay' || view.name === 'agendaWeek') {

        var calendarEl = this;

        var select = $('<select class="schedule_change_slots input_select"/>')
            .append('<option value="1">1m</option>')
            .append('<option value="5">5m</option>')
            .append('<option value="10">10m</option>')
            .append('<option value="15">15m</option>')
            .append('<option value="30">30m</option>')
            .append('<option value="60">60m</option>')
            .change(function(){
                var slotMin = $(this).val();
                var opt = view.calendar.options;
                var date = $(calendarEl).fullCalendar('getDate');

                opt.slotMinutes = parseInt(slotMin);
                opt.events = getFullCalendarEvents;
                opt.defaultView = view.name;

                //re-initialize calendar with new slotmin options
                $(calendarEl)
                    .fullCalendar('destroy')
                    .fullCalendar(opt)
                    .fullCalendar( 'gotoDate', date );
            });

        var topLeft = $(view.element).find("table.fc-agenda-days > thead th:first");

        select.width(topLeft.width())
            .height(topLeft.height());

        topLeft.empty()
            .append(select);

        var slotMin = view.calendar.options.slotMinutes;
        $('.schedule_change_slots option[value="'+slotMin+'"]').attr('selected', 'selected');
    }

    if(($("#add-show-form").length == 1) && ($("#add-show-form").css('display')=='none') && ($('.fc-header-left > span').length == 5)) {
        makeAddShowButton();
    }
}

function eventRender(event, element, view) {

    //only put progress bar on shows that aren't being recorded.
	if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.record === 0) {
		var div = $('
');
		div
			.height('5px')
			.width('95%')
			.css('margin-top', '1px')
            .css('margin-left', 'auto')
            .css('margin-right', 'auto')
			.progressbar({
				value: event.percent
			});

		$(element).find(".fc-event-content").append(div);
	}

    //add the record/rebroadcast icons if needed.

    //record icon (only if not on soundcloud, will always be true for future events)
    if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.record === 1 && event.soundcloud_id === -1) {

		$(element).find(".fc-event-time").before('');
	}
    if(view.name === 'month' && event.record === 1 && event.soundcloud_id === -1) {

		$(element).find(".fc-event-title").after('');
	}
    //rebroadcast icon
    if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.rebroadcast === 1) {

		$(element).find(".fc-event-time").before('');
	}
    if(view.name === 'month' && event.rebroadcast === 1) {

		$(element).find(".fc-event-title").after('');
	}
    //soundcloud icon
    if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.soundcloud_id !== -1 && event.record === 1) {

		$(element).find(".fc-event-time").before('');
	}
    if(view.name === 'month' && event.soundcloud_id !== -1 && event.record === 1) {

		$(element).find(".fc-event-title").after('');
	}
}

function eventAfterRender( event, element, view ) {

    $(element)
		.jjmenu("click",
			[{get:"/Schedule/make-context-menu/format/json/id/#id#"}],
			{id: event.id},
			{xposition: "mouse", yposition: "mouse"});
}

function eventDrop(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
	var url;

	url = '/Schedule/move-show/format/json';

	$.post(url,
		{day: dayDelta, min: minuteDelta, showInstanceId: event.id},
		function(json){
			if(json.error) {
                alert(json.error);
				revertFunc();
			}
		});
}

function eventResize( event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view ) {
	var url;

	url = '/Schedule/resize-show/format/json';

	$.post(url,
		{day: dayDelta, min: minuteDelta, showInstanceId: event.id},
		function(json){
			if(json.error) {
                alert(json.error);
				revertFunc();
			}

            scheduleRefetchEvents();
		});
}

function getFullCalendarEvents(start, end, callback) {
	var url, start_date, end_date;

	start_date = makeTimeStamp(start);
	end_date = makeTimeStamp(end);

	url = '/Schedule/event-feed';

	var d = new Date();

	$.post(url, {format: "json", start: start_date, end: end_date, cachep: d.getTime()}, function(json){
		callback(json.events);
	});
}
<|endoftext|>


<commit_before>/* eslint-disable react/forbid-prop-types */
/* eslint-disable no-undef */
/* eslint-disable no-console */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/* eslint-disable global-require */

import React from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';

import {
  BackHandler,
  Image,
  Text,
  TouchableOpacity,
  TouchableWithoutFeedback,
  View,
} from 'react-native';

import { Scheduler } from 'sussol-utilities';
import { NavigationActions } from 'react-navigation';

import { FirstUsePage, FINALISABLE_PAGES } from './pages';

import { Synchroniser, PostSyncProcessor, SyncModal } from './sync';
import { FinaliseButton, NavigationBar, SyncState, Spinner } from './widgets';
import { FinaliseModal, LoginModal } from './widgets/modals';

import { getCurrentParams, getCurrentRouteName, ReduxNavigator } from './navigation';
import { syncCompleteTransaction } from './actions/SyncActions';
import { migrateDataToVersion } from './dataMigration';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import Settings from './settings/MobileAppSettings';
import Database from './database/BaseDatabase';
import { UIDatabase } from './database';

import globalStyles, { textStyles, SUSSOL_ORANGE } from './globalStyles';
import { UserActions } from './actions';
import { debounce } from './utilities';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds.
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds.

class MSupplyMobileAppContainer extends React.Component {
  handleBackEvent = debounce(
    () => {
      const { dispatch } = this.props;
      const { confirmFinalise, syncModalIsOpen } = this.state;
      // If finalise or sync modals are open, close them rather than navigating.
      if (confirmFinalise || syncModalIsOpen) {
        this.setState({ confirmFinalise: false, syncModalIsOpen: false });
        return true;
      }
      // If we are on base screen (e.g. home), back button should close app as we can't go back.
      if (!this.getCanNavigateBack()) BackHandler.exitApp();
      else dispatch(NavigationActions.back());

      return true;
    },
    400,
    true
  );

  constructor(props, ...otherArgs) {
    super(props, ...otherArgs);

    migrateDataToVersion(UIDatabase, Settings);
    this.userAuthenticator = new UserAuthenticator(UIDatabase, Settings);
    const syncAuthenticator = new SyncAuthenticator(Settings);
    this.synchroniser = new Synchroniser(Database, syncAuthenticator, Settings, props.dispatch);
    this.postSyncProcessor = new PostSyncProcessor(UIDatabase, Settings);
    this.scheduler = new Scheduler();
    const isInitialised = this.synchroniser.isInitialised();
    this.scheduler.schedule(this.synchronise, SYNC_INTERVAL);
    this.scheduler.schedule(() => {
      const { currentUser } = this.props;
      if (currentUser !== null) {
        // Only re-authenticate if currently logged in.
        this.userAuthenticator.reauthenticate(this.onAuthentication);
      }
    }, AUTHENTICATION_INTERVAL);
    this.state = {
      confirmFinalise: false,
      isInitialised,
      isLoading: false,
      syncModalIsOpen: false,
    };
  }

  componentDidMount = () => BackHandler.addEventListener('hardwareBackPress', this.handleBackEvent);

  componentWillUnmount = () => {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackEvent);
    this.scheduler.clearAll();
  };

  onAuthentication = user => {
    const { dispatch } = this.props;
    dispatch(UserActions.login(user));
    this.postSyncProcessor.setUser(user);
  };

  onInitialised = () => {
    this.setState({ isInitialised: true });
    this.postSyncProcessor.processAnyUnprocessedRecords();
  };

  getCanNavigateBack = () => {
    const { navigationState } = this.props;
    return navigationState.index !== 0;
  };

  // eslint-disable-next-line class-methods-use-this
  getCurrentRouteName(navigationState) {
    if (!navigationState) return null;

    const route = navigationState.routes[navigationState.index];

    // dive into nested navigators
    if (route.routes) return getCurrentRouteName(route);

    return route.routeName;
  }

  runWithLoadingIndicator = async functionToRun => {
    UIDatabase.isLoading = true;
    // We here set up an asynchronous promise that will be resolved after a timeout
    // of 1 millisecond. This allows a fraction of a delay for the javascript thread
    // to unblock and allow the spinner animation to start up. The |functionToRun| should
    // not be run inside a |setTimeout| as that relegates to a lower priority, resulting
    // in very slow performance.
    await new Promise(resolve => {
      this.setState({ isLoading: true }, () => setTimeout(resolve, 1));
    });
    functionToRun();
    this.setState({ isLoading: false });
    UIDatabase.isLoading = false;
  };

  synchronise = async () => {
    const { syncState, dispatch } = this.props;
    const { isInitialised } = this.state;
    if (!isInitialised || syncState.isSyncing) return; // Ignore if syncing.
    // True if most recent call to |this.synchroniser.synchronise()| failed.
    const lastSyncFailed = this.synchroniser.lastSyncFailed();
    const lastPostSyncProcessingFailed = this.postSyncProcessor.lastPostSyncProcessingFailed();
    await this.synchroniser.synchronise();
    if (lastSyncFailed || lastPostSyncProcessingFailed) {
      // If last sync was interrupted, it did not enter this block. If the app was closed, it did
      // not store the records left in the record queue, so tables should be checked for unprocessed
      // records. If the last processing of the record queue was interrupted by app crash then all
      // records need to be checked.
      this.postSyncProcessor.processAnyUnprocessedRecords();
    } else {
      this.postSyncProcessor.processRecordQueue();
    }
    dispatch(syncCompleteTransaction());
  };

  renderFinaliseButton = () => {
    const { finaliseItem } = this.props;
    return (
      <FinaliseButton
        isFinalised={finaliseItem.record.isFinalised}
        onPress={() => this.setState({ confirmFinalise: true })}
      />
    );
  };

  renderLogo = () => {
    const { isInAdminMode } = this.state;

    return (
      <TouchableWithoutFeedback
        delayLongPress={3000}
        onLongPress={() => this.setState({ isInAdminMode: !isInAdminMode })}
      >
        <Image resizeMode="contain" source={require('./images/logo.png')} />
      </TouchableWithoutFeedback>
    );
  };

  renderLoadingIndicator = () => {
    const { isLoading } = this.state;
    return (
      <View style={globalStyles.loadingIndicatorContainer}>
        <Spinner isSpinning={isLoading} color={SUSSOL_ORANGE} />
      </View>
    );
  };

  renderPageTitle = () => {
    const { currentTitle } = this.props;
    return <Text style={textStyles}>{currentTitle}</Text>;
  };

  renderSyncState = () => {
    const { syncState } = this.props;
    return (
      <TouchableOpacity
        style={{ flexDirection: 'row' }}
        onPress={() => this.setState({ syncModalIsOpen: true })}
      >
        <SyncState state={syncState} />
      </TouchableOpacity>
    );
  };

  render() {
    const { dispatch, finaliseItem, navigationState, syncState, currentUser } = this.props;
    const {
      confirmFinalise,
      isInAdminMode,
      isInitialised,
      isLoading,
      syncModalIsOpen,
    } = this.state;

    if (!isInitialised) {
      return (
        <FirstUsePage
          synchroniser={this.synchroniser}
          onInitialised={this.onInitialised}
          syncState={syncState}
        />
      );
    }

    return (
      <View style={globalStyles.appBackground}>
        <NavigationBar
          routeName={this.getCurrentRouteName(navigationState)}
          onPressBack={this.getCanNavigateBack() ? this.handleBackEvent : null}
          LeftComponent={this.getCanNavigateBack() ? this.renderPageTitle : null}
          CentreComponent={this.renderLogo}
          RightComponent={finaliseItem ? this.renderFinaliseButton : this.renderSyncState}
        />
        <ReduxNavigator
          state={navigationState}
          dispatch={dispatch}
          screenProps={{
            database: UIDatabase,
            settings: Settings,
            currentUser,
            routeName: navigationState.routes[navigationState.index].routeName,
            runWithLoadingIndicator: this.runWithLoadingIndicator,
            isInAdminMode,
          }}
        />
        <FinaliseModal
          database={UIDatabase}
          isOpen={confirmFinalise}
          onClose={() => this.setState({ confirmFinalise: false })}
          finaliseItem={finaliseItem}
          user={currentUser}
          runWithLoadingIndicator={this.runWithLoadingIndicator}
        />
        <SyncModal
          database={UIDatabase}
          isOpen={syncModalIsOpen}
          state={syncState}
          onPressManualSync={this.synchronise}
          onClose={() => this.setState({ syncModalIsOpen: false })}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          settings={Settings}
          isAuthenticated={!!currentUser}
          onAuthentication={this.onAuthentication}
        />
        {isLoading && this.renderLoadingIndicator()}
      </View>
    );
  }
}

const mapStateToProps = state => {
  const { nav: navigationState, sync: syncState } = state;
  const currentParams = getCurrentParams(navigationState);
  const currentTitle = currentParams && currentParams.title;
  const finaliseItem = FINALISABLE_PAGES[getCurrentRouteName(navigationState)];
  if (finaliseItem && currentParams) {
    finaliseItem.record = currentParams[finaliseItem.recordToFinaliseKey];
  }

  return {
    currentTitle,
    finaliseItem,
    navigationState,
    syncState,
    currentUser: state.user.currentUser,
  };
};

MSupplyMobileAppContainer.defaultProps = {
  currentUser: null,
  currentTitle: '',
  finaliseItem: null,
};

MSupplyMobileAppContainer.propTypes = {
  currentTitle: PropTypes.string,
  dispatch: PropTypes.func.isRequired,
  finaliseItem: PropTypes.object,
  navigationState: PropTypes.object.isRequired,
  syncState: PropTypes.object.isRequired,
  currentUser: PropTypes.object,
};

export default connect(mapStateToProps)(MSupplyMobileAppContainer);
<commit_msg>Add payload to backnavigation action<commit_after>/* eslint-disable react/forbid-prop-types */
/* eslint-disable no-undef */
/* eslint-disable no-console */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/* eslint-disable global-require */

import React from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';

import {
  BackHandler,
  Image,
  Text,
  TouchableOpacity,
  TouchableWithoutFeedback,
  View,
} from 'react-native';

import { Scheduler } from 'sussol-utilities';
import { NavigationActions } from 'react-navigation';

import { FirstUsePage, FINALISABLE_PAGES } from './pages';

import { Synchroniser, PostSyncProcessor, SyncModal } from './sync';
import { FinaliseButton, NavigationBar, SyncState, Spinner } from './widgets';
import { FinaliseModal, LoginModal } from './widgets/modals';

import { getCurrentParams, getCurrentRouteName, ReduxNavigator } from './navigation';
import { syncCompleteTransaction } from './actions/SyncActions';
import { migrateDataToVersion } from './dataMigration';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import Settings from './settings/MobileAppSettings';
import Database from './database/BaseDatabase';
import { UIDatabase } from './database';

import globalStyles, { textStyles, SUSSOL_ORANGE } from './globalStyles';
import { UserActions } from './actions';
import { debounce } from './utilities';
import { prevRouteNameSelector } from './navigation/selectors';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds.
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds.

class MSupplyMobileAppContainer extends React.Component {
  handleBackEvent = debounce(
    () => {
      const { dispatch, prevRouteName } = this.props;
      const { confirmFinalise, syncModalIsOpen } = this.state;
      // If finalise or sync modals are open, close them rather than navigating.
      if (confirmFinalise || syncModalIsOpen) {
        this.setState({ confirmFinalise: false, syncModalIsOpen: false });
        return true;
      }
      // If we are on base screen (e.g. home), back button should close app as we can't go back.
      if (!this.getCanNavigateBack()) BackHandler.exitApp();
      else dispatch({ ...NavigationActions.back(), payload: { prevRouteName } });

      return true;
    },
    400,
    true
  );

  constructor(props, ...otherArgs) {
    super(props, ...otherArgs);

    migrateDataToVersion(UIDatabase, Settings);
    this.userAuthenticator = new UserAuthenticator(UIDatabase, Settings);
    const syncAuthenticator = new SyncAuthenticator(Settings);
    this.synchroniser = new Synchroniser(Database, syncAuthenticator, Settings, props.dispatch);
    this.postSyncProcessor = new PostSyncProcessor(UIDatabase, Settings);
    this.scheduler = new Scheduler();
    const isInitialised = this.synchroniser.isInitialised();
    this.scheduler.schedule(this.synchronise, SYNC_INTERVAL);
    this.scheduler.schedule(() => {
      const { currentUser } = this.props;
      if (currentUser !== null) {
        // Only re-authenticate if currently logged in.
        this.userAuthenticator.reauthenticate(this.onAuthentication);
      }
    }, AUTHENTICATION_INTERVAL);
    this.state = {
      confirmFinalise: false,
      isInitialised,
      isLoading: false,
      syncModalIsOpen: false,
    };
  }

  componentDidMount = () => BackHandler.addEventListener('hardwareBackPress', this.handleBackEvent);

  componentWillUnmount = () => {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackEvent);
    this.scheduler.clearAll();
  };

  onAuthentication = user => {
    const { dispatch } = this.props;
    dispatch(UserActions.login(user));
    this.postSyncProcessor.setUser(user);
  };

  onInitialised = () => {
    this.setState({ isInitialised: true });
    this.postSyncProcessor.processAnyUnprocessedRecords();
  };

  getCanNavigateBack = () => {
    const { navigationState } = this.props;
    return navigationState.index !== 0;
  };

  // eslint-disable-next-line class-methods-use-this
  getCurrentRouteName(navigationState) {
    if (!navigationState) return null;

    const route = navigationState.routes[navigationState.index];

    // dive into nested navigators
    if (route.routes) return getCurrentRouteName(route);

    return route.routeName;
  }

  runWithLoadingIndicator = async functionToRun => {
    UIDatabase.isLoading = true;
    // We here set up an asynchronous promise that will be resolved after a timeout
    // of 1 millisecond. This allows a fraction of a delay for the javascript thread
    // to unblock and allow the spinner animation to start up. The |functionToRun| should
    // not be run inside a |setTimeout| as that relegates to a lower priority, resulting
    // in very slow performance.
    await new Promise(resolve => {
      this.setState({ isLoading: true }, () => setTimeout(resolve, 1));
    });
    functionToRun();
    this.setState({ isLoading: false });
    UIDatabase.isLoading = false;
  };

  synchronise = async () => {
    const { syncState, dispatch } = this.props;
    const { isInitialised } = this.state;
    if (!isInitialised || syncState.isSyncing) return; // Ignore if syncing.
    // True if most recent call to |this.synchroniser.synchronise()| failed.
    const lastSyncFailed = this.synchroniser.lastSyncFailed();
    const lastPostSyncProcessingFailed = this.postSyncProcessor.lastPostSyncProcessingFailed();
    await this.synchroniser.synchronise();
    if (lastSyncFailed || lastPostSyncProcessingFailed) {
      // If last sync was interrupted, it did not enter this block. If the app was closed, it did
      // not store the records left in the record queue, so tables should be checked for unprocessed
      // records. If the last processing of the record queue was interrupted by app crash then all
      // records need to be checked.
      this.postSyncProcessor.processAnyUnprocessedRecords();
    } else {
      this.postSyncProcessor.processRecordQueue();
    }
    dispatch(syncCompleteTransaction());
  };

  renderFinaliseButton = () => {
    const { finaliseItem } = this.props;
    return (
      <FinaliseButton
        isFinalised={finaliseItem.record.isFinalised}
        onPress={() => this.setState({ confirmFinalise: true })}
      />
    );
  };

  renderLogo = () => {
    const { isInAdminMode } = this.state;

    return (
      <TouchableWithoutFeedback
        delayLongPress={3000}
        onLongPress={() => this.setState({ isInAdminMode: !isInAdminMode })}
      >
        <Image resizeMode="contain" source={require('./images/logo.png')} />
      </TouchableWithoutFeedback>
    );
  };

  renderLoadingIndicator = () => {
    const { isLoading } = this.state;
    return (
      <View style={globalStyles.loadingIndicatorContainer}>
        <Spinner isSpinning={isLoading} color={SUSSOL_ORANGE} />
      </View>
    );
  };

  renderPageTitle = () => {
    const { currentTitle } = this.props;
    return <Text style={textStyles}>{currentTitle}</Text>;
  };

  renderSyncState = () => {
    const { syncState } = this.props;
    return (
      <TouchableOpacity
        style={{ flexDirection: 'row' }}
        onPress={() => this.setState({ syncModalIsOpen: true })}
      >
        <SyncState state={syncState} />
      </TouchableOpacity>
    );
  };

  render() {
    const { dispatch, finaliseItem, navigationState, syncState, currentUser } = this.props;
    const {
      confirmFinalise,
      isInAdminMode,
      isInitialised,
      isLoading,
      syncModalIsOpen,
    } = this.state;

    if (!isInitialised) {
      return (
        <FirstUsePage
          synchroniser={this.synchroniser}
          onInitialised={this.onInitialised}
          syncState={syncState}
        />
      );
    }

    return (
      <View style={globalStyles.appBackground}>
        <NavigationBar
          routeName={this.getCurrentRouteName(navigationState)}
          onPressBack={this.getCanNavigateBack() ? this.handleBackEvent : null}
          LeftComponent={this.getCanNavigateBack() ? this.renderPageTitle : null}
          CentreComponent={this.renderLogo}
          RightComponent={finaliseItem ? this.renderFinaliseButton : this.renderSyncState}
        />
        <ReduxNavigator
          state={navigationState}
          dispatch={dispatch}
          screenProps={{
            database: UIDatabase,
            settings: Settings,
            currentUser,
            routeName: navigationState.routes[navigationState.index].routeName,
            runWithLoadingIndicator: this.runWithLoadingIndicator,
            isInAdminMode,
          }}
        />
        <FinaliseModal
          database={UIDatabase}
          isOpen={confirmFinalise}
          onClose={() => this.setState({ confirmFinalise: false })}
          finaliseItem={finaliseItem}
          user={currentUser}
          runWithLoadingIndicator={this.runWithLoadingIndicator}
        />
        <SyncModal
          database={UIDatabase}
          isOpen={syncModalIsOpen}
          state={syncState}
          onPressManualSync={this.synchronise}
          onClose={() => this.setState({ syncModalIsOpen: false })}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          settings={Settings}
          isAuthenticated={!!currentUser}
          onAuthentication={this.onAuthentication}
        />
        {isLoading && this.renderLoadingIndicator()}
      </View>
    );
  }
}

const mapStateToProps = state => {
  const { nav: navigationState, sync: syncState } = state;

  const currentParams = getCurrentParams(navigationState);
  const currentTitle = currentParams && currentParams.title;
  const finaliseItem = FINALISABLE_PAGES[getCurrentRouteName(navigationState)];
  if (finaliseItem && currentParams) {
    finaliseItem.record = currentParams[finaliseItem.recordToFinaliseKey];
  }

  return {
    currentTitle,
    prevRouteName: prevRouteNameSelector(state),
    finaliseItem,
    navigationState,
    syncState,
    currentUser: state.user.currentUser,
  };
};

MSupplyMobileAppContainer.defaultProps = {
  currentUser: null,
  currentTitle: '',
  finaliseItem: null,
};

MSupplyMobileAppContainer.propTypes = {
  currentTitle: PropTypes.string,
  dispatch: PropTypes.func.isRequired,
  finaliseItem: PropTypes.object,
  navigationState: PropTypes.object.isRequired,
  syncState: PropTypes.object.isRequired,
  currentUser: PropTypes.object,
  prevRouteName: PropTypes.string.isRequired,
};

export default connect(mapStateToProps)(MSupplyMobileAppContainer);
<|endoftext|>


<commit_before>
var assert = require('assert')

module.exports = function () {
  return function (req, res, next) {
    assert(req.session, 'a req.session is required!')
    res.locals.flash = req.session.flash = req.session.flash || []
    req.flash = res.flash = push
    next()
  }
}

function push(type, msg) {
  if (!msg) {
    msg = type
    type = 'info'
  }
  var res = this.res || this
  res.locals.flash.push({
    type: type,
    message: msg,
  })
  return this
}
<commit_msg>make sure messages are arrays<commit_after>
var assert = require('assert')

module.exports = function () {
  return function (req, res, next) {
    assert(req.session, 'a req.session is required!')
    if (!Array.isArray(req.session.flash)) req.session.flash = []
    res.locals.flash = req.session.flash
    req.flash = res.flash = push
    next()
  }
}

function push(type, msg) {
  if (!msg) {
    msg = type
    type = 'info'
  }
  var res = this.res || this
  res.locals.flash.push({
    type: type,
    message: msg,
  })
  return this
}
<|endoftext|>


<commit_before>// not yet ported. feel like it?<commit_msg>Can't move array_slice to functions yet<commit_after>function array_slice(arr, offst, lgth, preserve_keys) {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir
    // *     example 1: array_slice(["a", "b", "c", "d", "e"], 2, -1);
    // *     returns 1: {0: 'c', 1: 'd'}
    // *     example 2: array_slice(["a", "b", "c", "d", "e"], 2, -1, true);
    // *     returns 2: {2: 'c', 3: 'd'}

	if (!(arr instanceof Array) || (preserve_keys && offst != 0)) { // Assoc. array as input or if required as output
		var lgt =0, newAssoc = {};
		for (var key in arr) {
			if (key !== 'length') {
				lgt += 1;
				newAssoc[key] = arr[key];
			}
		}
		arr = newAssoc;

		offst = (offst < 0) ? lgt + offst : offst;
		lgth  = lgth == undefined ? lgt : (lgth < 0) ? lgt + lgth - offst : lgth;

		var assoc = {};
		var start = false, it=-1, arrlgth=0, no_pk_idx=0;
		for (var key in arr) {
		    ++it;
		    if (arrlgth >= lgth) {
		      break;
		    }
		    if (it == offst){
		      start = true;
		    }
		    if (!start) {
		       continue;
		    }
		    ++arrlgth;
		    if (!isNaN(key) && !preserve_keys) {
                assoc[no_pk_idx++] = arr[key];
		    } else {
		        assoc[key] = arr[key];
		    }
		}
		assoc.length = arrlgth; // Make as array-like object (though length will not be dynamic)
		return assoc;
	}
}<|endoftext|>


<commit_before>var path = require("path")

module.exports = peerModule

function peerModule(opts) {
    var base = "../" || opts.peerDirectory

    return function (name) {
        return require(path.join(base, name))
    }
}
<commit_msg>path resolved<commit_after>var path = require("path")

module.exports = peerModule

function peerModule(opts) {
    var base = (opts && opts.peerDirectory) || "../"

    return function (name) {
        return require(path.join(base, name))
    }
}
<|endoftext|>


<commit_before>var spawn = require('win-spawn');
var gutil = require('gulp-util');
var Buffer = require('buffer').Buffer;
var PluginError = gutil.PluginError;
var clone = require('clone');
var through = require('through2');

const PLUGIN_NAME = 'gulp-ruby-haml';

module.exports = function (opt) {
  function modifyFile(file, enc, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      this.emit('error',
                new PluginError(PLUGIN_NAME, 'Streaming not supported'));
      return callback(null, file);
    }

    opt = opt || {};
    var options = {};
    options.outExtension = opt.outExtension || '.html';
    options.doubleQuote = opt.doubleQuote || false;

    var str = file.contents.toString('utf8');
    var args = ['haml'];
    if (options.doubleQuote) {
      args.push('-q');
    }
    args.push(file.path);
    var cp = spawn(args.shift(), args);

    var self = this;
    cp.on('error', function (err) {
      self.emit('error', new PluginError(PLUGIN_NAME, err));
      return callback(null, file);
    });

    var haml_data = '';
    cp.stdout.on('data', function (data) { haml_data += data.toString(); });

    var errors = '';
    cp.stderr.setEncoding('utf8');
    cp.stderr.on('data', function (data) { errors += data.toString(); });

    cp.on('close', function (code) {
      if (errors) {
        self.emit('error', new PluginError(PLUGIN_NAME, errors));
        return callback(null, null);
      }

      if (code > 0) {
        self.emit('error', new PluginError(PLUGIN_NAME,
                                           'Exited with error code ' + code));
        return callback(null, null);
      }

      var newFile = clone(file);
      newFile.path = gutil.replaceExtension(file.path, options.outExtension);
      newFile.contents = new Buffer(haml_data);
      return callback(null, newFile);
    });
  }

  return through.obj(modifyFile);
};
<commit_msg>added haml encoding option<commit_after>var spawn = require('win-spawn');
var gutil = require('gulp-util');
var Buffer = require('buffer').Buffer;
var PluginError = gutil.PluginError;
var clone = require('clone');
var through = require('through2');

const PLUGIN_NAME = 'gulp-ruby-haml';

module.exports = function (opt) {
  function modifyFile(file, enc, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      this.emit('error',
                new PluginError(PLUGIN_NAME, 'Streaming not supported'));
      return callback(null, file);
    }

    opt = opt || {};
    var options = {};
    options.outExtension = opt.outExtension || '.html';
    options.doubleQuote = opt.doubleQuote || false;
    options.encodings = opt.encodings || false;

    var str = file.contents.toString('utf8');
    var args = ['haml'];
    if (options.doubleQuote) {
      args.push('-q');
    }
    if (options.encodings) {
      args.push('-E');
      args.push(options.encodings);
    }
    args.push(file.path);
    var cp = spawn(args.shift(), args);

    var self = this;
    cp.on('error', function (err) {
      self.emit('error', new PluginError(PLUGIN_NAME, err));
      return callback(null, file);
    });

    var haml_data = '';
    cp.stdout.on('data', function (data) { haml_data += data.toString(); });

    var errors = '';
    cp.stderr.setEncoding('utf8');
    cp.stderr.on('data', function (data) { errors += data.toString(); });

    cp.on('close', function (code) {
      if (errors) {
        self.emit('error', new PluginError(PLUGIN_NAME, errors));
        return callback(null, null);
      }

      if (code > 0) {
        self.emit('error', new PluginError(PLUGIN_NAME,
                                           'Exited with error code ' + code));
        return callback(null, null);
      }

      var newFile = clone(file);
      newFile.path = gutil.replaceExtension(file.path, options.outExtension);
      newFile.contents = new Buffer(haml_data);
      return callback(null, newFile);
    });
  }

  return through.obj(modifyFile);
};
<|endoftext|>