<commit_before>/* Pi-hole: A black hole for Internet advertisements
*  (c) 2017 Pi-hole, LLC (https://pi-hole.net)
*  Network-wide ad blocking via your own hardware.
*
*  This file is copyright under the latest version of the EUPL.
*  Please see LICENSE file for your rights under this license. */

/*global
    moment
*/

var start__ = moment().subtract(6, "days");
var from = moment(start__).utc().valueOf()/1000;
var end__ = moment();
var until = moment(end__).utc().valueOf()/1000;
var instantquery = false;
var daterange;

var timeoutWarning = $("#timeoutWarning");

// Do we want to filter queries?
var GETDict = {};
location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];});

if("from" in GETDict && "until" in GETDict)
{
    from = parseInt(GETDict["from"]);
    until = parseInt(GETDict["until"]);
    start__ = moment(1000*from);
    end__ = moment(1000*until);
    instantquery = true;
}

$(function () {
    daterange = $("#querytime").daterangepicker(
    {
      timePicker: true, timePickerIncrement: 15,
      locale: { format: "MMMM Do YYYY, HH:mm" },
      ranges: {
        "Today": [moment().startOf("day"), moment()],
        "Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")],
        "Last 7 Days": [moment().subtract(6, "days"), moment()],
        "Last 30 Days": [moment().subtract(29, "days"), moment()],
        "This Month": [moment().startOf("month"), moment()],
        "Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")],
        "This Year": [moment().startOf("year"), moment()],
        "All Time": [moment(0), moment()]
      },
      "opens": "center", "showDropdowns": true
    },
    function (startt, endt) {
      from = moment(startt).utc().valueOf()/1000;
      until = moment(endt).utc().valueOf()/1000;
    });
});

var tableApi, statistics;

function escapeRegex(text) {
  var map = {
    "(": "\\(",
    ")": "\\)",
    ".": "\\.",
  };
  return text.replace(/[().]/g, function(m) { return map[m]; });
}

function add(domain,list) {
    var token = $("#token").html();
    var alInfo = $("#alInfo");
    var alList = $("#alList");
    var alDomain = $("#alDomain");
    alDomain.html(domain);
    var alSuccess = $("#alSuccess");
    var alFailure = $("#alFailure");
    var err = $("#err");

    if(list === "white")
    {
        alList.html("Whitelist");
    }
    else
    {
        alList.html("Blacklist");
    }

    alInfo.show();
    alSuccess.hide();
    alFailure.hide();
    $.ajax({
        url: "scripts/pi-hole/php/add.php",
        method: "post",
        data: {"domain":domain, "list":list, "token":token},
        success: function(response) {
            if (response.indexOf("not a valid argument") >= 0 || response.indexOf("is not a valid domain") >= 0)
            {
                alFailure.show();
                err.html(response);
                alFailure.delay(4000).fadeOut(2000, function() { alFailure.hide(); });
            }
            else
            {
                alSuccess.show();
                alSuccess.delay(1000).fadeOut(2000, function() { alSuccess.hide(); });
            }
            alInfo.delay(1000).fadeOut(2000, function() {
                alInfo.hide();
                alList.html("");
                alDomain.html("");
            });
        },
        error: function(jqXHR, exception) {
            alFailure.show();
            err.html("");
            alFailure.delay(1000).fadeOut(2000, function() {
                alFailure.hide();
            });
            alInfo.delay(1000).fadeOut(2000, function() {
                alInfo.hide();
                alList.html("");
                alDomain.html("");
            });
        }
    });
}
function handleAjaxError( xhr, textStatus, error ) {
    if ( textStatus === "timeout" )
    {
        alert( "The server took too long to send the data." );
    }
    else if(xhr.responseText.indexOf("Connection refused") >= 0)
    {
        alert( "An error occured while loading the data: Connection refused. Is FTL running?" );
    }
    else
    {
        alert( "An unknown error occured while loading the data.\n"+xhr.responseText );
    }
    $("#all-queries_processing").hide();
    tableApi.clear();
    tableApi.draw();
}

var reloadCallback = function()
{
    timeoutWarning.hide();
    statistics = [0,0,0,0];
    var data = tableApi.rows().data();
    for (var i = 0; i < data.length; i++) {
        statistics[0]++;
        if(data[i][4] === 1)
        {
            statistics[2]++;
        }
        else if(data[i][4] === 3)
        {
            statistics[1]++;
        }
        else if(data[i][4] === 4)
        {
            statistics[3]++;
        }
    }
    $("h3#dns_queries").text(statistics[0]);
    $("h3#ads_blocked_exact").text(statistics[2]);
    $("h3#ads_wildcard_blocked").text(statistics[3]);

    var percent = 0.0;
    if(statistics[2] + statistics[3] > 0)
    {
        percent = 100.0*(statistics[2] + statistics[3]) / statistics[0];
    }
    $("h3#ads_percentage_today").text(parseFloat(percent).toFixed(1)+" %");
};

function refreshTableData() {
    timeoutWarning.show();
    var APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
    statistics = [0,0,0];
    tableApi.ajax.url(APIstring).load(reloadCallback);
}

$(document).ready(function() {
    var status;

    var APIstring;
    if(instantquery)
    {
        APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
    }
    else
    {
        APIstring = "api_db.php?getAllQueries=empty";
    }

    tableApi = $("#all-queries").DataTable( {
        "rowCallback": function( row, data, index ){
            if (data[4] === 1)
            {
                $(row).css("color","red");
                $("td:eq(4)", row).html( "Pi-holed" );
                $("td:eq(5)", row).html( "<button style=\"color:green; white-space: nowrap;\"> Whitelist</button>" );
                // statistics[2]++;
            }
            else if (data[4] === 2)
            {
                $(row).css("color","green");
                $("td:eq(4)", row).html( "OK
(forwarded)" );
                $("td:eq(5)", row).html( "<button style=\"color:red; white-space: nowrap;\"> Blacklist</button>" );
            }
            else if (data[4] === 3)
            {
                $(row).css("color","green");
                $("td:eq(4)", row).html( "OK
(cached)" );
                $("td:eq(5)", row).html( "<button style=\"color:red; white-space: nowrap;\"> Blacklist</button>" );
                // statistics[1]++;

            }
            else if (data[4] === 4)
            {
                $(row).css("color","red");
                $("td:eq(4)", row).html( "Pi-holed
(wildcard)" );
                $("td:eq(5)", row).html( "" );
                // statistics[3]++;
            }
            else
            {
                $("td:eq(4)", row).html( "Unknown
("+data[4]+")" );
                $("td:eq(5)", row).html( "" );
            }
            // statistics[0]++;
        },
        dom: "<'row'<'col-sm-12'f>>" +
             "<'row'<'col-sm-4'l><'col-sm-8'p>>" +
             "<'row'<'col-sm-12'<'table-responsive'tr>>>" +
             "<'row'<'col-sm-5'i><'col-sm-7'p>>",
        "ajax": {"url": APIstring, "error": handleAjaxError },
        "autoWidth" : false,
        "processing": true,
        "deferRender": true,
        "order" : [[0, "desc"]],
        "columns": [
            { "width" : "15%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(data).format("Y-MM-DD [
]HH:mm:ss z");}else{return data;} }},
            { "width" : "10%" },
            { "width" : "40%" },
            { "width" : "20%" },
            { "width" : "10%" },
            { "width" : "5%" },
        ],
        "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
        "columnDefs": [ {
            "targets": -1,
            "data": null,
            "defaultContent": ""
        } ],
        "initComplete": reloadCallback
    });
    $("#all-queries tbody").on( "click", "button", function () {
        var data = tableApi.row( $(this).parents("tr") ).data();
        if (data[4] === "1")
        {
          add(data[2],"white");
        }
        else
        {
          add(data[2],"black");
        }
    } );

    if(instantquery)
    {
        daterange.val(start__.format("MMMM Do YYYY, HH:mm") + " - " + end__.format("MMMM Do YYYY, HH:mm"));
    }
} );

$("#querytime").on("apply.daterangepicker", function(ev, picker) {
    refreshTableData();
});

<commit_msg>Improve readability of long term summary stats<commit_after>/* Pi-hole: A black hole for Internet advertisements
*  (c) 2017 Pi-hole, LLC (https://pi-hole.net)
*  Network-wide ad blocking via your own hardware.
*
*  This file is copyright under the latest version of the EUPL.
*  Please see LICENSE file for your rights under this license. */

/*global
    moment
*/

var start__ = moment().subtract(6, "days");
var from = moment(start__).utc().valueOf()/1000;
var end__ = moment();
var until = moment(end__).utc().valueOf()/1000;
var instantquery = false;
var daterange;

var timeoutWarning = $("#timeoutWarning");

// Do we want to filter queries?
var GETDict = {};
location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];});

if("from" in GETDict && "until" in GETDict)
{
    from = parseInt(GETDict["from"]);
    until = parseInt(GETDict["until"]);
    start__ = moment(1000*from);
    end__ = moment(1000*until);
    instantquery = true;
}

$(function () {
    daterange = $("#querytime").daterangepicker(
    {
      timePicker: true, timePickerIncrement: 15,
      locale: { format: "MMMM Do YYYY, HH:mm" },
      ranges: {
        "Today": [moment().startOf("day"), moment()],
        "Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")],
        "Last 7 Days": [moment().subtract(6, "days"), moment()],
        "Last 30 Days": [moment().subtract(29, "days"), moment()],
        "This Month": [moment().startOf("month"), moment()],
        "Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")],
        "This Year": [moment().startOf("year"), moment()],
        "All Time": [moment(0), moment()]
      },
      "opens": "center", "showDropdowns": true
    },
    function (startt, endt) {
      from = moment(startt).utc().valueOf()/1000;
      until = moment(endt).utc().valueOf()/1000;
    });
});

var tableApi, statistics;

function escapeRegex(text) {
  var map = {
    "(": "\\(",
    ")": "\\)",
    ".": "\\.",
  };
  return text.replace(/[().]/g, function(m) { return map[m]; });
}

