<commit_before>/*global define*/
/*jslint browser:true,plusplus:true*/
define([
	"dojo/_base/declare",
	"dojo/dom-class",
	"dojo/Evented",
	"dojo/on",
	"dijit/form/HorizontalSlider",
	"esri/dijit/Legend"
], function (declare, domClass, Evented, on, HorizontalSlider, Legend) {
	"use strict";
	var LayerChooser, LayerRadioButton, SublayerList;

	SublayerList = declare([Evented], {
		/** @property {HTMLUListElement} */
		domNode: null,
		constructor: function (layer) {
			var self = this, i, l, layerInfos, layerInfo, li, radioButton, label, clickHandler;

			clickHandler = function() {
				var sublayerIds = this.value.split(",").map(function (v) {
					return parseInt(v, 10);
				});
				layer.setVisibleLayers(sublayerIds);
				self.emit("sublayer-select", {
					layer: layer,
					sublayerIds: sublayerIds
				});
			};

			layerInfos = layer.layerInfos;
			self.domNode = document.createElement("ul");
			for (i = 0, l = layerInfos.length; i < l; i += 1) {
				layerInfo = layerInfos[i];
				if (layerInfo.parentLayerId === -1) {
					li = document.createElement("li");
					self.domNode.appendChild(li);
					// create the radio button.
					radioButton = document.createElement("input");
					radioButton.id = ["layer", layer.id, layerInfo.id, "radio_button"].join("_");
					radioButton.name = [layer.id, "sublayers"].join("_");
					radioButton.type = "radio";
					radioButton.checked = layerInfo.defaultVisibility;
					radioButton.value = [layerInfo.id].concat(layerInfo.subLayerIds); // The value will be converted to a string.
					li.appendChild(radioButton);
					// Create label
					label = document.createElement("label");
					label.htmlFor = radioButton.id;
					label.textContent = layerInfo.name;
					li.appendChild(label);
					////radioButton.addEventListener("click", clickHandler);
					on(radioButton, "click", clickHandler);
				}
			}
		}
	});

	LayerRadioButton = declare([Evented], {
		radioButton: null,
		label: null,
		domNode: null,
		sublayerList: null,
		opacitySlider: null,
		legend: null,
		/**
		@param {Object} options
		@param {Object} options.operationalLayer
		@param {esri/layers/Layer} options.operationalLayer.layerObject
		@param {string} options.operationalLayer.id
		@param {string} options.operationalLayer.title
		@param {Array} options.operationalLayer.errors
		@param {boolean} [options.checked] Is the radio button checked?
		@param {boolean} [options.includeSublayers]
		@constructs
		*/
		constructor: function (options) {
			var self = this, opLayer = options.operationalLayer, legendDiv, controlsDiv, link;

			self.domNode = document.createElement("li");

			// Radio button
			self.radioButton = document.createElement("input");
			self.radioButton.type = "radio";
			self.radioButton.id = ["layer_chooser_radio_", opLayer.layerObject ? opLayer.layerObject.id : opLayer.id].join("");
			self.radioButton.value = opLayer.id;
			self.radioButton.name = "layer_chooser";
			if (options.checked) {
				self.radioButton.checked = true;
			}
			self.domNode.appendChild(self.radioButton);

			// Label
			self.label = document.createElement("label");
			self.label.htmlFor = self.radioButton.id;
			self.label.textContent = opLayer.title;

			// Add a link to the ArcGIS Online page for the layer.
			if (opLayer.itemId) {
				self.label.textContent += " ";
				link = document.createElement("a");
				link.href = "//wsdot.maps.arcgis.com/home/item.html?id=" + opLayer.itemId;
				link.textContent = "?";
				link.title = ['Click to get information about the "', opLayer.title, '" layer.'].join('');
				link.target = "_blank";
				link.classList.add("agol-link");
				self.label.appendChild(link);
			}

			self.domNode.appendChild(self.label);

			// If the layer has errors, disable the radio button
			if (opLayer.errors && opLayer.errors.length) {
				self.radioButton.disabled = true;
				//self.domNode.classList.add("layer-chooser-layer-error");
				domClass.add(self.domNode, "layer-chooser-layer-error");
			} else {
				on(self.radioButton, "click", function () {
					self.emit("checked", {
						id: self.radioButton.value,
						visible: self.radioButton.checked
					});
				});

				// Create the controls div.
				// The controls that are only shown when the layer is checked will be placed inside of this div.
				// The hiding of this div is performed by the stylesheet.
				controlsDiv = document.createElement("div");
				domClass.add(controlsDiv, "layer-chooser-layer-controls");
				self.domNode.appendChild(controlsDiv);

				// Add the opacity slider

				self.opacitySlider = new HorizontalSlider({
					value: opLayer.layerObject.opacity,
					minimum: 0,
					maximum: 1,
					onChange: function (value) {
						opLayer.layerObject.setOpacity(value);
					}
				});

				controlsDiv.appendChild(self.opacitySlider.domNode);

				if (options.includeSublayers) {
					self.sublayerList = new SublayerList(opLayer.layerObject);
					controlsDiv.appendChild(self.sublayerList.domNode);
					self.sublayerList.on("sublayer-select", function (e) {
						self.emit("sublayer-select", e);
					});
				}

				// Create the legend...
				legendDiv = document.createElement("div");
				////legendDiv.classList.add("layer-chooser-legend");
				domClass.add(legendDiv, "layer-chooser-legend");
				controlsDiv.appendChild(legendDiv);
				self.legend = new Legend({
					autoUpdate: true,
					map: options.map,
					layerInfos: [
						{
							layer: opLayer.layerObject,
							title: opLayer.title
						}
					]
				}, legendDiv);
			}
		}
	});

	LayerChooser = declare([Evented], {
		domNode: null,
		map: null,
		toggleLayer: function() {
			var qs, i, l, rb, layer;

			// Select all of the radio buttons.
			qs = this.domNode.querySelectorAll('input[name=layer_chooser]');

			// For each radio button, set the visibility based on whether or not the radio is checked.
			for (i = 0, l = qs.length; i < l; i += 1) {
				rb = qs.item(i);
				layer = this.map.getLayer(rb.value);
				if (layer) {
					if (rb.checked) {
						layer.show();
					} else {
						layer.hide();
					}
				}
			}
		},
		list: null,
		/**
		 * @param mapInfo The response of the arcgisUtils/createMap operation. See https://developers.arcgis.com/en/javascript/jshelp/intro_webmap.html
		 * @param {esri/Map} mapInfo.map
		 * @param {Object} mapInfo.itemInfo
		 * @param {Object} mapInfo.itemInfo.itemData
		 * @param {Object} mapInfo.itemInfo.itemData.baseMap
		 * @param {Array} mapInfo.itemInfo.itemData.operationalLayers
		 * @param {Object} mapInfo.clickEventHandle
		 * @param {Object} mapInfo.clickEventListener
		 * @param {Array} mapInfo.errors
		 * @param {String|HTMLElement} domRef
		 * @param {Object} [options]
		 * @param {Regexp} [omittedMapServices] Omitted map services. Any map service with a name matching the regex will not have a corresponding radio button.
		 * @constructs
		 */
		constructor: function (mapInfo, domRef, options) {
			var self = this, operationalLayers, i, layerRadio, opLayer, firstLayerFound = false;

			function toggleLayer() {
				self.toggleLayer();
			}

			function emitSublayerEvent(e) {
				self.emit("sublayer-select", e);
			}

			// Determine the root element from this dijit.
			if (!domRef) {
				throw new Error("The domRef parameter was not provided.");
			} else if (typeof domRef === "string") {
				this.domNode = document.getElementById(domRef);
			} else {
				this.domNode = domRef;
			}

			if (!options) {
				options = {};
			}

			self.list = document.createElement("ul");
			////self.list.classList.add("layer-list");
			domClass.add(self.list, "layer-list");
			self.domNode.appendChild(self.list);

			this.map = mapInfo.map;
			operationalLayers = mapInfo.itemInfo.itemData.operationalLayers;

			// Create the radio buttons and place each into a document fragment as it is created.

			for (i = operationalLayers.length - 1; i >= 0; i--) {
				try {
					opLayer = operationalLayers[i];

					if (!options.omittedMapServices || !options.omittedMapServices.test(opLayer.title)) {

						layerRadio = new LayerRadioButton({
							operationalLayer: opLayer,
							map: self.map,
							//layerId: opLayer.id,
							//label: opLayer.title,
							checked: !firstLayerFound, // Only check the first valid layer's radio button.
							//errors: opLayer.errors
							includeSublayers: !/\b(?:(?:Boundaries)|(?:Minority)|(?:Poverty)|(?:Veterans)|(?:Age))\b/i.test(opLayer.title)
						});

						layerRadio.on("checked", toggleLayer);
						layerRadio.on("sublayer-select", emitSublayerEvent);

						if (!(opLayer.errors && opLayer.errors.length)) {
							// Show the first layer, hide the others.
							if (!firstLayerFound) {
								opLayer.layerObject.show();
								firstLayerFound = true;
							} else {
								opLayer.layerObject.hide();
							}
						}

						self.list.appendChild(layerRadio.domNode);
						if (layerRadio.legend) {
							layerRadio.legend.startup();
						}
					}
				} catch (lError) {
					if (console && console.error) {
						console.error("Error creating layer radio button", lError);
					}
				}
			}
		}
	});

	return LayerChooser;
});<commit_msg>layerChooser layers now default to 60%.<commit_after>/*global define*/
/*jslint browser:true,plusplus:true*/
define([
	"dojo/_base/declare",
	"dojo/dom-class",
	"dojo/Evented",
	"dojo/on",
	"dijit/form/HorizontalSlider",
	"esri/dijit/Legend"
], function (declare, domClass, Evented, on, HorizontalSlider, Legend) {
	"use strict";
	var LayerChooser, LayerRadioButton, SublayerList;

	SublayerList = declare([Evented], {
		/** @property {HTMLUListElement} */
		domNode: null,
		constructor: function (layer) {
			var self = this, i, l, layerInfos, layerInfo, li, radioButton, label, clickHandler;

			clickHandler = function() {
				var sublayerIds = this.value.split(",").map(function (v) {
					return parseInt(v, 10);
				});
				layer.setVisibleLayers(sublayerIds);
				self.emit("sublayer-select", {
					layer: layer,
					sublayerIds: sublayerIds
				});
			};

			layerInfos = layer.layerInfos;
			self.domNode = document.createElement("ul");
			for (i = 0, l = layerInfos.length; i < l; i += 1) {
				layerInfo = layerInfos[i];
				if (layerInfo.parentLayerId === -1) {
					li = document.createElement("li");
					self.domNode.appendChild(li);
					// create the radio button.
					radioButton = document.createElement("input");
					radioButton.id = ["layer", layer.id, layerInfo.id, "radio_button"].join("_");
					radioButton.name = [layer.id, "sublayers"].join("_");
					radioButton.type = "radio";
					radioButton.checked = layerInfo.defaultVisibility;
					radioButton.value = [layerInfo.id].concat(layerInfo.subLayerIds); // The value will be converted to a string.
					li.appendChild(radioButton);
					// Create label
					label = document.createElement("label");
					label.htmlFor = radioButton.id;
					label.textContent = layerInfo.name;
					li.appendChild(label);
					////radioButton.addEventListener("click", clickHandler);
					on(radioButton, "click", clickHandler);
				}
			}
		}
	});

	LayerRadioButton = declare([Evented], {
		radioButton: null,
		label: null,
		domNode: null,
		sublayerList: null,
		opacitySlider: null,
		legend: null,
		/**
		@param {Object} options
		@param {Object} options.operationalLayer
		@param {esri/layers/Layer} options.operationalLayer.layerObject
		@param {string} options.operationalLayer.id
		@param {string} options.operationalLayer.title
		@param {Array} options.operationalLayer.errors
		@param {boolean} [options.checked] Is the radio button checked?
		@param {boolean} [options.includeSublayers]
		@constructs
		*/
		constructor: function (options) {
			var self = this, opLayer = options.operationalLayer, legendDiv, controlsDiv, link;

			self.domNode = document.createElement("li");

			// Radio button
			self.radioButton = document.createElement("input");
			self.radioButton.type = "radio";
			self.radioButton.id = ["layer_chooser_radio_", opLayer.layerObject ? opLayer.layerObject.id : opLayer.id].join("");
			self.radioButton.value = opLayer.id;
			self.radioButton.name = "layer_chooser";
			if (options.checked) {
				self.radioButton.checked = true;
			}
			self.domNode.appendChild(self.radioButton);

			// Label
			self.label = document.createElement("label");
			self.label.htmlFor = self.radioButton.id;
			self.label.textContent = opLayer.title;

			// Add a link to the ArcGIS Online page for the layer.
			if (opLayer.itemId) {
				self.label.textContent += " ";
				link = document.createElement("a");
				link.href = "//wsdot.maps.arcgis.com/home/item.html?id=" + opLayer.itemId;
				link.textContent = "?";
				link.title = ['Click to get information about the "', opLayer.title, '" layer.'].join('');
				link.target = "_blank";
				link.classList.add("agol-link");
				self.label.appendChild(link);
			}

			self.domNode.appendChild(self.label);

			// If the layer has errors, disable the radio button
			if (opLayer.errors && opLayer.errors.length) {
				self.radioButton.disabled = true;
				//self.domNode.classList.add("layer-chooser-layer-error");
				domClass.add(self.domNode, "layer-chooser-layer-error");
			} else {
				on(self.radioButton, "click", function () {
					self.emit("checked", {
						id: self.radioButton.value,
						visible: self.radioButton.checked
					});
				});

				// Create the controls div.
				// The controls that are only shown when the layer is checked will be placed inside of this div.
				// The hiding of this div is performed by the stylesheet.
				controlsDiv = document.createElement("div");
				domClass.add(controlsDiv, "layer-chooser-layer-controls");
				self.domNode.appendChild(controlsDiv);

				// Change the default opacity to 60%.
				opLayer.layerObject.setOpacity(0.6);

				// Add the opacity slider
				self.opacitySlider = new HorizontalSlider({
					value: opLayer.layerObject.opacity,
					minimum: 0,
					maximum: 1,
					onChange: function (value) {
						opLayer.layerObject.setOpacity(value);
					}
				});

				controlsDiv.appendChild(self.opacitySlider.domNode);

				if (options.includeSublayers) {
					self.sublayerList = new SublayerList(opLayer.layerObject);
					controlsDiv.appendChild(self.sublayerList.domNode);
					self.sublayerList.on("sublayer-select", function (e) {
						self.emit("sublayer-select", e);
					});
				}

				// Create the legend...
				legendDiv = document.createElement("div");
				////legendDiv.classList.add("layer-chooser-legend");
				domClass.add(legendDiv, "layer-chooser-legend");
				controlsDiv.appendChild(legendDiv);
				self.legend = new Legend({
					autoUpdate: true,
					map: options.map,
					layerInfos: [
						{
							layer: opLayer.layerObject,
							title: opLayer.title
						}
					]
				}, legendDiv);
			}
		}
	});

	LayerChooser = declare([Evented], {
		domNode: null,
		map: null,
		toggleLayer: function() {
			var qs, i, l, rb, layer;

			// Select all of the radio buttons.
			qs = this.domNode.querySelectorAll('input[name=layer_chooser]');

			// For each radio button, set the visibility based on whether or not the radio is checked.
			for (i = 0, l = qs.length; i < l; i += 1) {
				rb = qs.item(i);
				layer = this.map.getLayer(rb.value);
				if (layer) {
					if (rb.checked) {
						layer.show();
					} else {
						layer.hide();
					}
				}
			}
		},
		list: null,
		/**
		 * @param mapInfo The response of the arcgisUtils/createMap operation. See https://developers.arcgis.com/en/javascript/jshelp/intro_webmap.html
		 * @param {esri/Map} mapInfo.map
		 * @param {Object} mapInfo.itemInfo
		 * @param {Object} mapInfo.itemInfo.itemData
		 * @param {Object} mapInfo.itemInfo.itemData.baseMap
		 * @param {Array} mapInfo.itemInfo.itemData.operationalLayers
		 * @param {Object} mapInfo.clickEventHandle
		 * @param {Object} mapInfo.clickEventListener
		 * @param {Array} mapInfo.errors
		 * @param {String|HTMLElement} domRef
		 * @param {Object} [options]
		 * @param {Regexp} [omittedMapServices] Omitted map services. Any map service with a name matching the regex will not have a corresponding radio button.
		 * @constructs
		 */
		constructor: function (mapInfo, domRef, options) {
			var self = this, operationalLayers, i, layerRadio, opLayer, firstLayerFound = false;

			function toggleLayer() {
				self.toggleLayer();
			}

			function emitSublayerEvent(e) {
				self.emit("sublayer-select", e);
			}

			// Determine the root element from this dijit.
			if (!domRef) {
				throw new Error("The domRef parameter was not provided.");
			} else if (typeof domRef === "string") {
				this.domNode = document.getElementById(domRef);
			} else {
				this.domNode = domRef;
			}

			if (!options) {
				options = {};
			}

			self.list = document.createElement("ul");
			////self.list.classList.add("layer-list");
			domClass.add(self.list, "layer-list");
			self.domNode.appendChild(self.list);

			this.map = mapInfo.map;
			operationalLayers = mapInfo.itemInfo.itemData.operationalLayers;

			// Create the radio buttons and place each into a document fragment as it is created.

			for (i = operationalLayers.length - 1; i >= 0; i--) {
				try {
					opLayer = operationalLayers[i];

					if (!options.omittedMapServices || !options.omittedMapServices.test(opLayer.title)) {

						layerRadio = new LayerRadioButton({
							operationalLayer: opLayer,
							map: self.map,
							//layerId: opLayer.id,
							//label: opLayer.title,
							checked: !firstLayerFound, // Only check the first valid layer's radio button.
							//errors: opLayer.errors
							includeSublayers: !/\b(?:(?:Boundaries)|(?:Minority)|(?:Poverty)|(?:Veterans)|(?:Age))\b/i.test(opLayer.title)
						});

						layerRadio.on("checked", toggleLayer);
						layerRadio.on("sublayer-select", emitSublayerEvent);

						if (!(opLayer.errors && opLayer.errors.length)) {
							// Show the first layer, hide the others.
							if (!firstLayerFound) {
								opLayer.layerObject.show();
								firstLayerFound = true;
							} else {
								opLayer.layerObject.hide();
							}
						}

						self.list.appendChild(layerRadio.domNode);
						if (layerRadio.legend) {
							layerRadio.legend.startup();
						}
					}
				} catch (lError) {
					if (console && console.error) {
						console.error("Error creating layer radio button", lError);
					}
				}
			}
		}
	});

	return LayerChooser;
});<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Oculus Info Inc.
 * http://www.oculusinfo.com/
 *
 * Released under the MIT License.
 *
 * 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.
 */

