<commit_before>var myLatLng = {lat: -36.8576017, lng: 174.7590294};
var image = 'here.png';
var zoomAmount = 18;
var map, marker, infoWindow;

function getFoodPlaces(){
	var service = new google.maps.places.PlacesService(map);
	service.nearbySearch({
		location: myLatLng,
		radius: 500,
		types: ['bakery', 'bar' , 'cafe','food',
		'grocery_or_supermarket', 'hospital', 'meal_delivery' , 'meal_takeaway',
		'restaurant' , 'school']
	}, createFoodMarker);
}

function createFoodMarker(results, status) {
	if (status === google.maps.places.PlacesServiceStatus.OK) {
		for (var i = 0; i < results.length; i++) {
			createMarker(results[i]);
		}
	}
}

function createMarker(place) {
	var placeLoc = place.geometry.location;
	var marker = new google.maps.Marker({
		position: place.geometry.location,
		map: map
	});
	var infoWindowContent = place.name + '
 5 min away';

	google.maps.event.addListener(marker, 'click', function() {
		infoWindow.setContent(infoWindowContent);
		infoWindow.open(map, this);
	});
}

function loadFoodPage(){
	console.log("1");
	window.location.href = "food.html";
}

function initInfoWindow(){
	infoWindow = new google.maps.InfoWindow({
		map: map,
		content: 'You are here'
	});
	infoWindow.open(map, marker);
	google.maps.event.addListener(infoWindow, 'click', loadFoodPage());
}

function initMarker(){
	marker = new google.maps.Marker({
		position: myLatLng,
		map: map,
		icon: image
	});
}

function initMap() {
	map = new google.maps.Map(document.getElementById('map'), {
		zoom: zoomAmount,
		center: myLatLng
	});

	initMarker();
	initInfoWindow();
	getFoodPlaces();
}

<commit_msg>added link to info window maps<commit_after>var myLatLng = {lat: -36.8576017, lng: 174.7590294};
var image = 'here.png';
var zoomAmount = 18;
var map, marker, infoWindow;

function getFoodPlaces(){
	var service = new google.maps.places.PlacesService(map);
	service.nearbySearch({
		location: myLatLng,
		radius: 500,
		types: ['bakery', 'bar' , 'cafe','food',
		'grocery_or_supermarket', 'hospital', 'meal_delivery' , 'meal_takeaway',
		'restaurant' , 'school']
	}, createFoodMarker);
}

function createFoodMarker(results, status) {
	if (status === google.maps.places.PlacesServiceStatus.OK) {
		for (var i = 0; i < results.length; i++) {
			createMarker(results[i]);
		}
	}
}

function createMarker(place) {
	var placeLoc = place.geometry.location;
	var marker = new google.maps.Marker({
		position: place.geometry.location,
		map: map
	});
	var infoWindowContent = place.name + '
 5 min away';

	google.maps.event.addListener(marker, 'click', function() {
		infoWindow.setContent(infoWindowContent);
		infoWindow.open(map, this);
	});
}

function loadFoodPage(){
	console.log("1");
	window.location.href = "food.html";
}

function initInfoWindow(){
	infoWindow = new google.maps.InfoWindow({
		map: map,
		content: 'You are here'
	});
	infoWindow.open(map, marker);
	google.maps.event.addListener(infoWindow, 'click', loadFoodPage);
}

function initMarker(){
	marker = new google.maps.Marker({
		position: myLatLng,
		map: map,
		icon: image
	});
}

function initMap() {
	map = new google.maps.Map(document.getElementById('map'), {
		zoom: zoomAmount,
		center: myLatLng
	});

	initMarker();
	initInfoWindow();
	getFoodPlaces();
}

<|endoftext|>


<commit_before>var myLatLng = {lat: -36.8576017, lng: 174.7590294};
var image = 'here.png';
var zoomAmount = 18;
var map, marker, infoWindow;

function getFoodPlaces(){
	var service = new google.maps.places.PlacesService(map);
	service.nearbySearch({
		location: myLatLng,
		radius: 500,
		types: ['bakery', 'bar' , 'cafe','food',
		'grocery_or_supermarket', 'hospital', 'meal_delivery' , 'meal_takeaway',
		'restaurant' , 'school']
	}, createFoodMarker);
}

function createFoodMarker(results, status) {
	if (status === google.maps.places.PlacesServiceStatus.OK) {
		for (var i = 0; i < results.length; i++) {
			createMarker(results[i]);
		}
	}
}

function createMarker(place) {
	var placeLoc = place.geometry.location;
	var marker = new google.maps.Marker({
		position: place.geometry.location,
		map: map
	});
	var infoWindowContent = '' + place.name + '
 5 min away';

	google.maps.event.addListener(marker, 'click', function() {
		infoWindow.setContent(infoWindowContent);
		infoWindow.open(map, this);
	});
}

function loadFoodPage(){
	console.log("1");
	window.location.href = "food.html";
}

function initInfoWindow(){
	infoWindow = new google.maps.InfoWindow({
		map: map,
		content: 'You are here'
	});
	infoWindow.open(map, marker);
}

function initMarker(){
	marker = new google.maps.Marker({
		position: myLatLng,
		map: map,
		icon: image
	});
}

function initMap() {
	map = new google.maps.Map(document.getElementById('map'), {
		zoom: zoomAmount,
		center: myLatLng
	});

	initMarker();
	initInfoWindow();
	getFoodPlaces();
}

<commit_msg>added link to info window maps<commit_after>var myLatLng = {lat: -36.8576017, lng: 174.7590294};
var image = 'here.png';
var zoomAmount = 18;
var map, marker, infoWindow;

function getFoodPlaces(){
	var service = new google.maps.places.PlacesService(map);
	service.nearbySearch({
		location: myLatLng,
		radius: 500,
		types: ['bakery', 'bar' , 'cafe','food',
		'grocery_or_supermarket', 'hospital', 'meal_delivery' , 'meal_takeaway',
		'restaurant' , 'school']
	}, createFoodMarker);
}

function createFoodMarker(results, status) {
	if (status === google.maps.places.PlacesServiceStatus.OK) {
		for (var i = 0; i < results.length; i++) {
			createMarker(results[i]);
		}
	}
}

function createMarker(place) {
	var placeLoc = place.geometry.location;
	var marker = new google.maps.Marker({
		position: place.geometry.location,
		map: map
	});
	var infoWindowContent = '
' + place.name + '
 5 min away
';

	google.maps.event.addListener(marker, 'click', function() {
		infoWindow.setContent(infoWindowContent);
		infoWindow.open(map, this);
	});
}

function loadFoodPage(){
	console.log("1");
	window.location.href = "food.html";
}

function initInfoWindow(){
	infoWindow = new google.maps.InfoWindow({
		map: map,
		content: 'You are here'
	});
	infoWindow.open(map, marker);
}

function initMarker(){
	marker = new google.maps.Marker({
		position: myLatLng,
		map: map,
		icon: image
	});
}

function initMap() {
	map = new google.maps.Map(document.getElementById('map'), {
		zoom: zoomAmount,
		center: myLatLng
	});

	initMarker();
	initInfoWindow();
	getFoodPlaces();
}

<|endoftext|>


<commit_before>

   /*
    * We can add projections using Proj4js, using the ADD_PROJECTION function.
    * Here, we need the UTM zone 33 projection
    */

   var utmproj = ADD_PROJECTION
    (  "EPSG:32633", "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs",
       [-2500000, 3500000, 3045984, 9045984]
    );

   /*
    * The tiled WMS layers need a grid definition.
    * See http://openlayers.org/en/latest/apidoc/ol.tilegrid.TileGrid.html
    */

   var KV_grid = new ol.tilegrid.TileGrid({
                  extent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34],
                  resolutions: [39135.75848201023, 19567.87924100512, 9783.93962050256, 4891.96981025128,2445.98490512564, 1222.99245256282, 611.49622628141, 305.7481131407048, 152.8740565703525, 76.43702828517624, 38.21851414258813, 19.10925707129406,9.554628535647032, 4.777314267823516, 2.388657133911758, 1.194328566955879]
               });

   var KV_grid_UTM = new ol.tilegrid.TileGrid({
                  extent: [-2500000, 3500000, 3045984, 9045984],
                  resolutions: [21664, 10832, 5416, 2708, 1354, 677, 338.5, 169.25, 84.625, 42.3125, 21.15625, 10.5781255, 5.2890625, 2.64453125, 1.322265625]
               });

  /*
   * Map browser configuration
   *
   */

  /* Default projection */
  PROJECTION( "EPSG:900913" );

  /* Default center and scale */
  CENTER    ( 14, 66 );
  SCALE     ( 20000 );

  /*
   * Layers.
   *
   * Use the LAYERS function to define map layers. This function takes some options and an array
   * of layers as arguments. Use options to tell if layers are base-layers, and to set a
   * predicate (a function that returns a boolean to say if layers should be displayed or not.
   * You can also use these options to set projection or the attribution.
   *
   * Use OpenLayers to define layers:  http://openlayers.org/en/latest/apidoc/ol.layer.html
   * An option 'name' should be set on all layers to identify each of them in the layer
   * switcher list.
   *
   * The createLayer_WFS is a convenience function to simplify creation of WFS layer
   * (see example below).
   */

  LAYERS(
     { base: true,
       predicate: TRUE,
       projection: "EPSG:900913",
       attribution: "Openstreetmap"
     },
     [
        new ol.layer.Tile({
          name: 'OpenStreetMap',
          source: new ol.source.OSM()
         })
     ]
  );

  /* Base layers in UTM projection */

  LAYERS(
     { base: true,
       predicate: TRUE,
       projection: utmproj,
       attribution: "Statens kartverk"
     },
     [
      /* This will be a reprojection of OSM. Just to demonstrate */
      new ol.layer.Tile({
          name: 'OpenStreetMap - UTM',
          source: new ol.source.OSM()
         }),

      new ol.layer.Tile({
            name: "SK Topo Raster 3",
            opacity: 0.8,

            source: new ol.source.TileWMS({
               url: "http://opencache.statkart.no/gatekeeper/gk/gk.open?",
               projection: utmproj,
               params: {'LAYERS': 'toporaster3', VERSION: "1.1.1"},
               tilegrid: KV_grid
            })
          }),

      new ol.layer.Tile({
            name: "SK Topo 2",
            preload: 2,
            opacity: 0.66,

            source: new ol.source.TileWMS({
               url: "http://opencache.statkart.no/gatekeeper/gk/gk.open?",
               projection: utmproj,
               params: {'LAYERS': 'topo2', VERSION: "1.1.1"},
               tilegrid: KV_grid_UTM,
               cacheSize: 4096

            })
          })

  ]);