function add(domain,list) {
    var token = $("#token").html();
    var alInfo = $("#alInfo");
    var alList = $("#alList");
    var alDomain = $("#alDomain");
    alDomain.html(domain);
    var alSuccess = $("#alSuccess");
    var alFailure = $("#alFailure");
    var err = $("#err");

    if(list === "white")
    {
        alList.html("Whitelist");
    }
    else
    {
        alList.html("Blacklist");
    }

    alInfo.show();
    alSuccess.hide();
    alFailure.hide();
    $.ajax({
        url: "scripts/pi-hole/php/add.php",
        method: "post",
        data: {"domain":domain, "list":list, "token":token},
        success: function(response) {
            if (response.indexOf("not a valid argument") >= 0 || response.indexOf("is not a valid domain") >= 0)
            {
                alFailure.show();
                err.html(response);
                alFailure.delay(4000).fadeOut(2000, function() { alFailure.hide(); });
            }
            else
            {
                alSuccess.show();
                alSuccess.delay(1000).fadeOut(2000, function() { alSuccess.hide(); });
            }
            alInfo.delay(1000).fadeOut(2000, function() {
                alInfo.hide();
                alList.html("");
                alDomain.html("");
            });
        },
        error: function(jqXHR, exception) {
            alFailure.show();
            err.html("");
            alFailure.delay(1000).fadeOut(2000, function() {
                alFailure.hide();
            });
            alInfo.delay(1000).fadeOut(2000, function() {
                alInfo.hide();
                alList.html("");
                alDomain.html("");
            });
        }
    });
}
function handleAjaxError( xhr, textStatus, error ) {
    if ( textStatus === "timeout" )
    {
        alert( "The server took too long to send the data." );
    }
    else if(xhr.responseText.indexOf("Connection refused") >= 0)
    {
        alert( "An error occured while loading the data: Connection refused. Is FTL running?" );
    }
    else
    {
        alert( "An unknown error occured while loading the data.\n"+xhr.responseText );
    }
    $("#all-queries_processing").hide();
    tableApi.clear();
    tableApi.draw();
}

var reloadCallback = function()
{
    timeoutWarning.hide();
    statistics = [0,0,0,0];
    var data = tableApi.rows().data();
    for (var i = 0; i < data.length; i++) {
        statistics[0]++;
        if(data[i][4] === 1)
        {
            statistics[2]++;
        }
        else if(data[i][4] === 3)
        {
            statistics[1]++;
        }
        else if(data[i][4] === 4)
        {
            statistics[3]++;
        }
    }
    $("h3#dns_queries").text(statistics[0].toLocaleString());
    $("h3#ads_blocked_exact").text(statistics[2].toLocaleString());
    $("h3#ads_wildcard_blocked").text(statistics[3].toLocaleString());

    var percent = 0.0;
    if(statistics[2] + statistics[3] > 0)
    {
        percent = 100.0*(statistics[2] + statistics[3]) / statistics[0];
    }
    $("h3#ads_percentage_today").text(parseFloat(percent).toFixed(1).toLocaleString()+" %");
};

function refreshTableData() {
    timeoutWarning.show();
    var APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
    statistics = [0,0,0];
    tableApi.ajax.url(APIstring).load(reloadCallback);
}