var appStart = function() {

    "use strict";

    // request layers from server
    tiles.LayerService.getLayers( function( layers ) {

        // parse layers into nicer format
        layers = tiles.LayerUtil.parse( layers.layers );

        var map,
            axis0,
            axis1,
            baseLayer,
            serverLayer;

        baseLayer = new tiles.BaseLayer({
            options: {
                color: "#000"
            }
        });

        serverLayer = new tiles.ServerLayer({
            source: layers["julia-set"]
        });

        axis0 = new tiles.Axis({
            title: 'X',
            position: 'bottom',
            enabled: true,
            intervals: {
                type: 'fixed',
                increment: 86400000,
                scaleByZoom: false,
                minPixelWidth: 80
            },
            units: {
                type: 'time'
            }
        });

        axis1 = new tiles.Axis({
            title: 'Y',
            position: 'left',
            enabled: true,
            intervals: {
                increment: 20,
                pivot: 0
            },
            units: {
                type: 'decimal'
            }
        });

        map = new tiles.Map( "map", {
            pyramid : {
                type : "AreaOfInterest",
                minX: -2,
				maxX: 2,
				minY: -2,
				maxY: 2
            }
        });
        map.add( axis0 );
        map.add( axis1 );
        map.add( serverLayer );
        map.add( baseLayer );

        $( '.controls' ).append( tiles.LayerControls.create( [ serverLayer ] ) );
    });
};
<commit_msg>corrects X axis in julia demo<commit_after>/*
 * Copyright (c) 2014 Oculus Info Inc.
 * http://www.oculusinfo.com/
 *
 * Released under the MIT License.
 *
 * 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.
 */