/* Overlays for all projections */
LAYERS (
   { base: false,
     predicate: function() { return scale() < 800; }
   },
   [
      new ol.layer.Image({
            name: "Naturvernområder (DN)",
            source: new ol.source.ImageWMS ({
                ratio: 1,
                url: "http://arcgisproxy.dirnat.no/arcgis/services/vern/MapServer/WmsServer",
                params: {'LAYERS':'naturvern_klasser_omrade', VERSION: "1.1.1"}
            })
      }),
      new ol.layer.Image({
            name: "UTM/MGRS Rutenett",
            source: new ol.source.ImageWMS ({
               ratio: 1,
               url: "http://openwms.statkart.no/skwms1/wms.rutenett",
               params: {'LAYERS':'UTMrutenett', VERSION: "1.1.1"}
            })
      }),
      createLayer_WFS({
          name : "O-kart dekning",
          url  : "http://gis.umb.no/nof/o_kart_wfs",
          ftype: "okart:o-kart_nof",
          style: TESTRES( 50, SETLABEL("Blue", "id"), GETSTYLE("Red"))
      })

       /* TESTRES, SETLABEL and GETSTYLE return functions that return styles.
        * TESTRES returns the second argument if resolution is less than 50, and
        * the third argument if it is greater.
        *
        * GETSTYLE just return the named style (see STYLES below).
        * SETLABEL return the named style but adds text for labels using a named attribute
        * of each feature. In this example, 'id' is such an attribute.
        */

   ]);

/*
 * Predefined styles, mainly for vector layers.
 *
 * STYLES takes an array of style-definitions each with an identifier and
 * values for the options in the OpenLayers style class.
 * See http://openlayers.org/en/latest/apidoc/ol.style.Style.html
 *
 * Note that we simplify a bit: we just need to give the values for the options
 * given to ol.style Stroke, ol.style.Fill and ol.style.Text. We also offer
 * convenience functions CIRCLE and ICON to define image properties.
 */

STYLES ([
   { id: "Red",
        stroke: {color: 'rgba(200,0,0,1)', width: 1.5},
	    fill  : 'rgba(255,240,220,0.3)',
	    text  : {scale: 1.2, fill: '#300', stroke: {color: '#fff', width: 3} },
	    image : CIRCLE(7, {fill: '#f66'})
   },
   { id: "Blue",
        stroke: {color: 'rgba(0,0,200,1)', width: 1.5, lineDash: [3,3]},
	    fill  : 'rgba(200,220,253,0.3)',
	    text  : {scale: 1.2, fill: '#003', stroke: {color: '#fff', width: 3} },
	    image : CIRCLE(7, {fill: '#66f'})
   }
]);

/*
 * Menu of predefined map-extents.
 *
 * Extents are upper left corner (1) and lower right corner (2) in decimal degrees
 * [longitude-1, latitude-1, longitude-2, latitude-2]
 */

var defaultView = 'default';
VIEWS ([
   { name: 'finnm',     title: 'Finnmark',        extent: [19.006, 68.064, 33.848, 71.662] },
   { name: 'troms',     title: 'Troms',           extent: [15.549, 68.641, 22.454, 70.196]  },
   { name: 'nordl',     title: 'Nordland',        extent: [8.242, 65.462, 20.91, 68.301] },
   { name: 'ntrond',    title: 'Nord-Trøndelag',  extent: [ 9.0436, 63.2859, 15.3995, 64.8541] },
   { name: 'strond',    title: 'Sør-Trøndelag',   extent: [ 7.3903, 62.0338, 13.5351, 63.6724] },
   { name: 'moreroms',  title: 'Møre og Romsdal', extent: [ 3.5993, 61.5234,  9.7916, 63.3084] },
   { name: 'sognf',     title: 'Sogn og fjordane',extent: [ 2.8448, 60.4411,  8.8474, 62.2549] },
   { name: 'hordal',    title: 'Hordaland',       extent: [ 3.1295, 59.3777,  8.9257, 61.1814] },
   { name: 'agrog',     title: 'Agder/Rogaland',  extent: [4.508,57.965,9.311,59.645]},
   { name: 'tele',      title: 'Telemark',        extent: [ 7.4777, 58.7404, 10.2363, 59.5893] },
   { name: 'hardanger', title: 'Hardangervidda/Buskerud', extent: [ 6.4033, 59.3222, 12.0772, 61.0049] },
   { name: 'oslofj',    title: 'Østfold/Vestfold',extent: [ 7.8612, 58.8272, 13.3971, 60.4553] },
   { name: 'osloaker',  title: 'Oslo/Akershus',   extent: [ 9.3833, 59.3858, 12.161,  60.1985] },
   { name: 'hedopp',    title: 'Hedmark/Oppland', extent: [ 8.2261, 59.8479, 13.9201, 61.4599] },
   { name: 'default',   title: 'Utgangspunkt',    extent: [ -16.0421, 56.929, 43.2233, 67.989], hidden: true }
]);

<commit_msg>Mapconfig update<commit_after>

   /*
    * We can add projections using Proj4js, using the ADD_PROJECTION function.
    * Here, we need the UTM zone 33 projection
    */

   var utmproj = ADD_PROJECTION
    (  "EPSG:32633", "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs",
       [-2500000, 3500000, 3045984, 9045984]
    );

   /*
    * The tiled WMS layers need a grid definition.
    * See http://openlayers.org/en/latest/apidoc/ol.tilegrid.TileGrid.html
    */

   var KV_grid = new ol.tilegrid.TileGrid({
                  extent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34],
                  resolutions: [39135.75848201023, 19567.87924100512, 9783.93962050256, 4891.96981025128,2445.98490512564, 1222.99245256282, 611.49622628141, 305.7481131407048, 152.8740565703525, 76.43702828517624, 38.21851414258813, 19.10925707129406,9.554628535647032, 4.777314267823516, 2.388657133911758, 1.194328566955879]
               });

   var KV_grid_UTM = new ol.tilegrid.TileGrid({
                  extent: [-2500000, 3500000, 3045984, 9045984],
                  resolutions: [21664, 10832, 5416, 2708, 1354, 677, 338.5, 169.25, 84.625, 42.3125, 21.15625, 10.5781255, 5.2890625, 2.64453125, 1.322265625]
               });

  /*
   * Map browser configuration
   *
   */

  /* Default projection */
  PROJECTION( "EPSG:900913" );

  /* Default center and scale */
  CENTER    ( 14, 66 );
  SCALE     ( 20000 );

  /*
   * Layers.
   *
   * Use the LAYERS function to define map layers. This function takes some options and an array
   * of layers as arguments. Use options to tell if layers are base-layers, and to set a
   * predicate (a function that returns a boolean to say if layers should be displayed or not.
   * You can also use these options to set projection or the attribution.
   *
   * Use OpenLayers to define layers:  http://openlayers.org/en/latest/apidoc/ol.layer.html
   * An option 'name' should be set on all layers to identify each of them in the layer
   * switcher list.
   *
   * The createLayer_WFS is a convenience function to simplify creation of WFS layer
   * (see example below).
   */

  LAYERS(
     { base: true,
       predicate: TRUE,
       projection: "EPSG:900913",
       attribution: "Openstreetmap"
     },
     [
        new ol.layer.Tile({
          name: 'OpenStreetMap',
          source: new ol.source.OSM()
         })
     ]
  );

  /* Base layers in UTM projection */

  LAYERS(
     { base: true,
       predicate: TRUE,
       projection: utmproj,
       attribution: "Statens kartverk"
     },
     [
      /* This will be a reprojection of OSM. Just to demonstrate */
      new ol.layer.Tile({
          name: 'OpenStreetMap - UTM',
          source: new ol.source.OSM()
         }),

      new ol.layer.Tile({
            name: "SK Topo Raster 3",
            opacity: 0.8,

            source: new ol.source.TileWMS({
               url: "http://opencache.statkart.no/gatekeeper/gk/gk.open?",
               projection: utmproj,
               params: {'LAYERS': 'toporaster3', VERSION: "1.1.1"},
               tilegrid: KV_grid
            })
          }),

      new ol.layer.Tile({
            name: "SK Topo 2",
            preload: 2,
            opacity: 0.66,

            source: new ol.source.TileWMS({
               url: "http://opencache.statkart.no/gatekeeper/gk/gk.open?",
               projection: utmproj,
               params: {'LAYERS': 'topo2', VERSION: "1.1.1"},
               tilegrid: KV_grid_UTM,
               cacheSize: 4096

            })
          })

  ]);

/* Overlays for all projections */
LAYERS (
   { base: false,
     predicate: RESOLUTION_LT (3600)
   },
   [
      new ol.layer.Image({
            name: "Naturvernområder (DN)",
            source: new ol.source.ImageWMS ({
                ratio: 1,
                url: "http://arcgisproxy.dirnat.no/arcgis/services/vern/MapServer/WmsServer",
                params: {'LAYERS':'naturvern_klasser_omrade', VERSION: "1.1.1"}
            })
      }),
      new ol.layer.Image({
            name: "UTM/MGRS Rutenett",
            source: new ol.source.ImageWMS ({
               ratio: 1,
               url: "http://openwms.statkart.no/skwms1/wms.rutenett",
               params: {'LAYERS':'UTMrutenett', VERSION: "1.1.1"}
            })
      }),
      createLayer_WFS({
          name : "O-kart dekning",
          url  : "http://gis.umb.no/nof/o_kart_wfs",
          ftype: "okart:o-kart_nof",
          style: TESTRES( 50, SETLABEL("Blue", "$(id): $(kartnavn)"), GETSTYLE("Red"))
      })

       /* TESTRES, SETLABEL and GETSTYLE return functions that return styles.
        * TESTRES returns the second argument if resolution is less than 50, and
        * the third argument if it is greater.
        *
        * GETSTYLE just return the named style (see STYLES below).
        * SETLABEL return the named style and adds text for labels, using named attributes
        * of each feature. Any $(attr) is replaced with the value of the attribute.
	    * In this example, 'id' is such an attribute.
        */

   ]);

