<commit_before>var randomIndex = function(maxLength) {
	var randIndex = Math.round(Math.random() * maxLength);
	if (randIndex < 0) {
		randIndex = 0;
	}
	else if (randIndex >= maxLength) {
		randIndex = maxLength - 1;
	}
	return randIndex;
};

var eventLoop = function() {
	var alphabets = function(){
		var alphabets = [];
		for(var i = 65; i <= 90; i++) {
			alphabets.push(String.fromCharCode(i))
		}

		alphabets = alphabets.join('');
		return alphabets;
	}();

	var alphabetsLength = alphabets.length
	var currentLevel = 1;
	var initialLevelRequirement = 0;
	var blockSpeed = 10000; //seconds to reach ground
	var spawnSpeed = 1000; //block manifest every 3 seconds
	var alphabetsQueue = [];
	var alphabetsObjectQueue = [];
	var alphabetsCount = 0;
	//dark | light
	var alphabetColours = {"red": ["#9E302D", "#D56865"],
						   "orange": ["#9E612D", "#D59865"],
						   "green": ["#247C29", "#4FA755"],
						   "blue": ["#234367", "#48678B"],
						   "purple": ["#502269", "#75476E"],
						   "yellow": ["#9E9E2D", "D5D565"]};
	var alphabetColoursKeys = Object.keys(alphabetColours);
	var haveLost = false;
	//stops level
	var levelBreakers = [];
	/*
	Type of queue:
		It's either a queue structure or a pseudo-queue.
		Add a letter into the queue:
			push(letter)
			then, add element.alpha-block.alpha-<alphabet> into #alpha-board with append
		Record a delete from the queue structure:
			search for element index in queue (first encounter will be recorded)
				if index > -1:
					splice it out of the queue
					find jquery elements corresponding to letter
					remove first element with .remove()

	*/
	var startKeyDown = function() {
		$(document).on("keydown", handler = function(event) {
			//get character from char code
			var character = String.fromCharCode(event.which);

			//find character within queue
			var character_i_in_cache = alphabetsQueue.indexOf(character);

			if (alphabets.indexOf(character) > -1 && character_i_in_cache > -1) {
				//render alphabets captured
				alphabetsCount++;
				$("#alpha-count").html(alphabetsCount);
				//remove element from queue and object queue
				alphabetsQueue.splice(character_i_in_cache, 1);
				alphabetsObjectQueue.splice(character_i_in_cache, 1);

				//remove alphabet from board
				var $alphaBlock = $(".alpha-" + character).slice(-1).remove()
			}
		});
	};

	//you lose
	var renderYouLose = function() {
		console.log("You have lost!");
		$("#alphabets-count").hide();
		$("#you-lose").show();
		$(document).off("keydown");
		haveLost = true;

	};

	startKeyDown();

	var levelInterval = function(spawnSpeed, blockSpeed) {
		levelBreakers.push(setInterval(function() {
			var $alphaBoard = $("#alpha-board");

			//get a random alphabet
			var randIndex = randomIndex(alphabetsLength);
			var randomAlpha = alphabets[randIndex];

			var alphaBlockClass = "alpha-" + randomAlpha;

			//add alpha-block to alpha-board
			$alphaBoard.prepend("

" + randomAlpha + "

");

			//get alpha-block as jquery object
			var $currentAlphaBlock = $alphaBoard.children("." + alphaBlockClass).slice(0, 1)

			//set position
			$currentAlphaBlock.css("left", String(Math.random() * ($alphaBoard.width())) + "px");
			$currentAlphaBlock.css("top", "50px");

			//set color| dark, light
			var colorScheme = alphabetColours[alphabetColoursKeys[randomIndex(alphabetColoursKeys.length)]];
			$currentAlphaBlock.css("background-color", colorScheme[1])
							  .css("border", "2px solid " + colorScheme[0]);

			//console.log element
			//console.log($currentAlphaBlock);

			//drop element
			//render you lose upon complete
			$currentAlphaBlock.transition({y: $(document).height() - 45},
										  blockSpeed,
										  complete = function() {
										  	//lose if block is still in queue
										  	if (!haveLost && $(this).is(alphabetsObjectQueue[0])) {
										  		console.log("lost!!!!!");
										  		//render final score
										  		$("#you-lose-final-score").html(alphabetsCount);
										  		renderYouLose();
										  	}
										  });

			//add letter into cache
			alphabetsQueue.push(randomAlpha);

			//add object into cache
			alphabetsObjectQueue.push($currentAlphaBlock);
		}, spawnSpeed));
	}

	//level variables
	var thisLevelRequirement = initialLevelRequirement;
	var thisLevel = currentLevel;
	var thisBlockSpeed = blockSpeed; //0.98
	var thisSpawnSpeed = spawnSpeed; //0.99
	var thisLevelDifficulty = 2 // Means that 2 threads running at a time
						    	// every 10 levels increase by 1

	//activate level loop
	var selfBreaker = setInterval(function() {
		//stops game if lost
		if (haveLost || $("body").data("title") !== "game") {
			window.clearInterval(selfBreaker); //breaks self
			//clear all levels
			for (var i in levelBreakers) {
				window.clearInterval(levelBreakers[i]);
			}
		}

		if (alphabetsCount >= thisLevelRequirement) {
			console.log("-------------------")
			console.log("Level " + thisLevel);
			console.log("Threads: " + levelBreakers.length);

			//run next level
			levelInterval(thisSpawnSpeed, thisBlockSpeed);

			//render level
			$("#alpha-level").html("Level " + thisLevel);
			//pop a thread. Based on thisLevelDifficulty.
			if (levelBreakers.length >= thisLevelDifficulty  ) {
				console.log("Thread popped.");
				window.clearInterval(levelBreakers.shift());
			}

			//increase level
			thisLevel++;

			//increase level difficulty if requirement met
			if (thisLevel % 7 == 0) {
				console.log("Level difficulty increased!");
				thisLevelDifficulty += 1;
				thisSpawnSpeed *= 1.3;
			}
			//set next level requirement and settings
			thisLevelRequirement += 2;
			thisBlockSpeed *= 0.99;
			thisSpawnSpeed *= 0.98;
		}
	}, 500)

}

$(document).ready(function() {
	if ($("body").data("title") === "main") {
		$("#footer").click(function() {
			window.location.href = "/../../";
		});
	}
	if ($("body").data("title") === "game") {
		console.log("start");
		eventLoop();
	}
});
<commit_msg>narrows spawn area of alphabets<commit_after>var randomIndex = function(maxLength) {
	var randIndex = Math.round(Math.random() * maxLength);
	if (randIndex < 0) {
		randIndex = 0;
	}
	else if (randIndex >= maxLength) {
		randIndex = maxLength - 1;
	}
	return randIndex;
};

var eventLoop = function() {
	var alphabets = function(){
		var alphabets = [];
		for(var i = 65; i <= 90; i++) {
			alphabets.push(String.fromCharCode(i))
		}

		alphabets = alphabets.join('');
		return alphabets;
	}();

	var alphabetsLength = alphabets.length
	var currentLevel = 1;
	var initialLevelRequirement = 0;
	var blockSpeed = 10000; //seconds to reach ground
	var spawnSpeed = 1000; //block manifest every 3 seconds
	var alphabetsQueue = [];
	var alphabetsObjectQueue = [];
	var alphabetsCount = 0;
	//dark | light
	var alphabetColours = {"red": ["#9E302D", "#D56865"],
						   "orange": ["#9E612D", "#D59865"],
						   "green": ["#247C29", "#4FA755"],
						   "blue": ["#234367", "#48678B"],
						   "purple": ["#502269", "#75476E"],
						   "yellow": ["#9E9E2D", "D5D565"]};
	var alphabetColoursKeys = Object.keys(alphabetColours);
	var haveLost = false;
	//stops level
	var levelBreakers = [];
	/*
	Type of queue:
		It's either a queue structure or a pseudo-queue.
		Add a letter into the queue:
			push(letter)
			then, add element.alpha-block.alpha-<alphabet> into #alpha-board with append
		Record a delete from the queue structure:
			search for element index in queue (first encounter will be recorded)
				if index > -1:
					splice it out of the queue
					find jquery elements corresponding to letter
					remove first element with .remove()

	*/
	var startKeyDown = function() {
		$(document).on("keydown", handler = function(event) {
			//get character from char code
			var character = String.fromCharCode(event.which);

			//find character within queue
			var character_i_in_cache = alphabetsQueue.indexOf(character);

			if (alphabets.indexOf(character) > -1 && character_i_in_cache > -1) {
				//render alphabets captured
				alphabetsCount++;
				$("#alpha-count").html(alphabetsCount);
				//remove element from queue and object queue
				alphabetsQueue.splice(character_i_in_cache, 1);
				alphabetsObjectQueue.splice(character_i_in_cache, 1);

				//remove alphabet from board
				var $alphaBlock = $(".alpha-" + character).slice(-1).remove()
			}
		});
	};

	//you lose
	var renderYouLose = function() {
		console.log("You have lost!");
		$("#alphabets-count").hide();
		$("#you-lose").show();
		$(document).off("keydown");
		haveLost = true;

	};

	startKeyDown();

	var levelInterval = function(spawnSpeed, blockSpeed) {
		levelBreakers.push(setInterval(function() {
			var $alphaBoard = $("#alpha-board");

			//get a random alphabet
			var randIndex = randomIndex(alphabetsLength);
			var randomAlpha = alphabets[randIndex];

			var alphaBlockClass = "alpha-" + randomAlpha;

			//add alpha-block to alpha-board
			$alphaBoard.prepend("

" + randomAlpha + "

");

			//get alpha-block as jquery object
			var $currentAlphaBlock = $alphaBoard.children("." + alphaBlockClass).slice(0, 1)

			//set position
			var spawnLocation = function(start, end) {
				return start + Math.random() * (end - start);
			};
			$currentAlphaBlock.css("left", String(spawnLocation(230, $alphaBoard.width() - 50)) + "px");
			$currentAlphaBlock.css("top", "50px");

			//set color| dark, light
			var colorScheme = alphabetColours[alphabetColoursKeys[randomIndex(alphabetColoursKeys.length)]];
			$currentAlphaBlock.css("background-color", colorScheme[1])
							  .css("border", "2px solid " + colorScheme[0]);

			//console.log element
			//console.log($currentAlphaBlock);

			//drop element
			//render you lose upon complete
			$currentAlphaBlock.transition({y: $(document).height() - 45},
										  blockSpeed,
										  complete = function() {
										  	//lose if block is still in queue
										  	if (!haveLost && $(this).is(alphabetsObjectQueue[0])) {
										  		console.log("lost!!!!!");
										  		//render final score
										  		$("#you-lose-final-score").html(alphabetsCount);
										  		renderYouLose();
										  	}
										  });

			//add letter into cache
			alphabetsQueue.push(randomAlpha);

			//add object into cache
			alphabetsObjectQueue.push($currentAlphaBlock);
		}, spawnSpeed));
	}

	//level variables
	var thisLevelRequirement = initialLevelRequirement;
	var thisLevel = currentLevel;
	var thisBlockSpeed = blockSpeed; //10000
	var thisSpawnSpeed = spawnSpeed; //1000
	var thisLevelDifficulty = 2 // Means that 2 threads running at a time
						    	// every 10 levels increase by 1

	//activate level loop
	var selfBreaker = setInterval(function() {
		//stops game if lost
		if (haveLost || $("body").data("title") !== "game") {
			//clear all levels
			window.clearInterval(selfBreaker); //breaks self
			for (var i in levelBreakers) {
				window.clearInterval(levelBreakers[i]);
			}
			return;

		}

		if (alphabetsCount >= thisLevelRequirement) {
			console.log("-------------------")
			console.log("Level " + thisLevel);
			console.log("Threads: " + levelBreakers.length);

			//run next level
			levelInterval(thisSpawnSpeed, thisBlockSpeed);

			//render level
			$("#alpha-level").html("Level " + thisLevel);
			//pop a thread. Based on thisLevelDifficulty.
			if (levelBreakers.length >= thisLevelDifficulty  ) {
				console.log("Thread popped.");
				window.clearInterval(levelBreakers.shift());
			}

			//increase level
			thisLevel++;

			//increase level difficulty if requirement met
			if (thisLevel % 5 == 0) {
				console.log("Level difficulty increased!");
				thisLevelDifficulty += 1;
				thisSpawnSpeed *= 1.4;
			}
			//set next level requirement and settings
			thisLevelRequirement += 3;
			thisBlockSpeed *= 0.99;
			thisSpawnSpeed *= 0.97;
		}
	}, 500)

}

$(document).ready(function() {
	if ($("body").data("title") === "main") {
		$("#footer").click(function() {
			window.location.href = "/../../";
		});
	}
	if ($("body").data("title") === "game") {
		console.log("start");
		eventLoop();
	}
});
<|endoftext|>


<commit_before>/* globals Liquid Quantity App Metric globals */
(function () {
  /**
   * Determines if ETE errors should be shown to the visitor instead of a simple
   * message.
   */
  var showFullErrors = function showFullErrors() {
    return (
      globals.env === 'development' ||
      globals.env === 'test' ||
      globals.debug_js
    );
  };

  /**
   * Formats individual ETE error messages.
   */
  var formatError = function formatError(message) {
    var split = message.split(' | ');
    var messageEl = $('
')
      .append($('
').text(split[0]));

    if (split.length > 1) {
      messageEl.append($('
').html(split[1]));
    }

    return messageEl;
  };

  // ---------------------------------------------------------------------------

  // Matches queries in a string.
  var queryRe = /^(?:present|future)\.([a-z0-9_]+)$/i;

  /**
   * Provided a Liquid.js block node (typically an "if") extracts the queries
   * used to satisfy the condition.
   */
  var queriesFromBlock = function queriesFromBlock(block) {
    var queries = [];

    if (block.left && block.left.match(queryRe)) {
      queries.push(block.left.match(queryRe)[1]);
    }

    if (block.right && block.right.match(queryRe)) {
      queries.push(block.right.match(queryRe)[1]);
    }

    return queries;
  };

  /**
   * Given a Liquid.js nodelist, recursively extracts a list of all queries
   * used.
   *
   * @example
   *   extractQueries(Liquid.parse(string).root.nodelist);
   *   // => ['query_one', 'query_two']
   *
   * @param  {[array]} nodelist Array of nodes in the template.
   * @return {[array]}          Array of queries used.
   */
  var extractQueries = function extractQueries(nodelist) {
    var queries = [];

    nodelist.forEach(function (node) {
      if (node.blocks) {
        node.blocks.forEach(function (block) {
          queries = queries.concat(queriesFromBlock(block));
        });
      } else if (node.name && node.name.match(queryRe)) {
        queries = queries.concat([node.name.match(queryRe)[1]]);
      }

      if (node.nodelist) {
        queries = queries.concat(extractQueries(node.nodelist));
      }
    });

    return _.uniq(queries);
  };

  /**
   * Given a list of query keys, transforms the present and future values from
   * these queries into an object which may be used in a Liquid template.
   *
   * @param  {array} queryKeys An array of query keys.
   * @return {object} An object of the form { present: {}, future: {} }
   */
  var queryValues = function queryValues(queryKeys) {
    return _.reduce(queryKeys, function (memo, key) {
      var query = window.gqueries.with_key(key);
      var unit = query.get('unit');

      if (!Quantity.isSupported(unit)) {
        unit = '#';
      }

      // eslint-disable-next-line no-param-reassign
      memo.present[key] = new Quantity(query.get('present'), unit);
      // eslint-disable-next-line no-param-reassign
      memo.future[key] = new Quantity(query.get('future'), unit);

      return memo;
    }, { present: {}, future: {} });
  };

  var renderLiquid = function renderLiquid(onSuccess, onError) {
    var template = Liquid.parse($('#report-template').html());
    var queryKeys = extractQueries(template.root.nodelist);

    // In order to fetch the query values during App.call_api, the queries
    // need to be added to the global collection.
    queryKeys.forEach(function (queryKey) {
      window.gqueries.find_or_create_by_key(queryKey);
    });

    App.call_api({}, {
      success: function () {
        onSuccess(template.render(queryValues(queryKeys)));
      },
      error: function (resp) {
        onError(resp.responseJSON.errors);
      }
    });
  };

  // ---------------------------------------------------------------------------

  /**
   * Takes an array of report component data and recursively renders the
   * components.
   *
   * For example
   *   new ReportView({ components: [{ ... }] });
   */
  var ReportView = Backbone.View.extend({
    className: 'report-view',

    /**
     * Renders the report into the given element, running post-processing
     * methods as necessary to fetch charts and other scenario data. Prefer this
     * over using render() and renderCharts().
     */
    renderInto: function (container) {
      var self = this;

      container.append(this.render(function () {
        self.renderCharts();
      }));
    },

    /**
     * Renders the report. Provide an optional callback function to be invoked
     * once the template text has been parsed and rendered.
     */
    render: function (cb) {
      var self = this;

      renderLiquid(
        // onSuccess
        function (template) {
          self.$el.html(template);
          if (cb) cb(template);
        },
        // onError
        function (errors) {
          self.renderErrors(errors);
          if (cb) cb();
        }
      );

      return this.$el;
    },

    /**
     * In the event of an error during template rendering, shows the errors to
     * the user.
     */
    renderErrors: function (messages) {
      var errors = $('

');

      errors.append($('
').text(
        'Sorry, your report could not be created.'
      ));

      if (showFullErrors()) {
        errors.append($('
').append(messages.map(formatError)));
      }

      this.$el.empty().append(errors);

      return this.$el;
    },

    /**
     * Post-processing method which looks through the rendered report for a list
     * of charts to be rendered.
     */
    renderCharts: function () {
      var requests = {};

      $(this.$el.find('.chart_inner')).each(function (index, el) {
        var chartEl = $(el);
        var holderId = _.uniqueId('rchart_holder_');
        var chartId = chartEl.data('report-chart-id');

        window.charts.add_container_if_needed(holderId, {
          wrapper: '#' + chartEl.attr('id'),
          header: false
        });

        requests[holderId] = chartId + '-C';
      });

      window.charts.load_charts(requests);
    }
  });

  // ---------------------------------------------------------------------------

  Liquid.Template.registerFilter({
    /**
     * Renders a query value without the unit.
     *
     * @example
     *   "{{ future.query_key | without_unit }}"
     */
    without_unit: function (value) {
      if (value instanceof Quantity) {
        return value.value;
      }

      return value;
    },

    /**
     * Liquid filter which rounds numbers to the desired precision.
     *
     * @example
     *   "{{ future.query_key | round: 2 }}"
     */
    round: function (value, precision) {
      var multiplier = Math.pow(10, precision || 2);

      if (value instanceof Quantity) {
        return new Quantity(
          Math.round(value.value * multiplier) / multiplier,
          value.unit.name
        );
      }

      return Math.round(value * multiplier) / multiplier;
    },

    autoscale: function (value, unit) {
      return Metric.autoscale_value(value, unit);
    }
  });

  /**
   * Liquid component which renders a chart with an optional caption.
   *
   * @example
   *   "{% chart 52 %}{% endchart %}"
   *
   * @example
   *   "{% chart 52 %}This is a caption{% endchart %}"
   */
  Liquid.Template.registerTag('chart', Liquid.Block.extend({
    tagSyntax: /(\d+)/,

    // Underscore template which renders the necessary elements around the
    // chart.
    template: _.template(
      '
' +
      '  <div ' +
      '    class="chart_inner" ' +
      '    id="<%= _.uniqueId("rchart_") %>" ' +
      '  data-report-chart-id="<%= chartId %>" ' +
      '>
 ' +
      '  <% if (caption && caption.length) { %>' +
      '
<%= caption %>
' +
      '  <% } %>' +
      '
'
    ),

    init: function (tagName, markup, tokens) {
      var parts = markup.match(this.tagSyntax);

      if (parts) {
        this.chartId = parts[1];
      } else {
        throw new Error('Syntax error in "chart" - Valid syntax: chart key');
      }

      // eslint-disable-next-line no-underscore-dangle
      this._super(tagName, markup, tokens);
    },

    render: function (context) {
      return this.template({
        chartId: this.chartId,
        // eslint-disable-next-line no-underscore-dangle
        caption: this._super(context).join('').trim()
      });
    }
  }));

  window.ReportView = ReportView;
}());
<commit_msg>Make some scenario settings available in the report<commit_after>/* globals Liquid Quantity App Metric globals */
(function () {
  /**
   * Determines if ETE errors should be shown to the visitor instead of a simple
   * message.
   */
  var showFullErrors = function showFullErrors() {
    return (
      globals.env === 'development' ||
      globals.env === 'test' ||
      globals.debug_js
    );
  };

  /**
   * Formats individual ETE error messages.
   */
  var formatError = function formatError(message) {
    var split = message.split(' | ');
    var messageEl = $('
')
      .append($('
').text(split[0]));

    if (split.length > 1) {
      messageEl.append($('
').html(split[1]));
    }

    return messageEl;
  };

  // ---------------------------------------------------------------------------

  // Matches queries in a string.
  var queryRe = /^(?:present|future)\.([a-z0-9_]+)$/i;

  /**
   * Provided a Liquid.js block node (typically an "if") extracts the queries
   * used to satisfy the condition.
   */
  var queriesFromBlock = function queriesFromBlock(block) {
    var queries = [];

    if (block.left && block.left.match(queryRe)) {
      queries.push(block.left.match(queryRe)[1]);
    }

    if (block.right && block.right.match(queryRe)) {
      queries.push(block.right.match(queryRe)[1]);
    }

    return queries;
  };

  /**
   * Given a Liquid.js nodelist, recursively extracts a list of all queries
   * used.
   *
   * @example
   *   extractQueries(Liquid.parse(string).root.nodelist);
   *   // => ['query_one', 'query_two']
   *
   * @param  {[array]} nodelist Array of nodes in the template.
   * @return {[array]}          Array of queries used.
   */
  var extractQueries = function extractQueries(nodelist) {
    var queries = [];

    nodelist.forEach(function (node) {
      if (node.blocks) {
        node.blocks.forEach(function (block) {
          queries = queries.concat(queriesFromBlock(block));
        });
      } else if (node.name && node.name.match(queryRe)) {
        queries = queries.concat([node.name.match(queryRe)[1]]);
      }

      if (node.nodelist) {
        queries = queries.concat(extractQueries(node.nodelist));
      }
    });

    return _.uniq(queries);
  };

  /**
   * Given a list of query keys, transforms the present and future values from
   * these queries into an object which may be used in a Liquid template.
   *
   * @param  {array} queryKeys An array of query keys.
   * @return {object} An object of the form { present: {}, future: {} }
   */
  var queryValues = function queryValues(queryKeys) {
    return _.reduce(queryKeys, function (memo, key) {
      var query = window.gqueries.with_key(key);
      var unit = query.get('unit');

      if (!Quantity.isSupported(unit)) {
        unit = '#';
      }

      // eslint-disable-next-line no-param-reassign
      memo.present[key] = new Quantity(query.get('present'), unit);
      // eslint-disable-next-line no-param-reassign
      memo.future[key] = new Quantity(query.get('future'), unit);

      return memo;
    }, { present: {}, future: {} });
  };

  var renderLiquid = function renderLiquid(onSuccess, onError) {
    var template = Liquid.parse($('#report-template').html());
    var queryKeys = extractQueries(template.root.nodelist);

    // In order to fetch the query values during App.call_api, the queries
    // need to be added to the global collection.
    queryKeys.forEach(function (queryKey) {
      window.gqueries.find_or_create_by_key(queryKey);
    });

    App.call_api({}, {
      success: function () {
        onSuccess(template.render(
          $.extend(queryValues(queryKeys), { settings: {
            area_code: App.settings.get('area_code'),
            end_year: App.settings.get('end_year'),
            merit_order_enabled: App.settings.merit_order_enabled(),
            start_year: App.settings.get('start_year'),
          }})
        ));
      },
      error: function (resp) {
        onError(resp.responseJSON.errors);
      }
    });
  };

  // ---------------------------------------------------------------------------

  /**
   * Takes an array of report component data and recursively renders the
   * components.
   *
   * For example
   *   new ReportView({ components: [{ ... }] });
   */
  var ReportView = Backbone.View.extend({
    className: 'report-view',

    /**
     * Renders the report into the given element, running post-processing
     * methods as necessary to fetch charts and other scenario data. Prefer this
     * over using render() and renderCharts().
     */
    renderInto: function (container) {
      var self = this;

      container.append(this.render(function () {
        self.renderCharts();
      }));
    },

    /**
     * Renders the report. Provide an optional callback function to be invoked
     * once the template text has been parsed and rendered.
     */
    render: function (cb) {
      var self = this;

      renderLiquid(
        // onSuccess
        function (template) {
          self.$el.html(template);
          if (cb) cb(template);
        },
        // onError
        function (errors) {
          self.renderErrors(errors);
          if (cb) cb();
        }
      );

      return this.$el;
    },

    /**
     * In the event of an error during template rendering, shows the errors to
     * the user.
     */
    renderErrors: function (messages) {
      var errors = $('

');

      errors.append($('
').text(
        'Sorry, your report could not be created.'
      ));

      if (showFullErrors()) {
        errors.append($('
').append(messages.map(formatError)));
      }

      this.$el.empty().append(errors);

      return this.$el;
    },

    /**
     * Post-processing method which looks through the rendered report for a list
     * of charts to be rendered.
     */
    renderCharts: function () {
      var requests = {};

      $(this.$el.find('.chart_inner')).each(function (index, el) {
        var chartEl = $(el);
        var holderId = _.uniqueId('rchart_holder_');
        var chartId = chartEl.data('report-chart-id');

        window.charts.add_container_if_needed(holderId, {
          wrapper: '#' + chartEl.attr('id'),
          header: false
        });

        requests[holderId] = chartId + '-C';
      });

      window.charts.load_charts(requests);
    }
  });

  // ---------------------------------------------------------------------------

  Liquid.Template.registerFilter({
    /**
     * Renders a query value without the unit.
     *
     * @example
     *   "{{ future.query_key | without_unit }}"
     */
    without_unit: function (value) {
      if (value instanceof Quantity) {
        return value.value;
      }

      return value;
    },

    /**
     * Liquid filter which rounds numbers to the desired precision.
     *
     * @example
     *   "{{ future.query_key | round: 2 }}"
     */
    round: function (value, precision) {
      var multiplier = Math.pow(10, precision || 2);

      if (value instanceof Quantity) {
        return new Quantity(
          Math.round(value.value * multiplier) / multiplier,
          value.unit.name
        );
      }

      return Math.round(value * multiplier) / multiplier;
    },

    autoscale: function (value, unit) {
      return Metric.autoscale_value(value, unit);
    }
  });

  /**
   * Liquid component which renders a chart with an optional caption.
   *
   * @example
   *   "{% chart 52 %}{% endchart %}"
   *
   * @example
   *   "{% chart 52 %}This is a caption{% endchart %}"
   */
  Liquid.Template.registerTag('chart', Liquid.Block.extend({
    tagSyntax: /(\d+)/,

    // Underscore template which renders the necessary elements around the
    // chart.
    template: _.template(
      '
' +
      '  <div ' +
      '    class="chart_inner" ' +
      '    id="<%= _.uniqueId("rchart_") %>" ' +
      '  data-report-chart-id="<%= chartId %>" ' +
      '>
 ' +
      '  <% if (caption && caption.length) { %>' +
      '
<%= caption %>
' +
      '  <% } %>' +
      '
'
    ),

    init: function (tagName, markup, tokens) {
      var parts = markup.match(this.tagSyntax);

      if (parts) {
        this.chartId = parts[1];
      } else {
        throw new Error('Syntax error in "chart" - Valid syntax: chart key');
      }

      // eslint-disable-next-line no-underscore-dangle
      this._super(tagName, markup, tokens);
    },

    render: function (context) {
      return this.template({
        chartId: this.chartId,
        // eslint-disable-next-line no-underscore-dangle
        caption: this._super(context).join('').trim()
      });
    }
  }));

  window.ReportView = ReportView;
}());
<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery.ui.all
//= require jquery_ujs
//= require bootstrap
//= require_self
//= require multipage/jquery.localscroll-min
//= require multipage/jquery.scrollTo-min
//= require multipage/tinyscrolling

jQuery('document').ready(function() {

  // display validation errors for the "request invitation" form
  if (jQuery('.alert-error').length > 0) {
    jQuery("#request-invite").modal('toggle');
  }

  // use AJAX to submit the "request invitation" form
  jQuery('#invitation_button').on('click', function() {
    email = jQuery('#invit_user #user_email').val();
    dataString = 'user[email]='+ email;
    jQuery.ajax({
      type: "POST",
      url: "/fr/users",
      data: dataString,
      success: function(data) {
        jQuery('#request-invite').html(data);
        loadSocial();
      }
    });
    return false;
  });

})

// load social sharing scripts if the page includes a Twitter "share" button
function loadSocial() {

    //Twitter
    if (typeof (twttr) != 'undefined') {
      twttr.widgets.load();
    } else {
      jQuery.getScript('http://platform.twitter.com/widgets.js');
    }

    //Facebook
    if (typeof (FB) != 'undefined') {
      FB.init({ status: true, cookie: true, xfbml: true });
    } else {
      jQuery.getScript("http://connect.facebook.net/en_US/all.js#xfbml=1", function () {
        FB.init({ status: true, cookie: true, xfbml: true });
      });
    }

    //Google+
    if (typeof (gapi) != 'undefined') {
      jQuery(".g-plusone").each(function () {
        gapi.plusone.render($(this).get(0));
      });
    } else {
      jQuery.getScript('https://apis.google.com/js/plusone.js');
    }
}

jQuery('.login-toggle').click(function(){
  console.log("ter")
  if (!jQuery('#login-tab').hasClass("invisible")) {
    jQuery('#login-tab').addClass("invisible");
    //jQuery('#nav').addClass("hidden");
    jQuery('#socialfixed').addClass("hidden");
    //jQuery('#socialfixed').addClass("invisible");
    //jQuery('#langswitch').addClass("invisible");
    jQuery('#login-form').removeClass("invisible");
    jQuery("input:text:visible:first").focus();
  } else {
    jQuery('#login-tab').removeClass("invisible");
    //jQuery('#nav').removeClass("hidden");
    jQuery('#socialfixed').removeClass("hidden");

    //jQuery('#socialfixed').removeClass("invisible");
    //jQuery('#langswitch').removeClass("invisible");
    jQuery('#login-form').addClass("invisible");
  }

});

jQuery("[rel='tooltip']").tooltip();

jQuery('.login-btn').removeClass("btn");

jQuery('.nav-collapse .nav > li > a').click(function(){

			jQuery('.collapse.in').removeClass('in').css('height', '0');

});<commit_msg>fix a source bug<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery.ui.all
//= require jquery_ujs
//= require bootstrap
//= require_self
//= require multipage/tinyscrolling

jQuery('document').ready(function() {

  // display validation errors for the "request invitation" form
  if (jQuery('.alert-error').length > 0) {
    jQuery("#request-invite").modal('toggle');
  }

  // use AJAX to submit the "request invitation" form
  jQuery('#invitation_button').on('click', function() {
    email = jQuery('#invit_user #user_email').val();
    dataString = 'user[email]='+ email;
    jQuery.ajax({
      type: "POST",
      url: "/fr/users",
      data: dataString,
      success: function(data) {
        jQuery('#request-invite').html(data);
        loadSocial();
      }
    });
    return false;
  });

})

// load social sharing scripts if the page includes a Twitter "share" button
function loadSocial() {

    //Twitter
    if (typeof (twttr) != 'undefined') {
      twttr.widgets.load();
    } else {
      jQuery.getScript('http://platform.twitter.com/widgets.js');
    }

    //Facebook
    if (typeof (FB) != 'undefined') {
      FB.init({ status: true, cookie: true, xfbml: true });
    } else {
      jQuery.getScript("http://connect.facebook.net/en_US/all.js#xfbml=1", function () {
        FB.init({ status: true, cookie: true, xfbml: true });
      });
    }

    //Google+
    if (typeof (gapi) != 'undefined') {
      jQuery(".g-plusone").each(function () {
        gapi.plusone.render($(this).get(0));
      });
    } else {
      jQuery.getScript('https://apis.google.com/js/plusone.js');
    }
}

jQuery('.login-toggle').click(function(){
  console.log("ter")
  if (!jQuery('#login-tab').hasClass("invisible")) {
    jQuery('#login-tab').addClass("invisible");
    //jQuery('#nav').addClass("hidden");
    jQuery('#socialfixed').addClass("hidden");
    //jQuery('#socialfixed').addClass("invisible");
    //jQuery('#langswitch').addClass("invisible");
    jQuery('#login-form').removeClass("invisible");
    jQuery("input:text:visible:first").focus();
  } else {
    jQuery('#login-tab').removeClass("invisible");
    //jQuery('#nav').removeClass("hidden");
    jQuery('#socialfixed').removeClass("hidden");

    //jQuery('#socialfixed').removeClass("invisible");
    //jQuery('#langswitch').removeClass("invisible");
    jQuery('#login-form').addClass("invisible");
  }

});

jQuery("[rel='tooltip']").tooltip();

jQuery('.login-btn').removeClass("btn");

jQuery('.nav-collapse .nav > li > a').click(function(){

			jQuery('.collapse.in').removeClass('in').css('height', '0');

});<|endoftext|>


<commit_before>function schedulerInit() {
    $('#appointed_tabs').tab();

    function fillInput(lbond, ubond, id) {
        var _days = _.range(lbond, ubond, $("#" + id).val());
        $("#" + id + "_input").val(_.join(_days, ", "));
    }

    $("#months_days").change(function (p) {
        fillInput(1, 32, "months_days");
        updateSchedulerValue();
    });

    $("#months").change(function (p) {
        fillInput(1, 13, "months");
        updateSchedulerValue();
    });

    $("#hours").change(function (p) {
        fillInput(0, 24, "hours");
        updateSchedulerValue();
    });

    $("#minutes").change(function (p) {
        fillInput(0, 60, "minutes");
        updateSchedulerValue();
    });

    $(":checkbox").change(function (p) {
        updateSchedulerValue();
    });

    $(":text").change(function (p) {
        updateSchedulerValue();
    });

    $("#scheduler_kinds").change(function (p) {
        if ($("#scheduler_kinds").val() === "1") {
            cyclic.show();
            appointed.hide();
        } else {
            cyclic.hide();
            appointed.show();
        }
        updateSchedulerValue();
    });

    function createSchedulerValue() {
        function input_validation(id) {
            return $(id).val().indexOf(",") != -1 ?
                _.map($(id).val().split(","), function (e) {
                    return Number(e);
                }) : ($(id).val().trim() == "" ?
                [] : [Number($(id).val().trim())])
        }

        var position_tab = $("#position").attr('class').indexOf('active') != -1;

        var cyclic_tab = $("#scheduler_kinds").val() === "1";

        var res = {

            "type": cyclic_tab ? "cyclic" : "appointed_" + (position_tab ? "position" : "number"),

            "months_days": input_validation("#months_days_input"),

            "weeks_days": _.filter(_.range(0, 7), function (e) {
                return $("#week_day_" + e).is(":checked")
            }),

            "weeks_month": _.concat(_.filter(_.range(1, 3), function (e) {
                    return $("#week_month_" + e).is(":checked")
                }),
                _.map(_.filter(_.range(1, 2), function (e) {
                    return $("#week_month_reverse_" + e).is(":checked")
                }), function (e) {
                    return e * -1;
                })),

            "last_day_in_month": $("#last_day_in_month").is(":checked"),

            "months": input_validation("#months_input"),

            "hours": input_validation("#hours_input"),

            "minutes": input_validation("#minutes_input")
        };

        if (cyclic_tab)
            res["cyclic_expression"] = $("#cyclic_expression").val();

        return res;
    }

    var position_scheduler_month_days = $("#position_scheduler_month_days");
    var number_scheduler_month_days = $("#number_scheduler_month_days");
    var type_of_days_btn = $("#type_of_days_btn");

    var cyclic = $("#cyclic");
    var appointed = $("#appointed");

    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
        updateSchedulerValue();
    });

    function updateSchedulerValue() {
        $("#setup_scheduler_expression").val(JSON.stringify(createSchedulerValue()));
    }

}
<commit_msg>Ensuring scheduler.js only affects _scheduler form<commit_after>function schedulerInit() {
    var cyclic = $("#cyclic");
    var appointed = $("#appointed");

    if ((cyclic.length == 0) || (appointed.length == 0)){
        return;
    }

    $('#appointed_tabs').tab();

    function fillInput(lbond, ubond, id) {
        var _days = _.range(lbond, ubond, $("#" + id).val());
        $("#" + id + "_input").val(_.join(_days, ", "));
    }

    $("#months_days").change(function (p) {
        fillInput(1, 32, "months_days");
        updateSchedulerValue();
    });

    $("#months").change(function (p) {
        fillInput(1, 13, "months");
        updateSchedulerValue();
    });

    $("#hours").change(function (p) {
        fillInput(0, 24, "hours");
        updateSchedulerValue();
    });

    $("#minutes").change(function (p) {
        fillInput(0, 60, "minutes");
        updateSchedulerValue();
    });

    $(":checkbox").change(function (p) {
        updateSchedulerValue();
    });

    $(":text").change(function (p) {
        updateSchedulerValue();
    });

    $("#scheduler_kinds").change(function (p) {
        if ($("#scheduler_kinds").val() === "1") {
            cyclic.show();
            appointed.hide();
        } else {
            cyclic.hide();
            appointed.show();
        }
        updateSchedulerValue();
    });

    function createSchedulerValue() {
        function input_validation(id) {
            return $(id).val().indexOf(",") != -1 ?
                _.map($(id).val().split(","), function (e) {
                    return Number(e);
                }) : ($(id).val().trim() == "" ?
                [] : [Number($(id).val().trim())])
        }

        var position_tab = $("#position").attr('class').indexOf('active') != -1;

        var cyclic_tab = $("#scheduler_kinds").val() === "1";

        var res = {

            "type": cyclic_tab ? "cyclic" : "appointed_" + (position_tab ? "position" : "number"),

            "months_days": input_validation("#months_days_input"),

            "weeks_days": _.filter(_.range(0, 7), function (e) {
                return $("#week_day_" + e).is(":checked")
            }),

            "weeks_month": _.concat(_.filter(_.range(1, 3), function (e) {
                    return $("#week_month_" + e).is(":checked")
                }),
                _.map(_.filter(_.range(1, 2), function (e) {
                    return $("#week_month_reverse_" + e).is(":checked")
                }), function (e) {
                    return e * -1;
                })),

            "last_day_in_month": $("#last_day_in_month").is(":checked"),

            "months": input_validation("#months_input"),

            "hours": input_validation("#hours_input"),

            "minutes": input_validation("#minutes_input")
        };

        if (cyclic_tab)
            res["cyclic_expression"] = $("#cyclic_expression").val();

        return res;
    }

    var position_scheduler_month_days = $("#position_scheduler_month_days");
    var number_scheduler_month_days = $("#number_scheduler_month_days");
    var type_of_days_btn = $("#type_of_days_btn");

    appointed.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
        updateSchedulerValue();
    });

    function updateSchedulerValue() {
        $("#setup_scheduler_expression").val(JSON.stringify(createSchedulerValue()));
    }

}
<|endoftext|>


<commit_before>angular.module('ocWebGui.stats', ['ui.router', 'nvd3'])
  .config(function ($stateProvider) {
    $stateProvider
      .state('stats', {
        url: '/stats',
        templateUrl: 'stats/_stats.html',
        controller: 'StatsController',
        controllerAs: 'stats'
      });
  })
  .controller('StatsController', function ($interval, $scope, $http) {
    var vm = this;
    vm.title = 'Tilastot';

    vm.api = {};
    vm.options = {
      chart: {
        type: 'scatterChart',
        width: 700,
        height: 550,
        margin: {
          top: 30,
          right: 90,
          bottom: 60,
          left: 90
        },
        color: d3.scale.category10().range(),
        showDistX: true,
        showDistY: true,
        xAxis: {
          axisLabel: 'Kellonaika',
          tickFormat: function (d) {
            return d3.time.format('%H.%M')(new Date(d));
          }
        },
        yAxis: {
          axisLabel: 'Jonotusaika',
          axisLabelDistance: 10,
          tickFormat: function (seconds) {
            var formatTime = d3.time.format('%H:%M');
            return formatTime(new Date(1864, 7, 7, 0, seconds));
          }
        },
        x: function (d) { return d.hour; },
        y: function (d) { return d.calls; }
      }
    };

    vm.data = [{
      'key': 'Jonotusaika',
      'values': []
    }];

    vm.api2 = {};
    vm.options2 = {
      chart: {
        type: 'multiChart',
        width: 700,
        height: 550,
        margin: {
          top: 30,
          right: 90,
          bottom: 60,
          left: 40
        },
        duration: 500,
        xAxis: {
          axisLabel: 'Kellonaika',
          tickFormat: function (d) {
            return d3.time.format('%H.%M')(new Date(d));
          }
        },
        yAxis2: {
          ticks: 10,
          tickFormat: function (seconds) {
            var formatTime = d3.time.format('%H:%M');
            return formatTime(new Date(1864, 7, 7, 0, seconds));
          }
        }
      }
    };

    vm.data2 = [{
      'key': 'Henkilöitä',
      'values': [],
      'type': 'line',
      'yAxis': 1,
      'color': '#ff00ff'
    }, {
      'key': 'Luopuneet',
      'values': [],
      'type': 'line',
      'yAxis': 1,
      'color': '#0000ff'
    }, {
      'key': 'Jonotuksen keskiarvo',
      'values': [],
      'type': 'bar',
      'yAxis': 2,
      'color': '#00ff00'
    }];

    function fetchContactStats() {
      $http.get('contacts/stats.json').then(function (response) {
        var data = response.data;

        var queueDurationsByTimes = data.queue_durations_by_times
          .map(function (j) { return { hour: new Date(j[0]).getTime(), calls: j[1] }; });
        vm.data[0].values = queueDurationsByTimes;

        var clock8 = new Date();
        clock8.setDate(clock8.getDate());
        clock8.setHours(8, 0, 0);

        var clock18 = new Date();
        clock18.setDate(clock18.getDate());
        clock18.setHours(18, 0, 0);
        var first = data.correlation_of_average_queue_length_and_missed_calls
          .map(function (j) { return { x: new Date(j[0]).getTime(), y: j[1] }; })
          .filter(function (item) { return item.x >= clock8 && item.x <= clock18; });
        vm.data2[0].values = first;

        var second = data.correlation_of_average_queue_length_and_missed_calls
          .map(function (j) { return { x: new Date(j[0]).getTime(), y: j[2] }; })
          .filter(function (item) { return item.x >= clock8 && item.x <= clock18; });
        vm.data2[1].values = second;

        var third = data.correlation_of_average_queue_length_and_missed_calls
          .map(function (j) { return { x: new Date(j[0]).getTime(), y: j[3] }; })
          .filter(function (item) { return item.x >= clock8 && item.x <= clock18; });
        vm.data2[2].values = third;

        vm.options2.chart.xAxis.tickValues = d3.time.hour.range(clock8, clock18, 1)
          .map(function (f) { return f.getTime() });
      });
    }

    var fetchContactStatsInterval = $interval(fetchContactStats, 5 * 60 * 1000);
    $scope.$on('$destroy', function () {
      $interval.cancel(fetchContactStatsInterval);
    });

    fetchContactStats();
  });
<commit_msg>changed line chart to area chart<commit_after>angular.module('ocWebGui.stats', ['ui.router', 'nvd3'])
  .config(function ($stateProvider) {
    $stateProvider
      .state('stats', {
        url: '/stats',
        templateUrl: 'stats/_stats.html',
        controller: 'StatsController',
        controllerAs: 'stats'
      });
  })
  .controller('StatsController', function ($interval, $scope, $http) {
    var vm = this;
    vm.title = 'Tilastot';

    vm.api = {};
    vm.options = {
      chart: {
        type: 'scatterChart',
        width: 700,
        height: 550,
        margin: {
          top: 30,
          right: 90,
          bottom: 60,
          left: 90
        },
        color: d3.scale.category10().range(),
        showDistX: true,
        showDistY: true,
        xAxis: {
          axisLabel: 'Kellonaika',
          tickFormat: function (d) {
            return d3.time.format('%H.%M')(new Date(d));
          }
        },
        yAxis: {
          axisLabel: 'Jonotusaika',
          axisLabelDistance: 10,
          tickFormat: function (seconds) {
            var formatTime = d3.time.format('%H:%M');
            return formatTime(new Date(1864, 7, 7, 0, seconds));
          }
        },
        x: function (d) { return d.hour; },
        y: function (d) { return d.calls; }
      }
    };

    vm.data = [{
      'key': 'Jonotusaika',
      'values': []
    }];

    vm.api2 = {};
    vm.options2 = {
      chart: {
        type: 'multiChart',
        width: 700,
        height: 550,
        margin: {
          top: 30,
          right: 90,
          bottom: 60,
          left: 40
        },
        duration: 500,
        xAxis: {
          axisLabel: 'Kellonaika',
          tickFormat: function (d) {
            return d3.time.format('%H.%M')(new Date(d));
          }
        },
        yAxis2: {
          ticks: 10,
          tickFormat: function (seconds) {
            var formatTime = d3.time.format('%H:%M');
            return formatTime(new Date(1864, 7, 7, 0, seconds));
          }
        }
      }
    };

    vm.data2 = [{
      'key': 'Henkilöitä',
      'values': [],
      'type': 'line',
      'yAxis': 1,
      'color': '#ff00ff'
    }, {
      'key': 'Luopuneet',
      'values': [],
      'type': 'area',
      'yAxis': 1,
      'color': '#0000ff'
    }, {
      'key': 'Jonotuksen keskiarvo',
      'values': [],
      'type': 'bar',
      'yAxis': 2,
      'color': '#00ff00'
    }];

    function fetchContactStats() {
      $http.get('contacts/stats.json').then(function (response) {
        var data = response.data;

        var queueDurationsByTimes = data.queue_durations_by_times
          .map(function (j) { return { hour: new Date(j[0]).getTime(), calls: j[1] }; });
        vm.data[0].values = queueDurationsByTimes;

        var clock8 = new Date();
        clock8.setDate(clock8.getDate());
        clock8.setHours(8, 0, 0);

        var clock18 = new Date();
        clock18.setDate(clock18.getDate());
        clock18.setHours(18, 0, 0);
        var first = data.correlation_of_average_queue_length_and_missed_calls
          .map(function (j) { return { x: new Date(j[0]).getTime(), y: j[1] }; })
          .filter(function (item) { return item.x >= clock8 && item.x <= clock18; });
        vm.data2[0].values = first;

        var second = data.correlation_of_average_queue_length_and_missed_calls
          .map(function (j) { return { x: new Date(j[0]).getTime(), y: j[2] }; })
          .filter(function (item) { return item.x >= clock8 && item.x <= clock18; });
        vm.data2[1].values = second;

        var third = data.correlation_of_average_queue_length_and_missed_calls
          .map(function (j) { return { x: new Date(j[0]).getTime(), y: j[3] }; })
          .filter(function (item) { return item.x >= clock8 && item.x <= clock18; });
        vm.data2[2].values = third;

        vm.options2.chart.xAxis.tickValues = d3.time.hour.range(clock8, clock18, 1)
          .map(function (f) { return f.getTime() });
      });
    }

    var fetchContactStatsInterval = $interval(fetchContactStats, 5 * 60 * 1000);
    $scope.$on('$destroy', function () {
      $interval.cancel(fetchContactStatsInterval);
    });

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


<commit_before>$.extend({
  keys: function(obj){
    var a = [];
    $.each(obj, function(k){ a.push(k) });
    return a;
  }
});

if (!Array.indexOf) Array.prototype.indexOf = function(obj) {
  for(var i = 0; i < this.length; i++){
    if(this[i] == obj) {
      return i;
    }
  }
  return -1;
}

if (!Array.find_matches) Array.find_matches = function(a) {
  var i, m = [];
  a = a.sort();
  i = a.length
  while(i--) {
    if (a[i - 1] == a[i]) {
      m.push(a[i]);
    }
  }
  if (m.length == 0) {
    return false;
  }
  return m;
}

function VariantOptions(params) {

  var options = params['options'];
  var allow_backorders = !params['track_inventory_levels'] ||  params['allow_backorders'];
  var allow_select_outofstock = params['allow_select_outofstock'];
  var default_instock = params['default_instock'];

  var variant, divs, parent, index = 0;
  var selection = [];
  var buttons;

  function init() {
    divs = $('#product-variants .variant-options');
    disable(divs.find('a.option-value').addClass('locked'));
    update();
    enable(parent.find('a.option-value'));
    toggle();
    $('.clear-option a.clear-button').hide().click(handle_clear);

    if (default_instock) {
      divs.each(function(){
        $(this).find("ul.variant-option-values li a.in-stock:first").click();
      });
    }
  }

  function get_index(parent) {
    return parseInt($(parent).attr('class').replace(/[^\d]/g, ''));
  }

  function update(i) {
    index = isNaN(i) ? index : i;
    parent = $(divs.get(index));
    buttons = parent.find('a.option-value');
    parent.find('a.clear-button').hide();
  }

  function disable(btns) {
    return btns.removeClass('selected');
  }

  function enable(btns) {
    bt = btns.not('.unavailable').removeClass('locked').unbind('click')
    if (!allow_select_outofstock && !allow_backorders)
      bt = bt.filter('.in-stock')
    return bt.click(handle_click).filter('.auto-click').removeClass('auto-click').click();
  }

  function advance() {
    index++
    update();
    inventory(buttons.removeClass('locked'));
    enable(buttons);
  }

  function inventory(btns) {
    var keys, variants, count = 0, selected = {};
    var sels = $.map(divs.find('a.selected'), function(i) { return i.rel });
    $.each(sels, function(key, value) {
      key = value.split('-');
      var v = options[key[0]][key[1]];
      keys = $.keys(v);
      var m = Array.find_matches(selection.concat(keys));
      if (selection.length == 0) {
        selection = keys;
      } else if (m) {
        selection = m;
      }
    });
    btns.removeClass('in-stock out-of-stock unavailable').each(function(i, element) {
      variants = get_variant_objects(element.rel);
      keys = $.keys(variants);
      if (keys.length == 0) {
        disable($(element).addClass('unavailable locked').unbind('click'));
      } else if (keys.length == 1) {
        _var = variants[keys[0]];
        $(element).addClass((allow_backorders || _var.count) ? selection.length == 1 ? 'in-stock auto-click' : 'in-stock' : 'out-of-stock');
      } else if (allow_backorders) {
        $(element).addClass('in-stock');
      } else {
        $.each(variants, function(key, value) { count += value.count });
        $(element).addClass(count ? 'in-stock' : 'out-of-stock');
      }
    });
  }

  function get_variant_objects(rels) {
    var i, ids, obj, variants = {};
    if (typeof(rels) == 'string') { rels = [rels]; }
    var otid, ovid, opt, opv;
    i = rels.length;
    try {
      while (i--) {
        ids = rels[i].split('-');
        otid = ids[0];
        ovid = ids[1];
        opt = options[otid];
        if (opt) {
          opv = opt[ovid];
          ids = $.keys(opv);
          if (opv && ids.length) {
            var j = ids.length;
            while (j--) {
              obj = opv[ids[j]];
              if (obj && $.keys(obj).length && 0 <= selection.indexOf(obj.id.toString())) {
                variants[obj.id] = obj;
              }
            }
          }
        }
      }
    } catch(error) {
      //console.log(error);
    }
    return variants;
  }

  function to_f(string) {
    return parseFloat(string.replace(/[^\d\.]/g, ''));
  }

  function find_variant() {
    var selected = divs.find('a.selected');
    var variants = get_variant_objects(selected.get(0).rel);
    if (selected.length == divs.length) {
      return variant = variants[selection[0]];
    } else {
      var prices = [];
      $.each(variants, function(key, value) { prices.push(value.price) });
      prices = $.unique(prices).sort(function(a, b) {
        return to_f(a) < to_f(b) ? -1 : 1;
      });
      if (prices.length == 1) {
        $('#product-price .price').html('' + prices[0] + '');
      } else {
        $('#product-price .price').html('' + prices[0] + ' - ' + prices[prices.length - 1] + '');
      }
      return false;
    }
  }

  function toggle() {
    if (variant) {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val(variant.id).change();
      var oldprice = $('#product-price .price').text();
      $('#product-price .price').removeClass('unselected');
      $('#product-price .price').text(variant.price);
      if (variant.retail_price.length > 0)
      	$('#product-price .retail').text(variant.retail_price);
      if (oldprice != variant.price) { // highlight price change
      	  $('#product-price .price').switchClass("price", "price-highlight");
      	  $('#product-price .price').switchClass("price-highlight", "price", 1000);
	   }
      if (variant.count > 0 || allow_backorders)
        $('#cart-form button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      $('form[data-form-type="variant"] button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      try {
        show_variant_images(variant.id);
      } catch(error) {
        // depends on modified version of product.js
      }
    } else {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val('').change();
      $('#cart-form button[type=submit], form[data-form-type="variant"] button[type=submit]').attr('disabled', true).fadeTo(0, 0.5);
    }
  }

  function clear(i) {
    variant = null;
    update(i);
    enable(buttons.removeClass('selected'));
    toggle();
    parent.nextAll().each(function(index, element) {
      disable($(element).find('a.option-value').show().removeClass('in-stock out-of-stock').addClass('locked').unbind('click'));
      $(element).find('a.clear-button').hide();
    });
    show_all_variant_images();
  }

  function handle_clear(evt) {
    evt.preventDefault();
    clear(get_index(this));
  }

  function handle_click(evt) {
    evt.preventDefault();
    variant = null;
    selection = [];
    var a = $(this);
    if (!parent.has(a).length) {
      clear(divs.index(a.parents('.variant-options:first')));
    }
    disable(buttons);
    var a = enable(a.addClass('selected'));
    parent.find('a.clear-button').css('display', 'block');
    advance();
    if (find_variant()) {
      toggle();
    }
  }

  $(document).ready(init);

};
<commit_msg>Fix animation for price change<commit_after>$.extend({
  keys: function(obj){
    var a = [];
    $.each(obj, function(k){ a.push(k) });
    return a;
  }
});

if (!Array.indexOf) Array.prototype.indexOf = function(obj) {
  for(var i = 0; i < this.length; i++){
    if(this[i] == obj) {
      return i;
    }
  }
  return -1;
}

if (!Array.find_matches) Array.find_matches = function(a) {
  var i, m = [];
  a = a.sort();
  i = a.length
  while(i--) {
    if (a[i - 1] == a[i]) {
      m.push(a[i]);
    }
  }
  if (m.length == 0) {
    return false;
  }
  return m;
}

function VariantOptions(params) {

  var options = params['options'];
  var allow_backorders = !params['track_inventory_levels'] ||  params['allow_backorders'];
  var allow_select_outofstock = params['allow_select_outofstock'];
  var default_instock = params['default_instock'];

  var variant, divs, parent, index = 0;
  var selection = [];
  var buttons;

  function init() {
    divs = $('#product-variants .variant-options');
    disable(divs.find('a.option-value').addClass('locked'));
    update();
    enable(parent.find('a.option-value'));
    toggle();
    $('.clear-option a.clear-button').hide().click(handle_clear);

    if (default_instock) {
      divs.each(function(){
        $(this).find("ul.variant-option-values li a.in-stock:first").click();
      });
    }
  }

  function get_index(parent) {
    return parseInt($(parent).attr('class').replace(/[^\d]/g, ''));
  }

  function update(i) {
    index = isNaN(i) ? index : i;
    parent = $(divs.get(index));
    buttons = parent.find('a.option-value');
    parent.find('a.clear-button').hide();
  }

  function disable(btns) {
    return btns.removeClass('selected');
  }

  function enable(btns) {
    bt = btns.not('.unavailable').removeClass('locked').unbind('click')
    if (!allow_select_outofstock && !allow_backorders)
      bt = bt.filter('.in-stock')
    return bt.click(handle_click).filter('.auto-click').removeClass('auto-click').click();
  }

  function advance() {
    index++
    update();
    inventory(buttons.removeClass('locked'));
    enable(buttons);
  }

  function inventory(btns) {
    var keys, variants, count = 0, selected = {};
    var sels = $.map(divs.find('a.selected'), function(i) { return i.rel });
    $.each(sels, function(key, value) {
      key = value.split('-');
      var v = options[key[0]][key[1]];
      keys = $.keys(v);
      var m = Array.find_matches(selection.concat(keys));
      if (selection.length == 0) {
        selection = keys;
      } else if (m) {
        selection = m;
      }
    });
    btns.removeClass('in-stock out-of-stock unavailable').each(function(i, element) {
      variants = get_variant_objects(element.rel);
      keys = $.keys(variants);
      if (keys.length == 0) {
        disable($(element).addClass('unavailable locked').unbind('click'));
      } else if (keys.length == 1) {
        _var = variants[keys[0]];
        $(element).addClass((allow_backorders || _var.count) ? selection.length == 1 ? 'in-stock auto-click' : 'in-stock' : 'out-of-stock');
      } else if (allow_backorders) {
        $(element).addClass('in-stock');
      } else {
        $.each(variants, function(key, value) { count += value.count });
        $(element).addClass(count ? 'in-stock' : 'out-of-stock');
      }
    });
  }

  function get_variant_objects(rels) {
    var i, ids, obj, variants = {};
    if (typeof(rels) == 'string') { rels = [rels]; }
    var otid, ovid, opt, opv;
    i = rels.length;
    try {
      while (i--) {
        ids = rels[i].split('-');
        otid = ids[0];
        ovid = ids[1];
        opt = options[otid];
        if (opt) {
          opv = opt[ovid];
          ids = $.keys(opv);
          if (opv && ids.length) {
            var j = ids.length;
            while (j--) {
              obj = opv[ids[j]];
              if (obj && $.keys(obj).length && 0 <= selection.indexOf(obj.id.toString())) {
                variants[obj.id] = obj;
              }
            }
          }
        }
      }
    } catch(error) {
      //console.log(error);
    }
    return variants;
  }

  function to_f(string) {
    return parseFloat(string.replace(/[^\d\.]/g, ''));
  }

  function find_variant() {
    var selected = divs.find('a.selected');
    var variants = get_variant_objects(selected.get(0).rel);
    if (selected.length == divs.length) {
      return variant = variants[selection[0]];
    } else {
      var prices = [];
      $.each(variants, function(key, value) { prices.push(value.price) });
      prices = $.unique(prices).sort(function(a, b) {
        return to_f(a) < to_f(b) ? -1 : 1;
      });
      if (prices.length == 1) {
        $('#product-price .price').html('' + prices[0] + '');
      } else {
        $('#product-price .price').html('' + prices[0] + ' - ' + prices[prices.length - 1] + '');
      }
      return false;
    }
  }

  function toggle() {
    if (variant) {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val(variant.id).change();
      var oldprice = $('#product-price .price').text();
      $('#product-price .price').removeClass('unselected');
      $('#product-price .price').text(variant.price);
      if (variant.retail_price.length > 0)
      	$('#product-price .retail').text(variant.retail_price);
      if (oldprice != variant.price) { // highlight price change
      	  $('#product-price .price').addClass("price-highlight",200);
      	  $('#product-price .price').removeClass("price-highlight",800);
	   }
      if (variant.count > 0 || allow_backorders)
        $('#cart-form button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      $('form[data-form-type="variant"] button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      try {
        show_variant_images(variant.id);
      } catch(error) {
        // depends on modified version of product.js
      }
    } else {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val('').change();
      $('#cart-form button[type=submit], form[data-form-type="variant"] button[type=submit]').attr('disabled', true).fadeTo(0, 0.5);
    }
  }

  function clear(i) {
    variant = null;
    update(i);
    enable(buttons.removeClass('selected'));
    toggle();
    parent.nextAll().each(function(index, element) {
      disable($(element).find('a.option-value').show().removeClass('in-stock out-of-stock').addClass('locked').unbind('click'));
      $(element).find('a.clear-button').hide();
    });
    show_all_variant_images();
  }

  function handle_clear(evt) {
    evt.preventDefault();
    clear(get_index(this));
  }

  function handle_click(evt) {
    evt.preventDefault();
    variant = null;
    selection = [];
    var a = $(this);
    if (!parent.has(a).length) {
      clear(divs.index(a.parents('.variant-options:first')));
    }
    disable(buttons);
    var a = enable(a.addClass('selected'));
    parent.find('a.clear-button').css('display', 'block');
    advance();
    if (find_variant()) {
      toggle();
    }
  }

  $(document).ready(init);

};
<|endoftext|>


<commit_before>$.extend({
  keys: function(obj){
    var a = [];
    $.each(obj, function(k){ a.push(k) });
    return a;
  }
});

if (!Array.indexOf) Array.prototype.indexOf = function(obj) {
  for(var i = 0; i < this.length; i++){
    if(this[i] == obj) {
      return i;
    }
  }
  return -1;
}

if (!Array.find_matches) Array.find_matches = function(a) {
  var i, m = [];
  a = a.sort();
  i = a.length
  while(i--) {
    if (a[i - 1] == a[i]) {
      m.push(a[i]);
    }
  }
  if (m.length == 0) {
    return false;
  }
  return m;
}

function VariantOptions(params) {

  var options = params['options'];
  var allow_backorders = !params['track_inventory_levels'] ||  params['allow_backorders'];
  var allow_select_outofstock = params['allow_select_outofstock'];
  var default_instock = params['default_instock'];

  var variant, divs, parent, index = 0;
  var selection = [];
  var buttons;

  function init() {
    divs = $('#product-variants .variant-options');
    disable(divs.find('a.option-value').addClass('locked'));
    update();
    enable(parent.find('a.option-value'));
    toggle();
    $('.clear-option a.clear-button').hide().click(handle_clear);

    if (default_instock) {
      divs.each(function(){
        $(this).find("ul.variant-option-values li a.in-stock:first").click();
      });
    }
  }

  function get_index(parent) {
    return parseInt($(parent).attr('class').replace(/[^\d]/g, ''));
  }

  function update(i) {
    index = isNaN(i) ? index : i;
    parent = $(divs.get(index));
    buttons = parent.find('a.option-value');
    parent.find('a.clear-button').hide();
  }

  function disable(btns) {
    return btns.removeClass('selected');
  }

  function enable(btns) {
    bt = btns.not('.unavailable').removeClass('locked').unbind('click')
    if (!allow_select_outofstock && !allow_backorders)
      bt = bt.filter('.in-stock')
    return bt.click(handle_click).filter('.auto-click').removeClass('auto-click').click();
  }

  function advance() {
    index++
    update();
    inventory(buttons.removeClass('locked'));
    enable(buttons);
  }

  function inventory(btns) {
    var keys, variants, count = 0, selected = {};
    var sels = $.map(divs.find('a.selected'), function(i) { return i.rel });
    $.each(sels, function(key, value) {
      key = value.split('-');
      var v = options[key[0]][key[1]];
      keys = $.keys(v);
      var m = Array.find_matches(selection.concat(keys));
      if (selection.length == 0) {
        selection = keys;
      } else if (m) {
        selection = m;
      }
    });
    btns.removeClass('in-stock out-of-stock unavailable').each(function(i, element) {
      variants = get_variant_objects(element.rel);
      keys = $.keys(variants);
      if (keys.length == 0) {
        disable($(element).addClass('unavailable locked').unbind('click'));
      } else if (keys.length == 1) {
        _var = variants[keys[0]];
        $(element).addClass((allow_backorders || _var.count) ? selection.length == 1 ? 'in-stock auto-click' : 'in-stock' : 'out-of-stock');
      } else if (allow_backorders) {
        $(element).addClass('in-stock');
      } else {
        $.each(variants, function(key, value) { count += value.count });
        $(element).addClass(count ? 'in-stock' : 'out-of-stock');
      }
    });
  }

  function get_variant_objects(rels) {
    var i, ids, obj, variants = {};
    if (typeof(rels) == 'string') { rels = [rels]; }
    var otid, ovid, opt, opv;
    i = rels.length;
    try {
      while (i--) {
        ids = rels[i].split('-');
        otid = ids[0];
        ovid = ids[1];
        opt = options[otid];
        if (opt) {
          opv = opt[ovid];
          ids = $.keys(opv);
          if (opv && ids.length) {
            var j = ids.length;
            while (j--) {
              obj = opv[ids[j]];
              if (obj && $.keys(obj).length && 0 <= selection.indexOf(obj.id.toString())) {
                variants[obj.id] = obj;
              }
            }
          }
        }
      }
    } catch(error) {
      //console.log(error);
    }
    return variants;
  }

  function to_f(string) {
    return parseFloat(string.replace(/[^\d\.]/g, ''));
  }

  function find_variant() {
    var selected = divs.find('a.selected');
    var variants = get_variant_objects(selected.get(0).rel);
    if (selected.length == divs.length) {
      return variant = variants[selection[0]];
    } else {
      var prices = [];
      $.each(variants, function(key, value) { prices.push(value.price) });
      prices = $.unique(prices).sort(function(a, b) {
        return to_f(a) < to_f(b) ? -1 : 1;
      });
      if (prices.length == 1) {
        $('#product-price .price').html('' + prices[0] + '');
      } else {
        $('#product-price .price').html('' + prices[0] + ' - ' + prices[prices.length - 1] + '');
      }
      return false;
    }
  }

  function toggle() {
    if (variant) {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val(variant.id);
      $('#product-price .price').removeClass('unselected').text(variant.price);
      if (variant.count > 0 || allow_backorders)
        $('#cart-form button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      $('form[data-form-type="variant"] button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      try {
        show_variant_images(variant.id);
      } catch(error) {
        // depends on modified version of product.js
      }
    } else {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val('');
      $('#cart-form button[type=submit], form[data-form-type="variant"] button[type=submit]').attr('disabled', true).fadeTo(0, 0.5);
    }
  }

  function clear(i) {
    variant = null;
    update(i);
    enable(buttons.removeClass('selected'));
    toggle();
    parent.nextAll().each(function(index, element) {
      disable($(element).find('a.option-value').show().removeClass('in-stock out-of-stock').addClass('locked').unbind('click'));
      $(element).find('a.clear-button').hide();
    });
    show_all_variant_images();
  }

  function handle_clear(evt) {
    evt.preventDefault();
    clear(get_index(this));
  }

  function handle_click(evt) {
    evt.preventDefault();
    variant = null;
    selection = [];
    var a = $(this);
    if (!parent.has(a).length) {
      clear(divs.index(a.parents('.variant-options:first')));
    }
    disable(buttons);
    var a = enable(a.addClass('selected'));
    parent.find('a.clear-button').css('display', 'block');
    advance();
    if (find_variant()) {
      toggle();
    }
  }

  $(document).ready(init);

};
<commit_msg>Highlight price changes<commit_after>$.extend({
  keys: function(obj){
    var a = [];
    $.each(obj, function(k){ a.push(k) });
    return a;
  }
});

if (!Array.indexOf) Array.prototype.indexOf = function(obj) {
  for(var i = 0; i < this.length; i++){
    if(this[i] == obj) {
      return i;
    }
  }
  return -1;
}

if (!Array.find_matches) Array.find_matches = function(a) {
  var i, m = [];
  a = a.sort();
  i = a.length
  while(i--) {
    if (a[i - 1] == a[i]) {
      m.push(a[i]);
    }
  }
  if (m.length == 0) {
    return false;
  }
  return m;
}

function VariantOptions(params) {

  var options = params['options'];
  var allow_backorders = !params['track_inventory_levels'] ||  params['allow_backorders'];
  var allow_select_outofstock = params['allow_select_outofstock'];
  var default_instock = params['default_instock'];

  var variant, divs, parent, index = 0;
  var selection = [];
  var buttons;

  function init() {
    divs = $('#product-variants .variant-options');
    disable(divs.find('a.option-value').addClass('locked'));
    update();
    enable(parent.find('a.option-value'));
    toggle();
    $('.clear-option a.clear-button').hide().click(handle_clear);

    if (default_instock) {
      divs.each(function(){
        $(this).find("ul.variant-option-values li a.in-stock:first").click();
      });
    }
  }

  function get_index(parent) {
    return parseInt($(parent).attr('class').replace(/[^\d]/g, ''));
  }

  function update(i) {
    index = isNaN(i) ? index : i;
    parent = $(divs.get(index));
    buttons = parent.find('a.option-value');
    parent.find('a.clear-button').hide();
  }

  function disable(btns) {
    return btns.removeClass('selected');
  }

  function enable(btns) {
    bt = btns.not('.unavailable').removeClass('locked').unbind('click')
    if (!allow_select_outofstock && !allow_backorders)
      bt = bt.filter('.in-stock')
    return bt.click(handle_click).filter('.auto-click').removeClass('auto-click').click();
  }

  function advance() {
    index++
    update();
    inventory(buttons.removeClass('locked'));
    enable(buttons);
  }

  function inventory(btns) {
    var keys, variants, count = 0, selected = {};
    var sels = $.map(divs.find('a.selected'), function(i) { return i.rel });
    $.each(sels, function(key, value) {
      key = value.split('-');
      var v = options[key[0]][key[1]];
      keys = $.keys(v);
      var m = Array.find_matches(selection.concat(keys));
      if (selection.length == 0) {
        selection = keys;
      } else if (m) {
        selection = m;
      }
    });
    btns.removeClass('in-stock out-of-stock unavailable').each(function(i, element) {
      variants = get_variant_objects(element.rel);
      keys = $.keys(variants);
      if (keys.length == 0) {
        disable($(element).addClass('unavailable locked').unbind('click'));
      } else if (keys.length == 1) {
        _var = variants[keys[0]];
        $(element).addClass((allow_backorders || _var.count) ? selection.length == 1 ? 'in-stock auto-click' : 'in-stock' : 'out-of-stock');
      } else if (allow_backorders) {
        $(element).addClass('in-stock');
      } else {
        $.each(variants, function(key, value) { count += value.count });
        $(element).addClass(count ? 'in-stock' : 'out-of-stock');
      }
    });
  }

  function get_variant_objects(rels) {
    var i, ids, obj, variants = {};
    if (typeof(rels) == 'string') { rels = [rels]; }
    var otid, ovid, opt, opv;
    i = rels.length;
    try {
      while (i--) {
        ids = rels[i].split('-');
        otid = ids[0];
        ovid = ids[1];
        opt = options[otid];
        if (opt) {
          opv = opt[ovid];
          ids = $.keys(opv);
          if (opv && ids.length) {
            var j = ids.length;
            while (j--) {
              obj = opv[ids[j]];
              if (obj && $.keys(obj).length && 0 <= selection.indexOf(obj.id.toString())) {
                variants[obj.id] = obj;
              }
            }
          }
        }
      }
    } catch(error) {
      //console.log(error);
    }
    return variants;
  }

  function to_f(string) {
    return parseFloat(string.replace(/[^\d\.]/g, ''));
  }

  function find_variant() {
    var selected = divs.find('a.selected');
    var variants = get_variant_objects(selected.get(0).rel);
    if (selected.length == divs.length) {
      return variant = variants[selection[0]];
    } else {
      var prices = [];
      $.each(variants, function(key, value) { prices.push(value.price) });
      prices = $.unique(prices).sort(function(a, b) {
        return to_f(a) < to_f(b) ? -1 : 1;
      });
      if (prices.length == 1) {
        $('#product-price .price').html('' + prices[0] + '');
      } else {
        $('#product-price .price').html('' + prices[0] + ' - ' + prices[prices.length - 1] + '');
      }
      return false;
    }
  }

  function toggle() {
    if (variant) {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val(variant.id);
      var oldprice = $('#product-price .price').text();
      $('#product-price .price').removeClass('unselected').text(variant.price);
      if (oldprice != variant.price) { // highlight price change
      	  $('#product-price .price').switchClass("price", "price-highlight");
      	  $('#product-price .price').switchClass("price-highlight", "price", 1000);
	   }
      if (variant.count > 0 || allow_backorders)
        $('#cart-form button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      $('form[data-form-type="variant"] button[type=submit]').attr('disabled', false).fadeTo(100, 1);
      try {
        show_variant_images(variant.id);
      } catch(error) {
        // depends on modified version of product.js
      }
    } else {
      $('#variant_id, form[data-form-type="variant"] input[name$="[variant_id]"]').val('');
      $('#cart-form button[type=submit], form[data-form-type="variant"] button[type=submit]').attr('disabled', true).fadeTo(0, 0.5);
    }
  }

  function clear(i) {
    variant = null;
    update(i);
    enable(buttons.removeClass('selected'));
    toggle();
    parent.nextAll().each(function(index, element) {
      disable($(element).find('a.option-value').show().removeClass('in-stock out-of-stock').addClass('locked').unbind('click'));
      $(element).find('a.clear-button').hide();
    });
    show_all_variant_images();
  }

  function handle_clear(evt) {
    evt.preventDefault();
    clear(get_index(this));
  }

  function handle_click(evt) {
    evt.preventDefault();
    variant = null;
    selection = [];
    var a = $(this);
    if (!parent.has(a).length) {
      clear(divs.index(a.parents('.variant-options:first')));
    }
    disable(buttons);
    var a = enable(a.addClass('selected'));
    parent.find('a.clear-button').css('display', 'block');
    advance();
    if (find_variant()) {
      toggle();
    }
  }

  $(document).ready(init);

};
<|endoftext|>


<commit_before>define([
  'jquery',
  'backbone',
  'underscore',
  'handlebars',
  'uri',
  'views/ModalView',
  'presenters/SourceModalPresenter',
  'text!templates/sourceModal.handlebars',
  'text!templates/sourceModalStatic.handlebars'

], function($,Backbone, _, Handlebars, UriTemplate, ModalView, SourceModalPresenter, tpl, tplStatic) {

  var SourceModel = Backbone.Model.extend({

    _uriTemplate: 'http://54.88.79.102/gfw-sync/metadata/{slug}',

    initialize: function(options) {
      this.options = _.extend({}, options);
      this.setUrl();
    },

    setUrl: function() {
      this.url = new UriTemplate(this._uriTemplate).fillFromObject(this.options);
    },

    parse: function(response) {
      return response;
    }
  });

  var SourceModalView = ModalView.extend({

    id: '#sourceModal',

    className: "modal",

    template: Handlebars.compile(tpl),
    templateStatic: Handlebars.compile(tplStatic),

    initialize: function() {
      // Inits
      this.constructor.__super__.initialize.apply(this);
      this.presenter = new SourceModalPresenter(this);
      this.render();
      this._initVars();
      this.setListeners();
      this.$body.append(this.el);
    },

    setListeners: function() {
      this.$body.on('click', '.source', _.bind(this.sourceClick, this ));
    },

    render: function() {
      this.$el.html(this.template());
      return this;
    },

    // Fetch model when click
    sourceClick: function(e) {
      e && e.preventDefault() && e.stopPropagation();
      // current
      this.$current = $(e.currentTarget);
      this.$current.find('svg').attr('class','spinner start');

      this.sourceModel = new SourceModel({
        slug: this.$current.data('source'),
      });
      this.sourceModel.fetch({
        update:true,
        parse: true,
        success: this.sourceSuccess.bind(this),
        error: this.sourceError.bind(this),
      });
    },

    sourceSuccess: function() {
      this.$current.find('svg').attr('class','');
      this.$el.html(this.template(this.sourceModel.toJSON()));
      this.show();
      this.setTargetOfLinks();
      ga('send', 'event', document.title.replace('| Global Forest Watch',''), 'Info', this.sourceModel.get('slug'));
    },

    sourceError: function(error) {
      this.$current.find('svg').attr('class','');
      console.info('The id you are searching for does not exist in the API');
      this.sourceStatic(this.sourceModel.get('slug'));
    },

    // Fetch content when click fails
    sourceStatic: function(slug) {
      var $clone = $('#' + slug).clone();
      if (!!$clone.length) {
        this.$el.html(this.templateStatic({ clone: $clone.html() }));
        this.show();
        this.setTargetOfLinks();
      } else {
        console.info('The id you are searching for does not exist');
        this.presenter.notificate('not-no-metadata')
      }
    },

    setTargetOfLinks: function() {
      this.$el.find('a').attr('target', '_blank');
    }

  });

  return SourceModalView;

});
<commit_msg>API call for metadata windows<commit_after>define([
  'jquery',
  'backbone',
  'underscore',
  'handlebars',
  'uri',
  'views/ModalView',
  'presenters/SourceModalPresenter',
  'text!templates/sourceModal.handlebars',
  'text!templates/sourceModalStatic.handlebars'

], function($,Backbone, _, Handlebars, UriTemplate, ModalView, SourceModalPresenter, tpl, tplStatic) {

  var SourceModel = Backbone.Model.extend({

    _uriTemplate: window.gfw.config.GFW_API_HOST + '/metadata/{slug}',

    initialize: function(options) {
      this.options = _.extend({}, options);
      this.setUrl();
    },

    setUrl: function() {
      this.url = new UriTemplate(this._uriTemplate).fillFromObject(this.options);
    },

    parse: function(response) {
      return response;
    }
  });

  var SourceModalView = ModalView.extend({

    id: '#sourceModal',

    className: "modal",

    template: Handlebars.compile(tpl),
    templateStatic: Handlebars.compile(tplStatic),

    initialize: function() {
      // Inits
      this.constructor.__super__.initialize.apply(this);
      this.presenter = new SourceModalPresenter(this);
      this.render();
      this._initVars();
      this.setListeners();
      this.$body.append(this.el);
    },

    setListeners: function() {
      this.$body.on('click', '.source', _.bind(this.sourceClick, this ));
    },

    render: function() {
      this.$el.html(this.template());
      return this;
    },

    // Fetch model when click
    sourceClick: function(e) {
      e && e.preventDefault() && e.stopPropagation();
      // current
      this.$current = $(e.currentTarget);
      this.$current.find('svg').attr('class','spinner start');

      this.sourceModel = new SourceModel({
        slug: this.$current.data('source'),
      });
      this.sourceModel.fetch({
        update:true,
        parse: true,
        success: this.sourceSuccess.bind(this),
        error: this.sourceError.bind(this),
      });
    },

    sourceSuccess: function() {
      this.$current.find('svg').attr('class','');
      this.$el.html(this.template(this.sourceModel.toJSON()));
      this.show();
      this.setTargetOfLinks();
      ga('send', 'event', document.title.replace('| Global Forest Watch',''), 'Info', this.sourceModel.get('slug'));
    },

    sourceError: function(error) {
      this.$current.find('svg').attr('class','');
      console.info('The id you are searching for does not exist in the API');
      this.sourceStatic(this.sourceModel.get('slug'));
    },

    // Fetch content when click fails
    sourceStatic: function(slug) {
      var $clone = $('#' + slug).clone();
      if (!!$clone.length) {
        this.$el.html(this.templateStatic({ clone: $clone.html() }));
        this.show();
        this.setTargetOfLinks();
      } else {
        console.info('The id you are searching for does not exist');
        this.presenter.notificate('not-no-metadata')
      }
    },

    setTargetOfLinks: function() {
      this.$el.find('a').attr('target', '_blank');
    }

  });

  return SourceModalView;

});
<|endoftext|>


<commit_before>Package.describe({
  summary: "Meteor's latency-compensated distributed data framework",
  version: '1.3.0'
});

Package.onUse(function (api) {
  api.use(['ddp-client'], ['client', 'server']);
  api.use(['ddp-server'], 'server');

  api.export('DDP');
  api.export('DDPServer', 'server');

  api.imply('ddp-client');
  api.imply('ddp-server');
});
<commit_msg>Bump ddp package patch version.<commit_after>Package.describe({
  summary: "Meteor's latency-compensated distributed data framework",
  version: '1.3.1'
});

Package.onUse(function (api) {
  api.use(['ddp-client'], ['client', 'server']);
  api.use(['ddp-server'], 'server');

  api.export('DDP');
  api.export('DDPServer', 'server');

  api.imply('ddp-client');
  api.imply('ddp-server');
});
<|endoftext|>