var appStart = function() {

    "use strict";

    // request layers from server
    tiles.LayerService.getLayers( function( layers ) {

        // parse layers into nicer format
        layers = tiles.LayerUtil.parse( layers.layers );

        var map,
            axis0,
            axis1,
            baseLayer,
            serverLayer;

        baseLayer = new tiles.BaseLayer({
            options: {
                color: "#000"
            }
        });

        serverLayer = new tiles.ServerLayer({
            source: layers["julia-set"]
        });

        axis0 = new tiles.Axis({
            title: 'X',
            position: 'bottom',
            enabled: true,
            intervals: {
                increment: 20,
                pivot: 0
            },
            units: {
                type: 'decimal'
            }
        });

        axis1 = new tiles.Axis({
            title: 'Y',
            position: 'left',
            enabled: true,
            intervals: {
                increment: 20,
                pivot: 0
            },
            units: {
                type: 'decimal'
            }
        });

        map = new tiles.Map( "map", {
            pyramid : {
                type : "AreaOfInterest",
                minX: -2,
				maxX: 2,
				minY: -2,
				maxY: 2
            }
        });
        map.add( axis0 );
        map.add( axis1 );
        map.add( serverLayer );
        map.add( baseLayer );

        $( '.controls' ).append( tiles.LayerControls.create( [ serverLayer ] ) );
    });
};
<|endoftext|>


<commit_before><commit_msg>board<commit_after><|endoftext|>


<commit_before>/**
* An annotation which specifies what needs to be injected into the annotated function/class.
*
* @class Inject
* @constructor
* @param {Object} ...keys The keys for the requested instances.
*/
export class Inject {
  constructor(...keys) {
    this.keys = keys;
  }
}

/**
* An abstract annotation used to allow functions/classes to indicate how they should be registered with the container.
*
* @class Registration
* @constructor
*/
export class Registration {
  /**
  * Called by the container to allow custom registration logic for the annotated function/class.
  *
  * @method register
  * @param {Container} container The container to register with.
  * @param {Object} key The key to register as.
  * @param {Object} fn The function to register (target of the annotation).
  */
  register(container, key, fn){
    throw new Error('A custom Registration must implement register(container, key, fn).');
  }
}

/**
* An annotation used to allow functions/classes to indicate that they should be registered as transients with the container.
*
* @class Transient
* @constructor
* @extends Registration
* @param {Object} [key] The key to register as.
*/
export class Transient extends Registration {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to register the annotated function/class as transient.
  *
  * @method register
  * @param {Container} container The container to register with.
  * @param {Object} key The key to register as.
  * @param {Object} fn The function to register (target of the annotation).
  */
  register(container, key, fn){
    container.registerTransient(this.key || key, fn);
  }
}

/**
* An annotation used to allow functions/classes to indicate that they should be registered as singletons with the container.
*
* @class Singleton
* @constructor
* @extends Registration
* @param {Object} [key] The key to register as.
*/
export class Singleton extends Registration {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to register the annotated function/class as a singleton.
  *
  * @method register
  * @param {Container} container The container to register with.
  * @param {Object} key The key to register as.
  * @param {Object} fn The function to register (target of the annotation).
  */
  register(container, key, fn){
    container.registerSingleton(this.key || key, fn);
  }
}

/**
* An abstract annotation used to allow functions/classes to specify custom dependency resolution logic.
*
* @class Resolver
* @constructor
*/
export class Resolver {
  /**
  * Called by the container to allow custom resolution of dependencies for a function/class.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Object} Returns the resolved object.
  */
  get(container){
    throw new Error('A custom Resolver must implement get(container) and return the resolved instance(s).');
  }
}

/**
* An annotation used to allow functions/classes to specify lazy resolution logic.
*
* @class Lazy
* @constructor
* @extends Resolver
* @param {Object} key The key to lazily resolve.
*/
export class Lazy extends Resolver {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to lazily resolve the dependency into a lazy locator function.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Function} Returns a function which can be invoked at a later time to obtain the actual dependency.
  */
  get(container){
    return () => {
      return container.get(this.key);
    };
  }

  /**
  * Creates a Lazy Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to lazily resolve.
  * @return {Lazy} Returns an insance of Lazy for the key.
  */
  static of(key){
    return new Lazy(key);
  }
}

/**
* An annotation used to allow functions/classes to specify resolution of all matches to a key.
*
* @class All
* @constructor
* @extends Resolver
* @param {Object} key The key to lazily resolve all matches for.
*/
export class All extends Resolver {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to resolve all matching dependencies as an array of instances.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Object[]} Returns an array of all matching instances.
  */
  get(container){
    return container.getAll(this.key);
  }

  /**
  * Creates an All Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to resolve all instances for.
  * @return {All} Returns an insance of All for the key.
  */
  static of(key){
    return new All(key);
  }
}

/**
* An annotation used to allow functions/classes to specify an optional dependency, which will be resolved only if already registred with the container.
*
* @class Optional
* @constructor
* @extends Resolver
* @param {Object} key The key to optionally resolve for.
* @param {Boolean} [checkParent=false] Indicates whether or not the parent container hierarchy should be checked.
*/
export class Optional extends Resolver {
  constructor(key, checkParent=false){
    this.key = key;
    this.checkParent = checkParent;
  }

  /**
  * Called by the container to provide optional resolution of the key.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Object} Returns the instance if found; otherwise null.
  */
  get(container){
    if(container.hasHandler(this.key, this.checkParent)){
      return container.get(this.key);
    }

    return null;
  }

  /**
  * Creates an Optional Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to optionally resolve for.
  * @param {Boolean} [checkParent=false] Indicates whether or not the parent container hierarchy should be checked.
  * @return {Optional} Returns an insance of Optional for the key.
  */
  static of(key, checkParent=false){
    return new Optional(key, checkParent);
  }
}

/**
* An annotation used to inject the dependency from the parent container instead of the current one
*
* @class Parent
* @constructor
* @extends Resolver
* @param {Object} key The key to resolve from the parent container.
*/
export class Parent extends Resolver {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to load the dependency from the parent container
  *
  * @method get
  * @param {Container} container The container to resolve the parent from.
  * @return {Function} Returns the matching instance from the parent container
  */
  get(container){
    return container.parent
      ? container.parent.get(this.key)
      : null;
  }

  /**
  * Creates a Parent Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to resolve.
  * @return {Parent} Returns an insance of Parent for the key.
  */
  static of(key){
    return new Parent(key);
  }
}<commit_msg>style(annotations): add missing period<commit_after>/**
* An annotation which specifies what needs to be injected into the annotated function/class.
*
* @class Inject
* @constructor
* @param {Object} ...keys The keys for the requested instances.
*/
export class Inject {
  constructor(...keys) {
    this.keys = keys;
  }
}

/**
* An abstract annotation used to allow functions/classes to indicate how they should be registered with the container.
*
* @class Registration
* @constructor
*/
export class Registration {
  /**
  * Called by the container to allow custom registration logic for the annotated function/class.
  *
  * @method register
  * @param {Container} container The container to register with.
  * @param {Object} key The key to register as.
  * @param {Object} fn The function to register (target of the annotation).
  */
  register(container, key, fn){
    throw new Error('A custom Registration must implement register(container, key, fn).');
  }
}

/**
* An annotation used to allow functions/classes to indicate that they should be registered as transients with the container.
*
* @class Transient
* @constructor
* @extends Registration
* @param {Object} [key] The key to register as.
*/
export class Transient extends Registration {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to register the annotated function/class as transient.
  *
  * @method register
  * @param {Container} container The container to register with.
  * @param {Object} key The key to register as.
  * @param {Object} fn The function to register (target of the annotation).
  */
  register(container, key, fn){
    container.registerTransient(this.key || key, fn);
  }
}

/**
* An annotation used to allow functions/classes to indicate that they should be registered as singletons with the container.
*
* @class Singleton
* @constructor
* @extends Registration
* @param {Object} [key] The key to register as.
*/
export class Singleton extends Registration {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to register the annotated function/class as a singleton.
  *
  * @method register
  * @param {Container} container The container to register with.
  * @param {Object} key The key to register as.
  * @param {Object} fn The function to register (target of the annotation).
  */
  register(container, key, fn){
    container.registerSingleton(this.key || key, fn);
  }
}

/**
* An abstract annotation used to allow functions/classes to specify custom dependency resolution logic.
*
* @class Resolver
* @constructor
*/
export class Resolver {
  /**
  * Called by the container to allow custom resolution of dependencies for a function/class.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Object} Returns the resolved object.
  */
  get(container){
    throw new Error('A custom Resolver must implement get(container) and return the resolved instance(s).');
  }
}

/**
* An annotation used to allow functions/classes to specify lazy resolution logic.
*
* @class Lazy
* @constructor
* @extends Resolver
* @param {Object} key The key to lazily resolve.
*/
export class Lazy extends Resolver {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to lazily resolve the dependency into a lazy locator function.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Function} Returns a function which can be invoked at a later time to obtain the actual dependency.
  */
  get(container){
    return () => {
      return container.get(this.key);
    };
  }

  /**
  * Creates a Lazy Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to lazily resolve.
  * @return {Lazy} Returns an insance of Lazy for the key.
  */
  static of(key){
    return new Lazy(key);
  }
}

/**
* An annotation used to allow functions/classes to specify resolution of all matches to a key.
*
* @class All
* @constructor
* @extends Resolver
* @param {Object} key The key to lazily resolve all matches for.
*/
export class All extends Resolver {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to resolve all matching dependencies as an array of instances.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Object[]} Returns an array of all matching instances.
  */
  get(container){
    return container.getAll(this.key);
  }

  /**
  * Creates an All Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to resolve all instances for.
  * @return {All} Returns an insance of All for the key.
  */
  static of(key){
    return new All(key);
  }
}

/**
* An annotation used to allow functions/classes to specify an optional dependency, which will be resolved only if already registred with the container.
*
* @class Optional
* @constructor
* @extends Resolver
* @param {Object} key The key to optionally resolve for.
* @param {Boolean} [checkParent=false] Indicates whether or not the parent container hierarchy should be checked.
*/
export class Optional extends Resolver {
  constructor(key, checkParent=false){
    this.key = key;
    this.checkParent = checkParent;
  }