$(document).ready(function() {
    var status;

    var APIstring;
    if(instantquery)
    {
        APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
    }
    else
    {
        APIstring = "api_db.php?getAllQueries=empty";
    }

    tableApi = $("#all-queries").DataTable( {
        "rowCallback": function( row, data, index ){
            if (data[4] === 1)
            {
                $(row).css("color","red");
                $("td:eq(4)", row).html( "Pi-holed" );
                $("td:eq(5)", row).html( "<button style=\"color:green; white-space: nowrap;\"> Whitelist</button>" );
                // statistics[2]++;
            }
            else if (data[4] === 2)
            {
                $(row).css("color","green");
                $("td:eq(4)", row).html( "OK
(forwarded)" );
                $("td:eq(5)", row).html( "<button style=\"color:red; white-space: nowrap;\"> Blacklist</button>" );
            }
            else if (data[4] === 3)
            {
                $(row).css("color","green");
                $("td:eq(4)", row).html( "OK
(cached)" );
                $("td:eq(5)", row).html( "<button style=\"color:red; white-space: nowrap;\"> Blacklist</button>" );
                // statistics[1]++;

            }
            else if (data[4] === 4)
            {
                $(row).css("color","red");
                $("td:eq(4)", row).html( "Pi-holed
(wildcard)" );
                $("td:eq(5)", row).html( "" );
                // statistics[3]++;
            }
            else
            {
                $("td:eq(4)", row).html( "Unknown
("+data[4]+")" );
                $("td:eq(5)", row).html( "" );
            }
            // statistics[0]++;
        },
        dom: "<'row'<'col-sm-12'f>>" +
             "<'row'<'col-sm-4'l><'col-sm-8'p>>" +
             "<'row'<'col-sm-12'<'table-responsive'tr>>>" +
             "<'row'<'col-sm-5'i><'col-sm-7'p>>",
        "ajax": {"url": APIstring, "error": handleAjaxError },
        "autoWidth" : false,
        "processing": true,
        "deferRender": true,
        "order" : [[0, "desc"]],
        "columns": [
            { "width" : "15%", "render": function (data, type, full, meta) { if(type === "display"){return moment.unix(data).format("Y-MM-DD [
]HH:mm:ss z");}else{return data;} }},
            { "width" : "10%" },
            { "width" : "40%" },
            { "width" : "20%" },
            { "width" : "10%" },
            { "width" : "5%" },
        ],
        "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
        "columnDefs": [ {
            "targets": -1,
            "data": null,
            "defaultContent": ""
        } ],
        "initComplete": reloadCallback
    });
    $("#all-queries tbody").on( "click", "button", function () {
        var data = tableApi.row( $(this).parents("tr") ).data();
        if (data[4] === "1")
        {
          add(data[2],"white");
        }
        else
        {
          add(data[2],"black");
        }
    } );

    if(instantquery)
    {
        daterange.val(start__.format("MMMM Do YYYY, HH:mm") + " - " + end__.format("MMMM Do YYYY, HH:mm"));
    }
} );

$("#querytime").on("apply.daterangepicker", function(ev, picker) {
    refreshTableData();
});

<|endoftext|>


<commit_before>/**
 * @author Your Name
 * @copyright Your office or the organisation that pays you
 * @license MIT license
 */

/**
 * @requires sMap/Module.js
 */

sMap.Module.MiljoReda = OpenLayers.Class(sMap.Module, {

	/**
	 * The events that this module will listen to. Each event listener
	 * is connected to a method defined in this module, with the same
	 * name as the event. When another module triggers this event, the
	 * method will be called (and other modules which are listening
	 * to the same event).
	 *
	 * Look at the event listeners as a public API of the module.
	 */
	EVENT_LISTENERS : ["selected", "unselected", "afterapplyingwebparams"],

	/**
	 * The events triggered from this module. Note that some modules
	 * both listens to and trigger events.
	 */
	EVENT_TRIGGERS : [],

	options: {
		idSeparator: ";",
		key: "objectid",

		layer: {
			format: new OpenLayers.Format.GeoJSON(),
			layerType: "VECTOR",
			protocol: new OpenLayers.Protocol.WFS({
				url: "http://sbkvmgeoserver.malmo.se:8080/geoserver/wfs",
				featureType: "MILJO_MILJOREDA_ALLA_PT",
				featureNS: "malmows",
				geometryName: "geom",
				outputFormat: "JSON",
				readFormat: new OpenLayers.Format.GeoJSON()
			}),
			displayName: "Miljoreda",
			name: "miljoreda_layer",
			selectable : true,
			geomType : 'area',
			style: {
				"default": {externalGraphic: "http://sbkvmgeoserver.malmo.se:8080/geoserver/wms?REQUEST=GetLegendGraphic&VERSION=1.1.1&FORMAT=image/png&LAYER=malmows:MILJO_MILJOREDA_ALLA_PT&STYLE=MILJOREDA_AVFALL_PT&RULE=0"}
			},
			options: {
				isBaseLayer: false,
				opacity: 1,
				zIndex: 350,
				ratio: 1,
				singleTile : true
			},
			popup :
					"
Avfall
" +
					"
Objid: ${objid}
" +
					"
Grupp: ${grupp}
" +
					"
Sökbegrepp: ${sokbegrepp}
" +
					"
Attributkod: ${attributkod}
" +
					"
Huvudrubrik: ${huvudrubrik}
" +
					"
Underrubrik: ${underrubrik}
" +
					"
Namn1: ${namn1}
" +
					"
Adress1: ${adress1}
" +
					"
Handläggare: ${handlaggare}
" +
					"
Provningsplikt: ${provningsplikt}
" +
					"
" +
					"
Stadsområde: ${sof_namn}
" +
					"
Delområde: ${delomr}
" +
					"
" +
					"
Visa snedbild
" +
					"
Visa gatuvy
"

		}

	},

	initialize : function(options) {
		options = options || {};

		this.EVENT_LISTENERS =
			sMap.Module.MiljoReda.prototype.EVENT_LISTENERS.concat(
				sMap.Module.prototype.EVENT_LISTENERS
		);
		this.EVENT_TRIGGERS =
			sMap.Module.MiljoReda.prototype.EVENT_TRIGGERS.concat(
				sMap.Module.prototype.EVENT_TRIGGERS
		);

		// This allows your control to be extended by sending in a parameter hash object
		// For example overriding a method in this class or in the parent class (see next step).
		OpenLayers.Util.applyDefaults(this, options);
		// This calls the parent class's constructor and allows to
		// extend it (e.g. override methods).
		sMap.Module.prototype.initialize.apply(this, [options]);

	},

	activate : function() {
		if (this.active===true) {
			return false;
		}
		// Call the activate method of the parent class
		return sMap.Module.prototype.activate.apply(
				this, arguments);
	},

	deactivate : function() {
		if (this.active!==true) {
			return false;
		}
		// Call the deactivate method of the parent class
		return sMap.Module.prototype.deactivate.apply(
				this, arguments
			);
	},

	destroy : function() {
		// Call the destroy method of the parent class
		return sMap.Module.prototype.destroy.apply(this, arguments);
	},

	selected: function(e) {
		var fs = e.selectedFeatures || [];

		var f, props,
			arr = [];
		for (var i=0,len=fs.length; i<len; i++) {
			f = fs[i];
			props = f.attributes || {};
			arr.push(props.objectid);
		}

		// Set the global variable that some unkown magical desktop application can read
		window.EDPget = arr.join(this.options.idSeparator);
		// console.log(window.EDPget);

	},

	unselected: function(e) {
		this.selected(e);
	},

	afterapplyingwebparams: function(e) {
		var p = e.params;
		if (p.ID) {
			var arr = p.ID instanceof Array ? p.ID : p.ID.split(",");

			// TODO: Should we:
			// 	a) Create a new layer where only these features are visible (using a WMS-filter)
			// 	b) Show all miljöreda layers and select the specified features
			// 	c) Show only the layer(s) which holds given ID:s and select the specified features

			// Create a filter which shows the specified features

			var filters = [];
			for (var i=0,len=arr.length; i<len; i++) {
				filters.push(
					new OpenLayers.Filter.Comparison({
						type: OpenLayers.Filter.Comparison.EQUAL_TO,
						property: this.options.key,
						value: parseInt(arr[i])
					})
				);
			}
			var filter = new OpenLayers.Filter.Logical({
					type: OpenLayers.Filter.Logical.OR,
					filters: filters
			});
			var writer = new OpenLayers.Format.Filter.v1_1_0();
			filter = new OpenLayers.Format.XML().write(writer.write(filter));
			var t = this.options.layer;
			// t.params.filter = filter;

			this._layer = new OpenLayers.Layer.Vector(t.name);
			this._layer.zIndex = 900;
			this._layer.displayName = t.displayName;
			this._layer.selectable = t.selectable;
			sMap.config.layers.overlays.push(this.options.layer);
			this.map.addLayer(this._layer);

			$.ajax({
				url: sMap.config.proxyHost ? sMap.config.proxyHost + t.protocol.url : t.protocol.url,
				context: this,
				dataType: "text",
				type: "POST",
				data: {
					typeName: t.protocol.featureNS+":"+t.protocol.featureType,
					service: "WFS",
					version: "1.1.0",
					request: "GetFeature",
					srsName: this.map.projection,
					format: "text/geojson",
					maxFeatures: 10000,
					filter: filter,
					outputFormat: "json"
				},
				success: function(data) {
					var olFormat = t.format;
					var fs = olFormat.read(data);
					// if (t.shiftCoords) {
					// 	for (i=0,len=fs.length; i<len; i++) {
					// 		// Due to new (?) standards (adopted by OL but not WFS), lat comes before long in geojson.
					// 		f = fs[i];
					// 		x = f.geometry.x;
					// 		y = f.geometry.y;
					// 		f.geometry.x = y;
					// 		f.geometry.y = x;
					// 	}
					// }
					// if (t.transformFrom) {
					// 	var fromepsg = new OpenLayers.Projection(t.transformFrom),
					// 		toepsg = new OpenLayers.Projection(this.map.projection);
					// 	for (i=0,len=fs.length; i<len; i++) {
					// 		// transform with proj4js
					// 		f = fs[i];
					// 		f.geometry.transform(fromepsg,toepsg);
					// 	}
					// }
					this._layer.addFeatures(fs);
					sMap.events.triggerEvent("vectorloaded", this, {
						layerName: this._layer.name
					});
				},
				error: function(a,b,c) {},
				complete: function() {}
			});

			// t.filter = filter;

			// this._layer = new OpenLayers.Layer.Vector(t.name, {
			// 	strategies: [new OpenLayers.Strategy.BBOX()],
			// 	protocol: t.protocol
			// });
			// this._layer.filter = filter;

			// this._layer.zIndex = 900;

			// this._layer.displayName = t.displayName;
			// this._layer.selectable = t.selectable;

			// // this._layer = new OpenLayers.Layer.WMS(
			// // 	t.name,
			// // 	t.URL,
			// // 	t.params,
			// // 	t.options
			// // );
			// sMap.config.layers.overlays.push(this.options.layer);
			// this.map.addLayer(this._layer);

			// sMap.events.triggerEvent("addlayerwithconfig", this, {
			// 	config: this.options.layer
			// });

			//sMap.cmd.addlayer({layer: this._layer});
		}
	},

	/**
	 * Called when all modules are initialized, i.e. after initialize.
	 * All initial HTML should be produced from here.
	 * @returns {void}
	 */
	drawContent : function() {

	},

	// Class name needed when you want to fetch your module...
	// should correspond to the real class name.
	CLASS_NAME : "sMap.Module.MiljoReda"

});<commit_msg>miljoreda<commit_after>/**
 * @author Your Name
 * @copyright Your office or the organisation that pays you
 * @license MIT license
 */

/**
 * @requires sMap/Module.js
 */

sMap.Module.MiljoReda = OpenLayers.Class(sMap.Module, {

	/**
	 * The events that this module will listen to. Each event listener
	 * is connected to a method defined in this module, with the same
	 * name as the event. When another module triggers this event, the
	 * method will be called (and other modules which are listening
	 * to the same event).
	 *
	 * Look at the event listeners as a public API of the module.
	 */
	EVENT_LISTENERS : ["selected", "unselected", "afterapplyingwebparams"],

	/**
	 * The events triggered from this module. Note that some modules
	 * both listens to and trigger events.
	 */
	EVENT_TRIGGERS : [],

	options: {
		idSeparator: ";",
		key: "objid",

		layer: {
			format: new OpenLayers.Format.GeoJSON(),
			layerType: "VECTOR",
			protocol: new OpenLayers.Protocol.WFS({
				url: "http://sbkvmgeoserver.malmo.se:8080/geoserver/wfs",
				featureType: "MILJO_MILJOREDA_ALLA_PT",
				featureNS: "malmows",
				geometryName: "geom",
				outputFormat: "JSON",
				readFormat: new OpenLayers.Format.GeoJSON()
			}),
			displayName: "Miljoreda",
			name: "miljoreda_layer",
			selectable : true,
			geomType : 'area',
			style: {
				"default": {externalGraphic: "http://sbkvmgeoserver.malmo.se:8080/geoserver/wms?REQUEST=GetLegendGraphic&VERSION=1.1.1&FORMAT=image/png&LAYER=malmows:MILJO_MILJOREDA_ALLA_PT&STYLE=MILJOREDA_AVFALL_PT&RULE=0"}
			},
			options: {
				isBaseLayer: false,
				opacity: 1,
				zIndex: 350,
				ratio: 1,
				singleTile : true
			},
			popup :
					"
Avfall
" +
					"
Objid: ${objid}
" +
					"
Grupp: ${grupp}
" +
					"
Sökbegrepp: ${sokbegrepp}
" +
					"
Attributkod: ${attributkod}
" +
					"
Huvudrubrik: ${huvudrubrik}
" +
					"
Underrubrik: ${underrubrik}
" +
					"
Namn1: ${namn1}
" +
					"
Adress1: ${adress1}
" +
					"
Handläggare: ${handlaggare}
" +
					"
Provningsplikt: ${provningsplikt}
" +
					"
" +
					"
Stadsområde: ${sof_namn}
" +
					"
Delområde: ${delomr}
" +
					"
" +
					"
Visa snedbild
" +
					"
Visa gatuvy
"

		}

	},

	initialize : function(options) {
		options = options || {};

		this.EVENT_LISTENERS =
			sMap.Module.MiljoReda.prototype.EVENT_LISTENERS.concat(
				sMap.Module.prototype.EVENT_LISTENERS
		);
		this.EVENT_TRIGGERS =
			sMap.Module.MiljoReda.prototype.EVENT_TRIGGERS.concat(
				sMap.Module.prototype.EVENT_TRIGGERS
		);

		// This allows your control to be extended by sending in a parameter hash object
		// For example overriding a method in this class or in the parent class (see next step).
		OpenLayers.Util.applyDefaults(this, options);
		// This calls the parent class's constructor and allows to
		// extend it (e.g. override methods).
		sMap.Module.prototype.initialize.apply(this, [options]);

	},

	activate : function() {
		if (this.active===true) {
			return false;
		}
		// Call the activate method of the parent class
		return sMap.Module.prototype.activate.apply(
				this, arguments);
	},

	deactivate : function() {
		if (this.active!==true) {
			return false;
		}
		// Call the deactivate method of the parent class
		return sMap.Module.prototype.deactivate.apply(
				this, arguments
			);
	},

	destroy : function() {
		// Call the destroy method of the parent class
		return sMap.Module.prototype.destroy.apply(this, arguments);
	},

	selected: function(e) {
		var fs = e.selectedFeatures || [];

		var f, props,
			arr = [];
		for (var i=0,len=fs.length; i<len; i++) {
			f = fs[i];
			props = f.attributes || {};
			arr.push(props[this.options.key]);
		}

		// Set the global variable that some unkown magical desktop application can read
		window.EDPget = arr.join(this.options.idSeparator);
		// console.log(window.EDPget);

	},

	unselected: function(e) {
		this.selected(e);
	},

	afterapplyingwebparams: function(e) {
		var p = e.params;
		if (p.ID) {
			var arr = p.ID instanceof Array ? p.ID : p.ID.split(",");

			// TODO: Should we:
			// 	a) Create a new layer where only these features are visible (using a WMS-filter)
			// 	b) Show all miljöreda layers and select the specified features
			// 	c) Show only the layer(s) which holds given ID:s and select the specified features

			// Create a filter which shows the specified features

			var filters = [];
			for (var i=0,len=arr.length; i<len; i++) {
				filters.push(
					new OpenLayers.Filter.Comparison({
						type: OpenLayers.Filter.Comparison.EQUAL_TO,
						property: this.options.key,
						value: parseInt(arr[i])
					})
				);
			}
			var filter = new OpenLayers.Filter.Logical({
					type: OpenLayers.Filter.Logical.OR,
					filters: filters
			});
			var writer = new OpenLayers.Format.Filter.v1_1_0();
			filter = new OpenLayers.Format.XML().write(writer.write(filter));
			var t = this.options.layer;
			// t.params.filter = filter;

			this._layer = new OpenLayers.Layer.Vector(t.name);
			this._layer.zIndex = 900;
			this._layer.displayName = t.displayName;
			this._layer.selectable = t.selectable;
			sMap.config.layers.overlays.push(this.options.layer);
			this.map.addLayer(this._layer);

			$.ajax({
				url: sMap.config.proxyHost ? sMap.config.proxyHost + t.protocol.url : t.protocol.url,
				context: this,
				dataType: "text",
				type: "POST",
				data: {
					typeName: t.protocol.featureNS+":"+t.protocol.featureType,
					service: "WFS",
					version: "1.1.0",
					request: "GetFeature",
					srsName: this.map.projection,
					format: "text/geojson",
					maxFeatures: 10000,
					filter: filter,
					outputFormat: "json"
				},
				success: function(data) {
					var olFormat = t.format;
					var fs = olFormat.read(data);
					// if (t.shiftCoords) {
					// 	for (i=0,len=fs.length; i<len; i++) {
					// 		// Due to new (?) standards (adopted by OL but not WFS), lat comes before long in geojson.
					// 		f = fs[i];
					// 		x = f.geometry.x;
					// 		y = f.geometry.y;
					// 		f.geometry.x = y;
					// 		f.geometry.y = x;
					// 	}
					// }
					// if (t.transformFrom) {
					// 	var fromepsg = new OpenLayers.Projection(t.transformFrom),
					// 		toepsg = new OpenLayers.Projection(this.map.projection);
					// 	for (i=0,len=fs.length; i<len; i++) {
					// 		// transform with proj4js
					// 		f = fs[i];
					// 		f.geometry.transform(fromepsg,toepsg);
					// 	}
					// }
					this._layer.addFeatures(fs);
					sMap.events.triggerEvent("vectorloaded", this, {
						layerName: this._layer.name
					});
				},
				error: function(a,b,c) {},
				complete: function() {}
			});

			// t.filter = filter;

			// this._layer = new OpenLayers.Layer.Vector(t.name, {
			// 	strategies: [new OpenLayers.Strategy.BBOX()],
			// 	protocol: t.protocol
			// });
			// this._layer.filter = filter;

			// this._layer.zIndex = 900;

			// this._layer.displayName = t.displayName;
			// this._layer.selectable = t.selectable;

			// // this._layer = new OpenLayers.Layer.WMS(
			// // 	t.name,
			// // 	t.URL,
			// // 	t.params,
			// // 	t.options
			// // );
			// sMap.config.layers.overlays.push(this.options.layer);
			// this.map.addLayer(this._layer);

			// sMap.events.triggerEvent("addlayerwithconfig", this, {
			// 	config: this.options.layer
			// });

			//sMap.cmd.addlayer({layer: this._layer});
		}
	},

	/**
	 * Called when all modules are initialized, i.e. after initialize.
	 * All initial HTML should be produced from here.
	 * @returns {void}
	 */
	drawContent : function() {

	},

	// Class name needed when you want to fetch your module...
	// should correspond to the real class name.
	CLASS_NAME : "sMap.Module.MiljoReda"

});<|endoftext|>


<commit_before>/* global $, APP, require, Strophe, interfaceConfig */
var ConnectionIndicator = require("./ConnectionIndicator");
var SmallVideo = require("./SmallVideo");
var AudioLevels = require("../audio_levels/AudioLevels");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
var UIUtils = require("../util/UIUtil");
var XMPPEvents = require("../../../service/xmpp/XMPPEvents");

function RemoteVideo(peerJid, VideoLayout) {
    this.peerJid = peerJid;
    this.resourceJid = Strophe.getResourceFromJid(peerJid);
    this.videoSpanId = 'participant_' + this.resourceJid;
    this.VideoLayout = VideoLayout;
    this.addRemoteVideoContainer();
    this.connectionIndicator = new ConnectionIndicator(
        this, this.peerJid);
    this.setDisplayName();
    var nickfield = document.createElement('span');
    nickfield.className = "nick";
    nickfield.appendChild(document.createTextNode(this.resourceJid));
    this.container.appendChild(nickfield);
    this.bindHoverHandler();
    this.flipX = false;
    this.isLocal = false;
}

RemoteVideo.prototype = Object.create(SmallVideo.prototype);
RemoteVideo.prototype.constructor = RemoteVideo;

RemoteVideo.prototype.addRemoteVideoContainer = function() {
    this.container = RemoteVideo.createContainer(this.videoSpanId);
    if (APP.xmpp.isModerator())
        this.addRemoteVideoMenu();
    AudioLevels.updateAudioLevelCanvas(this.peerJid, this.VideoLayout);

    return this.container;
};

/**
 * Adds the remote video menu element for the given <tt>jid</tt> in the
 * given <tt>parentElement</tt>.
 *
 * @param jid the jid indicating the video for which we're adding a menu.
 * @param parentElement the parent element where this menu will be added
 */

if (!interfaceConfig.filmStripOnly) {
    RemoteVideo.prototype.addRemoteVideoMenu = function () {
        var spanElement = document.createElement('span');
        spanElement.className = 'remotevideomenu';

        this.container.appendChild(spanElement);

        var menuElement = document.createElement('i');
        menuElement.className = 'fa fa-angle-down';
        menuElement.title = 'Remote user controls';
        spanElement.appendChild(menuElement);

        var popupmenuElement = document.createElement('ul');
        popupmenuElement.className = 'popupmenu';
        popupmenuElement.id = 'remote_popupmenu_' + this.getResourceJid();
        spanElement.appendChild(popupmenuElement);

        var muteMenuItem = document.createElement('li');
        var muteLinkItem = document.createElement('a');

        var mutedIndicator = "";

        if (!this.isMuted) {
            muteLinkItem.innerHTML = mutedIndicator +
                "

";
            muteLinkItem.className = 'mutelink';
        }
        else {
            muteLinkItem.innerHTML = mutedIndicator +
                "

";
            muteLinkItem.className = 'mutelink disabled';
        }

        var self = this;
        muteLinkItem.onclick = function(){
            if ($(this).attr('disabled')) {
                event.preventDefault();
            }
            var isMute = !!self.isMuted;
            APP.xmpp.setMute(self.peerJid, !isMute);

            popupmenuElement.setAttribute('style', 'display:none;');

            if (isMute) {
                this.innerHTML = mutedIndicator +
                    "

";
                this.className = 'mutelink disabled';
            }
            else {
                this.innerHTML = mutedIndicator +
                    "

";
                this.className = 'mutelink';
            }
        };

        muteMenuItem.appendChild(muteLinkItem);
        popupmenuElement.appendChild(muteMenuItem);

        var ejectIndicator = "";

        var ejectMenuItem = document.createElement('li');
        var ejectLinkItem = document.createElement('a');
        var ejectText = "

";
        ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
        ejectLinkItem.onclick = function(){
            APP.xmpp.eject(self.peerJid);
            popupmenuElement.setAttribute('style', 'display:none;');
        };

        ejectMenuItem.appendChild(ejectLinkItem);
        popupmenuElement.appendChild(ejectMenuItem);

        var paddingSpan = document.createElement('span');
        paddingSpan.className = 'popupmenuPadding';
        popupmenuElement.appendChild(paddingSpan);
        APP.translation.translateElement(
            $("#" + popupmenuElement.id + " > li > a > div"));
    };

} else {
    RemoteVideo.prototype.addRemoteVideoMenu = function() {};
}

/**
 * Removes the remote stream element corresponding to the given stream and
 * parent container.
 *
 * @param stream the stream
 * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
 */
RemoteVideo.prototype.removeRemoteStreamElement =
    function (stream, isVideo, id) {
    if (!this.container)
        return false;

    var select = null;
    if (isVideo) {
        select = $('#' + id);
    }
    else
        select = $('#' + this.videoSpanId + '>audio');

    select.remove();

    console.info((isVideo ? "Video" : "Audio") +
                 " removed " + this.getResourceJid(), select);

    if (isVideo)
        this.VideoLayout.updateRemovedVideo(this.getResourceJid());
};

/**
 * Removes RemoteVideo from the page.
 */
RemoteVideo.prototype.remove = function () {
    console.log("Remove thumbnail", this.peerJid);
    this.removeConnectionIndicator();
    // Make sure that the large video is updated if are removing its
    // corresponding small video.
    this.VideoLayout.updateRemovedVideo(this.getResourceJid());
    // Remove whole container
    if (this.container.parentNode)
        this.container.parentNode.removeChild(this.container);
};

RemoteVideo.prototype.waitForPlayback = function (sel, stream) {

    var isVideo = stream.getVideoTracks().length > 0;
    if (!isVideo || stream.id === 'mixedmslabel') {
        return;
    }

    var self = this;
    var resourceJid = this.getResourceJid();

    // Register 'onplaying' listener to trigger 'videoactive' on VideoLayout
    // when video playback starts
    var onPlayingHandler = function () {
        // FIXME: why do i have to do this for FF?
        if (RTCBrowserType.isFirefox()) {
            APP.RTC.attachMediaStream(sel, stream);
        }
        if (RTCBrowserType.isTemasysPluginUsed()) {
            sel = self.selectVideoElement();
        }
        self.VideoLayout.videoactive(sel, resourceJid);
        sel[0].onplaying = null;
        if (RTCBrowserType.isTemasysPluginUsed()) {
            // 'currentTime' is used to check if the video has started
            // and the value is not set by the plugin, so we do it
            sel[0].currentTime = 1;
        }
    };
    sel[0].onplaying = onPlayingHandler;
};

RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
    if (!this.container)
        return;

    var self = this;
    var isVideo = stream.getVideoTracks().length > 0;
    var streamElement = SmallVideo.createStreamElement(stream);
    var newElementId = streamElement.id;

    // Put new stream element always in front
    UIUtils.prependChild(this.container, streamElement);

    var sel = $('#' + newElementId);
    sel.hide();

    // If the container is currently visible we attach the stream.
    if (!isVideo || (this.container.offsetParent !== null && isVideo)) {
        this.waitForPlayback(sel, stream);

        APP.RTC.attachMediaStream(sel, stream);
    }

    APP.RTC.addMediaStreamInactiveHandler(
        stream, function () {
            console.log('stream ended', this);

            self.removeRemoteStreamElement(stream, isVideo, newElementId);
    });

    // Add click handler.
    var onClickHandler = function (event) {

        self.VideoLayout.handleVideoThumbClicked(false, self.getResourceJid());

        // On IE we need to populate this handler on video <object>
        // and it does not give event instance as an argument,
        // so we check here for methods.
        if (event.stopPropagation && event.preventDefault) {
            event.stopPropagation();
            event.preventDefault();
        }
        return false;
    };
    this.container.onclick = onClickHandler;
    // reselect
    if (RTCBrowserType.isTemasysPluginUsed())
        sel = $('#' + newElementId);
    sel[0].onclick = onClickHandler;
},

/**
 * Show/hide peer container for the given resourceJid.
 */
RemoteVideo.prototype.showPeerContainer = function (state) {
    if (!this.container)
        return;

    var isHide = state === 'hide';
    var resizeThumbnails = false;

    if (!isHide) {
        if (!$(this.container).is(':visible')) {
            resizeThumbnails = true;
            $(this.container).show();
        }
        // Call showAvatar with undefined, so that we'll figure out if avatar
        // should be displayed based on video muted status and whether or not
        // it's in the lastN set
        this.showAvatar(undefined);
    }
    else if ($(this.container).is(':visible') && isHide)
    {
        resizeThumbnails = true;
        $(this.container).hide();
        if(this.connectionIndicator)
            this.connectionIndicator.hide();
    }

    if (resizeThumbnails) {
        this.VideoLayout.resizeThumbnails();
    }

    // We want to be able to pin a participant from the contact list, even
    // if he's not in the lastN set!
    // ContactList.setClickable(resourceJid, !isHide);

};

RemoteVideo.prototype.removeConnectionIndicator = function () {
    if (this.connectionIndicator)
        this.connectionIndicator.remove();
};

RemoteVideo.prototype.hideConnectionIndicator = function () {
    if (this.connectionIndicator)
        this.connectionIndicator.hide();
};

/**
 * Updates the remote video menu.
 *
 * @param jid the jid indicating the video for which we're adding a menu.
 * @param isMuted indicates the current mute state
 */
RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) {
    var muteMenuItem
        = $('#remote_popupmenu_' + this.getResourceJid() + '>li>a.mutelink');

    var mutedIndicator = "";

    if (muteMenuItem.length) {
        var muteLink = muteMenuItem.get(0);

        if (isMuted === 'true') {
            muteLink.innerHTML = mutedIndicator + ' Muted';
            muteLink.className = 'mutelink disabled';
        }
        else {
            muteLink.innerHTML = mutedIndicator + ' Mute';
            muteLink.className = 'mutelink';
        }
    }
};

/**
 * Sets the display name for the given video span id.
 */
RemoteVideo.prototype.setDisplayName = function(displayName, key) {

    if (!this.container) {
        console.warn( "Unable to set displayName - " + this.videoSpanId +
                " does not exist");
        return;
    }

    var nameSpan = $('#' + this.videoSpanId + '>span.displayname');

    // If we already have a display name for this video.
    if (nameSpan.length > 0) {
        if (displayName && displayName.length > 0) {
            $('#' + this.videoSpanId + '_name').html(displayName);
        }
        else if (key && key.length > 0) {
            var nameHtml = APP.translation.generateTranslationHTML(key);
            $('#' + this.videoSpanId + '_name').html(nameHtml);
        }
        else
            $('#' + this.videoSpanId + '_name').text(
                interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
    } else {
        nameSpan = document.createElement('span');
        nameSpan.className = 'displayname';
        $('#' + this.videoSpanId)[0].appendChild(nameSpan);

        if (displayName && displayName.length > 0) {
            nameSpan.innerText = displayName;
        }
        else
            nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;

        nameSpan.id = this.videoSpanId + '_name';
    }
};

/**
 * Removes remote video menu element from video element identified by
 * given <tt>videoElementId</tt>.
 *
 * @param videoElementId the id of local or remote video element.
 */
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
    var menuSpan = $('#' + this.videoSpanId + '>span.remotevideomenu');
    if (menuSpan.length) {
        menuSpan.remove();
    }
};

RemoteVideo.prototype.getResourceJid = function () {
    if (!this.resourceJid) {
        console.error("Undefined resource jid");
    }
    return this.resourceJid;
};

RemoteVideo.createContainer = function (spanId) {
    var container = document.createElement('span');
    container.id = spanId;
    container.className = 'videocontainer';
    var remotes = document.getElementById('remoteVideos');
    return remotes.appendChild(container);
};

module.exports = RemoteVideo;<commit_msg>Fixes mute check, prevents disabling the menu when the remote participant is muted.<commit_after>/* global $, APP, require, Strophe, interfaceConfig */
var ConnectionIndicator = require("./ConnectionIndicator");
var SmallVideo = require("./SmallVideo");
var AudioLevels = require("../audio_levels/AudioLevels");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
var UIUtils = require("../util/UIUtil");
var XMPPEvents = require("../../../service/xmpp/XMPPEvents");

function RemoteVideo(peerJid, VideoLayout) {
    this.peerJid = peerJid;
    this.resourceJid = Strophe.getResourceFromJid(peerJid);
    this.videoSpanId = 'participant_' + this.resourceJid;
    this.VideoLayout = VideoLayout;
    this.addRemoteVideoContainer();
    this.connectionIndicator = new ConnectionIndicator(
        this, this.peerJid);
    this.setDisplayName();
    var nickfield = document.createElement('span');
    nickfield.className = "nick";
    nickfield.appendChild(document.createTextNode(this.resourceJid));
    this.container.appendChild(nickfield);
    this.bindHoverHandler();
    this.flipX = false;
    this.isLocal = false;
}

RemoteVideo.prototype = Object.create(SmallVideo.prototype);
RemoteVideo.prototype.constructor = RemoteVideo;

RemoteVideo.prototype.addRemoteVideoContainer = function() {
    this.container = RemoteVideo.createContainer(this.videoSpanId);
    if (APP.xmpp.isModerator())
        this.addRemoteVideoMenu();
    AudioLevels.updateAudioLevelCanvas(this.peerJid, this.VideoLayout);

    return this.container;
};

/**
 * Adds the remote video menu element for the given <tt>jid</tt> in the
 * given <tt>parentElement</tt>.
 *
 * @param jid the jid indicating the video for which we're adding a menu.
 * @param parentElement the parent element where this menu will be added
 */

if (!interfaceConfig.filmStripOnly) {
    RemoteVideo.prototype.addRemoteVideoMenu = function () {
        var spanElement = document.createElement('span');
        spanElement.className = 'remotevideomenu';

        this.container.appendChild(spanElement);

        var menuElement = document.createElement('i');
        menuElement.className = 'fa fa-angle-down';
        menuElement.title = 'Remote user controls';
        spanElement.appendChild(menuElement);

        var popupmenuElement = document.createElement('ul');
        popupmenuElement.className = 'popupmenu';
        popupmenuElement.id = 'remote_popupmenu_' + this.getResourceJid();
        spanElement.appendChild(popupmenuElement);

        var muteMenuItem = document.createElement('li');
        var muteLinkItem = document.createElement('a');

        var mutedIndicator = "";

        if (!this.isMuted) {
            muteLinkItem.innerHTML = mutedIndicator +
                "

";
            muteLinkItem.className = 'mutelink';
        }
        else {
            muteLinkItem.innerHTML = mutedIndicator +
                "

";
            muteLinkItem.className = 'mutelink disabled';
        }

        var self = this;
        muteLinkItem.onclick = function(){
            if ($(this).attr('disabled')) {
                event.preventDefault();
            }
            var isMute = !!self.isMuted;
            APP.xmpp.setMute(self.peerJid, !isMute);

            popupmenuElement.setAttribute('style', 'display:none;');

            if (isMute) {
                this.innerHTML = mutedIndicator +
                    "

";
                this.className = 'mutelink disabled';
            }
            else {
                this.innerHTML = mutedIndicator +
                    "

";
                this.className = 'mutelink';
            }
        };

        muteMenuItem.appendChild(muteLinkItem);
        popupmenuElement.appendChild(muteMenuItem);

        var ejectIndicator = "";

        var ejectMenuItem = document.createElement('li');
        var ejectLinkItem = document.createElement('a');
        var ejectText = "

";
        ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
        ejectLinkItem.onclick = function(){
            APP.xmpp.eject(self.peerJid);
            popupmenuElement.setAttribute('style', 'display:none;');
        };

        ejectMenuItem.appendChild(ejectLinkItem);
        popupmenuElement.appendChild(ejectMenuItem);

        var paddingSpan = document.createElement('span');
        paddingSpan.className = 'popupmenuPadding';
        popupmenuElement.appendChild(paddingSpan);
        APP.translation.translateElement(
            $("#" + popupmenuElement.id + " > li > a > div"));
    };

} else {
    RemoteVideo.prototype.addRemoteVideoMenu = function() {};
}

/**
 * Removes the remote stream element corresponding to the given stream and
 * parent container.
 *
 * @param stream the stream
 * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
 */
RemoteVideo.prototype.removeRemoteStreamElement =
    function (stream, isVideo, id) {
    if (!this.container)
        return false;

    var select = null;
    if (isVideo) {
        select = $('#' + id);
    }
    else
        select = $('#' + this.videoSpanId + '>audio');

    select.remove();

    console.info((isVideo ? "Video" : "Audio") +
                 " removed " + this.getResourceJid(), select);

    if (isVideo)
        this.VideoLayout.updateRemovedVideo(this.getResourceJid());
};

/**
 * Removes RemoteVideo from the page.
 */
RemoteVideo.prototype.remove = function () {
    console.log("Remove thumbnail", this.peerJid);
    this.removeConnectionIndicator();
    // Make sure that the large video is updated if are removing its
    // corresponding small video.
    this.VideoLayout.updateRemovedVideo(this.getResourceJid());
    // Remove whole container
    if (this.container.parentNode)
        this.container.parentNode.removeChild(this.container);
};

RemoteVideo.prototype.waitForPlayback = function (sel, stream) {

    var isVideo = stream.getVideoTracks().length > 0;
    if (!isVideo || stream.id === 'mixedmslabel') {
        return;
    }

    var self = this;
    var resourceJid = this.getResourceJid();

    // Register 'onplaying' listener to trigger 'videoactive' on VideoLayout
    // when video playback starts
    var onPlayingHandler = function () {
        // FIXME: why do i have to do this for FF?
        if (RTCBrowserType.isFirefox()) {
            APP.RTC.attachMediaStream(sel, stream);
        }
        if (RTCBrowserType.isTemasysPluginUsed()) {
            sel = self.selectVideoElement();
        }
        self.VideoLayout.videoactive(sel, resourceJid);
        sel[0].onplaying = null;
        if (RTCBrowserType.isTemasysPluginUsed()) {
            // 'currentTime' is used to check if the video has started
            // and the value is not set by the plugin, so we do it
            sel[0].currentTime = 1;
        }
    };
    sel[0].onplaying = onPlayingHandler;
};

RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
    if (!this.container)
        return;

    var self = this;
    var isVideo = stream.getVideoTracks().length > 0;
    var streamElement = SmallVideo.createStreamElement(stream);
    var newElementId = streamElement.id;

    // Put new stream element always in front
    UIUtils.prependChild(this.container, streamElement);

    var sel = $('#' + newElementId);
    sel.hide();

    // If the container is currently visible we attach the stream.
    if (!isVideo || (this.container.offsetParent !== null && isVideo)) {
        this.waitForPlayback(sel, stream);

        APP.RTC.attachMediaStream(sel, stream);
    }

    APP.RTC.addMediaStreamInactiveHandler(
        stream, function () {
            console.log('stream ended', this);

            self.removeRemoteStreamElement(stream, isVideo, newElementId);
    });

    // Add click handler.
    var onClickHandler = function (event) {

        self.VideoLayout.handleVideoThumbClicked(false, self.getResourceJid());

        // On IE we need to populate this handler on video <object>
        // and it does not give event instance as an argument,
        // so we check here for methods.
        if (event.stopPropagation && event.preventDefault) {
            event.stopPropagation();
            event.preventDefault();
        }
        return false;
    };
    this.container.onclick = onClickHandler;
    // reselect
    if (RTCBrowserType.isTemasysPluginUsed())
        sel = $('#' + newElementId);
    sel[0].onclick = onClickHandler;
},

/**
 * Show/hide peer container for the given resourceJid.
 */
RemoteVideo.prototype.showPeerContainer = function (state) {
    if (!this.container)
        return;

    var isHide = state === 'hide';
    var resizeThumbnails = false;

    if (!isHide) {
        if (!$(this.container).is(':visible')) {
            resizeThumbnails = true;
            $(this.container).show();
        }
        // Call showAvatar with undefined, so that we'll figure out if avatar
        // should be displayed based on video muted status and whether or not
        // it's in the lastN set
        this.showAvatar(undefined);
    }
    else if ($(this.container).is(':visible') && isHide)
    {
        resizeThumbnails = true;
        $(this.container).hide();
        if(this.connectionIndicator)
            this.connectionIndicator.hide();
    }

    if (resizeThumbnails) {
        this.VideoLayout.resizeThumbnails();
    }

    // We want to be able to pin a participant from the contact list, even
    // if he's not in the lastN set!
    // ContactList.setClickable(resourceJid, !isHide);

};

RemoteVideo.prototype.removeConnectionIndicator = function () {
    if (this.connectionIndicator)
        this.connectionIndicator.remove();
};

RemoteVideo.prototype.hideConnectionIndicator = function () {
    if (this.connectionIndicator)
        this.connectionIndicator.hide();
};

/**
 * Updates the remote video menu.
 *
 * @param jid the jid indicating the video for which we're adding a menu.
 * @param isMuted indicates the current mute state
 */
RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) {
    var muteMenuItem
        = $('#remote_popupmenu_' + this.getResourceJid() + '>li>a.mutelink');

    var mutedIndicator = "";

    if (muteMenuItem.length) {
        var muteLink = muteMenuItem.get(0);

        if (isMuted) {
            muteLink.innerHTML = mutedIndicator + ' Muted';
            muteLink.className = 'mutelink disabled';
        }
        else {
            muteLink.innerHTML = mutedIndicator + ' Mute';
            muteLink.className = 'mutelink';
        }
    }
};

/**
 * Sets the display name for the given video span id.
 */
RemoteVideo.prototype.setDisplayName = function(displayName, key) {

    if (!this.container) {
        console.warn( "Unable to set displayName - " + this.videoSpanId +
                " does not exist");
        return;
    }

    var nameSpan = $('#' + this.videoSpanId + '>span.displayname');

    // If we already have a display name for this video.
    if (nameSpan.length > 0) {
        if (displayName && displayName.length > 0) {
            $('#' + this.videoSpanId + '_name').html(displayName);
        }
        else if (key && key.length > 0) {
            var nameHtml = APP.translation.generateTranslationHTML(key);
            $('#' + this.videoSpanId + '_name').html(nameHtml);
        }
        else
            $('#' + this.videoSpanId + '_name').text(
                interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
    } else {
        nameSpan = document.createElement('span');
        nameSpan.className = 'displayname';
        $('#' + this.videoSpanId)[0].appendChild(nameSpan);

        if (displayName && displayName.length > 0) {
            nameSpan.innerText = displayName;
        }
        else
            nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;

        nameSpan.id = this.videoSpanId + '_name';
    }
};

/**
 * Removes remote video menu element from video element identified by
 * given <tt>videoElementId</tt>.
 *
 * @param videoElementId the id of local or remote video element.
 */
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
    var menuSpan = $('#' + this.videoSpanId + '>span.remotevideomenu');
    if (menuSpan.length) {
        menuSpan.remove();
    }
};

RemoteVideo.prototype.getResourceJid = function () {
    if (!this.resourceJid) {
        console.error("Undefined resource jid");
    }
    return this.resourceJid;
};

RemoteVideo.createContainer = function (spanId) {
    var container = document.createElement('span');
    container.id = spanId;
    container.className = 'videocontainer';
    var remotes = document.getElementById('remoteVideos');
    return remotes.appendChild(container);
};

module.exports = RemoteVideo;<|endoftext|>


<commit_before>/*
 Copyright 2012 - $Date $ by PeopleWare n.v.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

define(["doh/main", "dojo/_base/lang"],
  function(doh, lang) {

    console.log("Loading ppwcode contracts doh extension");

//    var InvariantViolationError = declare(null, {
//      instance: null,
//      invariant: null,
//      constructor: function(instance, invariant) {
//        this.instance = instance;
//        this.invariant = invariant;
//      }
//    });

    doh._flattenInvars = function(context, /*Array*/ a, /*Array*/ acc) {
      doh.isNot(null, context);
      doh.isNot(null, a);
      doh.t(a instanceof Array);
      doh.isNot(null, acc);
      doh.t(acc instanceof Array);

      function forAllElementsOf(forAllInvar) {
        var conditionResult = forAllInvar.condition.call(context);
        if (conditionResult) {
          var selection = forAllInvar.selector.call(context);
          if (selection instanceof Array) {
            // for all elements
            var j;
            for (j = 0; j < selection.length; j++) {
              doh._flattenInvars(selection[j], forAllInvar.invars, acc);
            }
          }
          else {
            // selection is Object
            var propName;
            for (propName in selection) {
              if (selection.hasOwnProperty(propName)) {
                doh._flattenInvars(selection[propName], forAllInvar.invars, acc);
              }
              //else NOP
            }
          }
        }
      }

      var i;
      for (i = 0; i < a.length; i++) {
        var el = a[i];
        if (el instanceof Function) {
          acc.push({
            testMethodForPrint: el.toString(),
            testMethodInContext: lang.hitch(context, el)
          });
        }
        else {
          // we expect an object {condition: /*Function (optional)*/, objectSelector: /*Function*/, invars: /*Array*/ of /*Function*/
          if (el.hasOwnProperty("condition")) {
            forAllElementsOf(el);
          }
        }
      }
    };

    doh.validateInvariants = function(subject) {
      // subject is a _Mixin IDEA check with duck typing
      doh.isNot(null, subject);
      doh.t("_c_invar" in subject);
      doh.isNot(null, subject._c_invar);
      doh.t(subject._c_invar instanceof Array);

      var invars = [];
      this._flattenInvars(subject, subject._c_invar, invars);

      var i;
      for (i = 0; i < invars.length; i++) {
        var invar = invars[i];
        doh.isNot(null, invar);
        doh.t(invar.testMethodInContext instanceof Function);

        // inject for this
        var result = invar.testMethodInContext();
        if (!result) {
          throw new doh._AssertFailure("invariant error: " + invar.testMethodForPrint + " (on " + subject.toString() + ")");
        }
      }
    };
    doh.invars = doh.validateInvariants;

    doh.assertFailure = function(/*String?*/ hint, /*Error*/ error) {
      // summary:
      //    The test failed.
      var msg = "test failed";
      if (error) {
        msg += ('" + error + "');
      }
      throw new doh._AssertFailure(msg, hint);
    };
    doh.fail = doh.assertFailure;

    doh.unexpectedException = function(/*Error*/ exc) {
      // summary:
      //    exc was encountered, and this was unexpected
      var msg = "encountered an unexpected exception";
      throw new doh._AssertFailure(msg, exc);
    };
    doh.exc = doh.unexpectedException;

    var Test = function(kwargs) {
      lang.mixin(this, kwargs);
    };
    Test.prototype = {

      name: null,

      argFactories: null, // lock a copy in scope of this test

      testMethod: null,

      instantiateArguments: function() {

        function argInstance(argFactoryOrConstant) {
          if (typeof argFactoryOrConstant.factoryOrConstant === "function") {
            return argFactoryOrConstant.factoryOrConstant();
          }
          return argFactoryOrConstant.factoryOrConstant;
        }

        var self = this;
        var args = self.argFactories.map(argInstance);
        args = args.map(function(arg) {
          if (arg === "$this") {
            return args[0];
          }
          if (arg === "$this()") {
            return argInstance(self.argFactories[0]);
          }
          var match = /^\$args\[(\d+)\](\(\))?$/.exec(arg);
          if (match) {
            if (match.length === 3) {
              return argInstance(self.argFactories[match[1]]);
            }
            if (match.length === 2) {
              return args[match[1]];
            }
          }
          return arg;
        });
        return args;
      },

      runTest: function() {
        var args = this.instantiateArguments();
        this.testMethod.apply(this, args);
      }

    };

    var groupCache = [];

    function cached(Type) {
      if (!Type) {
        return "untyped";
      }
      var index = groupCache.indexOf(Type);
      if (index < 0) {
        index = groupCache.push(Type) - 1;
      }
      return "test group " + index;
    }

    function groupId(/*Function?*/ Type) {
      if (Type && (Type.mid || Type.declaredClass || Type.name)) {
        return Type.mid || Type.declaredClass || Type.name;
      }
      return cached(Type);
    }

    var testCounter = 0;

    doh.createMethodTest = function(Type, methodName, testMethod, argFactories) {

      if (argFactories.length > 0) {
        doh.register(
          groupId(Type),
          new Test({
            name: "(" + testCounter + ") " + methodName + " - " +
                  argFactories.map(function(af) {return af.argRepr;}).join("; "),
            argFactories: argFactories.slice(), // lock a copy in scope of this test
            testMethod: testMethod
          })
        );
        testCounter++;
      }
    };

    return doh;
  }
);
<commit_msg>removed superfluous code in comments<commit_after>/*
 Copyright 2012 - $Date $ by PeopleWare n.v.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

define(["doh/main", "dojo/_base/lang"],
  function(doh, lang) {

    console.log("Loading ppwcode contracts doh extension");

    doh._flattenInvars = function(context, /*Array*/ a, /*Array*/ acc) {
      doh.isNot(null, context);
      doh.isNot(null, a);
      doh.t(a instanceof Array);
      doh.isNot(null, acc);
      doh.t(acc instanceof Array);

      function forAllElementsOf(forAllInvar) {
        var conditionResult = forAllInvar.condition.call(context);
        if (conditionResult) {
          var selection = forAllInvar.selector.call(context);
          if (selection instanceof Array) {
            // for all elements
            var j;
            for (j = 0; j < selection.length; j++) {
              doh._flattenInvars(selection[j], forAllInvar.invars, acc);
            }
          }
          else {
            // selection is Object
            var propName;
            for (propName in selection) {
              if (selection.hasOwnProperty(propName)) {
                doh._flattenInvars(selection[propName], forAllInvar.invars, acc);
              }
              //else NOP
            }
          }
        }
      }

      var i;
      for (i = 0; i < a.length; i++) {
        var el = a[i];
        if (el instanceof Function) {
          acc.push({
            testMethodForPrint: el.toString(),
            testMethodInContext: lang.hitch(context, el)
          });
        }
        else {
          // we expect an object {condition: /*Function (optional)*/, objectSelector: /*Function*/, invars: /*Array*/ of /*Function*/
          if (el.hasOwnProperty("condition")) {
            forAllElementsOf(el);
          }
        }
      }
    };

    doh.validateInvariants = function(subject) {
      // subject is a _Mixin IDEA check with duck typing
      doh.isNot(null, subject);
      doh.t("_c_invar" in subject);
      doh.isNot(null, subject._c_invar);
      doh.t(subject._c_invar instanceof Array);

      var invars = [];
      this._flattenInvars(subject, subject._c_invar, invars);

      var i;
      for (i = 0; i < invars.length; i++) {
        var invar = invars[i];
        doh.isNot(null, invar);
        doh.t(invar.testMethodInContext instanceof Function);

        // inject for this
        var result = invar.testMethodInContext();
        if (!result) {
          throw new doh._AssertFailure("invariant error: " + invar.testMethodForPrint + " (on " + subject.toString() + ")");
        }
      }
    };
    doh.invars = doh.validateInvariants;

    doh.assertFailure = function(/*String?*/ hint, /*Error*/ error) {
      // summary:
      //    The test failed.
      var msg = "test failed";
      if (error) {
        msg += ('" + error + "');
      }
      throw new doh._AssertFailure(msg, hint);
    };
    doh.fail = doh.assertFailure;

    doh.unexpectedException = function(/*Error*/ exc) {
      // summary:
      //    exc was encountered, and this was unexpected
      var msg = "encountered an unexpected exception";
      throw new doh._AssertFailure(msg, exc);
    };
    doh.exc = doh.unexpectedException;

    var Test = function(kwargs) {
      lang.mixin(this, kwargs);
    };
    Test.prototype = {

      name: null,

      argFactories: null, // lock a copy in scope of this test

      testMethod: null,

      instantiateArguments: function() {

        function argInstance(argFactoryOrConstant) {
          if (typeof argFactoryOrConstant.factoryOrConstant === "function") {
            return argFactoryOrConstant.factoryOrConstant();
          }
          return argFactoryOrConstant.factoryOrConstant;
        }

        var self = this;
        var args = self.argFactories.map(argInstance);
        args = args.map(function(arg) {
          if (arg === "$this") {
            return args[0];
          }
          if (arg === "$this()") {
            return argInstance(self.argFactories[0]);
          }
          var match = /^\$args\[(\d+)\](\(\))?$/.exec(arg);
          if (match) {
            if (match.length === 3) {
              return argInstance(self.argFactories[match[1]]);
            }
            if (match.length === 2) {
              return args[match[1]];
            }
          }
          return arg;
        });
        return args;
      },

      runTest: function() {
        var args = this.instantiateArguments();
        this.testMethod.apply(this, args);
      }

    };

    var groupCache = [];

    function cached(Type) {
      if (!Type) {
        return "untyped";
      }
      var index = groupCache.indexOf(Type);
      if (index < 0) {
        index = groupCache.push(Type) - 1;
      }
      return "test group " + index;
    }

    function groupId(/*Function?*/ Type) {
      if (Type && (Type.mid || Type.declaredClass || Type.name)) {
        return Type.mid || Type.declaredClass || Type.name;
      }
      return cached(Type);
    }

    var testCounter = 0;

    doh.createMethodTest = function(Type, methodName, testMethod, argFactories) {

      if (argFactories.length > 0) {
        doh.register(
          groupId(Type),
          new Test({
            name: "(" + testCounter + ") " + methodName + " - " +
                  argFactories.map(function(af) {return af.argRepr;}).join("; "),
            argFactories: argFactories.slice(), // lock a copy in scope of this test
            testMethod: testMethod
          })
        );
        testCounter++;
      }
    };

    return doh;
  }
);
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      29.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('core/utility/logger.js');