/*
 * Predefined styles, mainly for vector layers.
 *
 * STYLES takes an array of style-definitions each with an identifier and
 * values for the options in the OpenLayers style class.
 * See http://openlayers.org/en/latest/apidoc/ol.style.Style.html
 *
 * Note that we simplify a bit: we just need to give the values for the options
 * given to ol.style Stroke, ol.style.Fill and ol.style.Text. We also offer
 * convenience functions CIRCLE and ICON to define image properties.
 */

STYLES ([
   { id: "Red",
        stroke: {color: 'rgba(200,0,0,1)', width: 1.5},
	    fill  : 'rgba(255,240,220,0.3)',
	    text  : {scale: 1.2, fill: '#300', stroke: {color: '#fff', width: 3} },
	    image : CIRCLE(7, {fill: '#f66'})
   },
   { id: "Green",
        stroke: {color: 'rgba(0,100,0,1)', width: 1.5},
	    fill  : 'rgba(220,255,220,0.3)',
	    text  : {scale: 1.2, fill: '#300', stroke: {color: '#fff', width: 3} },
	    image : CIRCLE(7, {fill: '#f66'})
   },
   { id: "Blue",
        stroke: {color: 'rgba(0,0,200,1)', width: 1.5, lineDash: [3,3]},
	    fill  : 'rgba(200,220,253,0.3)',
	    text  : {scale: 1.2, fill: '#003', stroke: {color: '#fff', width: 3} },
	    image : CIRCLE(7, {fill: '#66f'})
   },
   { id: "Blue - No fill",
        stroke: {color: 'rgba(0,0,200,1)', width: 1.5},
	    text  : {scale: 1.2, fill: '#003', stroke: {color: '#fff', width: 3} },
	    image : CIRCLE(7, {fill: '#66f'})
   }
]);

/*
 * Menu of predefined map-extents.
 *
 * Extents are upper left corner (1) and lower right corner (2) in decimal degrees
 * [longitude-1, latitude-1, longitude-2, latitude-2]
 */

var defaultView = 'default';
VIEWS ([
   { name: 'finnm',     title: 'Finnmark',        extent: [19.006, 68.064, 33.848, 71.662] },
   { name: 'troms',     title: 'Troms',           extent: [15.549, 68.641, 22.454, 70.196]  },
   { name: 'nordl',     title: 'Nordland',        extent: [8.242, 65.462, 20.91, 68.301] },
   { name: 'ntrond',    title: 'Nord-Trøndelag',  extent: [ 9.0436, 63.2859, 15.3995, 64.8541] },
   { name: 'strond',    title: 'Sør-Trøndelag',   extent: [ 7.3903, 62.0338, 13.5351, 63.6724] },
   { name: 'moreroms',  title: 'Møre og Romsdal', extent: [ 3.5993, 61.5234,  9.7916, 63.3084] },
   { name: 'sognf',     title: 'Sogn og fjordane',extent: [ 2.8448, 60.4411,  8.8474, 62.2549] },
   { name: 'hordal',    title: 'Hordaland',       extent: [ 3.1295, 59.3777,  8.9257, 61.1814] },
   { name: 'agrog',     title: 'Agder/Rogaland',  extent: [4.508,57.965,9.311,59.645]},
   { name: 'tele',      title: 'Telemark',        extent: [ 7.4777, 58.7404, 10.2363, 59.5893] },
   { name: 'hardanger', title: 'Hardangervidda/Buskerud', extent: [ 6.4033, 59.3222, 12.0772, 61.0049] },
   { name: 'oslofj',    title: 'Østfold/Vestfold',extent: [ 7.8612, 58.8272, 13.3971, 60.4553] },
   { name: 'osloaker',  title: 'Oslo/Akershus',   extent: [ 9.3833, 59.3858, 12.161,  60.1985] },
   { name: 'hedopp',    title: 'Hedmark/Oppland', extent: [ 8.2261, 59.8479, 13.9201, 61.4599] },
   { name: 'default',   title: 'Utgangspunkt',    extent: [ -16.0421, 56.929, 43.2233, 67.989], hidden: true }
]);

<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import { findDOMNode } from 'react-dom'
import { brushX, select, event as d3Event } from 'd3'

class BrushX extends React.Component {
  constructor (props) {
    super(props)
    this.brushSelection = []
    this.brushPhase = ''
  }
  componentDidMount () {
    this.initBrush()
  }
  shouldComponentUpdate () {
    if (this.brushPhase === 'brushed' || this.brushPhase === '') {
      return true
    }
    return false
  }
  componentDidUpdate (prevProps, prevState) {
    if (this.props.width !== prevProps.width || this.props.height !== prevProps.height) {
      this.initBrush()
    }
    this.clearBrush()
  }

  initBrush () {
    let thisNode = findDOMNode(this)
    let selection = select(thisNode)
    this.brush = brushX()
      .extent([[0, 0], [this.props.width, this.props.height]])
      .on('start', this._start.bind(this))
      .on('brush', this._brush.bind(this))
      .on('end', this._end.bind(this))
    selection.call(this.brush)
  }
  _start () {
    this.brushPhase = 'start'
    this.applySelection()
  }
  _brush () {
    this.brushPhase = 'brushing'
    this.applySelection()
  }
  _end () {
    this.brushPhase = 'brushed'
    if (d3Event.selection) {
      this.props.onBrush(this.brushSelection)
    }
  }
  clearBrush () {
    let thisNode = findDOMNode(this)
    let selection = select(thisNode)
    selection.call(this.brush.move, null)
    this.brushSelection = []
    this.brushPhase = ''
  }
  applySelection () {
    if (!d3Event.sourceEvent || d3Event.sourceEvent.type === 'brush' || !d3Event.selection) return
    let domain = this.calculateSelection(d3Event.selection.map(this.props.scale.invert))
    let thisNode = findDOMNode(this)
    select(thisNode)
        .call(this.brush.move, domain.map(this.props.scale))
    this.brushSelection = domain
  }
  calculateSelection (domain) {
    let { interval, scale } = this.props
    let dateScale = /time/.test(scale.type)
    if (dateScale) {
      domain = domain.map((val) => { return val.getTime() })
    }
    let nIntervals = Math.abs(scale.domain()[1] - scale.domain()[0]) / interval
    let out = domain.slice()
    for (let i = 0; i < nIntervals; i++) {
      let xVal = dateScale ? scale.domain()[0].getTime() : scale.domain()[0]
      xVal += interval * i
      if (domain[0] >= xVal && domain[0] < xVal + interval) {
        out[0] = xVal
      }
      if (domain[1] > xVal && domain[1] < xVal + interval) {
        out[1] = xVal
      }
    }
    if (out[0] === out[1]) {
      out[1] += interval
    }
    return dateScale ? [new Date(out[0]), new Date(out[1])] : out
  }
  render () {
    // console.log('brush selection is : ' + this.state.selection)
    return (
      <g className='brush'>{this.props.children}</g>
    )
  }
}

BrushX.defaultProps = {
  showHandles: false
}

BrushX.propTypes = {
  children: PropTypes.node,
  width: PropTypes.number.isRequired,
  height: PropTypes.number.isRequired,
  interval: PropTypes.number.isRequired,
  scale: PropTypes.func.isRequired,
  showHandles: PropTypes.bool.isRequired,
  onBrush: PropTypes.func
}

export default BrushX
<commit_msg>Brush wasn't firing on click events, fixed<commit_after>import React, { PropTypes } from 'react'
import { findDOMNode } from 'react-dom'
import { brushX, select, event as d3Event } from 'd3'

class BrushX extends React.Component {
  constructor (props) {
    super(props)
    this.brushSelection = []
    this.brushPhase = ''
  }
  componentDidMount () {
    this.initBrush()
  }
  shouldComponentUpdate () {
    if (this.brushPhase === 'brushed' || this.brushPhase === '') {
      return true
    }
    return false
  }
  componentDidUpdate (prevProps, prevState) {
    if (this.props.width !== prevProps.width || this.props.height !== prevProps.height) {
      this.initBrush()
    }
    this.clearBrush()
  }

  initBrush () {
    let thisNode = findDOMNode(this)
    let selection = select(thisNode)
    this.brush = brushX()
      .extent([[0, 0], [this.props.width, this.props.height]])
      .on('start', this._start.bind(this))
      .on('brush', this._brush.bind(this))
      .on('end', this._end.bind(this))
    selection.call(this.brush)
  }
  _start () {
    this.brushPhase = 'start'
    this.applySelection()
  }
  _brush () {
    this.brushPhase = 'brushing'
    this.applySelection()
  }
  _end () {
    if (d3Event.selection || d3Event.sourceEvent instanceof MouseEvent) {
      this.brushPhase = 'brushed'
      this.props.onBrush(this.brushSelection)
    }
  }
  clearBrush () {
    let thisNode = findDOMNode(this)
    let selection = select(thisNode)
    selection.call(this.brush.move, null)
    this.brushSelection = []
    this.brushPhase = ''
  }
  applySelection () {
    if (!d3Event.sourceEvent || d3Event.sourceEvent.type === 'brush' || !d3Event.selection) return
    let domain = this.calculateSelection(d3Event.selection.map(this.props.scale.invert))
    let thisNode = findDOMNode(this)
    select(thisNode)
        .call(this.brush.move, domain.map(this.props.scale))
    this.brushSelection = domain
  }
  calculateSelection (domain) {
    let { interval, scale } = this.props
    let dateScale = /time/.test(scale.type)
    if (dateScale) {
      domain = domain.map((val) => { return val.getTime() })
    }
    let nIntervals = Math.abs(scale.domain()[1] - scale.domain()[0]) / interval
    let out = domain.slice()
    for (let i = 0; i < nIntervals; i++) {
      let xVal = dateScale ? scale.domain()[0].getTime() : scale.domain()[0]
      xVal += interval * i
      if (domain[0] >= xVal && domain[0] < xVal + interval) {
        out[0] = xVal
      }
      if (domain[1] > xVal && domain[1] < xVal + interval) {
        out[1] = xVal
      }
    }
    if (out[0] === out[1]) {
      out[1] += interval
    }
    return dateScale ? [new Date(out[0]), new Date(out[1])] : out
  }
  render () {
    // console.log('brush selection is : ' + this.state.selection)
    return (
      <g className='brush'>{this.props.children}</g>
    )
  }
}

BrushX.defaultProps = {
  showHandles: false
}