  /**
  * Called by the container to provide optional resolution of the key.
  *
  * @method get
  * @param {Container} container The container to resolve from.
  * @return {Object} Returns the instance if found; otherwise null.
  */
  get(container){
    if(container.hasHandler(this.key, this.checkParent)){
      return container.get(this.key);
    }

    return null;
  }

  /**
  * Creates an Optional Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to optionally resolve for.
  * @param {Boolean} [checkParent=false] Indicates whether or not the parent container hierarchy should be checked.
  * @return {Optional} Returns an insance of Optional for the key.
  */
  static of(key, checkParent=false){
    return new Optional(key, checkParent);
  }
}

/**
* An annotation used to inject the dependency from the parent container instead of the current one.
*
* @class Parent
* @constructor
* @extends Resolver
* @param {Object} key The key to resolve from the parent container.
*/
export class Parent extends Resolver {
  constructor(key){
    this.key = key;
  }

  /**
  * Called by the container to load the dependency from the parent container
  *
  * @method get
  * @param {Container} container The container to resolve the parent from.
  * @return {Function} Returns the matching instance from the parent container
  */
  get(container){
    return container.parent
      ? container.parent.get(this.key)
      : null;
  }

  /**
  * Creates a Parent Resolver for the supplied key.
  *
  * @method of
  * @static
  * @param {Object} key The key to resolve.
  * @return {Parent} Returns an insance of Parent for the key.
  */
  static of(key){
    return new Parent(key);
  }
}<|endoftext|>


<commit_before><commit_msg>🐛 All rolls exceptions are managed<commit_after><|endoftext|>


<commit_before><commit_msg>remove button option for dropdown<commit_after><|endoftext|>


<commit_before><commit_msg>Markdown: fall back to defaultHandlers<commit_after><|endoftext|>


<commit_before>// ==========================================================================
//                          DG.ImageUtilities
//
//  Author:   Jonathan Sandoe
//
//  Copyright (c) 2017 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

/* global Promise */
DG.ImageUtilities = (function () {
  return {

    /**
     * Converts an SVG scene into a png image.
     * @param rootEl {Element} a DOM element. Either HTML or SVG. This routine
     *   will extract SVG elements from this object and place them in the final
     *   image. HTML DOM element will not be visible.
     * @param width {number}
     * @param height {number}
     * @param asDataURL {boolean} true - image returned as data URI, otherwise as blob
     * @return {Promise} The promise of an image.
     */
    captureSVGElementsToImage: function (rootEl, width, height, asDataURL) {

      function getCSSText() {
        var text = [], ix, jx;
        for (ix = 0; ix < document.styleSheets.length; ix += 1) {
          var styleSheet = document.styleSheets[ix];
          var rules = styleSheet.rules || styleSheet.cssRules || [];
          for (jx = 0; jx < rules.length; jx += 1) {
            var rule = rules[jx];
            text.push(rule.cssText);
          }
        }
        return text.join('\n');
      }

      function makeDataURLFromSVGElement(svgEl) {
        var svgClone = $(svgEl).clone();
        var css = $('<style>').text(getCSSText());
        svgClone.prepend(css);
        var svgData = new XMLSerializer().serializeToString(svgClone[0]);
        // Raphael overspecifies the url for the gradient. It prepends the
        // windows.location.href. This causes problems with the data url,
        // because we are no longer in this namespace. So, we remove.
        svgData = svgData.replace(
            new RegExp('url\\(\'[^#]*#', 'g'), 'url(\'#');
        // The use of unescape and encodeURIComponent are part of a well-
        // known hack work around btoa's handling of unicode characters.
        // see, eg:
        // http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
        return "data:image/svg+xml;base64,"
            + window.btoa(window.unescape(window.encodeURIComponent(svgData)));
      }

      /**
       * Create a canvas element with a white background. Not yet appended to
       * the DOM.
       * @param {number} width
       * @param {number} height
       * @returns {Canvas}
       */
      function makeCanvasEl(width, height) {
        var canvas = $("<canvas>").prop({width: width, height: height})[0];
        var ctx = canvas.getContext("2d");
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, width, height);
        return canvas;
      }

      /**
       * Add an image to the canvas at the specified location.
       * @param {Canvas} canvas DOM Element
       * @param {img} image DOM Element
       * @param {number} x
       * @param {number} y
       * @param {number} width
       * @param {number} height
       */
      function addImageToCanvas(canvas, image, x, y, width, height) {
        var ctx = canvas.getContext("2d");
        ctx.drawImage(image, x, y, width, height);
      }

      /**
       * Convert a canvas object to a blob.
       * @param canvas
       * @returns {*}
       */
      function makeCanvasBlob(canvas) {
        var canvasDataURL = canvas.toDataURL("image/png");
        var canvasData = atob(canvasDataURL.substring("data:image/png;base64,".length));
        var canvasAsArray = new Uint8Array(canvasData.length);  /* global Uint8Array */

        for (var i = 0, len = canvasData.length; i < len; ++i) {
          canvasAsArray[i] = canvasData.charCodeAt(i);
        }

        return new Blob([canvasAsArray.buffer], {type: "image/png"});
      }

      /**
       * @returns a promise of an image.
       * @param dataURL
       */
      function makeSVGImage(dataURL) {
        return new Promise(function (resolve, reject) {
              try {
                var img = $('<img/>')[0];
                img.onload = function () {
                  resolve(img);
                };
                img.src = dataURL;
              } catch (ex) {
                reject(ex);
              }
            }
        );
      }

      //
      // ######## convertImage begin ########
      //
      // find all svg elements that are not children of hidden divs
      var svgs = $(rootEl).find('div:not(.sc-hidden)>svg');
      var canvas = makeCanvasEl(width, height);
      var promises = [];

      // for each svg we calculate its geometry, then add it to the canvas
      // through a promise.
      // Note: This implementation starts a number of asynchronous operations,
      // one for each SVG in the hierarchy. If they overlap and are handled out
      // of order, it is possible that they may be written to the canvas in the
      // wrong order.
      if (svgs) {
        svgs.forEach(function (svg) {
          var width = svg.offsetWidth || svg.width.baseVal.value;
          var height = svg.offsetHeight || svg.height.baseVal.value;
          var left = 0;
          var top = 0;
          $(svg).add($(svg).parentsUntil(rootEl)).each(function () {
            left += this.offsetLeft || 0;
            top += this.offsetTop || 0;
          });
          // DG.log('SVG width/height/left/top: ' + [width, height, left, top].join('/'));
          var imgPromise = makeSVGImage(makeDataURLFromSVGElement(svg));
          imgPromise.then(function (img) {
                addImageToCanvas(canvas, img, left, top, width, height);
              },
              function (error) {
                DG.logError(error);
              }
          );
          promises.push(imgPromise);
        });
      }

      // when all promises have been fulfilled we make a blob, then invoke the
      // save image dialog.
      return Promise.all(promises).then(function () {
          return asDataURL ? canvas.toDataURL("image/png") : makeCanvasBlob(canvas);
        },
        function (error) {
          DG.logError(error);
        }
      );
    }
  };
}());<commit_msg>[#157002914] Fix bug: snapshot tool crashes CODAP<commit_after>// ==========================================================================
//                          DG.ImageUtilities
//
//  Author:   Jonathan Sandoe
//
//  Copyright (c) 2017 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

/* global Promise */
DG.ImageUtilities = (function () {
  return {

    /**
     * Converts an SVG scene into a png image.
     * @param rootEl {Element} a DOM element. Either HTML or SVG. This routine
     *   will extract SVG elements from this object and place them in the final
     *   image. HTML DOM element will not be visible.
     * @param width {number}
     * @param height {number}
     * @param asDataURL {boolean} true - image returned as data URI, otherwise as blob
     * @return {Promise} The promise of an image.
     */
    captureSVGElementsToImage: function (rootEl, width, height, asDataURL) {

      function getCSSText() {
        var text = [], ix, jx;
        for (ix = 0; ix < document.styleSheets.length; ix += 1) {
          try {
            var styleSheet = document.styleSheets[ix];
            if (styleSheet) {
              var rules = styleSheet.rules || styleSheet.cssRules || [];
              for (jx = 0; jx < rules.length; jx += 1) {
                var rule = rules[jx];
                text.push(rule.cssText);
              }
            }
          } catch (ex) {
            DG.logWarn('Exception retrieving stylesheet: ' + ex);
          }
        }
        return text.join('\n');
      }

      function makeDataURLFromSVGElement(svgEl) {
        var svgClone = $(svgEl).clone();
        var css = $('<style>').text(getCSSText());
        svgClone.prepend(css);
        var svgData = new XMLSerializer().serializeToString(svgClone[0]);
        // Raphael overspecifies the url for the gradient. It prepends the
        // windows.location.href. This causes problems with the data url,
        // because we are no longer in this namespace. So, we remove.
        svgData = svgData.replace(
            new RegExp('url\\(\'[^#]*#', 'g'), 'url(\'#');
        // The use of unescape and encodeURIComponent are part of a well-
        // known hack work around btoa's handling of unicode characters.
        // see, eg:
        // http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
        return "data:image/svg+xml;base64,"
            + window.btoa(window.unescape(window.encodeURIComponent(svgData)));
      }

      /**
       * Create a canvas element with a white background. Not yet appended to
       * the DOM.
       * @param {number} width
       * @param {number} height
       * @returns {Canvas}
       */
      function makeCanvasEl(width, height) {
        var canvas = $("<canvas>").prop({width: width, height: height})[0];
        var ctx = canvas.getContext("2d");
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, width, height);
        return canvas;
      }

      /**
       * Add an image to the canvas at the specified location.
       * @param {Canvas} canvas DOM Element
       * @param {img} image DOM Element
       * @param {number} x
       * @param {number} y
       * @param {number} width
       * @param {number} height
       */
      function addImageToCanvas(canvas, image, x, y, width, height) {
        var ctx = canvas.getContext("2d");
        ctx.drawImage(image, x, y, width, height);
      }

      /**
       * Convert a canvas object to a blob.
       * @param canvas
       * @returns {*}
       */
      function makeCanvasBlob(canvas) {
        var canvasDataURL = canvas.toDataURL("image/png");
        var canvasData = atob(canvasDataURL.substring("data:image/png;base64,".length));
        var canvasAsArray = new Uint8Array(canvasData.length);  /* global Uint8Array */

        for (var i = 0, len = canvasData.length; i < len; ++i) {
          canvasAsArray[i] = canvasData.charCodeAt(i);
        }

        return new Blob([canvasAsArray.buffer], {type: "image/png"});
      }

      /**
       * @returns a promise of an image.
       * @param dataURL
       */
      function makeSVGImage(dataURL) {
        return new Promise(function (resolve, reject) {
              try {
                var img = $('<img/>')[0];
                img.onload = function () {
                  resolve(img);
                };
                img.src = dataURL;
              } catch (ex) {
                reject(ex);
              }
            }
        );
      }

      //
      // ######## convertImage begin ########
      //
      // find all svg elements that are not children of hidden divs
      var svgs = $(rootEl).find('div:not(.sc-hidden)>svg');
      var canvas = makeCanvasEl(width, height);
      var promises = [];

      // for each svg we calculate its geometry, then add it to the canvas
      // through a promise.
      // Note: This implementation starts a number of asynchronous operations,
      // one for each SVG in the hierarchy. If they overlap and are handled out
      // of order, it is possible that they may be written to the canvas in the
      // wrong order.
      if (svgs) {
        svgs.forEach(function (svg) {
          var width = svg.offsetWidth || svg.width.baseVal.value;
          var height = svg.offsetHeight || svg.height.baseVal.value;
          var left = 0;
          var top = 0;
          $(svg).add($(svg).parentsUntil(rootEl)).each(function () {
            left += this.offsetLeft || 0;
            top += this.offsetTop || 0;
          });
          // DG.log('SVG width/height/left/top: ' + [width, height, left, top].join('/'));
          var imgPromise = makeSVGImage(makeDataURLFromSVGElement(svg));
          imgPromise.then(function (img) {
                addImageToCanvas(canvas, img, left, top, width, height);
              },
              function (error) {
                DG.logError(error);
              }
          );
          promises.push(imgPromise);
        });
      }

      // when all promises have been fulfilled we make a blob, then invoke the
      // save image dialog.
      return Promise.all(promises).then(function () {
          return asDataURL ? canvas.toDataURL("image/png") : makeCanvasBlob(canvas);
        },
        function (error) {
          DG.logError(error);
        }
      );
    }
  };
}());<|endoftext|>