/**
 * @class
 *
 * The observable knows all observers, mainly views, and pushes updates if necessary.
 *
 * @extends M.Object
 */
M.Observable = M.Object.extend(
/** @scope M.Observable.prototype */ {

    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.Observable',

    /**
     * List that contains pairs of an observer with an observable. An observer is tightened to one
     * observable, but one observable can have multiple observers.
     *
     * @type Array|Object
     */
    bindingList: null,

    /**
     * Attach an observer to an observable.
     *
     * @param {String} observer The observer.
     * @param {String} observable The observable.
     */
    attach: function(observer, observable) {
        if(!this.bindingList) {
            this.bindingList = [];
        }
        this.bindingList.push({
            observer: observer,
            observable: observable
        });
    },

    /**
     * Detach an observer from an observable.
     *
     * @param {String} observer The observer.
     */
    detach: function(observer) {
        /* grep is a jQuery function that finds
         * elements in an array that satisfy a certain criteria.
         * It works on a copy so we have to assign the "cleaned"
         * array to our bindingList.
         */
        this.bindlingList = $.grep(this.bindlingList, function(value, index) {
                return value.observer !== observer;
        });
    },

    /**
     * Notify all observers that observe the property behind 'key'.
     *
     * @param {String} key The key of the property that changed.
     */
    notifyObservers: function(key) {
        _.each(this.bindingList, function(entry){
            if(key === entry.observable) {
                entry.observer.contentDidChange();
            } else if(entry.observable.indexOf(key.substring(0, key.lastIndexOf('.'))) === 0) {//entry.observable.indexOf(key + '.') === 0 ||
                entry.observer.contentDidChange();
            }
        });
    }

});<commit_msg>fixed a bug in notifyObservers()<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      29.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('core/utility/logger.js');