BrushX.propTypes = {
  children: PropTypes.node,
  width: PropTypes.number.isRequired,
  height: PropTypes.number.isRequired,
  interval: PropTypes.number.isRequired,
  scale: PropTypes.func.isRequired,
  showHandles: PropTypes.bool.isRequired,
  onBrush: PropTypes.func
}

export default BrushX
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import EventListener from 'react-event-listener';
import Api from './Api';

export default class Canvas extends React.Component {

  static propTypes = {
    api: PropTypes.instanceOf(Api),
    zoom: PropTypes.number,
    fixed: PropTypes.bool,
    onFirstRender: PropTypes.func,
    snapDistance: PropTypes.number
  };

  static defaultProps = {
    fixed: false,
    zoom: 1,
    snapDistance: 5
  };

  static childContextTypes = {
    canvas: PropTypes.object,
    api: PropTypes.object
  };

  constructor(props, context) {
    super(props, context);

    this.api = props.api;
    this.api.on('selectionChange', this.handleSelectionChange);
    this.api.on('dataChange', this.handleDataChange);

    this.snaplines = {};
    this.nodes = {};

    this.state = {
      readyForRender: false,
      width: 0,
      height: 0,
      selection: this.api.selection,
      slide: this.api.slide,
      slideLeft: 0,
      slideTop: 0
    };

  }

  getChildContext() {
    return {
      canvas: this,
      api: this.props.api
    };
  }

  componentWillUnmount() {
    this.api.unbind('selectionChange', this.handleSelectionChange);
    this.api.unbind('dataChange', this.handleDataChange);
  }

  componentDidMount() {
    this.checkIfReadyForRender();
  }

  checkIfReadyForRender() {
    if (!this.state.readyForRender) {
      // check if DOM is ready to render
      const readyForRender = this.loadingNode && this.loadingNode.offsetHeight > 0;
      if (readyForRender) {
        this.setState({
          readyForRender: true
        });
      } else {
        setTimeout(() => {
          this.checkIfReadyForRender();
        }, 50);
      }
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.api !== this.props.api && nextProps.api) {
      this.props.api.unbind('selectionChange', this.handleSelectionChange);
      this.props.api.unbind('dataChange', this.handleDataChange);

      nextProps.api.bind('selectionChange', this.handleSelectionChange);
      nextProps.api.bind('dataChange', this.handleDataChange);

      this.handleDataChange();
      this.handleSelectionChange();
    }
  }

  componentDidUpdate(prevProps, prevState) {
    if (!prevState.readyForRender && this.state.readyForRender) {
      this.positionSlide();
      this.props.onFirstRender && this.props.onFirstRender(this);
    } else if (this.state.readyForRender && (prevProps.zoom !== this.props.zoom || this.state.slide !== prevState.slide)) {
      this.positionSlide();
    }

    if (prevState.slideLeft !== this.state.slideLeft
      || prevState.slideTop !== this.state.slideTop
      || prevState.width !== this.state.width
      || prevState.height !== this.state.height) {
      this.props.api.triggerSelectionChange();
      this.centerContent();
    }
  }

  centerContent() {
    if (this.props.fixed) {
      const bbox = this.svgRoot.parentNode.getBoundingClientRect();
      this.wrapperNode.scrollLeft = (this.state.width - bbox.width) * 0.5;
      this.wrapperNode.scrollTop = (this.state.height - bbox.height) * 0.5;
    }
  }

  positionSlide() {
    if (this.svgRoot) {
      const bbox = this.svgRoot.parentNode.getBoundingClientRect();
      const slide = this.state.slide;
      const zoom = this.props.zoom;
      const slideWidth = slide.width * zoom;
      const slideHeight = slide.height * zoom;
      const width = Math.max(slideWidth, bbox.width - 20);
      const height = Math.max(slideHeight, bbox.height - 20);

      const slideLeft = ((width || bbox.width) - slideWidth) * 0.5;
      const slideTop = ((height || bbox.height) - slideHeight) * 0.5;
      if (this.state.width !== width || this.state.height !== height || this.state.slideLeft !== slideLeft || this.state.slideTop !== slideTop) {
        this.setState({
          slideLeft,
          slideTop,
          width,
          height
        });
      }
    }
  }

  findSnaplines(node, snaplines) {
    if (!this.possibleSnaplines) {
      return {x: 0, y: 0};
    }
    const matchingSnaplines = [];
    const matchedSnapline = {};
    const diffs = {x: 0, y: 0};
    // (this.state.snaplines || []).forEach(s => s.ref.highlight(false));
    const maxDiff = {x: 3 * this.props.zoom, y: 3 * this.props.zoom};
    (snaplines || []).forEach((tmpSnapline) => {
      tmpSnapline = matchedSnapline[tmpSnapline.mode] || tmpSnapline;
      this.possibleSnaplines.forEach((snapline) => {
        const diff = tmpSnapline.pos - snapline.pos;
        if (tmpSnapline.mode === snapline.mode && Math.abs(diff) <= maxDiff[tmpSnapline.mode]) {
          maxDiff[tmpSnapline.mode] = 0;
          matchingSnaplines.push(snapline);
          matchedSnapline[tmpSnapline.mode] = matchedSnapline[tmpSnapline.mode] || snapline;
          diffs[tmpSnapline.mode] = diffs[tmpSnapline.mode] || diff;
        }
      });
    });

    this.possibleSnaplines.map(snapline => snapline.ref).filter((elem, pos, self) => self.indexOf(elem) === pos).forEach((element) => {
      element.highlight(matchingSnaplines.find(s => s.ref === element));
    });

    this.setState({
      snaplines: matchingSnaplines
    });
    return diffs;
  }

  registerNode(node) {
    if (node.props.id) {
      this.nodes[node.props.id] = node;
    }
  }

  unregisterNode(node) {
    if (node.props.id) {
      delete this.nodes[node.props.id];
    }
  }

  clearSnaplines() {
    this.state.snaplines && this.state.snaplines.forEach(s => s.ref.highlight(false));
    this.setState({
      snaplines: null
    });
  }

  prepareSnaplines(node) {
    let possibleSnaplines = [];
    Object.keys(this.nodes).forEach((nodeId) => {
      const oNode = this.nodes[nodeId];
      if (nodeId !== node.props.id && !node.contains(oNode)) {
        possibleSnaplines = possibleSnaplines.concat(oNode.getCurrentSnaplines());
      }
    });

    this.possibleSnaplines = possibleSnaplines;
  }

  focus() {
    this.wrapperNode && this.wrapperNode.focus();
  }

  handleResize = () => {
    this._resizeTimeout && clearTimeout(this._resizeTimeout);

    this._resizeTimeout = setTimeout(() => {
      this.positionSlide();
    }, 100);
  };

  handleKeyDown = (e) => {
    const api = this.props.api;
    if (!/input|textarea/gi.test(e.srcElement.tagName) && !e.srcElement.getAttribute('contenteditable')) {
      if (e.which === 8 || e.which === 46) {
        api.removeSelectedElements();
        api.triggerDataChange();
        api.triggerSelectionChange();
      } else if (e.which === 90 && e.metaKey) {
        e.preventDefault();
        if (!e.shiftKey) {
          api.undo();
        } else {
          api.redo();
        }
      }
    }
  };

  handleDataChange = () => {
    this.setState({
      slide: this.api.slide,
      selection: this.api.selection
    });
  };

  handleSelectionChange = () => {
    this.setState({
      selection: this.api.selection
    });
  };

  handleRef = (ref) => {
    this.firstNode = ref;
  };

  handleMouseDown = () => {
    this.mouseDown = true;
    this.triggerSelection(null);
  };

  handleMouseUp = () => {
    this.mouseDown = false;
  };

  triggerSelection() {
    // todo: implement multiple selections
    this.props.api.selectElement(null);
  }

  handleSelectionRefs = (ref) => {
    this.selections = ref;
  };

  handleRootRef = (ref) => {
    this.svgRoot = ref;
  };

  handleSlideRef = (ref) => {
    this.slideNode = ref;
  };

  handleLoadingRef = (ref) => {
    this.loadingNode = ref;
  };

  handleWrapperRef = (ref) => {
    this.wrapperNode = ref;
  };

  render() {
    if (!this.state.readyForRender) {
      // TODO: implement loader
      return
Loading ...
;
    }

    const wrapperStyle = {width: '100%', height: '100%', overflow: this.props.fixed ? 'hidden' : 'auto', position: 'absolute'};

    return (

      <EventListener target="window" onResize={this.handleResize}/>
      <EventListener target="window" onKeyDown={this.handleKeyDown}/>
      <svg
        xmlns="http://www.w3.org/2000/svg" version="1.1"
        width={this.state.width || '100%'} height={this.state.height || '100%'}
        ref={this.handleRootRef}
        shapeRendering="geometricPrecision"
        onTouchStart={this.handleMouseDown}
        onMouseDown={this.handleMouseDown}
        onMouseUp={this.handleMouseUp}
        onTouchEnd={this.handleMouseUp}
      >

        <g ref={this.handleRef}>
          <g ref={this.handleSlideRef} transform={`translate(${this.state.slideLeft}, ${this.state.slideTop}) scale(${this.props.zoom})`}>
            <rect
              width={this.state.slide.width}
              height={this.state.slide.height}
              fill={this.state.slide.background}
            />
            <g className="slide-elements">
              {this.state.slide.elements.map((el) => {
                const factory = this.props.api.resolveFactory(el.type);
                const {id, ...other} = el;
                return React.createElement(factory, {key: id, id, ...other});
              })}
            </g>
            <g className="snaplines">
              {(this.state.snaplines || []).map((snapline, i) => {
                if (snapline.mode === 'x') {
                  return <line key={i} vectorEffect="non-scaling-stroke" strokeDasharray="5 5" stroke="blue" strokeWidth="0.8" y1={0} y2={this.state.slide.height} x1={snapline.pos} x2={snapline.pos}/>
                } else {
                  return <line key={i} vectorEffect="non-scaling-stroke" strokeDasharray="5 5" stroke="blue" strokeWidth="0.8" x1={0} x2={this.state.slide.width} y1={snapline.pos} y2={snapline.pos}/>
                }
              })}
            </g>
          </g>
          <g ref={this.handleSelectionRefs} className="slide-selections">
            {Object.keys(this.state.selection).filter(id => !!this.nodes[id]).map(id => this.nodes[id].renderSelection())}
          </g>
        </g>
      </svg>

);
  }

}
<commit_msg>replace srcElement with target<commit_after>import React, {PropTypes} from 'react';
import EventListener from 'react-event-listener';
import Api from './Api';