<commit_before>// MIT license.

// Subscribing fetching gerrit changes.
chrome.alarms.onAlarm.addListener(function (alarm) {
  fetchChanges();
});

function intersect(a, b) {
    var t;
    if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
    return a.filter(function (e) {
        if (b.indexOf(e) !== -1) return true;
    });
}

// Fetch data from gerrit server. |updated_id| is missing, then fetch every item
function fetchChanges(update_id) {
  // Change badge background color red.
  chrome.browserAction.setBadgeBackgroundColor({ color: "#F00" });

  var query = ["status:open", "(reviewer:self OR owner:self)"].join('+');
  var gerrit_instance = new GerritQuery();
  gerrit_instance.getChangeList(query)
    .then(function(result) {
      chrome.storage.local.set({ 'changes': result });

      if (update_id !== undefined) {
        // update timestamp/read state
        var nike = result.filter(function(o){ return o._number === update_id });
        var pop_item = nike.pop();
        var updated = pop_item.updated;
        chrome.storage.local.get("timestamps", function(items) {
          var timestamps = items.timestamps || {};
          timestamps[update_id] = updated;
          chrome.storage.local.set({ 'timestamps': timestamps });
        });
      }
    }, function(e) {
      console.log("failed to fetch changes:", e.message);
      delete chrome.storage.local.changes;
    });
}

function updateIcon(changes) {
  try {
    var unread = changes.filter(function(value, index, array) {return !value.reviewed});
  } catch (e) {
  }
  chrome.browserAction.setBadgeText({ text: unread && unread.length.toString() || "..." });
}