/**
 * @class
 *
 * The observable knows all observers, mainly views, and pushes updates if necessary.
 *
 * @extends M.Object
 */
M.Observable = M.Object.extend(
/** @scope M.Observable.prototype */ {

    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.Observable',

    /**
     * List that contains pairs of an observer with an observable. An observer is tightened to one
     * observable, but one observable can have multiple observers.
     *
     * @type Array|Object
     */
    bindingList: null,

    /**
     * Attach an observer to an observable.
     *
     * @param {String} observer The observer.
     * @param {String} observable The observable.
     */
    attach: function(observer, observable) {
        if(!this.bindingList) {
            this.bindingList = [];
        }
        this.bindingList.push({
            observer: observer,
            observable: observable
        });
    },

    /**
     * Detach an observer from an observable.
     *
     * @param {String} observer The observer.
     */
    detach: function(observer) {
        /* grep is a jQuery function that finds
         * elements in an array that satisfy a certain criteria.
         * It works on a copy so we have to assign the "cleaned"
         * array to our bindingList.
         */
        this.bindlingList = $.grep(this.bindlingList, function(value, index) {
                return value.observer !== observer;
        });
    },

    /**
     * Notify all observers that observe the property behind 'key'.
     *
     * @param {String} key The key of the property that changed.
     */
    notifyObservers: function(key) {
        _.each(this.bindingList, function(entry){
            if(key === entry.observable || (entry.observable.indexOf('.') > 0 && entry.observable.indexOf(key) > -1)) {
                entry.observer.contentDidChange();
            } else if(key.indexOf('.') > 0 && entry.observable.indexOf(key.substring(0, key.lastIndexOf('.'))) === 0) {
                entry.observer.contentDidChange();
            }
        });
    }

});<|endoftext|>