export default class Canvas extends React.Component {

  static propTypes = {
    api: PropTypes.instanceOf(Api),
    zoom: PropTypes.number,
    fixed: PropTypes.bool,
    onFirstRender: PropTypes.func,
    snapDistance: PropTypes.number
  };

  static defaultProps = {
    fixed: false,
    zoom: 1,
    snapDistance: 5
  };

  static childContextTypes = {
    canvas: PropTypes.object,
    api: PropTypes.object
  };

  constructor(props, context) {
    super(props, context);

    this.api = props.api;
    this.api.on('selectionChange', this.handleSelectionChange);
    this.api.on('dataChange', this.handleDataChange);

    this.snaplines = {};
    this.nodes = {};

    this.state = {
      readyForRender: false,
      width: 0,
      height: 0,
      selection: this.api.selection,
      slide: this.api.slide,
      slideLeft: 0,
      slideTop: 0
    };

  }

  getChildContext() {
    return {
      canvas: this,
      api: this.props.api
    };
  }

  componentWillUnmount() {
    this.api.unbind('selectionChange', this.handleSelectionChange);
    this.api.unbind('dataChange', this.handleDataChange);
  }

  componentDidMount() {
    this.checkIfReadyForRender();
  }

  checkIfReadyForRender() {
    if (!this.state.readyForRender) {
      // check if DOM is ready to render
      const readyForRender = this.loadingNode && this.loadingNode.offsetHeight > 0;
      if (readyForRender) {
        this.setState({
          readyForRender: true
        });
      } else {
        setTimeout(() => {
          this.checkIfReadyForRender();
        }, 50);
      }
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.api !== this.props.api && nextProps.api) {
      this.props.api.unbind('selectionChange', this.handleSelectionChange);
      this.props.api.unbind('dataChange', this.handleDataChange);

      nextProps.api.bind('selectionChange', this.handleSelectionChange);
      nextProps.api.bind('dataChange', this.handleDataChange);

      this.handleDataChange();
      this.handleSelectionChange();
    }
  }

  componentDidUpdate(prevProps, prevState) {
    if (!prevState.readyForRender && this.state.readyForRender) {
      this.positionSlide();
      this.props.onFirstRender && this.props.onFirstRender(this);
    } else if (this.state.readyForRender && (prevProps.zoom !== this.props.zoom || this.state.slide !== prevState.slide)) {
      this.positionSlide();
    }

    if (prevState.slideLeft !== this.state.slideLeft
      || prevState.slideTop !== this.state.slideTop
      || prevState.width !== this.state.width
      || prevState.height !== this.state.height) {
      this.props.api.triggerSelectionChange();
      this.centerContent();
    }
  }

  centerContent() {
    if (this.props.fixed) {
      const bbox = this.svgRoot.parentNode.getBoundingClientRect();
      this.wrapperNode.scrollLeft = (this.state.width - bbox.width) * 0.5;
      this.wrapperNode.scrollTop = (this.state.height - bbox.height) * 0.5;
    }
  }

  positionSlide() {
    if (this.svgRoot) {
      const bbox = this.svgRoot.parentNode.getBoundingClientRect();
      const slide = this.state.slide;
      const zoom = this.props.zoom;
      const slideWidth = slide.width * zoom;
      const slideHeight = slide.height * zoom;
      const width = Math.max(slideWidth, bbox.width - 20);
      const height = Math.max(slideHeight, bbox.height - 20);

      const slideLeft = ((width || bbox.width) - slideWidth) * 0.5;
      const slideTop = ((height || bbox.height) - slideHeight) * 0.5;
      if (this.state.width !== width || this.state.height !== height || this.state.slideLeft !== slideLeft || this.state.slideTop !== slideTop) {
        this.setState({
          slideLeft,
          slideTop,
          width,
          height
        });
      }
    }
  }

  findSnaplines(node, snaplines) {
    if (!this.possibleSnaplines) {
      return {x: 0, y: 0};
    }
    const matchingSnaplines = [];
    const matchedSnapline = {};
    const diffs = {x: 0, y: 0};
    // (this.state.snaplines || []).forEach(s => s.ref.highlight(false));
    const maxDiff = {x: 3 * this.props.zoom, y: 3 * this.props.zoom};
    (snaplines || []).forEach((tmpSnapline) => {
      tmpSnapline = matchedSnapline[tmpSnapline.mode] || tmpSnapline;
      this.possibleSnaplines.forEach((snapline) => {
        const diff = tmpSnapline.pos - snapline.pos;
        if (tmpSnapline.mode === snapline.mode && Math.abs(diff) <= maxDiff[tmpSnapline.mode]) {
          maxDiff[tmpSnapline.mode] = 0;
          matchingSnaplines.push(snapline);
          matchedSnapline[tmpSnapline.mode] = matchedSnapline[tmpSnapline.mode] || snapline;
          diffs[tmpSnapline.mode] = diffs[tmpSnapline.mode] || diff;
        }
      });
    });

    this.possibleSnaplines.map(snapline => snapline.ref).filter((elem, pos, self) => self.indexOf(elem) === pos).forEach((element) => {
      element.highlight(matchingSnaplines.find(s => s.ref === element));
    });

    this.setState({
      snaplines: matchingSnaplines
    });
    return diffs;
  }

  registerNode(node) {
    if (node.props.id) {
      this.nodes[node.props.id] = node;
    }
  }

  unregisterNode(node) {
    if (node.props.id) {
      delete this.nodes[node.props.id];
    }
  }

  clearSnaplines() {
    this.state.snaplines && this.state.snaplines.forEach(s => s.ref.highlight(false));
    this.setState({
      snaplines: null
    });
  }

  prepareSnaplines(node) {
    let possibleSnaplines = [];
    Object.keys(this.nodes).forEach((nodeId) => {
      const oNode = this.nodes[nodeId];
      if (nodeId !== node.props.id && !node.contains(oNode)) {
        possibleSnaplines = possibleSnaplines.concat(oNode.getCurrentSnaplines());
      }
    });

    this.possibleSnaplines = possibleSnaplines;
  }

  focus() {
    this.wrapperNode && this.wrapperNode.focus();
  }

  handleResize = () => {
    this._resizeTimeout && clearTimeout(this._resizeTimeout);

    this._resizeTimeout = setTimeout(() => {
      this.positionSlide();
    }, 100);
  };

  handleKeyDown = (e) => {
    const api = this.props.api;
    if (!/input|textarea/gi.test(e.target.tagName) && !e.target.getAttribute('contenteditable')) {
      if (e.which === 8 || e.which === 46) {
        api.removeSelectedElements();
        api.triggerDataChange();
        api.triggerSelectionChange();
      } else if (e.which === 90 && e.metaKey) {
        e.preventDefault();
        if (!e.shiftKey) {
          api.undo();
        } else {
          api.redo();
        }
      }
    }
  };

  handleDataChange = () => {
    this.setState({
      slide: this.api.slide,
      selection: this.api.selection
    });
  };

  handleSelectionChange = () => {
    this.setState({
      selection: this.api.selection
    });
  };

  handleRef = (ref) => {
    this.firstNode = ref;
  };

  handleMouseDown = () => {
    this.mouseDown = true;
    this.triggerSelection(null);
  };

  handleMouseUp = () => {
    this.mouseDown = false;
  };

  triggerSelection() {
    // todo: implement multiple selections
    this.props.api.selectElement(null);
  }

  handleSelectionRefs = (ref) => {
    this.selections = ref;
  };

  handleRootRef = (ref) => {
    this.svgRoot = ref;
  };

  handleSlideRef = (ref) => {
    this.slideNode = ref;
  };

  handleLoadingRef = (ref) => {
    this.loadingNode = ref;
  };

  handleWrapperRef = (ref) => {
    this.wrapperNode = ref;
  };

  render() {
    if (!this.state.readyForRender) {
      // TODO: implement loader
      return
Loading ...
;
    }

    const wrapperStyle = {width: '100%', height: '100%', overflow: this.props.fixed ? 'hidden' : 'auto', position: 'absolute'};

    return (

      <EventListener target="window" onResize={this.handleResize}/>
      <EventListener target="window" onKeyDown={this.handleKeyDown}/>
      <svg
        xmlns="http://www.w3.org/2000/svg" version="1.1"
        width={this.state.width || '100%'} height={this.state.height || '100%'}
        ref={this.handleRootRef}
        shapeRendering="geometricPrecision"
        onTouchStart={this.handleMouseDown}
        onMouseDown={this.handleMouseDown}
        onMouseUp={this.handleMouseUp}
        onTouchEnd={this.handleMouseUp}
      >

        <g ref={this.handleRef}>
          <g ref={this.handleSlideRef} transform={`translate(${this.state.slideLeft}, ${this.state.slideTop}) scale(${this.props.zoom})`}>
            <rect
              width={this.state.slide.width}
              height={this.state.slide.height}
              fill={this.state.slide.background}
            />
            <g className="slide-elements">
              {this.state.slide.elements.map((el) => {
                const factory = this.props.api.resolveFactory(el.type);
                const {id, ...other} = el;
                return React.createElement(factory, {key: id, id, ...other});
              })}
            </g>
            <g className="snaplines">
              {(this.state.snaplines || []).map((snapline, i) => {
                if (snapline.mode === 'x') {
                  return <line key={i} vectorEffect="non-scaling-stroke" strokeDasharray="5 5" stroke="blue" strokeWidth="0.8" y1={0} y2={this.state.slide.height} x1={snapline.pos} x2={snapline.pos}/>
                } else {
                  return <line key={i} vectorEffect="non-scaling-stroke" strokeDasharray="5 5" stroke="blue" strokeWidth="0.8" x1={0} x2={this.state.slide.width} y1={snapline.pos} y2={snapline.pos}/>
                }
              })}
            </g>
          </g>
          <g ref={this.handleSelectionRefs} className="slide-selections">
            {Object.keys(this.state.selection).filter(id => !!this.nodes[id]).map(id => this.nodes[id].renderSelection())}
          </g>
        </g>
      </svg>

);
  }

}
<|endoftext|>


<commit_before>/**
 * 24.05.2017
 * TCP Chat using NodeJS
 * https://github.com/PatrikValkovic/TCPChat
 * Created by patri
 */
'use strict'

let counter = 0

/**
 * Represent connected client
 * @type {Client}
 */