function onNavigate(details) {
  console.log("onNavigate", details.url);
  try {
    var update_id = parseInt(details.url.match(/#\/c\/(\d+)/)[1]);
    fetchChanges(update_id);
  } catch (e) {
    console.log("Failed to parse id for", details.url);
  }
}

chrome.runtime.onSuspend.addListener(function() {
  chrome.browserAction.setBadgeBackgroundColor({color: "#888"});
});

chrome.runtime.onSuspendCanceled.addListener(function() {
  chrome.browserAction.setBadgeBackgroundColor({color: "#F0F"});
});

function getMessagesById(full_output, id) {
  var messages = [];
  full_output.forEach(function(item) {
    if (item.id === id) {
      messages = item.messages;
    }
    return item.id === id;
  });
  return messages;
}

chrome.storage.onChanged.addListener(function(changes, namespace) {
  for (key in changes) {
    var storageChange = changes[key];
    console.log('Storage key "%s" in namespace "%s" changed. ' +
      'Old value was "%s", new value is "%s".',
      key,
      namespace,
      storageChange.oldValue,
      storageChange.newValue);
    if (key === "changes") {
      updateIcon(storageChange.newValue);
      var new_id_list = [];

      storageChange.newValue.forEach(function(item) {
        new_id_list.push(item.id);
      });
      var old_id_list = [];
      storageChange.oldValue.forEach(function(item) {
        old_id_list.push(item.id);
      });
      var intersect_list = intersect(new_id_list, old_id_list);
      intersect_list.forEach(function(item) {
        var new_messages = getMessagesById(storageChange.newValue, item);
        var old_messages = getMessagesById(storageChange.oldValue, item);
        var diff_size = (new_messages.length - old_messages.length);

        for (j = 1; j <= diff_size; j++) {
          var new_msg = new_messages[old_messages.length + j - 1].message;
          var gerrit_instance = new GerritQuery();
          var account_id = new_messages[old_messages.length + j - 1].author._account_id;
          gerrit_instance.getChangeList(item.toString())
            .then(function(result) {
              if (result.length == 1) {
				// TODO(sungguk): Write account map<AccountId, AccountName>.
                if (localStorage["checkbot"] == "true" && account_id == 2254) // Checkbot
                  return;
                if (localStorage["build_linux_all"] == "true" && (account_id == 3505 || account_id == 4470 || account_id == 3000 || account_id == 4479 || account_id == 4480 || account_id == 4471 || account_id == 4481 || account_id == 3311 || account_id == 3076 || account_id == 1203 || account_id == 2813 || account_id == 3074 || account_id == 3073 || account_id == 3921 ||  account_id == 3685 || account_id == 3072 || account_id == 4472))  // BuildLinuxGcc5Happy, BuildLinuxGcc5Happy, BuildLInuxClangAddrSanHappy, BuildLinuxRel, Linux32Rel, BuildLinuxSP3GCC48Happy
                  return;
                if (localStorage["build_sun_all"] == "true" && (account_id == 3689 || account_id == 3691))  // Sun64Rel
                  return;
                if (localStorage["build_windows_all"] == "true" && (account_id == 3311|| account_id == 439 || account_id == 337 || account_id == 2809))  // BuildWIndowsVC2015HappyDbg, BuildWindowsDbg, BuildWindows, BuildWindows32Rel
                  return;
                if (localStorage["build_mac_all"] == "true" && (account_id == 2546 || account_id == 5043 || account_id == 3 || account_id == 4395))
                  return;

                new_msg = new_msg.replace(/(\n\n)/gm,"\n");
                var duration_ms = localStorage["duration"]
                  if (duration_ms === null)
                    duration_ms = 3;
                duration_ms = duration_ms * 1000;
				var require_interaction =
    				localStorage["remain_visible"] === undefined ? false : localStorage["remain_visible"] == "true";
                chrome.notifications.create(result[0]._number.toString(), {title: result[0].subject, iconUrl: './images/icon.png', message: new_msg, type:  'basic', eventTime: Date.now() + duration_ms, requireInteraction: require_interaction});
              }
            }, function(e) {
              console.log("failed to fetch changes:", e.message);
            });
        }
      });
    }
  }
});

chrome.notifications.onClicked.addListener(function(id) {
  chrome.notifications.clear(id);
  var BASE_URL = localStorage["api_endpoint"];
  chrome.tabs.create({url: BASE_URL + "/" + id});
});

chrome.webNavigation.onReferenceFragmentUpdated.addListener(onNavigate, {
  url: [{ hostSuffix: localStorage["api_endpoint"].split("://").pop() }]
});

chrome.webNavigation.onCommitted.addListener(onNavigate, {
  url: [{ hostSuffix: localStorage["api_endpoint"].split("://").pop() }]
});
<commit_msg>Add more account id for gcc7<commit_after>// MIT license.

// Subscribing fetching gerrit changes.
chrome.alarms.onAlarm.addListener(function (alarm) {
  fetchChanges();
});

function intersect(a, b) {
    var t;
    if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
    return a.filter(function (e) {
        if (b.indexOf(e) !== -1) return true;
    });
}

// Fetch data from gerrit server. |updated_id| is missing, then fetch every item
function fetchChanges(update_id) {
  // Change badge background color red.
  chrome.browserAction.setBadgeBackgroundColor({ color: "#F00" });

  var query = ["status:open", "(reviewer:self OR owner:self)"].join('+');
  var gerrit_instance = new GerritQuery();
  gerrit_instance.getChangeList(query)
    .then(function(result) {
      chrome.storage.local.set({ 'changes': result });

      if (update_id !== undefined) {
        // update timestamp/read state
        var nike = result.filter(function(o){ return o._number === update_id });
        var pop_item = nike.pop();
        var updated = pop_item.updated;
        chrome.storage.local.get("timestamps", function(items) {
          var timestamps = items.timestamps || {};
          timestamps[update_id] = updated;
          chrome.storage.local.set({ 'timestamps': timestamps });
        });
      }
    }, function(e) {
      console.log("failed to fetch changes:", e.message);
      delete chrome.storage.local.changes;
    });
}

function updateIcon(changes) {
  try {
    var unread = changes.filter(function(value, index, array) {return !value.reviewed});
  } catch (e) {
  }
  chrome.browserAction.setBadgeText({ text: unread && unread.length.toString() || "..." });
}

function onNavigate(details) {
  console.log("onNavigate", details.url);
  try {
    var update_id = parseInt(details.url.match(/#\/c\/(\d+)/)[1]);
    fetchChanges(update_id);
  } catch (e) {
    console.log("Failed to parse id for", details.url);
  }
}

chrome.runtime.onSuspend.addListener(function() {
  chrome.browserAction.setBadgeBackgroundColor({color: "#888"});
});

chrome.runtime.onSuspendCanceled.addListener(function() {
  chrome.browserAction.setBadgeBackgroundColor({color: "#F0F"});
});

function getMessagesById(full_output, id) {
  var messages = [];
  full_output.forEach(function(item) {
    if (item.id === id) {
      messages = item.messages;
    }
    return item.id === id;
  });
  return messages;
}

chrome.storage.onChanged.addListener(function(changes, namespace) {
  for (key in changes) {
    var storageChange = changes[key];
    console.log('Storage key "%s" in namespace "%s" changed. ' +
      'Old value was "%s", new value is "%s".',
      key,
      namespace,
      storageChange.oldValue,
      storageChange.newValue);
    if (key === "changes") {
      updateIcon(storageChange.newValue);
      var new_id_list = [];

      storageChange.newValue.forEach(function(item) {
        new_id_list.push(item.id);
      });
      var old_id_list = [];
      storageChange.oldValue.forEach(function(item) {
        old_id_list.push(item.id);
      });
      var intersect_list = intersect(new_id_list, old_id_list);
      intersect_list.forEach(function(item) {
        var new_messages = getMessagesById(storageChange.newValue, item);
        var old_messages = getMessagesById(storageChange.oldValue, item);
        var diff_size = (new_messages.length - old_messages.length);

        for (j = 1; j <= diff_size; j++) {
          var new_msg = new_messages[old_messages.length + j - 1].message;
          var gerrit_instance = new GerritQuery();
          var account_id = new_messages[old_messages.length + j - 1].author._account_id;
          gerrit_instance.getChangeList(item.toString())
            .then(function(result) {
              if (result.length == 1) {
                // TODO(sungguk): Write account map<AccountId, AccountName>.
                if (localStorage["checkbot"] == "true" && account_id == 2254) // Checkbot
                  return;
                if (localStorage["build_linux_all"] == "true" && (account_id == 3505 || account_id == 4470 || account_id == 3000 || account_id == 4479 || account_id == 4480 || account_id == 4471 || account_id == 4481 || account_id == 3311 || account_id == 3076 || account_id == 1203 || account_id == 2813 || account_id == 3074 || account_id == 3073 || account_id == 3921 ||  account_id == 3685 || account_id == 3072 || account_id == 4472 || account_id == 5331 || account_id == 5332 || account_id == 5333 || account_id == 5334 || account_id == 5335))  // BuildLinuxGcc5Happy, BuildLinuxGcc5Happy, BuildLInuxClangAddrSanHappy, BuildLinuxRel, Linux32Rel, BuildLinuxSP3GCC48Happy
                  return;
                if (localStorage["build_sun_all"] == "true" && (account_id == 3689 || account_id == 3691))  // Sun64Rel
                  return;
                if (localStorage["build_windows_all"] == "true" && (account_id == 3311|| account_id == 439 || account_id == 337 || account_id == 2809))  // BuildWIndowsVC2015HappyDbg, BuildWindowsDbg, BuildWindows, BuildWindows32Rel
                  return;
                if (localStorage["build_mac_all"] == "true" && (account_id == 2546 || account_id == 5043 || account_id == 3 || account_id == 4395))
                  return;

                new_msg = new_msg.replace(/(\n\n)/gm,"\n");
                var duration_ms = localStorage["duration"]
                  if (duration_ms === null)
                    duration_ms = 3;
                duration_ms = duration_ms * 1000;
				var require_interaction =
    				localStorage["remain_visible"] === undefined ? false : localStorage["remain_visible"] == "true";
                chrome.notifications.create(result[0]._number.toString(), {title: result[0].subject, iconUrl: './images/icon.png', message: new_msg, type:  'basic', eventTime: Date.now() + duration_ms, requireInteraction: require_interaction});
              }
            }, function(e) {
              console.log("failed to fetch changes:", e.message);
            });
        }
      });
    }
  }
});

chrome.notifications.onClicked.addListener(function(id) {
  chrome.notifications.clear(id);
  var BASE_URL = localStorage["api_endpoint"];
  chrome.tabs.create({url: BASE_URL + "/" + id});
});

chrome.webNavigation.onReferenceFragmentUpdated.addListener(onNavigate, {
  url: [{ hostSuffix: localStorage["api_endpoint"].split("://").pop() }]
});

chrome.webNavigation.onCommitted.addListener(onNavigate, {
  url: [{ hostSuffix: localStorage["api_endpoint"].split("://").pop() }]
});
<|endoftext|>


<commit_before>import firebase from '../../services/firebase'
import { errorWhile, fingerprint } from '../../utility'
import * as paths from './paths'

export const filterUserInfo = input => {
    const keptKeys = ['email', 'displayName', 'photoURL']
    const output = {}
    for (const key in input) {
        if (keptKeys.indexOf(key) !== -1) {
            output[key] = input[key]
        } else {
            // console.warn('The following key will be filtered out from user info:', key)
        }
    }
    return output
}

export const createUser = (uid, user = {}) => {
    const path = paths.user(uid)
    return firebase.db.once(path).then(snapshot => {
        if (snapshot.val() !== null) {
            return Promise.resolve() // Already exists
        }
        const data = filterUserInfo(user)
        return firebase.db.set(path, data)
    }).catch(errorWhile('creating user'))
}

export const updateUser = (uid, user) => {
    const data = filterUserInfo(user)
    return firebase.db.update(paths.user(uid), data)
        .catch(errorWhile('updating user'))
}

export const markUserAsOnline = (uid) => {
    const path = paths.online.user.location(uid, fingerprint.asNumber())
    firebase.db.onDisconnect(path).remove()
    return firebase.db.set(path, firebase.db.timestamp)
        .catch(errorWhile('marking user as online'))
}

export const markUserAsOffline = (uid) => {
    const path = paths.online.user.location(uid, fingerprint.asNumber())
    return firebase.db.remove(path)
        .catch(errorWhile('marking user as offline'))
}
<commit_msg>Ensure null idempotence.<commit_after>import firebase from '../../services/firebase'
import { errorWhile, fingerprint } from '../../utility'
import * as paths from './paths'

export const filterUserInfo = input => {
    if (input === null) {
        return null
    }

    const keptKeys = ['email', 'displayName', 'photoURL']
    const output = {}
    for (const key in input) {
        if (keptKeys.indexOf(key) !== -1) {
            output[key] = input[key]
        } else {
            // console.warn('The following key will be filtered out from user info:', key)
        }
    }
    return output
}

export const createUser = (uid, user = {}) => {
    const path = paths.user(uid)
    return firebase.db.once(path).then(snapshot => {
        if (snapshot.val() !== null) {
            return Promise.resolve() // Already exists
        }
        const data = filterUserInfo(user)
        return firebase.db.set(path, data)
    }).catch(errorWhile('creating user'))
}

export const updateUser = (uid, user) => {
    const data = filterUserInfo(user)
    return firebase.db.update(paths.user(uid), data)
        .catch(errorWhile('updating user'))
}

export const markUserAsOnline = (uid) => {
    const path = paths.online.user.location(uid, fingerprint.asNumber())
    firebase.db.onDisconnect(path).remove()
    return firebase.db.set(path, firebase.db.timestamp)
        .catch(errorWhile('marking user as online'))
}

export const markUserAsOffline = (uid) => {
    const path = paths.online.user.location(uid, fingerprint.asNumber())
    return firebase.db.remove(path)
        .catch(errorWhile('marking user as offline'))
}
<|endoftext|>


<commit_before><commit_msg>Update item lookup in reference resolution case with auto-assigned identities.  \!strict fixes #10583<commit_after><|endoftext|>


<commit_before><commit_msg>Delete systemjs.config.js<commit_after><|endoftext|>


<commit_before>var ArticleAlbum = {
    init: function () {
        this._initControls();
    },
    _initControls: function () {
        var articleAlbum = $.templates("#articleAlbumTemplate");
        var articleAlbumHtml = articleAlbum.render({});
        $("#main_content").append(articleAlbumHtml);
        this._generateCarousel(this._convertToJson());
    },

    _convertToJson: function () {
        return this.getImageAndDescriptionOfRichtextImgHolder();
    },

    getImageAndDescriptionOfRichtextImgHolder: function() {
        var self = this,
            jsonArray = [{
                src: this.getImageUrl($(".banner-container img")),
                description: "",
                article_title: $('#article-gallery-title').text(),
                id: 0
            }];

        $(".article-content .rich-text > .gallery, .article-content .rich-text > .rich-text-image-holder, .image-block .image > .gallery ").each(function(index) {
            jsonArray.push({
                src: self.getImageUrl($(this).find("img")),
                description: self.getDescription(this),
                article_title: $('#article-gallery-title').text(),
                id: index + 1
            });
        });
        return jsonArray;
    },

    getImageUrl: function(img) {
        var src = $(img).attr('srcset') || $(img).attr('data-srcset');
        if (typeof src !== 'undefined') {
            return src.split(',')[1];
        }
        return $(img).attr('data-src') || $(img).attr('currentSrc') || $(img).attr('src');
    },

    getDescription: function(item) {
      var description = $(item).find("img").next("i").text().trim();
      if(!description) {
          description = $(item).find("img").parents(".gallery").next("i").text().trim();
      }
      if(!description) {
          $(item).nextAll(".center.paragraph-holder:not('.rich-text-image-holder')").each(function() {
              if(!description) {
                description = $(this).find("i").text().trim();
              }
          });
          $(item).nextAll("i:not('.rich-text-image-holder')").each(function() {
              if(!description) {
                description = $(this).find("i").text().trim();
              }
          });
      }

      if(!description){
          description = $(item).parents('.image-block').siblings('.caption').find("p").html();
      }

      if(!description){
          description = $(item).parents('.image').siblings('.caption').find("p").html();
      }

      return description;
    },

    _generateCarousel: function (data) {
        this.carouselData = data;
        data.forEach(function (slide, index) {
            slide.carouselPageClass = index === 0 ? "item image-container active" : "item image-container";
            var carouselPage = $.templates("#carouselPage");
            var carouselPageHtml = carouselPage.render(slide);
            $(".carousel-items").append(carouselPageHtml);
        });

        $("#carousel").carousel("pause");
        this.handleCarouselEvents(this.carouselData);
    },

    handleCarouselEvents: function (carouselData) {
        var totalItems = $('.carousel-items .item').length,
            currentIndex = 0;
        updateCurrentPageData();

        $('#showSlideInfo').click(function () {
            $(this).toggleClass("selected");
            $(this).removeClass("fa-angle-right").removeClass("fa-info-circle");
            $(this).addClass($(this).hasClass("selected") ? "fa-angle-right" : "fa-info-circle");
            $(".photo-album").toggleClass("show-slide-info");
        });

        $('.back-to-albums').click(function () {
            $(".carousel-container").removeClass("carousel");
            $(".photo-album-popup").addClass("hide");
        });

        $('#carousel').on('slid.bs.carousel', function () {
            updateIndexOnSlide();

        });

        $('.rich-text .gallery, .modular-content .gallery').click(function (event) {

            $(".photo-album-popup").removeClass("hide");
            $(".carousel-container").addClass("carousel");
            $(".carousel-container").attr("data-ride", "carousel");
            $("#carousel").carousel("pause");
            $("#carousel").carousel({
                interval: 0,
                pause: true
            });
            var index = $(event.currentTarget).attr('id');
            $("#carousel").carousel(parseInt(index) + 1);

        });

        $('.preview').on('click', function () {
            $("#carousel").carousel(0);
            $(".photo-album-popup").removeClass("hide");
            $(".carousel-container").addClass("carousel");
            $("#carousel").carousel("pause");
            $(".carousel-container").attr("data-ride", "carousel");

        });

        function updateIndexOnSlide() {
            currentIndex = getSelectedCarouselIndex();
            updateCurrentPageData();
        }

        function getSelectedCarouselIndex() {
            return $('.photo-album .carousel-items li.active').index('.photo-album .carousel-items li.item');
        }

        function updateCurrentPageData() {
            totalItems = $('.carousel-items .item').length;
            $('.carousel-index').html((currentIndex + 1) + " / " + totalItems);

            var data = carouselData[currentIndex];
            $(".right-icons .open-in-new-tab").attr("href", data.src);

            if (currentIndex <= carouselData.length) {
                $(".slide-info .description").html(data.description);
                $(".slide-info .album-title").text(data.article_title);
            }
        }
    }

};

$(function () {
    $(".lazyload").css("display", "initial");

    $(".scrollToTop").hide();

    $(".full-row .info a").on("click", function () {
        $("body").animate({
            scrollTop: $(".article-title").offset().top
        }, 1000);
        $(".full-row .info").animate({
            toggleClass: "hidden"
        }, 1000);
    });
    $(document).on("scroll", function () {
        if ($(window).scrollTop() < 10) {
            $(".full-row .info").removeClass("hidden");
            $(".scrollToTop").hide();
        } else {
            $(".full-row .info").addClass("hidden");
            $(".scrollToTop").show();
        }
    });

    $(".scrollToTop").on("click", function () {
        $("body").animate({
            scrollTop: 0
        }, 1000);
    });

    $('.rich-text p, .rich-text h3, .rich-text h5').each(function () {
        if ($(this).find('img').length > 0) {
            $(this).addClass("rich-text-image-holder");
        } else {
            $(this).addClass("paragraph-holder");
        }
    });
    $('.rich-text img').each(function (index) {
        $(this).wrap('');
        $(this).parents('a').first().prepend('').css("position", "relative");
    });

    $('.modular-content img').not(".ignore-carousel").each(function (index) {
        if(!$(this).parents().is(".map-holder")) {
            $(this).wrap('');
            $(this).parents('a').first().prepend('');
        }
    });

    ArticleAlbum.init();

    function _dummy() {
        return [{
            "srcset": '/static/img/stories-1.jpg',
            "description": "Currently, image is being stored along with alt tags as single content. While doing this feature, we need to separate html & content. Hence we get the ability to add alt tags to images for SEO purposes",
            "album_title": "Weavers of walagpet"
        },
            {
                "srcset": '/static/img/stories-1.jpg',
                "description": "Currently, image is being stored along with alt tags as single content. While doing this feature, we need to separate html & content. Hence we get the ability to add alt tags to images for SEO purposes",
                "album_title": "Weavers of walagpet"
            }];
    }
});
<commit_msg>#172 [Lokesh/Sankar] Fixed hiding of urdu characters in carousel fullscreen<commit_after>var ArticleAlbum = {
    init: function () {
        this._initControls();
    },
    _initControls: function () {
        var articleAlbum = $.templates("#articleAlbumTemplate");
        var articleAlbumHtml = articleAlbum.render({});
        $("#main_content").append(articleAlbumHtml);
        this._generateCarousel(this._convertToJson());
    },

    _convertToJson: function () {
        return this.getImageAndDescriptionOfRichtextImgHolder();
    },

    getImageAndDescriptionOfRichtextImgHolder: function() {
        var self = this,
            jsonArray = [{
                src: this.getImageUrl($(".banner-container img")),
                description: "",
                article_title: $('#article-gallery-title').text(),
                id: 0
            }];

        $(".article-content .rich-text > .gallery, .article-content .rich-text > .rich-text-image-holder, .image-block .image > .gallery ").each(function(index) {
            jsonArray.push({
                src: self.getImageUrl($(this).find("img")),
                description: self.getDescription(this),
                article_title: $('#article-gallery-title').text(),
                id: index + 1
            });
        });
        return jsonArray;
    },

    getImageUrl: function(img) {
        var src = $(img).attr('srcset') || $(img).attr('data-srcset');
        if (typeof src !== 'undefined') {
            return src.split(',')[1];
        }
        return $(img).attr('data-src') || $(img).attr('currentSrc') || $(img).attr('src');
    },

    getDescription: function(item) {
      var description = $(item).find("img").next("i").text().trim();
      if(!description) {
          description = $(item).find("img").parents(".gallery").next("i").text().trim();
      }
      if(!description) {
          $(item).nextAll(".center.paragraph-holder:not('.rich-text-image-holder')").each(function() {
              if(!description) {
                description = $(this).find("i").text().trim();
              }
          });
          $(item).nextAll("i:not('.rich-text-image-holder')").each(function() {
              if(!description) {
                description = $(this).find("i").text().trim();
              }
          });
      }

      if(!description){
          description = $(item).parents('.image-block').siblings('.caption').find("p").html();
      }

      if(!description){
          description = $(item).parents('.image').siblings('.caption').find("p").html();
      }

      return description;
    },

    _generateCarousel: function (data) {
        this.carouselData = data;
        data.forEach(function (slide, index) {
            slide.carouselPageClass = index === 0 ? "item image-container active" : "item image-container";
            var carouselPage = $.templates("#carouselPage");
            var carouselPageHtml = carouselPage.render(slide);
            $(".carousel-items").append(carouselPageHtml);
        });

        $("#carousel").carousel("pause");
        this.handleCarouselEvents(this.carouselData);
    },

    handleCarouselEvents: function (carouselData) {
        var totalItems = $('.carousel-items .item').length,
            currentIndex = 0;
        updateCurrentPageData();

        $('#showSlideInfo').click(function () {
            $(this).toggleClass("selected");
            $(this).removeClass("fa-angle-right").removeClass("fa-info-circle");
            $(this).addClass($(this).hasClass("selected") ? "fa-angle-right" : "fa-info-circle");
            $(".photo-album").toggleClass("show-slide-info");
            $(".slide-info").toggleClass("hidden");
        });

        $('.back-to-albums').click(function () {
            $(".carousel-container").removeClass("carousel");
            $(".photo-album-popup").addClass("hide");
        });

        $('#carousel').on('slid.bs.carousel', function () {
            updateIndexOnSlide();

        });

        $('.rich-text .gallery, .modular-content .gallery').click(function (event) {

            $(".photo-album-popup").removeClass("hide");
            $(".carousel-container").addClass("carousel");
            $(".carousel-container").attr("data-ride", "carousel");
            $("#carousel").carousel("pause");
            $("#carousel").carousel({
                interval: 0,
                pause: true
            });
            var index = $(event.currentTarget).attr('id');
            $("#carousel").carousel(parseInt(index) + 1);

        });

        $('.preview').on('click', function () {
            $("#carousel").carousel(0);
            $(".photo-album-popup").removeClass("hide");
            $(".carousel-container").addClass("carousel");
            $("#carousel").carousel("pause");
            $(".carousel-container").attr("data-ride", "carousel");

        });

        function updateIndexOnSlide() {
            currentIndex = getSelectedCarouselIndex();
            updateCurrentPageData();
        }

        function getSelectedCarouselIndex() {
            return $('.photo-album .carousel-items li.active').index('.photo-album .carousel-items li.item');
        }

        function updateCurrentPageData() {
            totalItems = $('.carousel-items .item').length;
            $('.carousel-index').html((currentIndex + 1) + " / " + totalItems);

            var data = carouselData[currentIndex];
            $(".right-icons .open-in-new-tab").attr("href", data.src);

            if (currentIndex <= carouselData.length) {
                $(".slide-info .description").html(data.description);
                $(".slide-info .album-title").text(data.article_title);
            }
        }
    }

};

$(function () {
    $(".lazyload").css("display", "initial");

    $(".scrollToTop").hide();

    $(".full-row .info a").on("click", function () {
        $("body").animate({
            scrollTop: $(".article-title").offset().top
        }, 1000);
        $(".full-row .info").animate({
            toggleClass: "hidden"
        }, 1000);
    });
    $(document).on("scroll", function () {
        if ($(window).scrollTop() < 10) {
            $(".full-row .info").removeClass("hidden");
            $(".scrollToTop").hide();
        } else {
            $(".full-row .info").addClass("hidden");
            $(".scrollToTop").show();
        }
    });

    $(".scrollToTop").on("click", function () {
        $("body").animate({
            scrollTop: 0
        }, 1000);
    });

    $('.rich-text p, .rich-text h3, .rich-text h5').each(function () {
        if ($(this).find('img').length > 0) {
            $(this).addClass("rich-text-image-holder");
        } else {
            $(this).addClass("paragraph-holder");
        }
    });
    $('.rich-text img').each(function (index) {
        $(this).wrap('');
        $(this).parents('a').first().prepend('').css("position", "relative");
    });

    $('.modular-content img').not(".ignore-carousel").each(function (index) {
        if(!$(this).parents().is(".map-holder")) {
            $(this).wrap('');
            $(this).parents('a').first().prepend('');
        }
    });

    ArticleAlbum.init();

    function _dummy() {
        return [{
            "srcset": '/static/img/stories-1.jpg',
            "description": "Currently, image is being stored along with alt tags as single content. While doing this feature, we need to separate html & content. Hence we get the ability to add alt tags to images for SEO purposes",
            "album_title": "Weavers of walagpet"
        },
            {
                "srcset": '/static/img/stories-1.jpg',
                "description": "Currently, image is being stored along with alt tags as single content. While doing this feature, we need to separate html & content. Hence we get the ability to add alt tags to images for SEO purposes",
                "album_title": "Weavers of walagpet"
            }];
    }
});
<|endoftext|>


<commit_before>    var customIcons = {
        building: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/building_icon.png'
        },
        student_centre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/student_centre_icon.png'
        },
        lecture_theatre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/lecture_theatre_icon.png'
        },
        computer_lab: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/computer_lab_icon.png'
        },
        library: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/library_icon.png'
        },
        cycle_hire: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_hire_icon.png'
        },
        cycle_parking: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_parking_icon.png'
        },
        atm: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/atm_icon.png'
        }
    };

    var markerGroups = {
        "building": [],
        "student_centre": [],
        "lecture_theatre": [],
        "computer_lab": [],
        "library": [],
        "cycle_hire": [],
        "cycle_parking": [],
        "atm": []
    };

    // Add a Home control that returns the user to London
    function showCurrentLocation(currentLocationDiv, map) {
        currentLocationDiv.style.padding = '5px';
        var currentLocationUI = document.createElement('div');
        currentLocationUI.style.backgroundColor = 'white';
        currentLocationUI.style.border = '1px solid';
        currentLocationUI.style.cursor = 'pointer';
        currentLocationUI.style.textAlign = 'center';
        currentLocationUI.title = 'Shows current location on the map';
        currentLocationDiv.appendChild(currentLocationUI);
        var currentLocationText = document.createElement('div');
        currentLocationText.style.fontFamily = 'Arial,sans-serif';
        currentLocationText.style.fontSize = '11px';
        currentLocationText.style.paddingLeft = '4px';
        currentLocationText.style.paddingRight = '4px';
        currentLocationText.innerHTML = 'Current location';
        currentLocationUI.appendChild(currentLocationText);

        // Setup click-event listener: simply set the map to London
        google.maps.event.addDomListener(currentLocationUI, 'click', function () {

            if(navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function(position) {
                    var pos = new google.maps.LatLng(position.coords.latitude,
                        position.coords.longitude);

                    var current_location_marker = new google.maps.Marker({
                        map: map,
                        position: pos,
                        title: 'You are here.'
                    });

                    var current_location_infowindow = new google.maps.InfoWindow({
                        content: 'You are here.'
                    });

                    current_location_infowindow.open(map,current_location_marker);

                    google.maps.event.addListener(current_location_marker, 'click', function() {
                        current_location_infowindow.open(map,current_location_marker);
                    });

                    map.setCenter(pos);
                }, function() {
                    handleNoGeolocation(true);
                });
            } else {
                // Browser doesn't support Geolocation
                handleNoGeolocation(false);
            }

        function handleNoGeolocation(errorFlag) {
            if (errorFlag) {
                var content = 'Error: The Geolocation service failed.';
            } else {
                var content = 'Error: Your browser doesn\'t support geolocation.';
            }

            var options = {
                map: map,
                position: new google.maps.LatLng(60, 105),
                content: content
            };

            var no_geolocation_infowindow = new google.maps.InfoWindow(options);
            map.setCenter(options.position);
        }
        });
    }

    function loadMap() {
    var map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(51.527287, -0.103842),
        zoom: 15,
        mapTypeId: 'roadmap'
    });

        // Create a DIV to hold the control and call HomeControl()
    var currentLocationDiv = document.createElement('div');
    var currentLocation = new showCurrentLocation(currentLocationDiv, map);
    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(currentLocationDiv);

    downloadUrl("../../includes/university-map/source/overview_source.php", function(data) {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
        var name = markers[i].getAttribute("name");
        var notes = markers[i].getAttribute("notes");
        var category = markers[i].getAttribute("category");
        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var marker = createMarker(point, name, notes, category, map);
    }
    });
    }

    var infoWindow = new google.maps.InfoWindow({
        maxWidth: 400
    });

    function createMarker(point, name, notes, category, map) {
        var icon = customIcons[category] || {};
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,
            type: category
        });
        if (!markerGroups[category]) markerGroups[category] = [];
        markerGroups[category].push(marker);
        var html = "" + name + "