<commit_before>'use strict';

module.exports = {

  QUERY_TEMPLATES: {
    // annotation query -- using 'mockUser' for now until user support is added
    annotationQuery: {
        query: {
            query: {
                bool : {
                    must : [
                        {
                            term : { uri : '' }
                        },
                        {
                            term : { user : '' }
                        }
                    ]
                }
            }
        },
        pathsToValues: [
            'query.bool.must[0].term.uri', 'query.bool.must[1].term.user'
        ]
    },
    // Common query used among entities
    commonMatchQuery: {
        query:{
            match:{ '{{field}}' : '{{{value}}}' }
        }
    },

    commonTermQuery: {
        query:{
            term:{ '{{field}}' : '{{{value}}}' }
        }
    },

    commonMatchQueryOfferSorted: {
        query:{
            match:{ '{{field}}' : '{{value}}' }
        },
        "sort": [
                  {
                    "validFrom": {
                    "order": "desc"
                }
            }
        ]
    },

    offerLocation:{
      "aggs": {
        "phone": {
          "filter": {
            "term": {
              "{{field}}": "{{value}}"
            }
          },
          "aggs": {
            "city": {
              "terms": {
                "field": "availableAtOrFrom.address.key",
                "size": 0
              }
            }
          }
        }
      },
      "size": 0
    },

    peopleFeatures: {
      "query": {
        "filtered": {
          "filter": {
            "term": {
              "{{filterField}}": "{{filterValue}}"
            }
          }
        }
<<<<<<< HEAD
    },
    phoneOrEmailPeopleAggForImages: {
       "query": {
           "ids":{
                "values": "{{value}}"
           }
       },
       "aggs" : {
           "people_names": {
               "terms": {
                   "field": "name.raw",
                   "size": 0
               }
           },
           "people_ages": {
               "terms": {
                   "field": "age",
                   "size": 0
               }
           },
           "people_ethnicities": {
               "terms": {
                   "field": "ethnicity",
                   "size": 0
               }
           }
       }
    },
    // same one used in phone/email
    sellerPeopleAggs: {
        "query": {
            "filtered": {
                "filter": {
                    "term": {
                        "{{field}}": "{{value}}"
                    }
                }
            }
        },
        "aggs" : {
            "people_names": {
                "terms": {
                    "field": "name.raw",
                    "size": 0
                }
            },
            "people_ages": {
                "terms": {
                    "field": "age",
                    "size": 0
                }
            },
            "people_ethnicities": {
                "terms": {
                    "field": "ethnicity",
                    "size": 0
                }
            }
=======
      },
      "aggs": {
        "people_features": {
          "terms": {
            "field": "{{aggregationField}}",
            "size": 0
          }
>>>>>>> 7cc2c6f48775ad78ab29fdd10099a0afc0eed09b
        }
      }
    },

    offerRevisions: {
        query: {
            "query": {
                "filtered": {
                    "query": {
                        "match": { 'mainEntityOfPage.url.raw' : '' }
                    },
                    "filter": {
                        "not": {
                            "term": { 'uri' : '' }
                        }
                   }
                }
            }
        },
        pathsToValues: [
            "query.filtered.query.match['mainEntityOfPage.url.raw']",
            "query.filtered.filter.not.term['uri']"
        ]

   },

    // webpage entity queries
    webpageRevisions: {
        "query": {
            "filtered": {
                "filter": {
                    "term": {
                        '{{field}}' : '{{value}}'
                    }
                }
            }
        },
        "aggs": {
            "page_revisions": {
                "date_histogram": {
                    "field": "dateCreated",
                    "interval": "week"
                }
            }
        }
    },

    locationTimeline: {
      "aggs": {
        "location_timeline": {
          "filter": {
            "term": {
              '{{field}}': '{{value}}'
            }
          },
          "aggs": {
            "dates": {
              "date_histogram": {
                "field": "validFrom",
                "interval": "day"
              },
              "aggs": {
                "locations": {
                  "terms": {
                    "field": "availableAtOrFrom.address.key",
                    "order": { "_term" : "asc" },
                    "size": 0
                  },
                  "aggs": {
                    "publisher": {
                      "terms": {
                        "field": "mainEntityOfPage.publisher.name.raw",
                        "size": 0
                      }
                    },
                    "mentions": {
                      "terms": {
                        "field": "mainEntityOfPage.mentions",
                        "size": 0
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "size": 0
    }
  }
};
<commit_msg>fixes<commit_after>'use strict';

module.exports = {

  QUERY_TEMPLATES: {
    // annotation query -- using 'mockUser' for now until user support is added
    annotationQuery: {
        query: {
            query: {
                bool : {
                    must : [
                        {
                            term : { uri : '' }
                        },
                        {
                            term : { user : '' }
                        }
                    ]
                }
            }
        },
        pathsToValues: [
            'query.bool.must[0].term.uri', 'query.bool.must[1].term.user'
        ]
    },
    // Common query used among entities
    commonMatchQuery: {
        query:{
            match:{ '{{field}}' : '{{{value}}}' }
        }
    },

    commonTermQuery: {
        query:{
            term:{ '{{field}}' : '{{{value}}}' }
        }
    },

    commonMatchQueryOfferSorted: {
        query:{
            match:{ '{{field}}' : '{{value}}' }
        },
        "sort": [
                  {
                    "validFrom": {
                    "order": "desc"
                }
            }
        ]
    },

    offerLocation:{
      "aggs": {
        "phone": {
          "filter": {
            "term": {
              "{{field}}": "{{value}}"
            }
          },
          "aggs": {
            "city": {
              "terms": {
                "field": "availableAtOrFrom.address.key",
                "size": 0
              }
            }
          }
        }
      },
      "size": 0
    },

    peopleFeatures: {
      "query": {
        "filtered": {
          "filter": {
            "term": {
              "{{filterField}}": "{{filterValue}}"
            }
          }
        }
    },
    phoneOrEmailPeopleAggForImages: {
       "query": {
           "ids":{
                "values": "{{value}}"
           }
       },
       "aggs" : {
           "people_names": {
               "terms": {
                   "field": "name.raw",
                   "size": 0
               }
           },
           "people_ages": {
               "terms": {
                   "field": "age",
                   "size": 0
               }
           },
           "people_ethnicities": {
               "terms": {
                   "field": "ethnicity",
                   "size": 0
               }
           }
       }
    },
    // same one used in phone/email
    sellerPeopleAggs: {
        "query": {
            "filtered": {
                "filter": {
                    "term": {
                        "{{field}}": "{{value}}"
                    }
                }
            }
        },
        "aggs" : {
            "people_names": {
                "terms": {
                    "field": "name.raw",
                    "size": 0
                }
            },
            "people_ages": {
                "terms": {
                    "field": "age",
                    "size": 0
                }
            },
            "people_ethnicities": {
                "terms": {
                    "field": "ethnicity",
                    "size": 0
                }
            }
        }
      }
    },

    offerRevisions: {
        query: {
            "query": {
                "filtered": {
                    "query": {
                        "match": { 'mainEntityOfPage.url.raw' : '' }
                    },
                    "filter": {
                        "not": {
                            "term": { 'uri' : '' }
                        }
                   }
                }
            }
        },
        pathsToValues: [
            "query.filtered.query.match['mainEntityOfPage.url.raw']",
            "query.filtered.filter.not.term['uri']"
        ]

   },

    // webpage entity queries
    webpageRevisions: {
        "query": {
            "filtered": {
                "filter": {
                    "term": {
                        '{{field}}' : '{{value}}'
                    }
                }
            }
        },
        "aggs": {
            "page_revisions": {
                "date_histogram": {
                    "field": "dateCreated",
                    "interval": "week"
                }
            }
        }
    },

    locationTimeline: {
      "aggs": {
        "location_timeline": {
          "filter": {
            "term": {
              '{{field}}': '{{value}}'
            }
          },
          "aggs": {
            "dates": {
              "date_histogram": {
                "field": "validFrom",
                "interval": "day"
              },
              "aggs": {
                "locations": {
                  "terms": {
                    "field": "availableAtOrFrom.address.key",
                    "order": { "_term" : "asc" },
                    "size": 0
                  },
                  "aggs": {
                    "publisher": {
                      "terms": {
                        "field": "mainEntityOfPage.publisher.name.raw",
                        "size": 0
                      }
                    },
                    "mentions": {
                      "terms": {
                        "field": "mainEntityOfPage.mentions",
                        "size": 0
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "size": 0
    }
  }
};
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import styled from 'styled-components'
import * as theme from '../theme'
import Spinner from 'react-spinkit'

const Wrapper = styled.figure`
	margin: 0;
	display: flex;
	justify-content: center;
	align-items: center;
	flex-flow: column nowrap;
`

const Message = styled.figcaption`
	font-weight: 300;
	margin-top: 1em;
	color: ${theme.gray};

	&.info {
		color: ${theme.green};
	}
	&.warning {
		color: ${theme.orange};
	}
	&.error {
		color: ${theme.red};
	}
`

type LoadingProps = {
	children?: any,
	className?: string,
}

export default function Loading({className, children}: LoadingProps) {
	return (
		<Wrapper>
			<Spinner name="wave" color={theme.gray600} fadeIn="none" />
			<Message className={className}>{children}</Message>
		</Wrapper>
	)
}
<commit_msg>move className on Loading to the wrapper and use css variables<commit_after>// @flow
import React from 'react'
import styled from 'styled-components'
import * as theme from '../theme'
import Spinner from 'react-spinkit'

const Wrapper = styled.figure`
	margin: 0;
	display: flex;
	justify-content: center;
	align-items: center;
	flex-flow: column nowrap;
`

const Message = styled.figcaption`
	font-weight: 300;
	margin-top: 1em;
	color: var(--gray);

	&.info {
		color: var(--green);
	}
	&.warning {
		color: var(--orange);
	}
	&.error {
		color: var(--red);
	}
`

type LoadingProps = {
	children?: any,
	className?: string,
}

export default function Loading({className, children}: LoadingProps) {
	return (
		<Wrapper className={className}>
			<Spinner name="wave" color={theme.gray600} fadeIn="none" />
			<Message>{children}</Message>
		</Wrapper>
	)
}
<|endoftext|>


<commit_before>// @flow

import * as React from 'react'
import {Link} from '@reach/router'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {Icon} from './icon'
import {Toolbar, ToolbarButton} from './toolbar'
import Separator from './separator'
import {undo, redo} from '../redux/students/actions/undo'
import {
	iosUndo,
	iosUndoOutline,
	iosRedo,
	iosRedoOutline,
	iosSearch,
	iosPeopleOutline,
	iosUploadOutline,
	grid,
} from '../icons/ionicons'
import styled from 'styled-components'
import type {HydratedStudentType} from '@gob/object-student'
import type {Undoable} from '../types'

type Props = {
	redo: string => any,
	removeCourse: Function,
	student: Undoable<HydratedStudentType>,
	undo: string => any,

	search?: boolean,
	share?: boolean,
	backTo?: 'picker' | 'overview',
}

const StudentButtonsToolbar = styled(Toolbar)`
	margin-bottom: 0.5em;
	flex-shrink: 0;
`

export function SidebarToolbar(props: Props) {
	const {undo, redo, search = true, share = true, backTo = 'picker'} = props

	let student = props.student.present
	let studentId = student.id
	let canUndo = props.student.past.length > 0
	let canRedo = props.student.future.length > 0

	let toPicker = backTo === 'picker'
	let toOverview = backTo === 'overview'

	return (
		<StudentButtonsToolbar>
			{toPicker ? (
				<ToolbarButton as={Link} to="/" title="Students">
					<Icon block large>
						{iosPeopleOutline}
					</Icon>
				</ToolbarButton>
			) : toOverview ? (
				<ToolbarButton as={Link} to="../.." title="Courses">
					<Icon block large>
						{grid}
					</Icon>
				</ToolbarButton>
			) : (

			)}

			<Separator type="spacer" />

			{search ? (
				<ToolbarButton as={Link} to="./search" title="Search">
					<Icon block large>
						{iosSearch}
					</Icon>
				</ToolbarButton>
			) : (

			)}

			<ToolbarButton
				title="Undo"
				onClick={() => undo(studentId)}
				disabled={!canUndo}
			>
				<Icon block large>
					{!canUndo ? iosUndoOutline : iosUndo}
				</Icon>
			</ToolbarButton>
			<ToolbarButton
				title="Redo"
				onClick={() => redo(studentId)}
				disabled={!canRedo}
			>
				<Icon block large>
					{!canRedo ? iosRedoOutline : iosRedo}
				</Icon>
			</ToolbarButton>

			<Separator type="spacer" />

			{share ? (
				<ToolbarButton as={Link} to="?share" title="Share">
					<Icon block large>
						{iosUploadOutline}
					</Icon>
				</ToolbarButton>
			) : (

			)}
		</StudentButtonsToolbar>
	)
}

const mapDispatch = dispatch => bindActionCreators({undo, redo}, dispatch)

// $FlowFixMe
export const ConnectedSidebarToolbar = connect(
	undefined,
	mapDispatch,
)(SidebarToolbar)
<commit_msg>remove spacers<commit_after>// @flow

import * as React from 'react'
import {Link} from '@reach/router'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {Icon} from './icon'
import {Toolbar, ToolbarButton} from './toolbar'
import Separator from './separator'
import {undo, redo} from '../redux/students/actions/undo'
import {
	iosUndo,
	iosUndoOutline,
	iosRedo,
	iosRedoOutline,
	iosSearch,
	iosPeopleOutline,
	iosUploadOutline,
	grid,
} from '../icons/ionicons'
import styled from 'styled-components'
import type {HydratedStudentType} from '@gob/object-student'
import type {Undoable} from '../types'

type Props = {
	redo: string => any,
	removeCourse: Function,
	student: Undoable<HydratedStudentType>,
	undo: string => any,

	search?: boolean,
	share?: boolean,
	backTo?: 'picker' | 'overview',
}

const StudentButtonsToolbar = styled(Toolbar)`
	margin-bottom: 0.5em;
	flex-shrink: 0;
`

export function SidebarToolbar(props: Props) {
	const {undo, redo, search = true, share = true, backTo = 'picker'} = props

	let student = props.student.present
	let studentId = student.id
	let canUndo = props.student.past.length > 0
	let canRedo = props.student.future.length > 0

	let toPicker = backTo === 'picker'
	let toOverview = backTo === 'overview'

	return (
		<StudentButtonsToolbar>
			{toPicker ? (
				<ToolbarButton as={Link} to="/" title="Students">
					<Icon block large>
						{iosPeopleOutline}
					</Icon>
				</ToolbarButton>
			) : toOverview ? (
				<ToolbarButton as={Link} to="../.." title="Courses">
					<Icon block large>
						{grid}
					</Icon>
				</ToolbarButton>
			) : (

			)}

			{search ? (
				<ToolbarButton as={Link} to="./search" title="Search">
					<Icon block large>
						{iosSearch}
					</Icon>
				</ToolbarButton>
			) : (

			)}

			<ToolbarButton
				title="Undo"
				onClick={() => undo(studentId)}
				disabled={!canUndo}
			>
				<Icon block large>
					{!canUndo ? iosUndoOutline : iosUndo}
				</Icon>
			</ToolbarButton>

			<ToolbarButton
				title="Redo"
				onClick={() => redo(studentId)}
				disabled={!canRedo}
			>
				<Icon block large>
					{!canRedo ? iosRedoOutline : iosRedo}
				</Icon>
			</ToolbarButton>

			{share ? (
				<ToolbarButton as={Link} to="?share" title="Share">
					<Icon block large>
						{iosUploadOutline}
					</Icon>
				</ToolbarButton>
			) : (

			)}
		</StudentButtonsToolbar>
	)
}

const mapDispatch = dispatch => bindActionCreators({undo, redo}, dispatch)

// $FlowFixMe
export const ConnectedSidebarToolbar = connect(
	undefined,
	mapDispatch,
)(SidebarToolbar)
<|endoftext|>