module.exports = class Client {
    constructor(socket) {
        this.socket = socket
        this.name = 'anonymous'
        this.connected = true
        this.id = counter++
        this.groups = {}
    }

    /**
     * Disconnect client from server
     */
    disconnect() {
        this.connected = false
        this.socket.destroy()
    }

    /**
     * Check, if is user in specific group
     * @param {string} name Name of group to check
     * @returns {boolean} True if is user in group, false otherwise
     */
    isInGroup(name) {
        return this.groups.hasOwnProperty(name)
    }
}<commit_msg>Remove connected prooperty from client<commit_after>/**
 * 24.05.2017
 * TCP Chat using NodeJS
 * https://github.com/PatrikValkovic/TCPChat
 * Created by patri
 */
'use strict'

let counter = 0

/**
 * Represent connected client
 * @type {Client}
 */
module.exports = class Client {
    constructor(socket) {
        this.socket = socket
        this.name = 'anonymous'
        this.id = counter++
        this.groups = {}
    }

    /**
     * Disconnect client from server
     */
    disconnect() {
        this.socket.destroy()
    }

    /**
     * Check, if is user in specific group
     * @param {string} name Name of group to check
     * @returns {boolean} True if is user in group, false otherwise
     */
    isInGroup(name) {
        return this.groups.hasOwnProperty(name)
    }
}<|endoftext|>


<commit_before>import path from "path";

export class Config {
  constructor() {
    const context = process.cwd();
    const env = process.env.NODE_ENV || "development";
    const debug = ["development", "test"].indexOf(env) !== -1;

    this.options = {
      alias: {},      // [package]: folder
      context,        // Folder
      env,            // String
      debug,          // Boolean
      dest: null,     // Folder
      loader: {},     // [ext]: [ {...loader} ] ],
      src: {},        // [name]: [files]
    };
  }

  alias(pkg, folder) {
    this.options.alias[pkg] = path.resolve(this.options.context, folder);

    return this;
  }

  context(context) {
    this.options.context = context;

    return this;
  }

  create() {
    throw new Error("`Config.create` should be extended.");
  }

  debug(debug) {
    if (typeof debug === "undefined") {
      return this.options.debug;
    }

    this.options.debug = debug;

    return this;
  }

  defaults() {
    this
      .loader("babel", ".js", {
        exclude: /node_modules/,
        query: {
          cacheDirectory: true,
        },
      })
      .loader("json", ".json")
      .loader("url", [".gif", ".jpg", ".jpeg", ".png"], {
        query: {
          limit: 8192,
        },
      })
      .loader("style", ".css")
      .loader("css", ".css", {
        query: {
          localIdentName: "[name]-[local]--[hash:base64:5]",
        },
      })
    ;
  }

  dest(folder) {
    this.options.dest = folder;

    return this;
  }

  env(env) {
    if (!env) {
      return this.options.env;
    }

    this.options.env = env;

    return this;
  }

  loader(loader, extOrExts = ".js", settings = {}) {
    if (Array.isArray(extOrExts)) {
      extOrExts.forEach((ext) => this.loader(loader, ext, settings));

      return this;
    }

    const ext = extOrExts;

    if (!loader.match(/-loader$/)) {
      loader = `${loader}-loader`;
    }

    if (!this.options.loader[ext]) {
      this.options.loader[ext] = [];
    }

    if (typeof loader === "function") {
      this.options.loader[ext] = loader(this.options.loader[ext]);
    } else {
      const test = new RegExp(ext.replace(".", "\\."));

      this.options.loader[ext].push({
        loader,
        test,
        ...settings,
      });
    }

    return this;
  }

  src(src) {
    // Convert "./src/client.js" into { client: ["/.../src/client.js"] }
    if (typeof src === "string") {
      const parsed = path.parse(src);
      const basename = path.basename(parsed.base, parsed.ext).toLowerCase();

      // Arrays are best to avoid cyclical dependency issues
      src = {
        [basename]: [path.resolve(this.options.context, src)],
      };
    }

    this.options.src = src;

    return this;
  }
}
<commit_msg>Add .babel<commit_after>import path from "path";

export class Config {
  constructor() {
    const context = process.cwd();
    const env = process.env.NODE_ENV || "development";
    const debug = ["development", "test"].indexOf(env) !== -1;

    this.options = {
      alias: {},      // [package]: folder
      context,        // Folder
      env,            // String
      debug,          // Boolean
      dest: null,     // Folder
      loader: {},     // [ext]: [ {...loader} ] ],
      src: {},        // [name]: [files]
    };
  }

  alias(pkg, folder) {
    this.options.alias[pkg] = path.resolve(this.options.context, folder);

    return this;
  }

  babel(query) {
    this.loader("babel", [".js", ".jsx"], {
      exclude: /node_modules/,
      query: {
        cacheDirectory: true,
        ...query,
      },
    });

    return this;
  }

  context(context) {
    this.options.context = context;

    return this;
  }

  create() {
    throw new Error("`Config.create` should be extended.");
  }

  debug(debug) {
    if (typeof debug === "undefined") {
      return this.options.debug;
    }

    this.options.debug = debug;

    return this;
  }

  defaults() {
    this
      .babel()
      .loader("json", ".json")
      .loader("url", [".gif", ".jpg", ".jpeg", ".png"], {
        query: {
          limit: 8192,
        },
      })
      .loader("style", ".css")
      .loader("css", ".css", {
        query: {
          localIdentName: "[name]-[local]--[hash:base64:5]",
        },
      })
    ;
  }

  dest(folder) {
    this.options.dest = folder;

    return this;
  }

  env(env) {
    if (!env) {
      return this.options.env;
    }

    this.options.env = env;

    return this;
  }

  loader(loader, extOrExts = ".js", settings = {}) {
    if (Array.isArray(extOrExts)) {
      extOrExts.forEach((ext) => this.loader(loader, ext, settings));

      return this;
    }

    const ext = extOrExts;

    if (!loader.match(/-loader$/)) {
      loader = `${loader}-loader`;
    }

    if (!this.options.loader[ext]) {
      this.options.loader[ext] = [];
    }

    if (typeof loader === "function") {
      this.options.loader[ext] = loader(this.options.loader[ext]);
    } else {
      const test = new RegExp(ext.replace(".", "\\."));

      this.options.loader[ext].push({
        loader,
        test,
        ...settings,
      });
    }

    return this;
  }

  src(src) {
    // Convert "./src/client.js" into { client: ["/.../src/client.js"] }
    if (typeof src === "string") {
      const parsed = path.parse(src);
      const basename = path.basename(parsed.base, parsed.ext).toLowerCase();

      // Arrays are best to avoid cyclical dependency issues
      src = {
        [basename]: [path.resolve(this.options.context, src)],
      };
    }

    this.options.src = src;

    return this;
  }
}
<|endoftext|>


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

