<commit_before>/*
Language: TypeScript
Author: Panu Horsmalahti <panu.horsmalahti@iki.fi>
Description: TypeScript is a strict superset of JavaScript
Category: scripting
*/

function(hljs) {
  var KEYWORDS = {
    keyword:
      'in if for while finally var new function|0 do return void else break catch ' +
      'instanceof with throw case default try this switch continue typeof delete ' +
      'let yield const class public private get set super ' +
      'static implements enum export import declare type protected',
    literal:
      'true false null undefined NaN Infinity',
    built_in:
      'eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent ' +
      'encodeURI encodeURIComponent escape unescape Object Function Boolean Error ' +
      'EvalError InternalError RangeError ReferenceError StopIteration SyntaxError ' +
      'TypeError URIError Number Math Date String RegExp Array Float32Array ' +
      'Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array ' +
      'Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require ' +
      'module console window document any number boolean string void'
  };

  return {
    aliases: ['ts'],
    keywords: KEYWORDS,
    contains: [
      {
        className: 'pi',
        begin: /^\s*['"]use strict['"]/,
        relevance: 0
      },
      hljs.APOS_STRING_MODE,
      hljs.QUOTE_STRING_MODE,
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      {
        className: 'number',
        variants: [
          { begin: '\\b(0[bB][01]+)' },
          { begin: '\\b(0[oO][0-7]+)' },
          { begin: hljs.C_NUMBER_RE }
        ],
        relevance: 0
      },
      { // "value" container
        begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
        keywords: 'return throw case',
        contains: [
          hljs.C_LINE_COMMENT_MODE,
          hljs.C_BLOCK_COMMENT_MODE,
          hljs.REGEXP_MODE
        ],
        relevance: 0
      },
      {
        className: 'function',
        begin: 'function', end: /[\{;]/, excludeEnd: true,
        keywords: KEYWORDS,
        contains: [
          'self',
          hljs.inherit(hljs.TITLE_MODE, {begin: /[A-Za-z$_][0-9A-Za-z$_]*/}),
          {
            className: 'params',
            begin: /\(/, end: /\)/,
            excludeBegin: true,
            excludeEnd: true,
            keywords: KEYWORDS,
            contains: [
              hljs.C_LINE_COMMENT_MODE,
              hljs.C_BLOCK_COMMENT_MODE
            ],
            illegal: /["'\(]/
          }
        ],
        illegal: /\[|%/,
        relevance: 0 // () => {} is more typical in TypeScript
      },
      {
        className: 'constructor',
        beginKeywords: 'constructor', end: /\{/, excludeEnd: true,
        relevance: 10
      },
      {
        className: 'module',
        beginKeywords: 'module', end: /\{/, excludeEnd: true
      },
      {
        className: 'interface',
        beginKeywords: 'interface', end: /\{/, excludeEnd: true,
        keywords: 'interface extends'
      },
      {
        begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`
      },
      {
        begin: '\\.' + hljs.IDENT_RE, relevance: 0 // hack: prevents detection of keywords after dots
      }
    ]
  };
}
<commit_msg>Added 'abstract' and 'namespace' to TypeScript keywords.<commit_after>/*
Language: TypeScript
Author: Panu Horsmalahti <panu.horsmalahti@iki.fi>
Description: TypeScript is a strict superset of JavaScript
Category: scripting
*/

function(hljs) {
  var KEYWORDS = {
    keyword:
      'in if for while finally var new function|0 do return void else break catch ' +
      'instanceof with throw case default try this switch continue typeof delete ' +
      'let yield const class public private protected get set super ' +
      'static implements enum export import declare type namespace abstract',
    literal:
      'true false null undefined NaN Infinity',
    built_in:
      'eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent ' +
      'encodeURI encodeURIComponent escape unescape Object Function Boolean Error ' +
      'EvalError InternalError RangeError ReferenceError StopIteration SyntaxError ' +
      'TypeError URIError Number Math Date String RegExp Array Float32Array ' +
      'Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array ' +
      'Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require ' +
      'module console window document any number boolean string void'
  };

  return {
    aliases: ['ts'],
    keywords: KEYWORDS,
    contains: [
      {
        className: 'pi',
        begin: /^\s*['"]use strict['"]/,
        relevance: 0
      },
      hljs.APOS_STRING_MODE,
      hljs.QUOTE_STRING_MODE,
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      {
        className: 'number',
        variants: [
          { begin: '\\b(0[bB][01]+)' },
          { begin: '\\b(0[oO][0-7]+)' },
          { begin: hljs.C_NUMBER_RE }
        ],
        relevance: 0
      },
      { // "value" container
        begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
        keywords: 'return throw case',
        contains: [
          hljs.C_LINE_COMMENT_MODE,
          hljs.C_BLOCK_COMMENT_MODE,
          hljs.REGEXP_MODE
        ],
        relevance: 0
      },
      {
        className: 'function',
        begin: 'function', end: /[\{;]/, excludeEnd: true,
        keywords: KEYWORDS,
        contains: [
          'self',
          hljs.inherit(hljs.TITLE_MODE, {begin: /[A-Za-z$_][0-9A-Za-z$_]*/}),
          {
            className: 'params',
            begin: /\(/, end: /\)/,
            excludeBegin: true,
            excludeEnd: true,
            keywords: KEYWORDS,
            contains: [
              hljs.C_LINE_COMMENT_MODE,
              hljs.C_BLOCK_COMMENT_MODE
            ],
            illegal: /["'\(]/
          }
        ],
        illegal: /\[|%/,
        relevance: 0 // () => {} is more typical in TypeScript
      },
      {
        className: 'constructor',
        beginKeywords: 'constructor', end: /\{/, excludeEnd: true,
        relevance: 10
      },
      {
        className: 'module',
        beginKeywords: 'module', end: /\{/, excludeEnd: true
      },
      {
        className: 'interface',
        beginKeywords: 'interface', end: /\{/, excludeEnd: true,
        keywords: 'interface extends'
      },
      {
        begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`
      },
      {
        begin: '\\.' + hljs.IDENT_RE, relevance: 0 // hack: prevents detection of keywords after dots
      }
    ]
  };
}
<|endoftext|>


<commit_before>L.Control.Permalink = L.Class.extend({
	options: {
		position: L.Control.Position.BOTTOM_LEFT,
		useAnchor: true,
		useMarker: true,
		markerOptions: {},
	},

	initialize: function(layers, options) {
		L.Util.setOptions(this, options);
		this._set_urlvars();
		this._centered = false;
		this._layers = layers;
		this._marker = null;
	},

	onAdd: function(map) {
		this._container = L.DomUtil.create('div', 'leaflet-control-attribution permalink');
		L.DomEvent.disableClickPropagation(this._container);
		map.on('moveend', this._update_center, this);
		map.on('layeradd', this._update_layers, this);
		map.on('layerremove', this._update_layers, this);
		this._map = map;
		this._href = L.DomUtil.create('a', null, this._container);
		this._href.innerHTML = "Permalink";
		this._set_center(this._params);
		this._set_marker(this._params);
		this._update_layers();
		this._update_center();

		if (this.options.useAnchor && 'onhashchange' in window) {
			var _this = this, fn = window.onhashchange;
			window.onhashchange = function() {
				_this._set_urlvars();
				_this._set_center(_this._params, true);
				_this._set_marker(_this._params);
				if (fn) return fn();
			}
		}
	},

	getPosition: function() {
		return this.options.position;
	},

	getContainer: function() {
		return this._container;
	},

	_update_center: function() {
		if (!this._map) return;
		this._update_href();
	},

	_update_href: function() {
	  this.get_params();
		var params = L.Util.getParamString(this._params);
		var sep = '?';
		if (this.options.useAnchor) sep = '#';
		this._href.setAttribute('href', this._url_base + sep + params.slice(1))
	},

	_update_layers: function() {
		if (!this._layers) return;
		this._update_href();
	},

	get_params: function () {
		var center = this._map.getCenter();
		center = this._round_point(center);
		this._params['zoom'] = this._map.getZoom();
		this._params['lat'] = center.lat;
		this._params['lon'] = center.lng;
		var layer = this._layers.currentBaseLayer();
		if (layer) this._params['layer'] = layer.name;
		for(x in osm.map.control_layers._layers) {
		  if (osm.map.control_layers._layers[x].overlay)
		    if (this._map.hasLayer(osm.map.control_layers._layers[x].layer))
		      this._params['layer'] += ',' + osm.map.control_layers._layers[x].name;
		}
	},

	_round_point: function(point) {
		var bounds = this._map.getBounds(), size = this._map.getSize();
		var ne = bounds.getNorthEast(), sw = bounds.getSouthWest();

		var round = function (x, p) {
			if (p == 0) return x;
			shift = 1;
			while (p < 1 && p > -1) {
				x *= 10;
				p *= 10;
				shift *= 10;
			}
			return Math.floor(x)/shift;
		}
		point.lat = round(point.lat, (ne.lat - sw.lat) / size.y);
		point.lng = round(point.lng, (ne.lng - sw.lng) / size.x);
		return point;
	},

	_set_urlvars: function()
	{
		function alter(p) {
			if (!p.mlat || !p.mlon) return p;
			p.lat = p.mlat;
			p.lon = p.mlon;
			p.marker = '1';
			delete p['mlat'];
			delete p['mlon'];
			return p;
		}

		this._url_base = window.location.href.split('#')[0];
		var ph = {};
		if (this.options.useAnchor)
			ph = alter(L.UrlUtil.queryParse(window.location.hash.slice(1)));

		var q = L.UrlUtil.query();
		if (!q) {
			this._params = ph;
			return;
		}

		var pq = alter(L.UrlUtil.queryParse(q));

		if (!this.options.useAnchor) {
			this._url_base = this._url_base.split('?')[0]
			this._params = pq;
			return;
		}

		this._params = ph;
		if (pq.lat && pq.lon && pq.zoom)
			this._params = L.Util.extend({lat: pq.lat, lon: pq.lon, zoom: pq.zoom}, this._params);
		if (pq.layer)
			this._params = L.Util.extend({layer: pq.layer}, this._params);
	},

	_parse_urlvars: function(s) {
		var p = {};
		var params = s.split('&');
		for(var i = 0; i < params.length; i++) {
			var tmp = params[i].split('=');
			if (tmp.length != 2) continue;
			p[tmp[0]] = tmp[1];
		}
		return p;
	},

	_set_center: function(params, force)
	{
		if (!force && this._centered) return;
		if (params.zoom == undefined ||
		    params.lat == undefined ||
		    params.lon == undefined) return;
		this._centered = true;
		this._map.setView(new L.LatLng(params.lat, params.lon), params.zoom);
		if (params.layer && this._layers)
			this._layers.chooseBaseLayer(params.layer);
	},

	_set_marker: function(params)
	{
		if (this._marker)
			this._map.removeLayer(this._marker);
		this._marker = null;
		if (params.marker != '1' || !this._centered || !this.options.useMarker) return;
		this._marker = new L.Marker(new L.LatLng(params.lat, params.lon), this.options.markerOptions);
		this._map.addLayer(this._marker);
	}
});

L.Control.Layers.include({
	chooseBaseLayer: function(name) {
    var obj;
    var layers = new Array();
    var names = name.split(',');
		for (var n in names) {
		  for (var i in this._layers) {
			  if (!this._layers.hasOwnProperty(i))
				  continue;
			  obj = this._layers[i];
			  if (obj.name == names[n])
				  layers.push(obj.layer);
		  }
		}
		if (!layers || !layers.length)
			return;

		for (var i in this._layers) {
			if (!this._layers.hasOwnProperty(i))
				continue;
			obj = this._layers[i];
			if (this._map.hasLayer(obj.layer))
				this._map.removeLayer(obj.layer)
		}
		for (l in layers) {
		  this._map.addLayer(layers[l])
		}
		this._update();
	},

	currentBaseLayer: function() {
		for (var i in this._layers) {
			if (!this._layers.hasOwnProperty(i))
				continue;
			var obj = this._layers[i];
			if (obj.overlay) continue;
			if (!obj.overlay && this._map.hasLayer(obj.layer))
				return obj;
		}
	},
});

L.UrlUtil = {
	queryParse: function(s) {
		var p = {};
		var params = s.split('&');
		for(var i = 0; i < params.length; i++) {
			var tmp = params[i].split('=');
			if (tmp.length != 2) continue;
			p[tmp[0]] = tmp[1];
		}
		return p;
	},

	query: function() {
		var href = window.location.href.split('#')[0], idx = href.indexOf('?');
		if (idx < 0)
			return '';
		return href.slice(idx+1);
	}
};

<commit_msg>оптимизация пермалинка<commit_after>L.Control.Permalink = L.Class.extend({
	options: {
		position: L.Control.Position.BOTTOM_LEFT,
		useAnchor: true,
		useMarker: true,
		markerOptions: {},
	},

	initialize: function(layers, options) {
		L.Util.setOptions(this, options);
		this._set_urlvars();
		this._centered = false;
		this._layers = layers;
		this._marker = null;
	},

	onAdd: function(map) {
		this._container = L.DomUtil.create('div', 'leaflet-control-attribution permalink');
		L.DomEvent.disableClickPropagation(this._container);
		map.on('moveend', this._update_center, this);
		map.on('layeradd', this._update_layers, this);
		map.on('layerremove', this._update_layers, this);
		this._map = map;
		this._href = L.DomUtil.create('a', null, this._container);
		this._href.innerHTML = "Permalink";
		this._set_center(this._params);
		this._set_marker(this._params);
		this._update_layers();
		this._update_center();

		if (this.options.useAnchor && 'onhashchange' in window) {
			var _this = this, fn = window.onhashchange;
			window.onhashchange = function() {
				_this._set_urlvars();
				_this._set_center(_this._params, true);
				_this._set_marker(_this._params);
				if (fn) return fn();
			}
		}
	},

	getPosition: function() {
		return this.options.position;
	},

	getContainer: function() {
		return this._container;
	},

	_update_center: function() {
		if (!this._map) return;
		this._update_href();
	},

	_update_href: function() {
	  this.get_params();
		var params = L.Util.getParamString(this._params);
		var sep = '?';
		if (this.options.useAnchor) sep = '#';
		this._href.setAttribute('href', this._url_base + sep + params.slice(1))
	},

	_update_layers: function() {
		if (!this._layers) return;

		var layer = this._layers.currentBaseLayer();
		if (layer) this._params['layer'] = layer.name;
		for(x in osm.map.control_layers._layers) {
		  if (osm.map.control_layers._layers[x].overlay)
		    if (this._map.hasLayer(osm.map.control_layers._layers[x].layer))
		      this._params['layer'] += ',' + osm.map.control_layers._layers[x].name;
		}
		this._update_href();
	},

	get_params: function () {
		var center = this._map.getCenter();
		center = this._round_point(center);
		this._params['zoom'] = this._map.getZoom();
		this._params['lat'] = center.lat;
		this._params['lon'] = center.lng;
	},

	_round_point: function(point) {
		var bounds = this._map.getBounds(), size = this._map.getSize();
		var ne = bounds.getNorthEast(), sw = bounds.getSouthWest();

		var round = function (x, p) {
			if (p == 0) return x;
			shift = 1;
			while (p < 1 && p > -1) {
				x *= 10;
				p *= 10;
				shift *= 10;
			}
			return Math.floor(x)/shift;
		}
		point.lat = round(point.lat, (ne.lat - sw.lat) / size.y);
		point.lng = round(point.lng, (ne.lng - sw.lng) / size.x);
		return point;
	},

	_set_urlvars: function()
	{
		function alter(p) {
			if (!p.mlat || !p.mlon) return p;
			p.lat = p.mlat;
			p.lon = p.mlon;
			p.marker = '1';
			delete p['mlat'];
			delete p['mlon'];
			return p;
		}

		this._url_base = window.location.href.split('#')[0];
		var ph = {};
		if (this.options.useAnchor)
			ph = alter(L.UrlUtil.queryParse(window.location.hash.slice(1)));

		var q = L.UrlUtil.query();
		if (!q) {
			this._params = ph;
			return;
		}

		var pq = alter(L.UrlUtil.queryParse(q));

		if (!this.options.useAnchor) {
			this._url_base = this._url_base.split('?')[0]
			this._params = pq;
			return;
		}

		this._params = ph;
		if (pq.lat && pq.lon && pq.zoom)
			this._params = L.Util.extend({lat: pq.lat, lon: pq.lon, zoom: pq.zoom}, this._params);
		if (pq.layer)
			this._params = L.Util.extend({layer: pq.layer}, this._params);
	},

	_parse_urlvars: function(s) {
		var p = {};
		var params = s.split('&');
		for(var i = 0; i < params.length; i++) {
			var tmp = params[i].split('=');
			if (tmp.length != 2) continue;
			p[tmp[0]] = tmp[1];
		}
		return p;
	},

	_set_center: function(params, force)
	{
		if (!force && this._centered) return;
		if (params.zoom == undefined ||
		    params.lat == undefined ||
		    params.lon == undefined) return;
		this._centered = true;
		this._map.setView(new L.LatLng(params.lat, params.lon), params.zoom);
		if (params.layer && this._layers)
			this._layers.chooseBaseLayer(params.layer);
	},

	_set_marker: function(params)
	{
		if (this._marker)
			this._map.removeLayer(this._marker);
		this._marker = null;
		if (params.marker != '1' || !this._centered || !this.options.useMarker) return;
		this._marker = new L.Marker(new L.LatLng(params.lat, params.lon), this.options.markerOptions);
		this._map.addLayer(this._marker);
	}
});

L.Control.Layers.include({
	chooseBaseLayer: function(name) {
    var obj;
    var layers = new Array();
    var names = name.split(',');
		for (var n in names) {
		  for (var i in this._layers) {
			  if (!this._layers.hasOwnProperty(i))
				  continue;
			  obj = this._layers[i];
			  if (obj.name == names[n])
				  layers.push(obj.layer);
		  }
		}
		if (!layers || !layers.length)
			return;

		for (var i in this._layers) {
			if (!this._layers.hasOwnProperty(i))
				continue;
			obj = this._layers[i];
			if (this._map.hasLayer(obj.layer))
				this._map.removeLayer(obj.layer)
		}
		for (l in layers) {
		  this._map.addLayer(layers[l])
		}
		this._update();
	},

	currentBaseLayer: function() {
		for (var i in this._layers) {
			if (!this._layers.hasOwnProperty(i))
				continue;
			var obj = this._layers[i];
			if (obj.overlay) continue;
			if (!obj.overlay && this._map.hasLayer(obj.layer))
				return obj;
		}
	},
});

L.UrlUtil = {
	queryParse: function(s) {
		var p = {};
		var params = s.split('&');
		for(var i = 0; i < params.length; i++) {
			var tmp = params[i].split('=');
			if (tmp.length != 2) continue;
			p[tmp[0]] = tmp[1];
		}
		return p;
	},

	query: function() {
		var href = window.location.href.split('#')[0], idx = href.indexOf('?');
		if (idx < 0)
			return '';
		return href.slice(idx+1);
	}
};

<|endoftext|>


<commit_before>function emailFormHandler() {
  var sendEmailBtn = document.getElementById('squatch-send-email');
  var emailInput = document.getElementById('squatch-user-email');

  handleClicks(sendEmailBtn, function() {
    if (!isValidEmail(emailInput.value)) {
      my_addClass(emailInput, 'invalid');
      emailInput.onkeypress = function() {
        if (isValidEmail(this.value)) {
          my_removeClass(this, 'invalid');
          my_addClass(this, 'valid');
        }
      }
    } else {
      my_removeClass(emailInput, 'invalid');

      if (window.frameElement && window.frameElement.squatchJsApi) {
        var widget = window.frameElement.squatchJsApi;

        if (window.parent.squatch && window.parent.squatch.widgets().eventBus) {
          window.parent.squatch.widgets().eventBus.dispatch('submit_email', this, widget, emailInput.value);
        } else {
          window.frameElement.squatchJsApi.reload(emailInput.value);
        }
      }
    }
  });
}

function messengerHandler() {
  var messengerBtn = document.getElementsByClassName('messengerShare')[0];

  if (!messengerBtn) return;

  var messengerUrl = 'https://www.facebook.com/dialog/send?app_id=' + squatch.user.facebook.appId + '&link=' + squatch.user.facebook.link + '&redirect_uri=' + squatch.user.facebook.redirectUrl;
  messengerBtn.href = messengerUrl;

  handleClicks(messengerBtn, function(e) {
    // If it's not mobile, don't use href link
    if (e.type != 'touchstart') {
      e.preventDefault();

      var url = messengerUrl + "&display=popup";
      window.open(url, 'fb-messenger', 'status=0,width=620,height=400');
    }

    if (window.frameElement && window.frameElement.squatchJsApi) {
      window.frameElement.squatchJsApi._shareEvent(window.squatch, 'MESSENGER');
    }
  });
}

function smsHandler() {
  var smsBtn = document.getElementsByClassName('smsShare')[0];

  if (!smsBtn) return;

  // Test url
  var smsUrl = 'sms:?body=Jorge%20Conde%20Gomez%20Llanos%20invited%20you%20to%20join%20Airbnb.%20Sign%20up%20and%20get%20%2450%20CAD%20off%20your%20first%20adventure.%20https%3A%2F%2Fwww.airbnb.ca%2Fc%2Fjorgec263%3Fs%3D46';
  smsBtn.href = smsUrl;
}

function facebookHandler() {
  var facebookBtn = document.getElementsByClassName('fbShare')[0];

  if (!facebookBtn) return;

  var pictureString = (squatch.user.facebook.shareImage == "" || squatch.user.facebook.shareImage === null) ? "" : "&picture="+squatch.user.facebook.shareImage;
  var fbUrl = "https://www.facebook.com/dialog/feed?app_id=" + squatch.user.facebook.appId + "&link=" + squatch.user.facebook.link + "&name=" + squatch.user.facebook.title + "&description=" + squatch.user.facebook.summary + pictureString+ "&redirect_uri=" + squatch.user.facebook.redirectUrl;
  facebookBtn.href = fbUrl;

  handleClicks(facebookBtn, function(e) {
    // If it's not mobile, don't use href link
    if (e.type != 'touchstart') {
      e.preventDefault();

      var url = fbUrl + "&display=popup";
      window.open(url, 'fb', 'status=0,width=620,height=400');
    }

    if (window.frameElement && window.frameElement.squatchJsApi) {
      window.frameElement.squatchJsApi._shareEvent(window.squatch, 'FACEBOOK');
    }
  });
}

function twitterHandler() {
  var twitterBtn = document.getElementsByClassName('twShare')[0];
  var twUrl = "https://twitter.com/intent/tweet?source=webclient&text=" + squatch.user.twitter.message;

  if (!twitterBtn) return;
  twitterBtn.href = twUrl;

  handleClicks(twitterBtn, function(e) {
    if (e.type != 'touchstart') {
      e.preventDefault();
      window.open(twUrl, 'twitter', 'status=1,width=575,height=400');
    }

    if (window.frameElement && window.frameElement.squatchJsApi) {
      window.frameElement.squatchJsApi._shareEvent(window.squatch, 'TWITTER');
    }
  });
}

function emailHandler() {
  var emailBtn = document.getElementsByClassName('emailShare')[0];
  var emailUrl = squatch.user.email.share.mailToLink;

  if(!emailBtn) return;
  // emailBtn.href = emailUrl;

  var md = new MobileDetect('Version/4.0 Mobile Safari/534.30');
  var UA = md.userAgent();

  emailBtn.href = emailUrl;

  if (UA === 'Safari') {
    emailBtn.target = '_parent';
  } else {
    handleClicks(emailBtn, function(e) {
      if (e.type != 'touchstart') {
        e.preventDefault();

        var mailurl = emailUrl;
        mailTo(mailurl);
      }

      if (window.frameElement && window.frameElement.squatchJsApi) {
        window.frameElement.squatchJsApi._shareEvent(window.squatch, 'EMAIL');
      }
    });
  }
}
<commit_msg>JC - try another sms url<commit_after>function emailFormHandler() {
  var sendEmailBtn = document.getElementById('squatch-send-email');
  var emailInput = document.getElementById('squatch-user-email');

  handleClicks(sendEmailBtn, function() {
    if (!isValidEmail(emailInput.value)) {
      my_addClass(emailInput, 'invalid');
      emailInput.onkeypress = function() {
        if (isValidEmail(this.value)) {
          my_removeClass(this, 'invalid');
          my_addClass(this, 'valid');
        }
      }
    } else {
      my_removeClass(emailInput, 'invalid');

      if (window.frameElement && window.frameElement.squatchJsApi) {
        var widget = window.frameElement.squatchJsApi;

        if (window.parent.squatch && window.parent.squatch.widgets().eventBus) {
          window.parent.squatch.widgets().eventBus.dispatch('submit_email', this, widget, emailInput.value);
        } else {
          window.frameElement.squatchJsApi.reload(emailInput.value);
        }
      }
    }
  });
}

function messengerHandler() {
  var messengerBtn = document.getElementsByClassName('messengerShare')[0];

  if (!messengerBtn) return;

  var messengerUrl = 'https://www.facebook.com/dialog/send?app_id=' + squatch.user.facebook.appId + '&link=' + squatch.user.facebook.link + '&redirect_uri=' + squatch.user.facebook.redirectUrl;
  messengerBtn.href = messengerUrl;

  handleClicks(messengerBtn, function(e) {
    // If it's not mobile, don't use href link
    if (e.type != 'touchstart') {
      e.preventDefault();

      var url = messengerUrl + "&display=popup";
      window.open(url, 'fb-messenger', 'status=0,width=620,height=400');
    }

    if (window.frameElement && window.frameElement.squatchJsApi) {
      window.frameElement.squatchJsApi._shareEvent(window.squatch, 'MESSENGER');
    }
  });
}

function smsHandler() {
  var smsBtn = document.getElementsByClassName('smsShare')[0];

  if (!smsBtn) return;

  // Test url
  var smsUrl = 'sms:?body=Testbody';
  smsBtn.href = smsUrl;
}

function facebookHandler() {
  var facebookBtn = document.getElementsByClassName('fbShare')[0];

  if (!facebookBtn) return;

  var pictureString = (squatch.user.facebook.shareImage == "" || squatch.user.facebook.shareImage === null) ? "" : "&picture="+squatch.user.facebook.shareImage;
  var fbUrl = "https://www.facebook.com/dialog/feed?app_id=" + squatch.user.facebook.appId + "&link=" + squatch.user.facebook.link + "&name=" + squatch.user.facebook.title + "&description=" + squatch.user.facebook.summary + pictureString+ "&redirect_uri=" + squatch.user.facebook.redirectUrl;
  facebookBtn.href = fbUrl;

  handleClicks(facebookBtn, function(e) {
    // If it's not mobile, don't use href link
    if (e.type != 'touchstart') {
      e.preventDefault();

      var url = fbUrl + "&display=popup";
      window.open(url, 'fb', 'status=0,width=620,height=400');
    }

    if (window.frameElement && window.frameElement.squatchJsApi) {
      window.frameElement.squatchJsApi._shareEvent(window.squatch, 'FACEBOOK');
    }
  });
}

function twitterHandler() {
  var twitterBtn = document.getElementsByClassName('twShare')[0];
  var twUrl = "https://twitter.com/intent/tweet?source=webclient&text=" + squatch.user.twitter.message;

  if (!twitterBtn) return;
  twitterBtn.href = twUrl;

  handleClicks(twitterBtn, function(e) {
    if (e.type != 'touchstart') {
      e.preventDefault();
      window.open(twUrl, 'twitter', 'status=1,width=575,height=400');
    }

    if (window.frameElement && window.frameElement.squatchJsApi) {
      window.frameElement.squatchJsApi._shareEvent(window.squatch, 'TWITTER');
    }
  });
}

function emailHandler() {
  var emailBtn = document.getElementsByClassName('emailShare')[0];
  var emailUrl = squatch.user.email.share.mailToLink;

  if(!emailBtn) return;
  // emailBtn.href = emailUrl;

  var md = new MobileDetect('Version/4.0 Mobile Safari/534.30');
  var UA = md.userAgent();

  emailBtn.href = emailUrl;

  if (UA === 'Safari') {
    emailBtn.target = '_parent';
  } else {
    handleClicks(emailBtn, function(e) {
      if (e.type != 'touchstart') {
        e.preventDefault();

        var mailurl = emailUrl;
        mailTo(mailurl);
      }

      if (window.frameElement && window.frameElement.squatchJsApi) {
        window.frameElement.squatchJsApi._shareEvent(window.squatch, 'EMAIL');
      }
    });
  }
}
<|endoftext|>


<commit_before>var querystring = require('querystring');
var request = require('./request');

var VERSION = '0.1.2';
var _host = 'musicbrainz.org';
var _path = '/ws/2/';
var _limit = 25;
var _userAgent = 'nodebrainz/' + VERSION + ' ( https://github.com/jbraithwaite/nodebrainz/ )';

/**
 * Initialize Nodebrainz
 *
 * The configuration:
 * - host: custom host for querying data
 * - basePath: custom path to the data
 * - defaultLimit: default limit on request that require it
 * - userAgent: User agent sent in the request
 *
 * @param {Object} options The application configuration
 */
function BaseNodeBrainz(options) {

  options = options || {};

  this.host = options.host || _host;
  this.basePath = options.basePath || _path;
  this.limit = options.defaultLimit || _limit;
  this.userAgent = options.userAgent || _userAgent;
}

/**
 * Search
 *
 * Provides a way to search for entities. Behind the scenes, results are provided by a search server using Lucene technology.
 * Note there are different search fields depending on the entity.
 *
 * http://musicbrainz.org/doc/Development/XML_Web_Service/Version_2/Search
 *
 * @param {String} type The type of search (e.g. 'artist', 'releasegroup', 'release', 'recording', etc)
 * @param {Object} searchFields What to search for (e.g. {artist:'tool'})
 * @param {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.search = function(type, searchFields, callback){

  var query = '';
  var limit = this.limit;
  var offset = 0;
  var and = '';

  searchFields = searchFields || {};

  // See if the limit has been included in the search fields
  if (searchFields.hasOwnProperty('limit')){
    // Set the limit
    limit = searchFields.limit;
    // Delete it from search fields
    delete searchFields.limit;
  }

  // See if offset has been included in the search fields
  if (searchFields.hasOwnProperty('offset')){
    // Set the offset
    offset = searchFields.offset;
    // Delete it from search fields
    delete searchFields.offset;
  }

  // Set the query
  // https://lucene.apache.org/core/4_3_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description
  for (var key in searchFields){
    query += and + key + ':' + '"'+ encodeURIComponent(searchFields[key]) +'"';
    and = '%20AND%20';
  }

  // Set the path
  this.path = this.basePath + type + '/?query=' + query + '&limit=' + limit + '&offset=' + offset + '&fmt=json';

  request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * Lucene Search
 *
 * Direct access to the Lucene search query
 *
 * https://lucene.apache.org/core/4_3_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description
 *
 * @param  {String} type Entity type
 * @param  {Oject} data {query:'something AND something'}
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.luceneSearch = function(type, data, callback){

  var limit = this.limit;
  var offset = 0;
  var query = '';

  data = data || {};

  if (!data.hasOwnProperty('query')) return callback({error: 'Missing query'});

  // Encode the query
  query = encodeURIComponent(data.query);

  // See if the limit has been included in the search fields
  if (data.hasOwnProperty('limit')){
    // Set the limit
    limit = data.limit;
  }

  // See if offset has been included in the search fields
  if (data.hasOwnProperty('offset')){
    // Set the offset
    offset = data.offset;
  }

  // Set the path
  this.path = this.basePath + type + '/?query=' + query + '&limit=' + limit + '&offset=' + offset + '&fmt=json';

  request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * NodeBrainsBrowse
 *
 * Browse requests are a direct lookup of all the entities directly linked to another entity.
 * Browsed entities are always ordered alphabetically by gid. If you need to sort the entities,
 * you will have to fetch all entities and sort them yourself. For pagination, set a limit and offset.
 * Note that browse requests are not searches, in order to browse all the releases-groups for an artist,
 * you need to provide the MBID for the artist.
 *
 * http://musicbrainz.org/doc/Development/XML_Web_Service/Version_2/#Browse
 *
 * @param {String} type The type of search (e.g. 'artist', 'releasegroup', 'release', 'recording', etc)
 * @param {Object} data What to filter by and include
 * @param {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.browse = function(type, data, callback){

  var query = {};
  var inc = '';

  data = data || {};

  // JSON response
  query.fmt = 'json';

  // Include
  if (data.hasOwnProperty('inc')){
    // Can't pass this to the querystring object because it turns '+' into '%2B'
    inc = '&inc=' + data.inc;

    // Remove the include
    delete data.inc;
  }

  // Everything else (e.g. limit, offset, type, status)
  for (var key in data){
    query[key] = data[key];
  }

  // Make the query string;
  query = querystring.stringify(query);

  // Set the path
  this.path = this.basePath + type + '?' + query + inc;

  request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * NodeBrainsLookup
 *
 * http://musicbrainz.org/doc/Development/XML_Web_Service/Version_2/#Lookups
 *
 * @param {String} type The type of search (e.g. 'artist', 'releasegroup', 'release', 'recording', etc)
 * @param {String} mbid The id for the type
 * @param {Object} data The lookup criteria
 * @param {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype._lookup = function(type, mbid, data, callback){

  data = data || {};

  // You are allowed to not include data
  if (typeof data == 'function'){
    callback = data;
    data = {};
  }

  if (!mbid) return callback({error: 'Missing mbid'});

  var query = {};
  var inc = '';

  data = data || {};

  // JSON response
  query.fmt = 'json';

  // Include
  if (data.hasOwnProperty('inc')){
    // Can't pass this to the querystring object because it turns '+' into '%2B'
    inc = '&inc=' + data.inc;

    // Remove the include
    delete data.inc;
  }

  // Everything else (e.g. limit, offset, type, status)
  for (var key in data){
    query[key] = data[key];
  }

  // Make the query string;
  query = querystring.stringify(query);

  // Set the path
  this.path = this.basePath + type + '/' + mbid + '?' + query + inc;

  request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * Artist Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.artist = function(mbid, data, callback){
  this._lookup('artist', mbid, data, callback);
};

/**
 * Release Group Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.releaseGroup = function(mbid, data, callback){
  this._lookup('release-group', mbid, data, callback);
};

/**
 * Release Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.release = function(mbid, data, callback){
  this._lookup('release', mbid, data, callback);
};

/**
 * Recording Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.recording = function(mbid, data, callback){
  this._lookup('recording', mbid, data, callback);
};

/**
 * Work Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.work = function(mbid, data, callback){
  this._lookup('work', mbid, data, callback);
};

/**
 * Label Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.label = function(mbid, data, callback){
  this._lookup('label', mbid, data, callback);
};

/**
 * Area Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.area = function(mbid, data, callback){
  this._lookup('area', mbid, data, callback);
};

/**
 * URL Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.url = function(mbid, data, callback){
  this._lookup('url', mbid, data, callback);
};

module.exports = BaseNodeBrainz;
<commit_msg>Prototype request<commit_after>var querystring = require('querystring');
var request = require('./request');

var VERSION = '0.1.2';
var _host = 'musicbrainz.org';
var _path = '/ws/2/';
var _limit = 25;
var _userAgent = 'nodebrainz/' + VERSION + ' ( https://github.com/jbraithwaite/nodebrainz/ )';

/**
 * Initialize Nodebrainz
 *
 * The configuration:
 * - host: custom host for querying data
 * - basePath: custom path to the data
 * - defaultLimit: default limit on request that require it
 * - userAgent: User agent sent in the request
 *
 * @param {Object} options The application configuration
 */
function BaseNodeBrainz(options) {

  options = options || {};

  this.host = options.host || _host;
  this.basePath = options.basePath || _path;
  this.limit = options.defaultLimit || _limit;
  this.userAgent = options.userAgent || _userAgent;
}

BaseNodeBrainz.prototype.request = request;

/**
 * Search
 *
 * Provides a way to search for entities. Behind the scenes, results are provided by a search server using Lucene technology.
 * Note there are different search fields depending on the entity.
 *
 * http://musicbrainz.org/doc/Development/XML_Web_Service/Version_2/Search
 *
 * @param {String} type The type of search (e.g. 'artist', 'releasegroup', 'release', 'recording', etc)
 * @param {Object} searchFields What to search for (e.g. {artist:'tool'})
 * @param {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.search = function(type, searchFields, callback){

  var query = '';
  var limit = this.limit;
  var offset = 0;
  var and = '';

  searchFields = searchFields || {};

  // See if the limit has been included in the search fields
  if (searchFields.hasOwnProperty('limit')){
    // Set the limit
    limit = searchFields.limit;
    // Delete it from search fields
    delete searchFields.limit;
  }

  // See if offset has been included in the search fields
  if (searchFields.hasOwnProperty('offset')){
    // Set the offset
    offset = searchFields.offset;
    // Delete it from search fields
    delete searchFields.offset;
  }

  // Set the query
  // https://lucene.apache.org/core/4_3_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description
  for (var key in searchFields){
    query += and + key + ':' + '"'+ encodeURIComponent(searchFields[key]) +'"';
    and = '%20AND%20';
  }

  // Set the path
  this.path = this.basePath + type + '/?query=' + query + '&limit=' + limit + '&offset=' + offset + '&fmt=json';

  this.request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * Lucene Search
 *
 * Direct access to the Lucene search query
 *
 * https://lucene.apache.org/core/4_3_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description
 *
 * @param  {String} type Entity type
 * @param  {Oject} data {query:'something AND something'}
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.luceneSearch = function(type, data, callback){

  var limit = this.limit;
  var offset = 0;
  var query = '';

  data = data || {};

  if (!data.hasOwnProperty('query')) return callback({error: 'Missing query'});

  // Encode the query
  query = encodeURIComponent(data.query);

  // See if the limit has been included in the search fields
  if (data.hasOwnProperty('limit')){
    // Set the limit
    limit = data.limit;
  }

  // See if offset has been included in the search fields
  if (data.hasOwnProperty('offset')){
    // Set the offset
    offset = data.offset;
  }

  // Set the path
  this.path = this.basePath + type + '/?query=' + query + '&limit=' + limit + '&offset=' + offset + '&fmt=json';

  this.request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * NodeBrainsBrowse
 *
 * Browse requests are a direct lookup of all the entities directly linked to another entity.
 * Browsed entities are always ordered alphabetically by gid. If you need to sort the entities,
 * you will have to fetch all entities and sort them yourself. For pagination, set a limit and offset.
 * Note that browse requests are not searches, in order to browse all the releases-groups for an artist,
 * you need to provide the MBID for the artist.
 *
 * http://musicbrainz.org/doc/Development/XML_Web_Service/Version_2/#Browse
 *
 * @param {String} type The type of search (e.g. 'artist', 'releasegroup', 'release', 'recording', etc)
 * @param {Object} data What to filter by and include
 * @param {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.browse = function(type, data, callback){

  var query = {};
  var inc = '';

  data = data || {};

  // JSON response
  query.fmt = 'json';

  // Include
  if (data.hasOwnProperty('inc')){
    // Can't pass this to the querystring object because it turns '+' into '%2B'
    inc = '&inc=' + data.inc;

    // Remove the include
    delete data.inc;
  }

  // Everything else (e.g. limit, offset, type, status)
  for (var key in data){
    query[key] = data[key];
  }

  // Make the query string;
  query = querystring.stringify(query);

  // Set the path
  this.path = this.basePath + type + '?' + query + inc;

  this.request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * NodeBrainsLookup
 *
 * http://musicbrainz.org/doc/Development/XML_Web_Service/Version_2/#Lookups
 *
 * @param {String} type The type of search (e.g. 'artist', 'releasegroup', 'release', 'recording', etc)
 * @param {String} mbid The id for the type
 * @param {Object} data The lookup criteria
 * @param {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype._lookup = function(type, mbid, data, callback){

  data = data || {};

  // You are allowed to not include data
  if (typeof data == 'function'){
    callback = data;
    data = {};
  }

  if (!mbid) return callback({error: 'Missing mbid'});

  var query = {};
  var inc = '';

  data = data || {};

  // JSON response
  query.fmt = 'json';

  // Include
  if (data.hasOwnProperty('inc')){
    // Can't pass this to the querystring object because it turns '+' into '%2B'
    inc = '&inc=' + data.inc;

    // Remove the include
    delete data.inc;
  }

  // Everything else (e.g. limit, offset, type, status)
  for (var key in data){
    query[key] = data[key];
  }

  // Make the query string;
  query = querystring.stringify(query);

  // Set the path
  this.path = this.basePath + type + '/' + mbid + '?' + query + inc;

  this.request({
    host: this.host,
    path: this.path,
    userAgent: this.userAgent
  }, callback);
};

/**
 * Artist Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.artist = function(mbid, data, callback){
  this._lookup('artist', mbid, data, callback);
};

/**
 * Release Group Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.releaseGroup = function(mbid, data, callback){
  this._lookup('release-group', mbid, data, callback);
};

/**
 * Release Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.release = function(mbid, data, callback){
  this._lookup('release', mbid, data, callback);
};

/**
 * Recording Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.recording = function(mbid, data, callback){
  this._lookup('recording', mbid, data, callback);
};

/**
 * Work Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.work = function(mbid, data, callback){
  this._lookup('work', mbid, data, callback);
};

/**
 * Label Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.label = function(mbid, data, callback){
  this._lookup('label', mbid, data, callback);
};

/**
 * Area Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.area = function(mbid, data, callback){
  this._lookup('area', mbid, data, callback);
};

/**
 * URL Lookup
 *
 * @param  {String} mbid MusicBrainz ID
 * @param  {Object} data Filtering and subqueries information
 * @param  {Function} callback function(err, response)
 */
BaseNodeBrainz.prototype.url = function(mbid, data, callback){
  this._lookup('url', mbid, data, callback);
};

module.exports = BaseNodeBrainz;
<|endoftext|>


<commit_before>/*
 * L.TileLayer is used for standard xyz-numbered tile layers.
 */

L.TileLayer = L.Class.extend({
	includes: L.Mixin.Events,

	options: {
		minZoom: 0,
		maxZoom: 18,
		tileSize: 256,
		subdomains: 'abc',
		errorTileUrl: '',
		attribution: '',
		opacity: 1,
		scheme: 'xyz',
		continuousWorld: false,
		noWrap: false,
		zoomOffset: 0,
		zoomReverse: false,

		unloadInvisibleTiles: L.Browser.mobile,
		updateWhenIdle: L.Browser.mobile
	},

	initialize: function (url, options, urlParams) {
		L.Util.setOptions(this, options);

		this._url = url;
		this._urlParams = urlParams;

		if (typeof this.options.subdomains === 'string') {
			this.options.subdomains = this.options.subdomains.split('');
		}
	},

	onAdd: function (map, insertAtTheBottom) {
		this._map = map;
		this._insertAtTheBottom = insertAtTheBottom;

		// create a container div for tiles
		this._initContainer();

		// create an image to clone for tiles
		this._createTileProto();

		// set up events
		map.on('viewreset', this._resetCallback, this);

		if (this.options.updateWhenIdle) {
			map.on('moveend', this._update, this);
		} else {
			this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
			map.on('move', this._limitedUpdate, this);
		}

		this._reset();
		this._update();
	},

	onRemove: function (map) {
		this._map.getPanes().tilePane.removeChild(this._container);
		this._container = null;

		this._map.off('viewreset', this._resetCallback, this);

		if (this.options.updateWhenIdle) {
			this._map.off('moveend', this._update, this);
		} else {
			this._map.off('move', this._limitedUpdate, this);
		}
	},

	getAttribution: function () {
		return this.options.attribution;
	},

	setOpacity: function (opacity) {
		this.options.opacity = opacity;

		this._setOpacity(opacity);

		// stupid webkit hack to force redrawing of tiles
		if (L.Browser.webkit) {
			for (var i in this._tiles) {
				if (this._tiles.hasOwnProperty(i)) {
					this._tiles[i].style.webkitTransform += ' translate(0,0)';
				}
			}
		}
	},

	_setOpacity: function (opacity) {
		if (opacity < 1) {
			L.DomUtil.setOpacity(this._container, opacity);
		}
	},

	_initContainer: function () {
		var tilePane = this._map.getPanes().tilePane,
			first = tilePane.firstChild;

		if (!this._container || tilePane.empty) {
			this._container = L.DomUtil.create('div', 'leaflet-layer');

			if (this._insertAtTheBottom && first) {
				tilePane.insertBefore(this._container, first);
			} else {
				tilePane.appendChild(this._container);
			}

			this._setOpacity(this.options.opacity);
		}
	},

	_resetCallback: function (e) {
		this._reset(e.hard);
	},

	_reset: function (clearOldContainer) {
		var key;
		for (key in this._tiles) {
			if (this._tiles.hasOwnProperty(key)) {
				this.fire("tileunload", {tile: this._tiles[key]});
			}
		}
		this._tiles = {};

		if (this.options.reuseTiles) {
			this._unusedTiles = [];
		}

		if (clearOldContainer && this._container) {
			this._container.innerHTML = "";
		}
		this._initContainer();
	},

	_update: function () {
		var bounds = this._map.getPixelBounds(),
			tileSize = this.options.tileSize;

		var nwTilePoint = new L.Point(
				Math.floor(bounds.min.x / tileSize),
				Math.floor(bounds.min.y / tileSize)),
			seTilePoint = new L.Point(
				Math.floor(bounds.max.x / tileSize),
				Math.floor(bounds.max.y / tileSize)),
			tileBounds = new L.Bounds(nwTilePoint, seTilePoint);

		this._addTilesFromCenterOut(tileBounds);

		if (this.options.unloadInvisibleTiles ||
			this.options.reuseTiles) {
			this._removeOtherTiles(tileBounds);
		}
	},

	_addTilesFromCenterOut: function (bounds) {
		var queue = [],
			center = bounds.getCenter();

		for (var j = bounds.min.y; j <= bounds.max.y; j++) {
			for (var i = bounds.min.x; i <= bounds.max.x; i++) {
				if ((i + ':' + j) in this._tiles) {
					continue;
				}
				queue.push(new L.Point(i, j));
			}
		}

		// load tiles in order of their distance to center
		queue.sort(function (a, b) {
			return a.distanceTo(center) - b.distanceTo(center);
		});

		var fragment = document.createDocumentFragment();

		this._tilesToLoad = queue.length;
		for (var k = 0, len = this._tilesToLoad; k < len; k++) {
			this._addTile(queue[k], fragment);
		}

		this._container.appendChild(fragment);
	},

	_removeOtherTiles: function (bounds) {
		var kArr, x, y, key, tile;

		for (key in this._tiles) {
			if (this._tiles.hasOwnProperty(key)) {
				kArr = key.split(':');
				x = parseInt(kArr[0], 10);
				y = parseInt(kArr[1], 10);

				// remove tile if it's out of bounds
				if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {

					tile = this._tiles[key];
					this.fire("tileunload", {tile: tile, url: tile.src});

					// evil, don't do this! crashes Android 3, produces load errors, doesn't solve memory leaks
					// this._tiles[key].src = '';

					if (tile.parentNode === this._container) {
						this._container.removeChild(tile);
					}
					if (this.options.reuseTiles) {
						this._unusedTiles.push(this._tiles[key]);
					}
					delete this._tiles[key];
				}
			}
		}
	},

	_addTile: function (tilePoint, container) {
		var tilePos = this._getTilePos(tilePoint),
			zoom = this._map.getZoom(),
			key = tilePoint.x + ':' + tilePoint.y,
			tileLimit = Math.pow(2, this._getOffsetZoom(zoom));

		// wrap tile coordinates
		if (!this.options.continuousWorld) {
			if (!this.options.noWrap) {
				tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit;
			} else if (tilePoint.x < 0 || tilePoint.x >= tileLimit) {
				this._tilesToLoad--;
				return;
			}

			if (tilePoint.y < 0 || tilePoint.y >= tileLimit) {
				this._tilesToLoad--;
				return;
			}
		}

		// get unused tile - or create a new tile
		var tile = this._getTile();
		L.DomUtil.setPosition(tile, tilePos);

		this._tiles[key] = tile;

		if (this.options.scheme === 'tms') {
			tilePoint.y = tileLimit - tilePoint.y - 1;
		}

		this._loadTile(tile, tilePoint, zoom);

		container.appendChild(tile);
	},

	_getOffsetZoom: function (zoom) {
		zoom = this.options.zoomReverse ? this.options.maxZoom - zoom : zoom;
		return zoom + this.options.zoomOffset;
	},

	_getTilePos: function (tilePoint) {
		var origin = this._map.getPixelOrigin(),
			tileSize = this.options.tileSize;

		return tilePoint.multiplyBy(tileSize).subtract(origin);
	},

	// image-specific code (override to implement e.g. Canvas or SVG tile layer)

	getTileUrl: function (tilePoint, zoom) {
		var subdomains = this.options.subdomains,
			s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];

		return L.Util.template(this._url, L.Util.extend({
			s: s,
			z: this._getOffsetZoom(zoom),
			x: tilePoint.x,
			y: tilePoint.y
		}, this._urlParams));
	},

	_createTileProto: function () {
		this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
		this._tileImg.galleryimg = 'no';

		var tileSize = this.options.tileSize;
		this._tileImg.style.width = tileSize + 'px';
		this._tileImg.style.height = tileSize + 'px';
	},

	_getTile: function () {
		if (this.options.reuseTiles && this._unusedTiles.length > 0) {
			var tile = this._unusedTiles.pop();
			this._resetTile(tile);
			return tile;
		}
		return this._createTile();
	},

	_resetTile: function (tile) {
		// Override if data stored on a tile needs to be cleaned up before reuse
	},

	_createTile: function () {
		var tile = this._tileImg.cloneNode(false);
		tile.onselectstart = tile.onmousemove = L.Util.falseFn;
		return tile;
	},

	_loadTile: function (tile, tilePoint, zoom) {
		tile._layer = this;
		tile.onload = this._tileOnLoad;
		tile.onerror = this._tileOnError;
		tile.src = this.getTileUrl(tilePoint, zoom);
	},

	_tileOnLoad: function (e) {
		var layer = this._layer;

		this.className += ' leaflet-tile-loaded';

		layer.fire('tileload', {tile: this, url: this.src});

		layer._tilesToLoad--;
		if (!layer._tilesToLoad) {
			layer.fire('load');
		}
	},

	_tileOnError: function (e) {
		var layer = this._layer;

		layer.fire('tileerror', {tile: this, url: this.src});

		var newUrl = layer.options.errorTileUrl;
		if (newUrl) {
			this.src = newUrl;
		}
	}
});
<commit_msg>minor TileLayer edits<commit_after>/*
 * L.TileLayer is used for standard xyz-numbered tile layers.
 */

L.TileLayer = L.Class.extend({
	includes: L.Mixin.Events,

	options: {
		minZoom: 0,
		maxZoom: 18,
		tileSize: 256,
		subdomains: 'abc',
		errorTileUrl: '',
		attribution: '',
		opacity: 1,
		scheme: 'xyz',
		continuousWorld: false,
		noWrap: false,
		zoomOffset: 0,
		zoomReverse: false,

		unloadInvisibleTiles: L.Browser.mobile,
		updateWhenIdle: L.Browser.mobile,
		reuseTiles: false
	},

	initialize: function (url, options, urlParams) {
		L.Util.setOptions(this, options);

		this._url = url;
		this._urlParams = urlParams;

		if (typeof this.options.subdomains === 'string') {
			this.options.subdomains = this.options.subdomains.split('');
		}
	},

	onAdd: function (map, insertAtTheBottom) {
		this._map = map;
		this._insertAtTheBottom = insertAtTheBottom;

		// create a container div for tiles
		this._initContainer();

		// create an image to clone for tiles
		this._createTileProto();

		// set up events
		map.on('viewreset', this._resetCallback, this);

		if (this.options.updateWhenIdle) {
			map.on('moveend', this._update, this);
		} else {
			this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
			map.on('move', this._limitedUpdate, this);
		}

		this._reset();
		this._update();
	},

	onRemove: function (map) {
		this._map.getPanes().tilePane.removeChild(this._container);
		this._container = null;

		this._map.off('viewreset', this._resetCallback, this);

		if (this.options.updateWhenIdle) {
			this._map.off('moveend', this._update, this);
		} else {
			this._map.off('move', this._limitedUpdate, this);
		}
	},

	getAttribution: function () {
		return this.options.attribution;
	},

	setOpacity: function (opacity) {
		this.options.opacity = opacity;

		this._setOpacity(opacity);

		// stupid webkit hack to force redrawing of tiles
		if (L.Browser.webkit) {
			for (var i in this._tiles) {
				if (this._tiles.hasOwnProperty(i)) {
					this._tiles[i].style.webkitTransform += ' translate(0,0)';
				}
			}
		}
	},

	_setOpacity: function (opacity) {
		if (opacity < 1) {
			L.DomUtil.setOpacity(this._container, opacity);
		}
	},

	_initContainer: function () {
		var tilePane = this._map.getPanes().tilePane,
			first = tilePane.firstChild;

		if (!this._container || tilePane.empty) {
			this._container = L.DomUtil.create('div', 'leaflet-layer');

			if (this._insertAtTheBottom && first) {
				tilePane.insertBefore(this._container, first);
			} else {
				tilePane.appendChild(this._container);
			}

			this._setOpacity(this.options.opacity);
		}
	},

	_resetCallback: function (e) {
		this._reset(e.hard);
	},

	_reset: function (clearOldContainer) {
		var key;
		for (key in this._tiles) {
			if (this._tiles.hasOwnProperty(key)) {
				this.fire("tileunload", {tile: this._tiles[key]});
			}
		}
		this._tiles = {};

		if (this.options.reuseTiles) {
			this._unusedTiles = [];
		}

		if (clearOldContainer && this._container) {
			this._container.innerHTML = "";
		}
		this._initContainer();
	},

	_update: function () {
		var bounds = this._map.getPixelBounds(),
			tileSize = this.options.tileSize;

		var nwTilePoint = new L.Point(
				Math.floor(bounds.min.x / tileSize),
				Math.floor(bounds.min.y / tileSize)),
			seTilePoint = new L.Point(
				Math.floor(bounds.max.x / tileSize),
				Math.floor(bounds.max.y / tileSize)),
			tileBounds = new L.Bounds(nwTilePoint, seTilePoint);

		this._addTilesFromCenterOut(tileBounds);

		if (this.options.unloadInvisibleTiles || this.options.reuseTiles) {
			this._removeOtherTiles(tileBounds);
		}
	},

	_addTilesFromCenterOut: function (bounds) {
		var queue = [],
			center = bounds.getCenter();

		for (var j = bounds.min.y; j <= bounds.max.y; j++) {
			for (var i = bounds.min.x; i <= bounds.max.x; i++) {
				if ((i + ':' + j) in this._tiles) {
					continue;
				}
				queue.push(new L.Point(i, j));
			}
		}

		// load tiles in order of their distance to center
		queue.sort(function (a, b) {
			return a.distanceTo(center) - b.distanceTo(center);
		});

		var fragment = document.createDocumentFragment();

		this._tilesToLoad = queue.length;
		for (var k = 0, len = this._tilesToLoad; k < len; k++) {
			this._addTile(queue[k], fragment);
		}

		this._container.appendChild(fragment);
	},

	_removeOtherTiles: function (bounds) {
		var kArr, x, y, key, tile;

		for (key in this._tiles) {
			if (this._tiles.hasOwnProperty(key)) {
				kArr = key.split(':');
				x = parseInt(kArr[0], 10);
				y = parseInt(kArr[1], 10);

				// remove tile if it's out of bounds
				if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {

					tile = this._tiles[key];
					this.fire("tileunload", {tile: tile, url: tile.src});

					// evil, don't do this! crashes Android 3, produces load errors, doesn't solve memory leaks
					// this._tiles[key].src = '';

					//tile.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';

					if (tile.parentNode === this._container) {
						this._container.removeChild(tile);
					}
					if (this.options.reuseTiles) {
						this._unusedTiles.push(this._tiles[key]);
					}
					delete this._tiles[key];
				}
			}
		}
	},

	_addTile: function (tilePoint, container) {
		var tilePos = this._getTilePos(tilePoint),
			zoom = this._map.getZoom(),
			key = tilePoint.x + ':' + tilePoint.y,
			tileLimit = Math.pow(2, this._getOffsetZoom(zoom));

		// wrap tile coordinates
		if (!this.options.continuousWorld) {
			if (!this.options.noWrap) {
				tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit;
			} else if (tilePoint.x < 0 || tilePoint.x >= tileLimit) {
				this._tilesToLoad--;
				return;
			}

			if (tilePoint.y < 0 || tilePoint.y >= tileLimit) {
				this._tilesToLoad--;
				return;
			}
		}

		// get unused tile - or create a new tile
		var tile = this._getTile();
		L.DomUtil.setPosition(tile, tilePos);

		this._tiles[key] = tile;

		if (this.options.scheme === 'tms') {
			tilePoint.y = tileLimit - tilePoint.y - 1;
		}

		this._loadTile(tile, tilePoint, zoom);

		container.appendChild(tile);
	},

	_getOffsetZoom: function (zoom) {
		zoom = this.options.zoomReverse ? this.options.maxZoom - zoom : zoom;
		return zoom + this.options.zoomOffset;
	},

	_getTilePos: function (tilePoint) {
		var origin = this._map.getPixelOrigin(),
			tileSize = this.options.tileSize;

		return tilePoint.multiplyBy(tileSize).subtract(origin);
	},

	// image-specific code (override to implement e.g. Canvas or SVG tile layer)

	getTileUrl: function (tilePoint, zoom) {
		var subdomains = this.options.subdomains,
			s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];

		return L.Util.template(this._url, L.Util.extend({
			s: s,
			z: this._getOffsetZoom(zoom),
			x: tilePoint.x,
			y: tilePoint.y
		}, this._urlParams));
	},

	_createTileProto: function () {
		this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
		this._tileImg.galleryimg = 'no';

		var tileSize = this.options.tileSize;
		this._tileImg.style.width = tileSize + 'px';
		this._tileImg.style.height = tileSize + 'px';
	},

	_getTile: function () {
		if (this.options.reuseTiles && this._unusedTiles.length > 0) {
			var tile = this._unusedTiles.pop();
			this._resetTile(tile);
			return tile;
		}
		return this._createTile();
	},

	_resetTile: function (tile) {
		// Override if data stored on a tile needs to be cleaned up before reuse
	},

	_createTile: function () {
		var tile = this._tileImg.cloneNode(false);
		tile.onselectstart = tile.onmousemove = L.Util.falseFn;
		return tile;
	},

	_loadTile: function (tile, tilePoint, zoom) {
		tile._layer = this;
		tile.onload = this._tileOnLoad;
		tile.onerror = this._tileOnError;
		tile.src = this.getTileUrl(tilePoint, zoom);
	},

	_tileOnLoad: function (e) {
		var layer = this._layer;

		this.className += ' leaflet-tile-loaded';

		layer.fire('tileload', {tile: this, url: this.src});

		layer._tilesToLoad--;
		if (!layer._tilesToLoad) {
			layer.fire('load');
		}
	},

	_tileOnError: function (e) {
		var layer = this._layer;

		layer.fire('tileerror', {tile: this, url: this.src});

		var newUrl = layer.options.errorTileUrl;
		if (newUrl) {
			this.src = newUrl;
		}
	}
});
<|endoftext|>


<commit_before>// Navigation 1.0 ALPHA
//
// * Highlights the appropriate element in the navigation when scrolling through the page
// * Scrolls to appropriate section of the page when the navigation is clicked

var sections = [];
var articleSections = $();
var autoscrolling = false;

$(document).ready(function(){

  $("nav").on("click","a",function(){
    $(".selected").removeClass("selected");
    $(this).addClass("selected");
    var section = $(this).attr("href");

    autoscrolling = true;

    $('html, body').animate({
        scrollTop: $(section).offset().top
    }, 500, function(){
      autoscrolling = false;
      window.location.hash = section;
    });

    return false;
  });

  $("nav a").each(function(i,el){
    var sectionName = $(el).attr("href");
    if(sectionName.length > 0) {
      sectionName = sectionName.replace("#","").toLowerCase();
      sections.push(sectionName);
    }
  });

  var jam = $("article *[id]");
  $(jam).each(function(i,el){
    var id = $(el).attr("id");
    id = id.replace("#","").toLowerCase();
    if(sections.indexOf(id) > -1) {
      articleSections.push(el);
    }
  });

  $(window).on("scroll",function(){
    if(autoscrolling == false) {
      scroll();
    }
  });

  // Get the modal
var modal = document.getElementsByClassName(".modal");

// Get the image and insert it inside the modal - use its "alt" text as a caption
var img = document.getElementsByClassName(".modal-img");
var modalImg = document.getElementsByClassName(".modal-content");
var captionText = document.getElementsByClassName(".modal-caption");

for (var i = 0; i < img.length; i++) {
  var image = img[i];
  var mod = modal[i];
  var modimage = modalImg[i];
  var modcaption = captionText[i];
  image.onclick = function(evt) {
    mod.style.display = "block";
    modimage.src = this.src;
    modcaption.innerHTML = this.alt;
  }
}

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks on <span> (x), close the modal
span.onclick = function() {
    modal.style.display = "none";
}

});

function scroll(){
  articleSections.each(function(i,el){
    var windowTop = $(window).scrollTop();
    var offset = $(el).offset();
    var fromTop = offset.top - windowTop;
    if(fromTop > 0 && fromTop < 400) {
      var id = $(el).attr('id');
      id = id.toLowerCase().replace("#","");
      $("nav .selected").removeClass("selected");
      $("nav a[href=#"+id+"]").addClass("selected");
    }
  });
}
<commit_msg>debug multi-modal<commit_after>// Navigation 1.0 ALPHA
//
// * Highlights the appropriate element in the navigation when scrolling through the page
// * Scrolls to appropriate section of the page when the navigation is clicked

var sections = [];
var articleSections = $();
var autoscrolling = false;

$(document).ready(function(){

  $("nav").on("click","a",function(){
    $(".selected").removeClass("selected");
    $(this).addClass("selected");
    var section = $(this).attr("href");

    autoscrolling = true;

    $('html, body').animate({
        scrollTop: $(section).offset().top
    }, 500, function(){
      autoscrolling = false;
      window.location.hash = section;
    });

    return false;
  });

  $("nav a").each(function(i,el){
    var sectionName = $(el).attr("href");
    if(sectionName.length > 0) {
      sectionName = sectionName.replace("#","").toLowerCase();
      sections.push(sectionName);
    }
  });

  var jam = $("article *[id]");
  $(jam).each(function(i,el){
    var id = $(el).attr("id");
    id = id.replace("#","").toLowerCase();
    if(sections.indexOf(id) > -1) {
      articleSections.push(el);
    }
  });

  $(window).on("scroll",function(){
    if(autoscrolling == false) {
      scroll();
    }
  });

  // Get the modal
//var modal = document.getElementsByClassName(".modal");

// Get the image and insert it inside the modal - use its "alt" text as a caption
var img = document.getElementsByClassName(".modal-img");
//var modalImg = document.getElementsByClassName(".modal-content");
//var captionText = document.getElementsByClassName(".modal-caption");

for (var i = 0; i < img.length; i++) {
  var image = img[i];
  var modal = document.getElementsByClassName(".modal-img")[i].getElementsByClassName(".modal")[0];
  var modimage = document.getElementsByClassName(".modal-img")[i].getElementsByClassName(".modal-content")[0];
  var modcaption = document.getElementsByClassName(".modal-img")[i].getElementsByClassName(".modal-caption")[0];
  image.onclick = function(evt) {
    modal.style.display = "block";
    modimage.src = this.src;
    modcaption.innerHTML = this.alt;
  }
}

// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];

// When the user clicks on <span> (x), close the modal
span.onclick = function() {
    modal.style.display = "none";
}

});

function scroll(){
  articleSections.each(function(i,el){
    var windowTop = $(window).scrollTop();
    var offset = $(el).offset();
    var fromTop = offset.top - windowTop;
    if(fromTop > 0 && fromTop < 400) {
      var id = $(el).attr('id');
      id = id.toLowerCase().replace("#","");
      $("nav .selected").removeClass("selected");
      $("nav a[href=#"+id+"]").addClass("selected");
    }
  });
}
<|endoftext|>


<commit_before>// Config for the -dev server.
import { addonsServerDevCDN, analyticsHost, apiDevHost, baseUrlDev, devDomain } from './lib/shared';

const addonsFrontendCDN = 'https://addons-amo-dev-cdn.allizom.org';

module.exports = {
  baseURL: baseUrlDev,
  apiHost: apiDevHost,
  amoCDN: addonsServerDevCDN,
  staticHost: addonsFrontendCDN,

  cookieDomain: `.${devDomain}`,

  enableDevTools: true,

  // Content security policy.
  CSP: {
    directives: {
      connectSrc: [
        analyticsHost,
        apiDevHost,
      ],
      fontSrc: [
        `${addonsFrontendCDN}/static/`,
      ],
      imgSrc: [
        "'self'",
        'data:',
        addonsServerDevCDN,
        `${addonsFrontendCDN}/static/`,
        // This file isn't bundled with addons-frontend.
        `${addonsFrontendCDN}/favicon.ico`,
      ],
      scriptSrc: [
        `${addonsFrontendCDN}/static/`,
        `${analyticsHost}/analytics.js`,
      ],
      styleSrc: [
        `${addonsFrontendCDN}/static/`,
      ],
    },
  },

  allowErrorSimulation: true,

  extensionWorkshopUrl: 'https://extensionworkshop-dev.allizom.org',

  experiments: {
    '20210404_download_cta_experiment': true,
  },
};
<commit_msg>Disable the current experiment on dev (#10378)<commit_after>// Config for the -dev server.
import { addonsServerDevCDN, analyticsHost, apiDevHost, baseUrlDev, devDomain } from './lib/shared';

const addonsFrontendCDN = 'https://addons-amo-dev-cdn.allizom.org';

module.exports = {
  baseURL: baseUrlDev,
  apiHost: apiDevHost,
  amoCDN: addonsServerDevCDN,
  staticHost: addonsFrontendCDN,

  cookieDomain: `.${devDomain}`,

  enableDevTools: true,

  // Content security policy.
  CSP: {
    directives: {
      connectSrc: [
        analyticsHost,
        apiDevHost,
      ],
      fontSrc: [
        `${addonsFrontendCDN}/static/`,
      ],
      imgSrc: [
        "'self'",
        'data:',
        addonsServerDevCDN,
        `${addonsFrontendCDN}/static/`,
        // This file isn't bundled with addons-frontend.
        `${addonsFrontendCDN}/favicon.ico`,
      ],
      scriptSrc: [
        `${addonsFrontendCDN}/static/`,
        `${analyticsHost}/analytics.js`,
      ],
      styleSrc: [
        `${addonsFrontendCDN}/static/`,
      ],
    },
  },

  allowErrorSimulation: true,

  extensionWorkshopUrl: 'https://extensionworkshop-dev.allizom.org',

  experiments: {
    '20210404_download_cta_experiment': false,
  },
};
<|endoftext|>


<commit_before>/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2017 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
(function() {
    var query = window.location.search.substring(1);
    query = decodeURIComponent(query);

    function loadGoogleMapAPIJS(key, callback) {
        var url = 'https://maps.googleapis.com/maps/api/js?v=3&key=' + key;
        var script = document.createElement('script');
        script.src = url;
        script.onload = callback;
        document.body.appendChild(script);
    }

    function getQueryVariable(variable) {
        var vars = query.split("&");
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair[0] == variable) {
                return pair[1];
            }
        }
        return (false);
    }

    function loadMap() {

        var mapElement = document.getElementById('map');
        var loadingImage = document.getElementById('loadingImage');
        mapElement.style.visibility = "hidden";
        loadingImage.style.display = "inline";

        var options = {
            zoom: 3,
            center: new google.maps.LatLng(48.8357120, 2.5856770),
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var map = new google.maps.Map(document.getElementById('map'), options);
        var appHome = location.protocol + '//' + location.host + '/' + location.pathname.split('/')[1];

        google.maps.event.addListenerOnce(map, 'bounds_changed', function() {

            // Creating an array that will store the markers
            var markers = [];
            // To show Object details on click of Pinpoint
            var infowindow = new google.maps.InfoWindow();

            var requestP = $.ajax({
                type: "GET",
                contentType: 'application/json',
                url: appHome + "/ws/map/" + getQueryVariable("object")
            });

            requestP.done(function(result) {

                if (result.status == 0) {

                    for (var i = 0; i < result.data.length; i++) {

                        var d = result.data[i];
                        var icon = 'http://thydzik.com/thydzikGoogleMap/markerlink.php?text=' + d['pinChar'];
                        var latlng = new google.maps.LatLng(d['latit'], d['longit']);
                        var title = d['fullName'].trim();
                        var content = "" + title + "
" + d['address'] + "
 " + d['fixedPhone'];
                        content = content + "
 " + d['emailAddress'];
                        var iconcolor;

                        switch (d['pinColor']) {
                            case 'blue':
                                iconcolor = '5680FC';
                                break;
                            case 'gray':
                                iconcolor = 'A8A8A8 ';
                                break;
                            case 'orange':
                                iconcolor = 'EF9D3F';
                                break;
                            case 'yellow':
                                iconcolor = 'FCF356';
                                break;
                            case 'purple':
                                iconcolor = '7D54FC';
                                break;
                            case 'pink':
                                iconcolor = 'E14E9D';
                                break;
                            case 'brown':
                                iconcolor = '9E7151';
                                break;
                            default:
                                iconcolor = 'FC6355';
                                break;
                        }

                        icon = icon + '&color=' + iconcolor;

                        var marker = new google.maps.Marker({
                            position: latlng,
                            map: map,
                            title: title.split('
')[0],
                            icon: icon
                        });

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

                        markers.push(marker);

                    } //end loop
                } // end if
            });

            requestP.fail(function(jqXHR, textStatus) {
                alert("Request failed: " + textStatus);
            });

            requestP.complete(function() {
                mapElement.style.visibility = "visible";
                loadingImage.style.display = "none";
            });

            var markerclusterer = new MarkerClusterer(map, markers);

        });
    };

    window.onload = function() {
        loadGoogleMapAPIJS(getQueryVariable('key'), function() {
            loadMap();
        });
    }
})();
<commit_msg>RM8951: alert if Google Maps API key is missing.<commit_after>/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2017 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
(function() {
    var query = window.location.search.substring(1);
    query = decodeURIComponent(query);

    function loadGoogleMapAPIJS(key, callback) {
		if (!key) {
			throw 'Google Maps API key is missing.';
		}

    	var url = 'https://maps.googleapis.com/maps/api/js?v=3&key=' + key;
        var script = document.createElement('script');
        script.src = url;
        script.onload = callback;
        document.body.appendChild(script);
    }

    function getQueryVariable(variable) {
        var vars = query.split("&");
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair[0] == variable) {
                return pair[1];
            }
        }
        return (false);
    }

    function loadMap() {

        var mapElement = document.getElementById('map');
        var loadingImage = document.getElementById('loadingImage');
        mapElement.style.visibility = "hidden";
        loadingImage.style.display = "inline";

        var options = {
            zoom: 3,
            center: new google.maps.LatLng(48.8357120, 2.5856770),
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var map = new google.maps.Map(document.getElementById('map'), options);
        var appHome = location.protocol + '//' + location.host + '/' + location.pathname.split('/')[1];

        google.maps.event.addListenerOnce(map, 'bounds_changed', function() {

            // Creating an array that will store the markers
            var markers = [];
            // To show Object details on click of Pinpoint
            var infowindow = new google.maps.InfoWindow();

            var requestP = $.ajax({
                type: "GET",
                contentType: 'application/json',
                url: appHome + "/ws/map/" + getQueryVariable("object")
            });

            requestP.done(function(result) {

                if (result.status == 0) {

                    for (var i = 0; i < result.data.length; i++) {

                        var d = result.data[i];
                        var icon = 'http://thydzik.com/thydzikGoogleMap/markerlink.php?text=' + d['pinChar'];
                        var latlng = new google.maps.LatLng(d['latit'], d['longit']);
                        var title = d['fullName'].trim();
                        var content = "" + title + "
" + d['address'] + "
 " + d['fixedPhone'];
                        content = content + "
 " + d['emailAddress'];
                        var iconcolor;

                        switch (d['pinColor']) {
                            case 'blue':
                                iconcolor = '5680FC';
                                break;
                            case 'gray':
                                iconcolor = 'A8A8A8 ';
                                break;
                            case 'orange':
                                iconcolor = 'EF9D3F';
                                break;
                            case 'yellow':
                                iconcolor = 'FCF356';
                                break;
                            case 'purple':
                                iconcolor = '7D54FC';
                                break;
                            case 'pink':
                                iconcolor = 'E14E9D';
                                break;
                            case 'brown':
                                iconcolor = '9E7151';
                                break;
                            default:
                                iconcolor = 'FC6355';
                                break;
                        }

                        icon = icon + '&color=' + iconcolor;

                        var marker = new google.maps.Marker({
                            position: latlng,
                            map: map,
                            title: title.split('
')[0],
                            icon: icon
                        });

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

                        markers.push(marker);

                    } //end loop
                } // end if
            });

            requestP.fail(function(jqXHR, textStatus) {
                alert("Request failed: " + textStatus);
            });

            requestP.complete(function() {
                mapElement.style.visibility = "visible";
                loadingImage.style.display = "none";
            });

            var markerclusterer = new MarkerClusterer(map, markers);

        });
    };

    window.onload = function() {
		try {
	        loadGoogleMapAPIJS(getQueryVariable('key'), function() {
	            loadMap();
	        });
		} catch (err) {
			alert(err);
		}
    }
})();
<|endoftext|>


<commit_before>'use strict'

var C = require('ipp-encoder').CONSTANTS
var utils = require('./utils')
var groups = require('./groups')

exports.printJob = printJob
exports.validateJob = validateJob
exports.getPrinterAttributes = getPrinterAttributes
exports.getJobs = getJobs
exports.cancelJob = cancelJob
exports.getJobAttributes = getJobAttributes

function printJob (printer, req, res) {
  var job = createJob(printer, req.body)
  job.state = C.JOB_COMPLETED
  job.processingAt = Date.now()
  job.completedAt = Date.now()
  res.send(groups.jobAttributesTag(printer, job))
  printer.emit('job', job)
}

function validateJob (printer, req, res) {
  res.send()
}

function getPrinterAttributes (printer, req, res) {
  res.send([
    groups.unsupportedAttributesTagPrinter(printer, req.body),
    groups.printerAttributesTag(printer, req.body)
  ])
}

function getJobs (printer, req, res) {
  var attributes = getAttributesForGroup(req.body, C.OPERATION_ATTRIBUTES_TAG)
  var which = getFirstValueForName(attributes, 'which-jobs')
  var states

  switch (which) {
    case 'completed':
      states = [C.JOB_COMPLETED, C.JOB_CANCELED, C.JOB_ABORTED]
      break
    case 'not-completed':
      states = [C.JOB_PENDING, C.JOB_PROCESSING, C.JOB_PROCESSING_STOPPED, C.JOB_PENDING_HELD]
      break
    case undefined:
      // all is good :)
      break
    default:
      res.send(
        C.CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED,
        { tag: C.UNSUPPORTED_ATTRIBUTES_TAG, attributes: [
          { tag: C.UNSUPPORTED, name: 'which-jobs', value: which }
        ] }
      )
      return
  }

  var jobs = states
    ? printer.jobs.filter(function (job) { return ~states.indexOf(job.state) })
    : printer.jobs

  var _groups = jobs
    .sort(function (a, b) {
      if (a.completedAt && !b.completedAt) return -1
      if (!a.completedAt && b.completedAt) return 1
      if (!a.completedAt && !b.completedAt) return b.id - a.id
      return b.completedAt - b.completedAt
    })
    .map(groups.jobAttributesTag)

  res.send([groups.unsupportedAttributesTagJob(req.body)].concat(_groups))
}

function cancelJob (printer, req, res) {
  var job = getJobFromBody(printer, req.body)
  if (!job) return res.send(C.CLIENT_ERROR_NOT_POSSIBLE) // TODO: Not sure this is the correct status code
  switch (job.state) {
    case C.JOB_PENDING:
    case C.JOB_PENDING_HELD:
    case C.JOB_PROCESSING:
    case C.JOB_PROCESSING_STOPPED:
      job.state = C.JOB_CANCELED
      res.send(C.SUCCESSFUL_OK)
      break
    case C.JOB_CANCELED:
    case C.JOB_ABORTED:
    case C.JOB_COMPLETED:
      res.send(C.CLIENT_ERROR_NOT_POSSIBLE)
      break
    default:
      res.send(C.CLIENT_ERROR_NOT_POSSIBLE) // TODO: Not sure this is the correct status code
  }
}

function getJobAttributes (printer, req, res) {
  var job = getJobFromBody(printer, req.body)
  if (!job) return res.send(C.CLIENT_ERROR_NOT_POSSIBLE) // TODO: This doesn't seem to be the correct status code - OSX doesn't re-send the job
  res.send([groups.unsupportedAttributesTagJob(req.body)].concat(groups.jobAttributesTag(printer, job)))
}

/**
 * -----------------------------
 * HELPER FUNCTIONS
 * -----------------------------
 */

function createJob (printer, body) {
  var attributes = getAttributesForGroup(body, C.OPERATION_ATTRIBUTES_TAG)
  var jobName = getFirstValueForName(attributes, 'job-name')
  var userName = getFirstValueForName(attributes, 'requesting-user-name')
  var job = {
    id: ++printer._jobId,
    state: C.JOB_PENDING,
    data: body.data,
    attributes: [
      { tag: C.URI, name: 'job-printer-uri', value: printer.uri() },
      { tag: C.URI, name: 'job-uri', value: printer.uri() + printer._jobId },
      { tag: C.NAME_WITHOUT_LANG, name: 'job-name', value: jobName },
      { tag: C.NAME_WITHOUT_LANG, name: 'job-originating-user-name', value: userName },
      { tag: C.KEYWORD, name: 'job-state-reasons', value: 'none' },
      { tag: C.INTEGER, name: 'time-at-creation', value: utils.time(printer) },
      { tag: C.CHARSET, name: 'attributes-charset', value: 'utf-8' },
      { tag: C.NATURAL_LANG, name: 'attributes-natural-language', value: 'en-us' }
    ]
  }
  printer.jobs.push(job)
  return job
}

function getJobFromBody (printer, body) {
  var attributes = getAttributesForGroup(body, C.OPERATION_ATTRIBUTES_TAG)
  var id = getFirstValueForName(attributes, 'job-id')
  return printer.getJob(id)
}

function getAttributesForGroup (body, tag) {
  var result = findOneByKey(body.groups, 'tag', tag)
  if (result) return result.attributes
}

function getFirstValueForName (attributes, name) {
  var result = findOneByKey(attributes, 'name', name)
  if (result) return result.values ? result.values[0] : result.value
}

function findOneByKey (arr, key, value) {
  for (var i = 0, l = arr.length; i < l; i++) {
    if (arr[i][key] === value) return arr[i]
  }
}
<commit_msg>Fix getJobs bug<commit_after>'use strict'

var C = require('ipp-encoder').CONSTANTS
var utils = require('./utils')
var groups = require('./groups')

exports.printJob = printJob
exports.validateJob = validateJob
exports.getPrinterAttributes = getPrinterAttributes
exports.getJobs = getJobs
exports.cancelJob = cancelJob
exports.getJobAttributes = getJobAttributes

function printJob (printer, req, res) {
  var job = createJob(printer, req.body)
  job.state = C.JOB_COMPLETED
  job.processingAt = Date.now()
  job.completedAt = Date.now()
  res.send(groups.jobAttributesTag(printer, job))
  printer.emit('job', job)
}

function validateJob (printer, req, res) {
  res.send()
}

function getPrinterAttributes (printer, req, res) {
  res.send([
    groups.unsupportedAttributesTagPrinter(printer, req.body),
    groups.printerAttributesTag(printer, req.body)
  ])
}

function getJobs (printer, req, res) {
  var attributes = getAttributesForGroup(req.body, C.OPERATION_ATTRIBUTES_TAG)
  var which = getFirstValueForName(attributes, 'which-jobs')
  var states

  switch (which) {
    case 'completed':
      states = [C.JOB_COMPLETED, C.JOB_CANCELED, C.JOB_ABORTED]
      break
    case 'not-completed':
      states = [C.JOB_PENDING, C.JOB_PROCESSING, C.JOB_PROCESSING_STOPPED, C.JOB_PENDING_HELD]
      break
    case undefined:
      // all is good :)
      break
    default:
      res.send(
        C.CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED,
        { tag: C.UNSUPPORTED_ATTRIBUTES_TAG, attributes: [
          { tag: C.UNSUPPORTED, name: 'which-jobs', value: which }
        ] }
      )
      return
  }

  var jobs = states
    ? printer.jobs.filter(function (job) { return ~states.indexOf(job.state) })
    : printer.jobs

  var _groups = jobs
    .sort(function (a, b) {
      if (a.completedAt && !b.completedAt) return -1
      if (!a.completedAt && b.completedAt) return 1
      if (!a.completedAt && !b.completedAt) return b.id - a.id
      return b.completedAt - b.completedAt
    })
    .map(groups.jobAttributesTag.bind(null, printer))

  res.send([groups.unsupportedAttributesTagJob(req.body)].concat(_groups))
}

function cancelJob (printer, req, res) {
  var job = getJobFromBody(printer, req.body)
  if (!job) return res.send(C.CLIENT_ERROR_NOT_POSSIBLE) // TODO: Not sure this is the correct status code
  switch (job.state) {
    case C.JOB_PENDING:
    case C.JOB_PENDING_HELD:
    case C.JOB_PROCESSING:
    case C.JOB_PROCESSING_STOPPED:
      job.state = C.JOB_CANCELED
      res.send(C.SUCCESSFUL_OK)
      break
    case C.JOB_CANCELED:
    case C.JOB_ABORTED:
    case C.JOB_COMPLETED:
      res.send(C.CLIENT_ERROR_NOT_POSSIBLE)
      break
    default:
      res.send(C.CLIENT_ERROR_NOT_POSSIBLE) // TODO: Not sure this is the correct status code
  }
}

function getJobAttributes (printer, req, res) {
  var job = getJobFromBody(printer, req.body)
  if (!job) return res.send(C.CLIENT_ERROR_NOT_POSSIBLE) // TODO: This doesn't seem to be the correct status code - OSX doesn't re-send the job
  res.send([groups.unsupportedAttributesTagJob(req.body)].concat(groups.jobAttributesTag(printer, job)))
}

/**
 * -----------------------------
 * HELPER FUNCTIONS
 * -----------------------------
 */

function createJob (printer, body) {
  var attributes = getAttributesForGroup(body, C.OPERATION_ATTRIBUTES_TAG)
  var jobName = getFirstValueForName(attributes, 'job-name')
  var userName = getFirstValueForName(attributes, 'requesting-user-name')
  var job = {
    id: ++printer._jobId,
    state: C.JOB_PENDING,
    data: body.data,
    attributes: [
      { tag: C.URI, name: 'job-printer-uri', value: printer.uri() },
      { tag: C.URI, name: 'job-uri', value: printer.uri() + printer._jobId },
      { tag: C.NAME_WITHOUT_LANG, name: 'job-name', value: jobName },
      { tag: C.NAME_WITHOUT_LANG, name: 'job-originating-user-name', value: userName },
      { tag: C.KEYWORD, name: 'job-state-reasons', value: 'none' },
      { tag: C.INTEGER, name: 'time-at-creation', value: utils.time(printer) },
      { tag: C.CHARSET, name: 'attributes-charset', value: 'utf-8' },
      { tag: C.NATURAL_LANG, name: 'attributes-natural-language', value: 'en-us' }
    ]
  }
  printer.jobs.push(job)
  return job
}

function getJobFromBody (printer, body) {
  var attributes = getAttributesForGroup(body, C.OPERATION_ATTRIBUTES_TAG)
  var id = getFirstValueForName(attributes, 'job-id')
  return printer.getJob(id)
}

function getAttributesForGroup (body, tag) {
  var result = findOneByKey(body.groups, 'tag', tag)
  if (result) return result.attributes
}

function getFirstValueForName (attributes, name) {
  var result = findOneByKey(attributes, 'name', name)
  if (result) return result.values ? result.values[0] : result.value
}

function findOneByKey (arr, key, value) {
  for (var i = 0, l = arr.length; i < l; i++) {
    if (arr[i][key] === value) return arr[i]
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*!
 * sequomics® [v1.0.0]
 * ______________________________________________________________
 * karma, https://github.com/karma-runner/karma
 * The Spectacular Test Runner for JavaScript.
 * ______________________________________________________________
 * Architecture and Code Handcrafted by Prabhat Kumar.
 * Architectuur en Code handgemaakt door Prabhat Kumar.
 * @author    : Prabhat Kumar [http://prabhatkumar.org/]
 * @copyright : Sequømics Corporation [http://sequomics.com/]
 * ______________________________________________________________
 * @date      : 11-Jan-2016
 * @license   : Apache, version 2.0
 * @require   : Node.js®
 * @require   : NPM
 * ______________________________________________________________
 *
 * --/The Heart of Karma Test Runner System/-- of "sequomics®".
 * ______________________________________________________________
 */

// # Usage: $ node -v
// # Usage: $ npm -v

// =========================
// Test Module(s) Required.
// =========================
// main module.
// @require   : karma
// @require   : grunt-karma

/* Invoking strict mode. */
"use strict";
<commit_msg>Initial commit<commit_after>#!/usr/bin/env node

/*!
 * sequomics® [v1.0.0]
 * ______________________________________________________________
 * karma, https://github.com/karma-runner/karma
 * The Spectacular Test Runner for JavaScript.
 * ______________________________________________________________
 * Architecture and Code Handcrafted by Prabhat Kumar.
 * Architectuur en Code handgemaakt door Prabhat Kumar.
 * @author    : Prabhat Kumar [http://prabhatkumar.org/]
 * @copyright : Sequømics Corporation [http://sequomics.com/]
 * ______________________________________________________________
 * @date      : 11-Jan-2016
 * @license   : Apache, version 2.0
 * @require   : Node.js®
 * @require   : NPM
 * ______________________________________________________________
 *
 * --/The Heart of Karma Test Runner System/-- of "sequomics®".
 * ______________________________________________________________
 */

// # Usage: $ node -v
// # Usage: $ npm -v

// =========================
// Test Module(s) Required.
// =========================
// main module.
// @require   : karma
// @require   : grunt-karma

/* Invoking strict mode. */
"use strict";

/* ______________________________________________
 * Settings for Test System.                    |
 * _____________________________________________|
 */
var TESTSERVER_PORT   = 8080;
<|endoftext|>


<commit_before>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
  //Override application configuration here. Common examples follow in the comments.
  return {

    // API Proxying
    //
    // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
    // port as your lineman development server. By enabling the API proxy and setting the port, all
    // requests for paths that don't match a static asset in ./generated will be forwarded to
    // whatever service might be running on the specified port.
    //
    // server: {
    //   apiProxy: {
    //     enabled: true,
    //     host: 'localhost',
    //     port: 3000
    //   }
    // }

    // Sass
    //
    // Lineman supports Sass via grunt-contrib-sass, which requires you first
    // have Ruby installed as well as the `sass` gem. To enable it, comment out the
    // following line:
    //
    // enableSass: true

    // Asset Fingerprints
    //
    // Lineman can fingerprint your static assets by appending a hash to the filename
    // and logging a manifest of logical-to-hashed filenames in dist/assets.json
    // via grunt-asset-fingerprint
    //
    // enableAssetFingerprint: true

  };
};
<commit_msg>Fix typo. Whoops<commit_after>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat_sourcemap.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
  //Override application configuration here. Common examples follow in the comments.
  return {

    // API Proxying
    //
    // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
    // port as your lineman development server. By enabling the API proxy and setting the port, all
    // requests for paths that don't match a static asset in ./generated will be forwarded to
    // whatever service might be running on the specified port.
    //
    // server: {
    //   apiProxy: {
    //     enabled: true,
    //     host: 'localhost',
    //     port: 3000
    //   }
    // }

    // Sass
    //
    // Lineman supports Sass via grunt-contrib-sass, which requires you first
    // have Ruby installed as well as the `sass` gem. To enable it, comment out the
    // following line:
    //
    // enableSass: true

    // Asset Fingerprints
    //
    // Lineman can fingerprint your static assets by appending a hash to the filename
    // and logging a manifest of logical-to-hashed filenames in dist/assets.json
    // via grunt-asset-fingerprint
    //
    // enableAssetFingerprint: true

  };
};
<|endoftext|>