" + notes;
        bindInfoWindow(marker, map, infoWindow, html);
        return marker;
    }

    function toggleGroup(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            if (!marker.getVisible()) {
                marker.setVisible(true);
            } else {
                marker.setVisible(false);
            }
        }
    }

    function bindInfoWindow(marker, map, infoWindow, html) {
        google.maps.event.addListener(marker, 'click', function() {
            infoWindow.setContent(html);
            infoWindow.open(map, marker);

        });
    }

    function downloadUrl(url, callback) {
        var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();

        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                request.onreadystatechange = doNothing;
                callback(request, request.status);
            }
        };

        request.open('GET', url, true);
        request.send(null);
    }

    function doNothing() {}
<commit_msg>Changed structure<commit_after>    var customIcons = {
        building: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/building_icon.png'
        },
        student_centre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/student_centre_icon.png'
        },
        lecture_theatre: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/lecture_theatre_icon.png'
        },
        computer_lab: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/computer_lab_icon.png'
        },
        library: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/library_icon.png'
        },
        cycle_hire: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_hire_icon.png'
        },
        cycle_parking: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/cycle_parking_icon.png'
        },
        atm: {
            icon: 'https://student-portal.co.uk/assets/img/university-map/atm_icon.png'
        }
    };

    var markerGroups = {
        "building": [],
        "student_centre": [],
        "lecture_theatre": [],
        "computer_lab": [],
        "library": [],
        "cycle_hire": [],
        "cycle_parking": [],
        "atm": []
    };

    // Add a Home control that returns the user to London
    function showCurrentLocation(currentLocationDiv, map) {
        currentLocationDiv.style.padding = '5px';
        var currentLocationUI = document.createElement('div');
        currentLocationUI.style.backgroundColor = 'white';
        currentLocationUI.style.border = '1px solid';
        currentLocationUI.style.cursor = 'pointer';
        currentLocationUI.style.textAlign = 'center';
        currentLocationUI.title = 'Shows current location on the map';
        currentLocationDiv.appendChild(currentLocationUI);
        var currentLocationText = document.createElement('div');
        currentLocationText.style.fontFamily = 'Arial,sans-serif';
        currentLocationText.style.fontSize = '12px';
        currentLocationText.style.paddingLeft = '4px';
        currentLocationText.style.paddingRight = '4px';
        currentLocationText.innerHTML = 'Current location';
        currentLocationUI.appendChild(currentLocationText);

        // Setup click-event listener: simply set the map to London
        google.maps.event.addDomListener(currentLocationUI, 'click', function () {

            if(navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function(position) {
                    var pos = new google.maps.LatLng(position.coords.latitude,
                        position.coords.longitude);

                    var marker = new google.maps.Marker({
                        map: map,
                        position: pos,
                        title: 'You are here.'
                    });

                    var infowindow = new google.maps.InfoWindow({
                        content: 'You are here.'
                    });

                    infowindow.open(map,marker);

                    google.maps.event.addListener(marker, 'click', function() {
                        infowindow.open(map,marker);
                    });

                    map.setCenter(pos);
                }, function() {
                    handleNoGeolocation(true);
                });
            } else {
                // Browser doesn't support Geolocation
                handleNoGeolocation(false);
            }

        function handleNoGeolocation(errorFlag) {
            if (errorFlag) {
                var content = 'Error: The Geolocation service failed.';
            } else {
                var content = 'Error: Your browser doesn\'t support geolocation.';
            }

            var options = {
                map: map,
                position: new google.maps.LatLng(60, 105),
                content: content
            };

            var infowindow = new google.maps.InfoWindow(options);
            map.setCenter(options.position);
        }
        });
    }

    function loadMap() {
    var map = new google.maps.Map(document.getElementById("map"), {
        center: new google.maps.LatLng(51.527287, -0.103842),
        zoom: 15,
        mapTypeId: 'roadmap'
    });

        // Create a DIV to hold the control and call HomeControl()
    var currentLocationDiv = document.createElement('div');
    var currentLocation = new showCurrentLocation(currentLocationDiv, map);
    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(currentLocationDiv);

    downloadUrl("../../includes/university-map/source/overview_source.php", function(data) {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
        var name = markers[i].getAttribute("name");
        var notes = markers[i].getAttribute("notes");
        var category = markers[i].getAttribute("category");
        var point = new google.maps.LatLng(
            parseFloat(markers[i].getAttribute("lat")),
            parseFloat(markers[i].getAttribute("lng")));
        var marker = createMarker(point, name, notes, category, map);
    }
    });
    }

    var infoWindow = new google.maps.InfoWindow({
        maxWidth: 400
    });

    function createMarker(point, name, notes, category, map) {
        var icon = customIcons[category] || {};
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,
            type: category
        });
        if (!markerGroups[category]) markerGroups[category] = [];
        markerGroups[category].push(marker);
        var html = "" + name + "
" + notes;
        bindInfoWindow(marker, map, infoWindow, html);
        return marker;
    }

    function toggleGroup(category) {
        for (var i = 0; i < markerGroups[category].length; i++) {
            var marker = markerGroups[category][i];
            if (!marker.getVisible()) {
                marker.setVisible(true);
            } else {
                marker.setVisible(false);
            }
        }
    }

    function bindInfoWindow(marker, map, infoWindow, html) {
        google.maps.event.addListener(marker, 'click', function() {
            infoWindow.setContent(html);
            infoWindow.open(map, marker);

        });
    }

    function downloadUrl(url, callback) {
        var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();

        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                request.onreadystatechange = doNothing;
                callback(request, request.status);
            }
        };

        request.open('GET', url, true);
        request.send(null);
    }

    function doNothing() {}
<|endoftext|>