define('Sage/Platform/Mobile/Detail', ['Sage/Platform/Mobile/View', 'Sage/Platform/Mobile/Utility', 'Sage/Platform/Mobile/Format'], function() {

    return dojo.declare('Sage.Platform.Mobile.Detail', [Sage.Platform.Mobile.View], {
        attributeMap: {
            detailContent: {node: 'contentNode', type: 'innerHTML'}
        },
        widgetTemplate: new Simplate([
            '
',
            '{%! $.loadingTemplate %}',
            '

',
            '
'
        ]),
        emptyTemplate: new Simplate([
        ]),
        loadingTemplate: new Simplate([
            '
',
            '

{%: $.loadingText %}

',
            '
'
        ]),
        sectionBeginTemplate: new Simplate([
            '
',
            '{%: ($.title || $.options.title) %}<button class="collapsed-indicator" aria-label="{%: $$.toggleCollapseText %}"></button>',
            '
',
            '{% if ($.list || $.options.list) { %}',
            '
',
            '{% } else { %}',
            '
',
            '{% } %}'
        ]),
        sectionEndTemplate: new Simplate([
            '{% if ($.list || $.options.list) { %}',
            '
',
            '{% } else { %}',
            '
',
            '{% } %}'
        ]),
        propertyTemplate: new Simplate([
            '
',
            '{%: $.label %}',
            '{%= $.value %}', // todo: create a way to allow the value to not be surrounded with a span tag
            '
'
        ]),
        relatedPropertyTemplate: new Simplate([
            '
',
            '{%: $.label %}',
            '',
            '',
            '{%= $.value %}',
            '',
            '',
            '
'
        ]),
        relatedTemplate: new Simplate([
            '
',
            '',
            '{% if ($.icon) { %}',
            '',
            '{% } %}',
            '{%: $.label %}',
            '',
            '
'
        ]),
        actionPropertyTemplate: new Simplate([
            '
',
            '{%: $.label %}',
            '',
            '',
            '{%= $.value %}',
            '',
            '',
            '
'
        ]),
        actionTemplate: new Simplate([
            '
',
            '',
            '{% if ($.icon) { %}',
            '',
            '{% } %}',
            '{%: $.label %}',
            '{%= $.value %}',
            '',
            '
'
        ]),
        notAvailableTemplate: new Simplate([
            '
{%: $.notAvailableText %}
'
        ]),
        id: 'generic_detail',
        layout: null,
        security: false,
        customizationSet: 'detail',
        expose: false,
        editText: 'Edit',
        titleText: 'Detail',
        detailsText: 'Details',
        toggleCollapseText: 'toggle collapse',
        loadingText: 'loading...',
        requestErrorText: 'A server error occurred while requesting data.',
        notAvailableText: 'The requested entry is not available.',
        editView: false,

        postCreate: function() {
            this.inherited(arguments);
            this.connect(App, 'onRefresh', this._onRefresh);
            this.clear();
        },
        createToolLayout: function() {
            return this.tools || (this.tools = {
                'tbar': [{
                    id: 'edit',
                    action: 'navigateToEditView',
                    security: App.getViewSecurity(this.editView, 'update')
                }]
            });
        },
        invokeAction: function(name, parameters, evt, el) {
            if (parameters && /true/i.test(parameters['disableAction']))
                return;

            return this.inherited(arguments);
        },
        _onRefresh: function(o) {
            var descriptor = o.data && o.data['$descriptor'];

            if (this.options && this.options.key === o.key) {
                this.refreshRequired = true;

                if (descriptor) {
                    this.options.title = descriptor;
                    this.set('title', descriptor);
                }
            }
        },
        formatRelatedQuery: function(entry, fmt, property) {
            var property = property || '$key';

            return dojo.string.substitute(fmt, [Sage.Platform.Mobile.Utility.getValue(entry, property)]);
        },
        toggleSection: function(params) {
            var node = dojo.byId(params.$source);
            if (node)
                dojo.toggleClass(node, 'collapsed');
        },
        activateRelatedEntry: function(params) {
            if (params.context)
                this.navigateToRelatedView(params.view, dojo.fromJson(params.context), params.descriptor);
        },
        activateRelatedList: function(params) {
            if (params.context)
                this.navigateToRelatedView(params.view, dojo.fromJson(params.context), params.descriptor);
        },
        navigateToEditView: function(el) {
            var view = App.getView(this.editView);
            if (view)
                view.show({entry: this.entry});
        },
        navigateToRelatedView: function(view, o, descriptor) {
            var context,
                targetView;
            if (typeof o === 'string') {
                context = {
                    key: o,
                    descriptor: descriptor
                };
            } else {
                context = o;

                if (descriptor) context['descriptor'] = descriptor;
            }

            if (context) {
                targetView = App.getView(view);
                if (targetView)
                    targetView.show(context);
            }
        },
        createRequest: function() {
            var request = new Sage.SData.Client.SDataSingleResourceRequest(this.getService());

            /* test for complex selector */
            /* todo: more robust test required? */
            if (/(\s+)/.test(this.options.key))
                request.setResourceSelector(this.options.key);
            else
                request.setResourceSelector(dojo.string.substitute("'${0}'", [this.options.key]));

            if (this.resourceKind)
                request.setResourceKind(this.resourceKind);

            if (this.querySelect)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Select, this.querySelect.join(','));

            if (this.queryInclude)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Include, this.queryInclude.join(','));

            if (this.queryOrderBy)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.OrderBy, this.queryOrderBy);

            return request;
        },
        createLayout: function() {
            return this.layout || [];
        },
        processLayout: function(layout, entry)
        {
            var rows = (layout['children'] || layout['as'] || layout),
                options = layout['options'] || (layout['options'] = {
                    title: this.detailsText
                }),
                getValue = Sage.Platform.Mobile.Utility.getValue,
                encodeValue = Sage.Platform.Mobile.Format.encode,
                sectionQueue = [],
                sectionStarted = false,
                content = [];

            for (var i = 0; i < rows.length; i++) {
                var current = rows[i],
                    include = this.expandExpression(current['include'], entry),
                    exclude = this.expandExpression(current['exclude'], entry);

                if (include !== undefined && !include) continue;
                if (exclude !== undefined && exclude) continue;

                if (current['children'] || current['as'])
                {
                    if (sectionStarted)
                        sectionQueue.push(current);
                    else
                        this.processLayout(current, entry);

                    continue;
                }

                if (!sectionStarted)
                {
                    sectionStarted = true;
                    content.push(this.sectionBeginTemplate.apply(layout, this));
                }

                var provider = current['provider'] || getValue,
                    property = typeof current['property'] == 'string'
                        ? current['property']
                        : current['name'],
                    value = typeof current['value'] === 'undefined'
                        ? provider(entry, property)
                        : current['value'],
                    rendered,
                    formatted;

                if (current['template'] || current['tpl'])
                {
                    rendered = (current['template'] || current['tpl']).apply(value, this);
                    formatted = current['encode'] === true
                        ? encodeValue(rendered)
                        : rendered;
                }
                else if (current['renderer'] && typeof current['renderer'] === 'function')
                {
                    rendered = current['renderer'].call(this, value);
                    formatted = current['encode'] === true
                        ? encodeValue(rendered)
                        : rendered;
                }
                else
                {
                    formatted = current['encode'] !== false
                        ? encodeValue(value)
                        : value;
                }

                var data = dojo.mixin({}, {
                    entry: entry,
                    value: formatted,
                    raw: value
                }, current);

                if (current['descriptor'])
                    data['descriptor'] = typeof current['descriptor'] === 'function'
                        ? this.expandExpression(current['descriptor'], entry, value)
                        : provider(entry, current['descriptor']);

                if (current['action'])
                    data['action'] = this.expandExpression(current['action'], entry, value);

                var hasAccess = App.hasAccessTo(current['security']);
                if (current['security'])
                    data['disabled'] = !hasAccess;

                if (current['disabled'] && hasAccess)
                    data['disabled'] = this.expandExpression(current['disabled'], entry, value);

                if (current['view']) {
                    var context = {};
                    if (current['key'])
                        context['key'] = typeof current['key'] === 'function'
                            ? this.expandExpression(current['key'], entry)
                            : provider(entry, current['key']);
                    if (current['where'])
                        context['where'] = this.expandExpression(current['where'], entry);
                    if (current['resourceKind'])
                        context['resourceKind'] = this.expandExpression(current['resourceKind'], entry);
                    if (current['resourceProperty'])
                        context['resourceProperty'] = this.expandExpression(current['resourceProperty'], entry);
                    if (current['resourcePredicate'])
                        context['resourcePredicate'] = this.expandExpression(current['resourcePredicate'], entry);

                    data['view'] = current['view'];
                    data['context'] = dojo.toJson(context);
                }

                // priority: wrap > (relatedPropertyTemplate | relatedTemplate) > (actionPropertyTemplate | actionTemplate) > propertyTemplate
                var useListTemplate = (layout['list'] || options['list']),
                    template = current['use']
                        ? current['use']
                        : current['view']
                            ? useListTemplate
                                ? this.relatedTemplate
                                : this.relatedPropertyTemplate
                            : current['action']
                                ? useListTemplate
                                    ? this.actionTemplate
                                    : this.actionPropertyTemplate
                                : this.propertyTemplate;

                content.push(template.apply(data, this));
            }

            if (sectionStarted) content.push(this.sectionEndTemplate.apply(layout, this));

            dojo.query(this.contentNode).append(content.join(''));

            for (var i = 0; i < sectionQueue.length; i++)
            {
                var current = sectionQueue[i];

                this.processLayout(current, entry);
            }
        },
        processEntry: function(entry) {
            this.entry = entry;

            if (this.entry)
            {
                this.processLayout(this._createCustomizedLayout(this.createLayout()), this.entry);
            }
            else
            {
                this.set('detailContent', '');
            }
        },
        onRequestDataFailure: function(response, o) {
            if (response && response.status == 404)
                dojo.query(this.contentNode).append(this.notAvailableTemplate.apply(this));
            else
                alert(dojo.string.substitute(this.requestErrorText, [response, o]));

            dojo.removeClass(this.domNode, 'panel-loading');
        },
        onRequestDataAborted: function(response, o) {
            this.options = false; // force a refresh
            dojo.removeClass(this.domNode, 'panel-loading');
        },
        onRequestDataSuccess: function(entry) {
            this.processEntry(entry);
            dojo.removeClass(this.domNode, 'panel-loading');
        },
        requestData: function() {
            dojo.addClass(this.domNode, 'panel-loading');

            var request = this.createRequest();
            if (request)
                request.read({
                    success: this.onRequestDataSuccess,
                    failure: this.onRequestDataFailure,
                    aborted: this.onRequestDataAborted,
                    scope: this
                });
        },
        refreshRequiredFor: function(options) {
            if (this.options) {
                if (options) {
                    if (this.options.key !== options.key) return true;
                }
                return false;
            }
            else
                return this.inherited(arguments);
        },
        activate: function(tag, data) {
            var options = data && data.options;
            if (options && options.descriptor)
                options.title = options.title || options.descriptor;

            this.inherited(arguments);
        },
        show: function(options) {
            if (options && options.descriptor)
                options.title = options.title || options.descriptor;

            this.inherited(arguments);
        },
        getTag: function() {
            return this.options && this.options.key;
        },
        getContext: function() {
            return dojo.mixin(this.inherited(arguments), {
                resourceKind: this.resourceKind,
                key: this.options.key,
                descriptor: this.options.descriptor
            });
        },
        beforeTransitionTo: function() {
            this.inherited(arguments);

            this.canEdit = this.editor ? true : false;

            if (this.refreshRequired)
            {
                this.clear();
            }
        },
        refresh: function() {
            if (this.security && !App.hasAccessTo(this.expandExpression(this.security)))
            {
                dojo.query(this.contentNode).append(this.notAvailableTemplate.apply(this));
                return;
            }

            this.requestData();
        },
        transitionTo: function() {
            this.inherited(arguments);
        },
        clear: function() {
            this.set('detailContent', this.emptyTemplate.apply(this));
            this.context = false;
        }
    });
});
<commit_msg>small fix for layout name changes.<commit_after>/* Copyright (c) 2010, Sage Software, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define('Sage/Platform/Mobile/Detail', ['Sage/Platform/Mobile/View', 'Sage/Platform/Mobile/Utility', 'Sage/Platform/Mobile/Format'], function() {

    return dojo.declare('Sage.Platform.Mobile.Detail', [Sage.Platform.Mobile.View], {
        attributeMap: {
            detailContent: {node: 'contentNode', type: 'innerHTML'}
        },
        widgetTemplate: new Simplate([
            '
',
            '{%! $.loadingTemplate %}',
            '

',
            '
'
        ]),
        emptyTemplate: new Simplate([
        ]),
        loadingTemplate: new Simplate([
            '
',
            '

{%: $.loadingText %}

',
            '
'
        ]),
        sectionBeginTemplate: new Simplate([
            '
',
            '{%: ($.title || $.options.title) %}<button class="collapsed-indicator" aria-label="{%: $$.toggleCollapseText %}"></button>',
            '
',
            '{% if ($.list || $.options.list) { %}',
            '
',
            '{% } else { %}',
            '
',
            '{% } %}'
        ]),
        sectionEndTemplate: new Simplate([
            '{% if ($.list || $.options.list) { %}',
            '
',
            '{% } else { %}',
            '
',
            '{% } %}'
        ]),
        propertyTemplate: new Simplate([
            '
',
            '{%: $.label %}',
            '{%= $.value %}', // todo: create a way to allow the value to not be surrounded with a span tag
            '
'
        ]),
        relatedPropertyTemplate: new Simplate([
            '
',
            '{%: $.label %}',
            '',
            '',
            '{%= $.value %}',
            '',
            '',
            '
'
        ]),
        relatedTemplate: new Simplate([
            '
',
            '',
            '{% if ($.icon) { %}',
            '',
            '{% } %}',
            '{%: $.label %}',
            '',
            '
'
        ]),
        actionPropertyTemplate: new Simplate([
            '
',
            '{%: $.label %}',
            '',
            '',
            '{%= $.value %}',
            '',
            '',
            '
'
        ]),
        actionTemplate: new Simplate([
            '
',
            '',
            '{% if ($.icon) { %}',
            '',
            '{% } %}',
            '{%: $.label %}',
            '{%= $.value %}',
            '',
            '
'
        ]),
        notAvailableTemplate: new Simplate([
            '
{%: $.notAvailableText %}
'
        ]),
        id: 'generic_detail',
        layout: null,
        security: false,
        customizationSet: 'detail',
        expose: false,
        editText: 'Edit',
        titleText: 'Detail',
        detailsText: 'Details',
        toggleCollapseText: 'toggle collapse',
        loadingText: 'loading...',
        requestErrorText: 'A server error occurred while requesting data.',
        notAvailableText: 'The requested entry is not available.',
        editView: false,

        postCreate: function() {
            this.inherited(arguments);
            this.connect(App, 'onRefresh', this._onRefresh);
            this.clear();
        },
        createToolLayout: function() {
            return this.tools || (this.tools = {
                'tbar': [{
                    id: 'edit',
                    action: 'navigateToEditView',
                    security: App.getViewSecurity(this.editView, 'update')
                }]
            });
        },
        invokeAction: function(name, parameters, evt, el) {
            if (parameters && /true/i.test(parameters['disableAction']))
                return;

            return this.inherited(arguments);
        },
        _onRefresh: function(o) {
            var descriptor = o.data && o.data['$descriptor'];

            if (this.options && this.options.key === o.key) {
                this.refreshRequired = true;

                if (descriptor) {
                    this.options.title = descriptor;
                    this.set('title', descriptor);
                }
            }
        },
        formatRelatedQuery: function(entry, fmt, property) {
            var property = property || '$key';

            return dojo.string.substitute(fmt, [Sage.Platform.Mobile.Utility.getValue(entry, property)]);
        },
        toggleSection: function(params) {
            var node = dojo.byId(params.$source);
            if (node)
                dojo.toggleClass(node, 'collapsed');
        },
        activateRelatedEntry: function(params) {
            if (params.context)
                this.navigateToRelatedView(params.view, dojo.fromJson(params.context), params.descriptor);
        },
        activateRelatedList: function(params) {
            if (params.context)
                this.navigateToRelatedView(params.view, dojo.fromJson(params.context), params.descriptor);
        },
        navigateToEditView: function(el) {
            var view = App.getView(this.editView);
            if (view)
                view.show({entry: this.entry});
        },
        navigateToRelatedView: function(view, o, descriptor) {
            var context,
                targetView;
            if (typeof o === 'string') {
                context = {
                    key: o,
                    descriptor: descriptor
                };
            } else {
                context = o;

                if (descriptor) context['descriptor'] = descriptor;
            }

            if (context) {
                targetView = App.getView(view);
                if (targetView)
                    targetView.show(context);
            }
        },
        createRequest: function() {
            var request = new Sage.SData.Client.SDataSingleResourceRequest(this.getService());

            /* test for complex selector */
            /* todo: more robust test required? */
            if (/(\s+)/.test(this.options.key))
                request.setResourceSelector(this.options.key);
            else
                request.setResourceSelector(dojo.string.substitute("'${0}'", [this.options.key]));

            if (this.resourceKind)
                request.setResourceKind(this.resourceKind);

            if (this.querySelect)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Select, this.querySelect.join(','));

            if (this.queryInclude)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Include, this.queryInclude.join(','));

            if (this.queryOrderBy)
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.OrderBy, this.queryOrderBy);

            return request;
        },
        createLayout: function() {
            return this.layout || [];
        },
        processLayout: function(layout, entry)
        {
            var rows = (layout['children'] || layout['as'] || layout),
                options = layout['options'] || (layout['options'] = {
                    title: this.detailsText
                }),
                getValue = Sage.Platform.Mobile.Utility.getValue,
                encodeValue = Sage.Platform.Mobile.Format.encode,
                sectionQueue = [],
                sectionStarted = false,
                content = [];

            for (var i = 0; i < rows.length; i++) {
                var current = rows[i],
                    include = this.expandExpression(current['include'], entry),
                    exclude = this.expandExpression(current['exclude'], entry);

                if (include !== undefined && !include) continue;
                if (exclude !== undefined && exclude) continue;

                if (current['children'] || current['as'])
                {
                    if (sectionStarted)
                        sectionQueue.push(current);
                    else
                        this.processLayout(current, entry);

                    continue;
                }

                if (!sectionStarted)
                {
                    sectionStarted = true;
                    content.push(this.sectionBeginTemplate.apply(layout, this));
                }

                var provider = current['provider'] || getValue,
                    property = typeof current['property'] == 'string'
                        ? current['property']
                        : current['name'],
                    value = typeof current['value'] === 'undefined'
                        ? provider(entry, property)
                        : current['value'],
                    rendered,
                    formatted;

                if (current['template'] || current['tpl'])
                {
                    rendered = (current['template'] || current['tpl']).apply(value, this);
                    formatted = current['encode'] === true
                        ? encodeValue(rendered)
                        : rendered;
                }
                else if (current['renderer'] && typeof current['renderer'] === 'function')
                {
                    rendered = current['renderer'].call(this, value);
                    formatted = current['encode'] === true
                        ? encodeValue(rendered)
                        : rendered;
                }
                else
                {
                    formatted = current['encode'] !== false
                        ? encodeValue(value)
                        : value;
                }

                var data = dojo.mixin({}, {
                    entry: entry,
                    value: formatted,
                    raw: value
                }, current);

                if (current['descriptor'])
                    data['descriptor'] = typeof current['descriptor'] === 'function'
                        ? this.expandExpression(current['descriptor'], entry, value)
                        : provider(entry, current['descriptor']);

                if (current['action'])
                    data['action'] = this.expandExpression(current['action'], entry, value);

                var hasAccess = App.hasAccessTo(current['security']);
                if (current['security'])
                    data['disabled'] = !hasAccess;

                if (current['disabled'] && hasAccess)
                    data['disabled'] = this.expandExpression(current['disabled'], entry, value);

                if (current['view']) {
                    var context = {};
                    if (current['key'])
                        context['key'] = typeof current['key'] === 'function'
                            ? this.expandExpression(current['key'], entry)
                            : provider(entry, current['key']);
                    if (current['where'])
                        context['where'] = this.expandExpression(current['where'], entry);
                    if (current['resourceKind'])
                        context['resourceKind'] = this.expandExpression(current['resourceKind'], entry);
                    if (current['resourceProperty'])
                        context['resourceProperty'] = this.expandExpression(current['resourceProperty'], entry);
                    if (current['resourcePredicate'])
                        context['resourcePredicate'] = this.expandExpression(current['resourcePredicate'], entry);

                    data['view'] = current['view'];
                    data['context'] = dojo.toJson(context);
                }

                // priority: wrap > (relatedPropertyTemplate | relatedTemplate) > (actionPropertyTemplate | actionTemplate) > propertyTemplate
                var useListTemplate = (layout['list'] || options['list']),
                    template = current['use']
                        ? current['use']
                        : current['view']
                            ? useListTemplate
                                ? this.relatedTemplate
                                : this.relatedPropertyTemplate
                            : current['action']
                                ? useListTemplate
                                    ? this.actionTemplate
                                    : this.actionPropertyTemplate
                                : this.propertyTemplate;

                content.push(template.apply(data, this));
            }

            if (sectionStarted) content.push(this.sectionEndTemplate.apply(layout, this));

            dojo.query(this.contentNode).append(content.join(''));

            for (var i = 0; i < sectionQueue.length; i++)
            {
                var current = sectionQueue[i];

                this.processLayout(current, entry);
            }
        },
        processEntry: function(entry) {
            this.entry = entry;

            if (this.entry)
            {
                this.processLayout(this._createCustomizedLayout(this.createLayout()), this.entry);
            }
            else
            {
                this.set('detailContent', '');
            }
        },
        onRequestDataFailure: function(response, o) {
            if (response && response.status == 404)
                dojo.query(this.contentNode).append(this.notAvailableTemplate.apply(this));
            else
                alert(dojo.string.substitute(this.requestErrorText, [response, o]));

            dojo.removeClass(this.domNode, 'panel-loading');
        },
        onRequestDataAborted: function(response, o) {
            this.options = false; // force a refresh
            dojo.removeClass(this.domNode, 'panel-loading');
        },
        onRequestDataSuccess: function(entry) {
            this.processEntry(entry);
            dojo.removeClass(this.domNode, 'panel-loading');
        },
        requestData: function() {
            dojo.addClass(this.domNode, 'panel-loading');

            var request = this.createRequest();
            if (request)
                request.read({
                    success: this.onRequestDataSuccess,
                    failure: this.onRequestDataFailure,
                    aborted: this.onRequestDataAborted,
                    scope: this
                });
        },
        refreshRequiredFor: function(options) {
            if (this.options) {
                if (options) {
                    if (this.options.key !== options.key) return true;
                }
                return false;
            }
            else
                return this.inherited(arguments);
        },
        activate: function(tag, data) {
            var options = data && data.options;
            if (options && options.descriptor)
                options.title = options.title || options.descriptor;

            this.inherited(arguments);
        },
        show: function(options) {
            if (options && options.descriptor)
                options.title = options.title || options.descriptor;

            this.inherited(arguments);
        },
        getTag: function() {
            return this.options && this.options.key;
        },
        getContext: function() {
            return dojo.mixin(this.inherited(arguments), {
                resourceKind: this.resourceKind,
                key: this.options.key,
                descriptor: this.options.descriptor
            });
        },
        beforeTransitionTo: function() {
            this.inherited(arguments);

            this.canEdit = this.editor ? true : false;

            if (this.refreshRequired)
            {
                this.clear();
            }
        },
        refresh: function() {
            if (this.security && !App.hasAccessTo(this.expandExpression(this.security)))
            {
                dojo.query(this.contentNode).append(this.notAvailableTemplate.apply(this));
                return;
            }

            this.requestData();
        },
        transitionTo: function() {
            this.inherited(arguments);
        },
        clear: function() {
            this.set('detailContent', this.emptyTemplate.apply(this));
            this.context = false;
        }
    });
});
<|endoftext|>