<commit_before>/**
 * @author Roger Wolfer, Roman Schaller
 */

var INVENTORY_SERVER_PATH = '../inventoryServer/web_root/public/';

function AreaSelect() {

	//////////////////////// Method declarations ///////////////////////
	/**
	 * This function will be called if the user clicks on the plus or minus symbol at the beginning
	 * of a row.
	 */
	AreaSelect.prototype.onTableExpanderClicked = function () {
	    var nTr = this.parentNode.parentNode;
	    if ( this.src.match('details_close') ) {
	        /* This row is already open - close it */
	        this.src = "modules/area/images/details_open.png";
	        me.area_table.fnClose( nTr );
	    } else {
	        /* Open this row */
	        this.src = "modules/area/images/details_close.png";
	        me.area_table.fnOpen( nTr, me.formatDetails(nTr), 'details' );
	    }
	}

	/**
	 * This function is called when the user clicks on a row
	 */
	AreaSelect.prototype.onTableRowClicked = function(event) {
		var overlayId = event.target.parentNode.getAttribute('overlay_id');
		me.selectArea(overlayId);
	}

	/**
	 * This is called if the user hovers over a table row
	 */
	AreaSelect.prototype.onTableRowHover = function(event) {
		var overlayid = jQuery(event.srcElement).parent().attr('overlay_id');
		var overlay = me.mapOverlays.overlays[overlayid];
		if (overlay) {
			var parent = event.target.parentNode;
			if (event.type == 'mouseover') {
				jQuery(parent).addClass('row_highlighted');
				overlay.setStyle('highlighted');
			} else {
				jQuery(parent).removeClass('row_highlighted');
				overlay.setStyle('highlighted-disable');
			}
		}
	}

	/**
	 * This is called if an area is selected from any source (table, dropdown, map)
	 */
	AreaSelect.prototype.selectArea = function(overlayId) {
		// handle table highlighting
		jQuery(areaselect.area_table.fnSettings().aoData).each(function() {
			jQuery(this.nTr).removeClass('row_selected');
			if (this.nTr.getAttribute('overlay_id')) {
				areaselect.mapOverlays.overlays[this.nTr.getAttribute('overlay_id')].setStyle('selected-disable');
			}
		});
		jQuery('#area_table tbody tr[overlay_id="' + overlayId + '"]').addClass('row_selected');
		// handle map highlighting
		overlay = areaselect.mapOverlays.overlays[overlayId];
		overlay.setStyle('selected');
		areaselect.map.panTo(overlay.getCenter());
		areaselect.showAreaInfoBubble(overlay);
		// remember selected area
		areaselect.selected_area = overlayId;
	}

	/**
	 * Creates the google maps object and attaches it to the element with the id
	 * 'map_canvas'. Returns a google.maps.Map
	 */
	AreaSelect.prototype.createGoogleMaps = function() {
		var bruggCenter = new google.maps.LatLng(47.487084, 8.207273);
		var mapsOptions = {
				zoom : 15,
				center : bruggCenter,
				mapTypeId : google.maps.MapTypeId.ROADMAP
			};
		var map = new google.maps.Map(document.getElementById('map_canvas'), mapsOptions);
		util.geocode('map_search', 'map_search_button', map);
		return map;
	}

	/**
	 * Creates the bubble which shows information on an area when the user clicks on a area.
	 * Returns an InfoBubble
	 */
	AreaSelect.prototype.createAreaInfo = function(map) {
		areaInfo = new InfoBubble({
			map : map,
			shadowStyle : 1,
			padding : 8,
			borderRadius : 8,
			arrowSize : 40,
			borderWidth : 1,
			borderColor : '#2c2c2c',
			disableAutoPan : true,
			arrowPosition : 20,
			arrowStyle : 2
		});
		areaInfo.addTab('Details', '');
		areaInfo.addTab('Inventories', '');
		areaInfo.addTab('Habitats', '');
		return areaInfo;
	}

	/**
	 * Creates the overlay representing areas
	 * Returns MapGeometryOverlays
	 */
	AreaSelect.prototype.createOverlays = function(map) {
		var overlays = new MapGeometryOverlays(map);
		return overlays;
	}

	/**
	 * Creates the table showing areas
	 * Returns jQuery datatable
	 */
	AreaSelect.prototype.createDataTable = function(mapOverlays) {
		return jQuery('#area_table').dataTable( {
	        "oLanguage" : {
	            "sUrl" : "modules/area/languages/de_DE/DataTables.txt"
	        },
	        "bScrollInfinite": true,
	        "bScrollCollapse": true,
	        "sScrollY": "400px",
	        "bProcessing": true,
	        "bServerSide": true,
	        "sAjaxSource": INVENTORY_SERVER_PATH + "area-select/get-area",
	        "fnServerData": this.onRequestServerData,
	        "aoColumns": [
	        {"sClass": "center", "bSortable": false,  "bSearchable" : false},
	        {"sTitle": "Flurname"},
	        {"sTitle": "Ortschaft"},
	        {"sTitle": "Gemeinde"},
	        {"sTitle": "Kanton"},
	        {"sTitle": "Fläche (m²)"},
	        {"sTitle": "M.ü.M"},
	        {"sTitle": "Typ", "bSearchable" : false, "bSortable": false},
	        {"sTitle": "ParzellenNr.", "bSearchable" : false, "bVisible": false},
	        {"sTitle": "Lebensräume", "bSearchable" : false, "bVisible": false},
	        {"sTitle": "Beschreibung", "bSearchable" : false, "bVisible": false},
	        {"sTitle": "area_id", "bSearchable" : false, "bVisible": false}
	        ],
	        "aaSorting": [[1, 'asc']],
	        'fnInitComplete': function (){
	          this.fnSetFilteringDelay(250);
	        }
	    } );
	}

	/**
	 * Is called if new area data is needed. This makes a call to the server by ajax.
	 */
	AreaSelect.prototype.onRequestServerData = function ( sSource, aoData, fnCallback ) {
        /* Add some data to send to the source, and send as 'POST' */
        jQuery.ajax( {
            "dataType": 'json',
            "type": "POST",
            "url": sSource,
            "data": aoData,
            "success": function (json) {
                var aaData = [];
                var areas = json.areas;
                me.mapOverlays.clear();

                for(var i in areas) {
                    aaData.push([
                      '',
                      areas[i]['field_name'],
                      areas[i]['locality'],
                      areas[i]['township'],
                      areas[i]['canton'],
                      areas[i]['surface_area'],
                      areas[i]['altitude'],
                      areas[i]['type'],
                      areas[i]['parcel_nr'],
                      me.formatHabitats(areas[i]['habitats']),
                      areas[i]['comment'],
                      areas[i]['id']]);
                }
                var newJson = {
                    'sEcho' : json.sEcho,
                    'iTotalRecords' : json.iTotalRecords,
                    'iTotalDisplayRecords': json.iTotalDisplayRecords,
                    'aaData': aaData
                }
                me.mapOverlays.addOverlaysJson(json.areas);

                for(var i in me.mapOverlays.overlays) {
                    var overlay = me.mapOverlays.overlays[i];
                    me.addOverlayListener(overlay);
                }
                fnCallback(newJson);
                jQuery(me.area_table.fnSettings().aoData).each( function () {
                    this.nTr.setAttribute('overlay_id', this._aData[11]);
                });
            }
        } );
    }

	/**
	 * adds a listener for selecting and hover to geometry overlays
	 */
	AreaSelect.prototype.addOverlayListener = function(overlay) {
	    //hover
	    google.maps.event.addListener(overlay.gOverlay, 'mouseover', function(event) {
	        jQuery('tr[overlay_id="'+overlay.id+'"]').addClass('row_highlighted');
	        overlay.setStyle('highlighted');
	    });
	    google.maps.event.addListener(overlay.gOverlay, 'mouseout', function(event) {
	        jQuery('tr[overlay_id="'+overlay.id+'"]').removeClass('row_highlighted');
	        overlay.setStyle('highlighted-disable');
	    });

	    //select
	    google.maps.event.addListener(overlay.gOverlay, 'click', function(event) {
	    	me.selectArea(overlay.id);
	    });
	};

	/**
	 * Shows the info bubble of an area.
	 * It first closes the bubble, moves it's position, makes a ajax request and if that returns, updates and shows the bubble again.
	 */
	AreaSelect.prototype.showAreaInfoBubble = function(overlay) {
		// close and move
		me.areaInfo.close();
		me.areaInfo.setPosition(overlay.getCenter());

		// update and show area info
		jQuery.getJSON(Drupal.settings.basePath + 'area/json/' + overlay.id, function(data, textStatus, jqXHR) {
			// area details
			var details = '
';
			details += '' + data.field_name + '';
			details += '
' + data.locality + '
';
			details += data.zip + ' ' + data.township + '
';
			details += data.altitude + '
';
			details += data.surface_area + '
';
			details += '
';
			details += '
' + data.comment + '
';
			me.areaInfo.updateTab(0, 'Details', details);

			// inventories
			inventories = '';
			for ( var i = 0, len = data.inventories.invs.length; i < len; ++i) {
				inventory = data.inventories.invs[i];
				inventories += '
' + inventory.name + ':

';
				for ( var ie = 0, ieLen = inventory.types.length; ie < ieLen; ++ie) {
					type = data.inventories.invs[i].types[ie];
					inventories += type.name + ' (' + type.count + ' x)';
					if (ieLen > ie + 1) {
						inventories += ', ';
					}
				}
				inventories += '
';
			}
			me.areaInfo.updateTab(1, data.inventories.title, inventories);

			// habitats
			habitats = '
';
			if (data.habitats.habs) {
				for ( var i = 0, len = data.habitats.habs.length; i < len; ++i) {
					habitats += data.habitats.habs[i] + '
';
				}
			}
			habitats += '
';
			me.areaInfo.updateTab(2, data.habitats.title, habitats);

			// and finally show the fancy popup bubble:
			me.areaInfo.open(me.map);
		});
	}

	AreaSelect.prototype.formatDetails = function ( nTr ){
	  var aData = me.area_table.fnGetData( nTr );
	  var sOut = '
';
	  sOut += '
Parzellen Nr.:	'+aData[8]+'
';
	  sOut += '
Lebensräume:	'+aData[9]+'
';
	  sOut += '
Beschreibung:	'+aData[10]+'
';
	  sOut += '
';

	  return sOut;
	};

	AreaSelect.prototype.formatHabitats = function(habitats){
	  var sHabitats = '
';
	  for(var hi in habitats){
	    sHabitats += '
'+habitats[hi]['label'] + '	' + habitats[hi]['name_de']+'
';
	  }
	  sHabitats += '
';
	  return sHabitats;
	};

	/**
	 * This is called if the user clicks on the button "create inventory".
	 */
	AreaSelect.prototype.onCreateInventoryClicked = function() {
		if (areaselect.selected_area != null) {
			window.location.href = 'inventory/new/' + areaselect.selected_area;
		} else {
			alert('Bitte wählen Sie ein Gebiet aus.');
		}
	}

	AreaSelect.prototype.onControlAreaChooseClicked = function(event) {
		jQuery('#controlAreaChoose').addClass('selected');
		jQuery('#controlAreaCreate').removeClass('selected');
		areaselect.overlayControl.stopDigitizing();
		jQuery('#edit-areanewform--2').addClass('hidden');
	}

	AreaSelect.prototype.onControlAreaCreateClicked = function(event) {
		jQuery('#controlAreaChoose').removeClass('selected');
		jQuery('#controlAreaCreate').addClass('selected');
		jQuery('#edit-areanewform--2').removeClass('hidden');
		areaselect.overlayControl.startDigitizing();
	}

	//////////////////////// Class initialisation //////////////////////

	// Member variable initialisation
	var me = this; // references to the instance of AreaSelect
	me.map = this.createGoogleMaps();
	me.mapOverlays = this.createOverlays(me.map); // Overlays representing areas
	me.selected_area = null; // index of currently selected area
	me.areaInfo = this.createAreaInfo(me.map); // popup bubble shown if user clicks on an area
	me.area_table = this.createDataTable(me.mapOverlays); // the table containing areas
	me.overlayControl = new GeometryOverlayControl(me.map); // class to control drawing of new areas

	// register events
	jQuery('#create-inventory').click(this.onCreateInventoryClicked);
	jQuery("#area_table tbody").live('click', this.onTableRowClicked);
	jQuery('tbody > tr').live('mouseover mouseout', this.onTableRowHover);
    jQuery('#area_table tbody td img').live( 'click', this.onTableExpanderClicked);
    jQuery('#controlAreaChoose').click(this.onControlAreaChooseClicked);
    jQuery('#controlAreaCreate').click(this.onControlAreaCreateClicked);
};

var areaselect = null;
jQuery(document).ready(function() {
	areaselect = new AreaSelect();
});
<commit_msg>dont zoom with mousewheel<commit_after>/**
 * @author Roger Wolfer, Roman Schaller
 */

var INVENTORY_SERVER_PATH = '../inventoryServer/web_root/public/';

function AreaSelect() {

	//////////////////////// Method declarations ///////////////////////
	/**
	 * This function will be called if the user clicks on the plus or minus symbol at the beginning
	 * of a row.
	 */
	AreaSelect.prototype.onTableExpanderClicked = function () {
	    var nTr = this.parentNode.parentNode;
	    if ( this.src.match('details_close') ) {
	        /* This row is already open - close it */
	        this.src = "modules/area/images/details_open.png";
	        me.area_table.fnClose( nTr );
	    } else {
	        /* Open this row */
	        this.src = "modules/area/images/details_close.png";
	        me.area_table.fnOpen( nTr, me.formatDetails(nTr), 'details' );
	    }
	}

	/**
	 * This function is called when the user clicks on a row
	 */
	AreaSelect.prototype.onTableRowClicked = function(event) {
		var overlayId = event.target.parentNode.getAttribute('overlay_id');
		me.selectArea(overlayId);
	}

	/**
	 * This is called if the user hovers over a table row
	 */
	AreaSelect.prototype.onTableRowHover = function(event) {
		var overlayid = jQuery(event.srcElement).parent().attr('overlay_id');
		var overlay = me.mapOverlays.overlays[overlayid];
		if (overlay) {
			var parent = event.target.parentNode;
			if (event.type == 'mouseover') {
				jQuery(parent).addClass('row_highlighted');
				overlay.setStyle('highlighted');
			} else {
				jQuery(parent).removeClass('row_highlighted');
				overlay.setStyle('highlighted-disable');
			}
		}
	}

	/**
	 * This is called if an area is selected from any source (table, dropdown, map)
	 */
	AreaSelect.prototype.selectArea = function(overlayId) {
		// handle table highlighting
		jQuery(areaselect.area_table.fnSettings().aoData).each(function() {
			jQuery(this.nTr).removeClass('row_selected');
			if (this.nTr.getAttribute('overlay_id')) {
				areaselect.mapOverlays.overlays[this.nTr.getAttribute('overlay_id')].setStyle('selected-disable');
			}
		});
		jQuery('#area_table tbody tr[overlay_id="' + overlayId + '"]').addClass('row_selected');
		// handle map highlighting
		overlay = areaselect.mapOverlays.overlays[overlayId];
		overlay.setStyle('selected');
		areaselect.map.panTo(overlay.getCenter());
		areaselect.showAreaInfoBubble(overlay);
		// remember selected area
		areaselect.selected_area = overlayId;
	}

	/**
	 * Creates the google maps object and attaches it to the element with the id
	 * 'map_canvas'. Returns a google.maps.Map
	 */
	AreaSelect.prototype.createGoogleMaps = function() {
		var bruggCenter = new google.maps.LatLng(47.487084, 8.207273);
		var mapsOptions = {
				zoom : 15,
				center : bruggCenter,
				mapTypeId : google.maps.MapTypeId.ROADMAP,
				scrollwheel: false
			};
		var map = new google.maps.Map(document.getElementById('map_canvas'), mapsOptions);
		util.geocode('map_search', 'map_search_button', map);
		return map;
	}

	/**
	 * Creates the bubble which shows information on an area when the user clicks on a area.
	 * Returns an InfoBubble
	 */
	AreaSelect.prototype.createAreaInfo = function(map) {
		areaInfo = new InfoBubble({
			map : map,
			shadowStyle : 1,
			padding : 8,
			borderRadius : 8,
			arrowSize : 40,
			borderWidth : 1,
			borderColor : '#2c2c2c',
			disableAutoPan : true,
			arrowPosition : 20,
			arrowStyle : 2
		});
		areaInfo.addTab('Details', '');
		areaInfo.addTab('Inventories', '');
		areaInfo.addTab('Habitats', '');
		return areaInfo;
	}

	/**
	 * Creates the overlay representing areas
	 * Returns MapGeometryOverlays
	 */
	AreaSelect.prototype.createOverlays = function(map) {
		var overlays = new MapGeometryOverlays(map);
		return overlays;
	}

	/**
	 * Creates the table showing areas
	 * Returns jQuery datatable
	 */
	AreaSelect.prototype.createDataTable = function(mapOverlays) {
		return jQuery('#area_table').dataTable( {
	        "oLanguage" : {
	            "sUrl" : "modules/area/languages/de_DE/DataTables.txt"
	        },
	        "bScrollInfinite": true,
	        "bScrollCollapse": true,
	        "sScrollY": "400px",
	        "bProcessing": true,
	        "bServerSide": true,
	        "sAjaxSource": INVENTORY_SERVER_PATH + "area-select/get-area",
	        "fnServerData": this.onRequestServerData,
	        "aoColumns": [
	        {"sClass": "center", "bSortable": false,  "bSearchable" : false},
	        {"sTitle": "Flurname"},
	        {"sTitle": "Ortschaft"},
	        {"sTitle": "Gemeinde"},
	        {"sTitle": "Kanton"},
	        {"sTitle": "Fläche (m²)"},
	        {"sTitle": "M.ü.M"},
	        {"sTitle": "Typ", "bSearchable" : false, "bSortable": false},
	        {"sTitle": "ParzellenNr.", "bSearchable" : false, "bVisible": false},
	        {"sTitle": "Lebensräume", "bSearchable" : false, "bVisible": false},
	        {"sTitle": "Beschreibung", "bSearchable" : false, "bVisible": false},
	        {"sTitle": "area_id", "bSearchable" : false, "bVisible": false}
	        ],
	        "aaSorting": [[1, 'asc']],
	        'fnInitComplete': function (){
	          this.fnSetFilteringDelay(250);
	        }
	    } );
	}

	/**
	 * Is called if new area data is needed. This makes a call to the server by ajax.
	 */
	AreaSelect.prototype.onRequestServerData = function ( sSource, aoData, fnCallback ) {
        /* Add some data to send to the source, and send as 'POST' */
        jQuery.ajax( {
            "dataType": 'json',
            "type": "POST",
            "url": sSource,
            "data": aoData,
            "success": function (json) {
                var aaData = [];
                var areas = json.areas;
                me.mapOverlays.clear();

                for(var i in areas) {
                    aaData.push([
                      '',
                      areas[i]['field_name'],
                      areas[i]['locality'],
                      areas[i]['township'],
                      areas[i]['canton'],
                      areas[i]['surface_area'],
                      areas[i]['altitude'],
                      areas[i]['type'],
                      areas[i]['parcel_nr'],
                      me.formatHabitats(areas[i]['habitats']),
                      areas[i]['comment'],
                      areas[i]['id']]);
                }
                var newJson = {
                    'sEcho' : json.sEcho,
                    'iTotalRecords' : json.iTotalRecords,
                    'iTotalDisplayRecords': json.iTotalDisplayRecords,
                    'aaData': aaData
                }
                me.mapOverlays.addOverlaysJson(json.areas);

                for(var i in me.mapOverlays.overlays) {
                    var overlay = me.mapOverlays.overlays[i];
                    me.addOverlayListener(overlay);
                }
                fnCallback(newJson);
                jQuery(me.area_table.fnSettings().aoData).each( function () {
                    this.nTr.setAttribute('overlay_id', this._aData[11]);
                });
            }
        } );
    }

	/**
	 * adds a listener for selecting and hover to geometry overlays
	 */
	AreaSelect.prototype.addOverlayListener = function(overlay) {
	    //hover
	    google.maps.event.addListener(overlay.gOverlay, 'mouseover', function(event) {
	        jQuery('tr[overlay_id="'+overlay.id+'"]').addClass('row_highlighted');
	        overlay.setStyle('highlighted');
	    });
	    google.maps.event.addListener(overlay.gOverlay, 'mouseout', function(event) {
	        jQuery('tr[overlay_id="'+overlay.id+'"]').removeClass('row_highlighted');
	        overlay.setStyle('highlighted-disable');
	    });

	    //select
	    google.maps.event.addListener(overlay.gOverlay, 'click', function(event) {
	    	me.selectArea(overlay.id);
	    });
	};

	/**
	 * Shows the info bubble of an area.
	 * It first closes the bubble, moves it's position, makes a ajax request and if that returns, updates and shows the bubble again.
	 */
	AreaSelect.prototype.showAreaInfoBubble = function(overlay) {
		// close and move
		me.areaInfo.close();
		me.areaInfo.setPosition(overlay.getCenter());

		// update and show area info
		jQuery.getJSON(Drupal.settings.basePath + 'area/json/' + overlay.id, function(data, textStatus, jqXHR) {
			// area details
			var details = '
';
			details += '' + data.field_name + '';
			details += '
' + data.locality + '
';
			details += data.zip + ' ' + data.township + '
';
			details += data.altitude + '
';
			details += data.surface_area + '
';
			details += '
';
			details += '
' + data.comment + '
';
			me.areaInfo.updateTab(0, 'Details', details);

			// inventories
			inventories = '';
			for ( var i = 0, len = data.inventories.invs.length; i < len; ++i) {
				inventory = data.inventories.invs[i];
				inventories += '
' + inventory.name + ':

';
				for ( var ie = 0, ieLen = inventory.types.length; ie < ieLen; ++ie) {
					type = data.inventories.invs[i].types[ie];
					inventories += type.name + ' (' + type.count + ' x)';
					if (ieLen > ie + 1) {
						inventories += ', ';
					}
				}
				inventories += '
';
			}
			me.areaInfo.updateTab(1, data.inventories.title, inventories);

			// habitats
			habitats = '
';
			if (data.habitats.habs) {
				for ( var i = 0, len = data.habitats.habs.length; i < len; ++i) {
					habitats += data.habitats.habs[i] + '
';
				}
			}
			habitats += '
';
			me.areaInfo.updateTab(2, data.habitats.title, habitats);

			// and finally show the fancy popup bubble:
			me.areaInfo.open(me.map);
		});
	}

	AreaSelect.prototype.formatDetails = function ( nTr ){
	  var aData = me.area_table.fnGetData( nTr );
	  var sOut = '
';
	  sOut += '
Parzellen Nr.:	'+aData[8]+'
';
	  sOut += '
Lebensräume:	'+aData[9]+'
';
	  sOut += '
Beschreibung:	'+aData[10]+'
';
	  sOut += '
';

	  return sOut;
	};

	AreaSelect.prototype.formatHabitats = function(habitats){
	  var sHabitats = '
';
	  for(var hi in habitats){
	    sHabitats += '
'+habitats[hi]['label'] + '	' + habitats[hi]['name_de']+'
';
	  }
	  sHabitats += '
';
	  return sHabitats;
	};

	/**
	 * This is called if the user clicks on the button "create inventory".
	 */
	AreaSelect.prototype.onCreateInventoryClicked = function() {
		if (areaselect.selected_area != null) {
			window.location.href = 'inventory/new/' + areaselect.selected_area;
		} else {
			alert('Bitte wählen Sie ein Gebiet aus.');
		}
	}

	AreaSelect.prototype.onControlAreaChooseClicked = function(event) {
		jQuery('#controlAreaChoose').addClass('selected');
		jQuery('#controlAreaCreate').removeClass('selected');
		areaselect.overlayControl.stopDigitizing();
		jQuery('#edit-areanewform--2').addClass('hidden');
	}

	AreaSelect.prototype.onControlAreaCreateClicked = function(event) {
		jQuery('#controlAreaChoose').removeClass('selected');
		jQuery('#controlAreaCreate').addClass('selected');
		jQuery('#edit-areanewform--2').removeClass('hidden');
		areaselect.overlayControl.startDigitizing();
	}

	//////////////////////// Class initialisation //////////////////////

	// Member variable initialisation
	var me = this; // references to the instance of AreaSelect
	me.map = this.createGoogleMaps();
	me.mapOverlays = this.createOverlays(me.map); // Overlays representing areas
	me.selected_area = null; // index of currently selected area
	me.areaInfo = this.createAreaInfo(me.map); // popup bubble shown if user clicks on an area
	me.area_table = this.createDataTable(me.mapOverlays); // the table containing areas
	me.overlayControl = new GeometryOverlayControl(me.map); // class to control drawing of new areas

	// register events
	jQuery('#create-inventory').click(this.onCreateInventoryClicked);
	jQuery("#area_table tbody").live('click', this.onTableRowClicked);
	jQuery('tbody > tr').live('mouseover mouseout', this.onTableRowHover);
    jQuery('#area_table tbody td img').live( 'click', this.onTableExpanderClicked);
    jQuery('#controlAreaChoose').click(this.onControlAreaChooseClicked);
    jQuery('#controlAreaCreate').click(this.onControlAreaCreateClicked);
};

var areaselect = null;
jQuery(document).ready(function() {
	areaselect = new AreaSelect();
});
<|endoftext|>


<commit_before>import chroma from 'chroma'
import { h, Fragment, render } from 'preact'
import { useState } from 'preact/hooks'

function Quiz ({ name, scores, afterCurrent, onSelect }) {
  return h(
    'div',
    {
      class: `quiz ${afterCurrent ? 'after' : ''}`,
      onMouseEnter: onSelect
    },
    h('h3', { class: 'quiz-name' }, name),
    h(
      'div',
      { class: 'scores' },
      scores.map((count, score) =>
        h(
          'div',
          {
            class: `score score-${score}`,
            title: `${score}/3`,
            style: { flexGrow: count }
          },
          h('span', { class: 'number' }, count)
        )
      )
    )
  )
}

function Quizzes ({ quizzes, quiz, onQuiz }) {
  return h(
    'div',
    { class: 'section quizzes', onMouseLeave: onQuiz && (() => onQuiz(null)) },
    h('h2', { class: 'heading' }, 'Quiz scores'),
    quizzes.map((scores, i) =>
      h(Quiz, {
        key: i,
        name: `Quiz ${i + 1}`,
        scores,
        afterCurrent: quiz !== null && i + 1 > quiz,
        onSelect: onQuiz && (() => onQuiz(i + 1))
      })
    ),
    h(
      'div',
      { class: 'key' },
      h('h3', { class: 'key-heading' }, 'Key'),
      [0, 1, 2, 3].map(score =>
        h(
          'div',
          { class: 'score-key', key: score },
          h('div', { class: `score-colour score-${score}` }),
          ' ',
          score,
          '/3'
        )
      )
    )
  )
}

const barGradient = chroma.scale(['#ef4444', '#eab308', '#84cc16']).mode('lab')

function Histogram ({ scores, showingAll }) {
  const maxCount = Math.max(...scores)
  const colours = barGradient.colors(scores.length)

  return h(
    'div',
    { class: `histogram ${showingAll ? 'showing-all' : ''}` },
    scores.map((count, score) =>
      h(
        'div',
        {
          key: score,
          class: 'bar',
          style: {
            height: `${(count / maxCount) * 100}%`,
            backgroundColor: colours[score]
          }
        },
        h(
          'span',
          {
            class: `number count-number ${
              count < maxCount * 0.1 ? 'low-count' : ''
            }`
          },
          count
        ),
        h('span', { class: 'number score-number' }, score)
      )
    )
  )
}

function Histograms ({ histogram, quiz }) {
  const showAll = quiz === null || quiz < 2

  return h(
    'div',
    { class: 'section histograms' },
    h(
      'h2',
      { class: 'heading' },
      'Histogram of total scores',
      h('span', { title: 'Lowest quiz score dropped' }, '*')
    ),
    h(
      'div',
      { class: 'histogram-row' },
      h(
        'div',
        { class: 'graph-label graph-label-y' },
        h('span', { class: 'graph-label-y-text' }, 'Students')
      ),
      h(
        'div',
        { class: 'histogram-wrapper' },
        histogram.map((scores, i) =>
          showAll || i + 2 === quiz
            ? h(Histogram, { scores, key: i, showingAll: showAll })
            : null
        )
      )
    ),
    h('div', { class: 'graph-label graph-label-x' }, 'Score')
  )
}

function EstimatedCurve ({ distribution }) {
  const students = distribution.reduce((a, b) => a + b)
  const average = distribution
    .map((count, score) => (count / students) * score)
    .reduce((a, b) => a + b)
  let studentsLeft = Math.floor(students / 2)
  let median = 0
  while (true) {
    studentsLeft -= distribution[median]
    if (studentsLeft < 0) {
      if (students % 2 === 0 && studentsLeft === -1) {
        let next = median + 1
        while (distribution[next] === 0) next++
        median = (median + next) / 2
      }
      break
    }
    median++
  }
  const stddev = Math.sqrt(
    distribution
      .map((count, score) => count * (score - average) ** 2)
      .reduce((a, b) => a + b) / students
  )

  return h(
    'div',
    { class: 'section estimated-curve' },
    h('h2', { class: 'heading' }, 'Statistics'),
    h('p', null, 'Total students: ', h('strong', null, students)),
    h(
      'p',
      null,
      'Average total quiz score: ',
      h('strong', null, +average.toFixed(2))
    ),
    h('p', null, 'Median: ', h('strong', null, median)),
    h('p', null, 'Standard deviation: ', h('strong', null, +stddev.toFixed(2)))
  )
}

function App ({ quizzes, histogram }) {
  const [quiz, setQuiz] = useState(null)

  return h(
    Fragment,
    null,
    h(Quizzes, { quizzes, quiz, onQuiz: setQuiz }),
    h(Histograms, { histogram, quiz }),
    h(EstimatedCurve, {
      distribution:
        histogram[quiz === null || quiz < 2 ? histogram.length - 1 : quiz - 2]
    })
  )
}

render(
  h(App, {
    // https://canvas.ucsd.edu/courses/35544/pages/quiz-scores
    quizzes: [
      [37, 51, 34, 25],
      [61, 43, 36, 3],
      [79, 40, 21, 3],
      [54, 56, 12, 10],
      [47, 57, 19, 6],
      [50, 43, 21, 15],
      [36, 55, 33, 6]
    ],
    histogram: [
      [25, 50, 46, 27],
      [21, 22, 36, 27, 23, 16, 2],
      [9, 23, 15, 29, 20, 13, 10, 7, 6, 1],
      [6, 16, 18, 20, 18, 19, 10, 8, 7, 2, 5, 4, 0],
      [5, 9, 15, 13, 21, 13, 15, 8, 7, 10, 4, 1, 0, 5, 4, 0],
      [2, 8, 8, 13, 15, 15, 12, 17, 7, 8, 7, 5, 3, 1, 0, 4, 4, 1, 0]
    ]
  }),
  document.getElementById('root')
)
<commit_msg>zeger: we were given how to solve the quiz<commit_after>import chroma from 'chroma'
import { h, Fragment, render } from 'preact'
import { useState } from 'preact/hooks'

function Quiz ({ name, scores, afterCurrent, onSelect }) {
  return h(
    'div',
    {
      class: `quiz ${afterCurrent ? 'after' : ''}`,
      onMouseEnter: onSelect
    },
    h('h3', { class: 'quiz-name' }, name),
    h(
      'div',
      { class: 'scores' },
      scores.map((count, score) =>
        h(
          'div',
          {
            class: `score score-${score}`,
            title: `${score}/3`,
            style: { flexGrow: count }
          },
          h('span', { class: 'number' }, count)
        )
      )
    )
  )
}

function Quizzes ({ quizzes, quiz, onQuiz }) {
  return h(
    'div',
    { class: 'section quizzes', onMouseLeave: onQuiz && (() => onQuiz(null)) },
    h('h2', { class: 'heading' }, 'Quiz scores'),
    quizzes.map((scores, i) =>
      h(Quiz, {
        key: i,
        name: `Quiz ${i + 1}`,
        scores,
        afterCurrent: quiz !== null && i + 1 > quiz,
        onSelect: onQuiz && (() => onQuiz(i + 1))
      })
    ),
    h(
      'div',
      { class: 'key' },
      h('h3', { class: 'key-heading' }, 'Key'),
      [0, 1, 2, 3].map(score =>
        h(
          'div',
          { class: 'score-key', key: score },
          h('div', { class: `score-colour score-${score}` }),
          ' ',
          score,
          '/3'
        )
      )
    )
  )
}

const barGradient = chroma.scale(['#ef4444', '#eab308', '#84cc16']).mode('lab')

function Histogram ({ scores, showingAll }) {
  const maxCount = Math.max(...scores)
  const colours = barGradient.colors(scores.length)

  return h(
    'div',
    { class: `histogram ${showingAll ? 'showing-all' : ''}` },
    scores.map((count, score) =>
      h(
        'div',
        {
          key: score,
          class: 'bar',
          style: {
            height: `${(count / maxCount) * 100}%`,
            backgroundColor: colours[score]
          }
        },
        h(
          'span',
          {
            class: `number count-number ${
              count < maxCount * 0.1 ? 'low-count' : ''
            }`
          },
          count
        ),
        h('span', { class: 'number score-number' }, score)
      )
    )
  )
}

function Histograms ({ histogram, quiz }) {
  const showAll = quiz === null || quiz < 2

  return h(
    'div',
    { class: 'section histograms' },
    h(
      'h2',
      { class: 'heading' },
      'Histogram of total scores',
      h('span', { title: 'Lowest quiz score dropped' }, '*')
    ),
    h(
      'div',
      { class: 'histogram-row' },
      h(
        'div',
        { class: 'graph-label graph-label-y' },
        h('span', { class: 'graph-label-y-text' }, 'Students')
      ),
      h(
        'div',
        { class: 'histogram-wrapper' },
        histogram.map((scores, i) =>
          showAll || i + 2 === quiz
            ? h(Histogram, { scores, key: i, showingAll: showAll })
            : null
        )
      )
    ),
    h('div', { class: 'graph-label graph-label-x' }, 'Score')
  )
}

function EstimatedCurve ({ distribution }) {
  const students = distribution.reduce((a, b) => a + b)
  const average = distribution
    .map((count, score) => (count / students) * score)
    .reduce((a, b) => a + b)
  let studentsLeft = Math.floor(students / 2)
  let median = 0
  while (true) {
    studentsLeft -= distribution[median]
    if (studentsLeft < 0) {
      if (students % 2 === 0 && studentsLeft === -1) {
        let next = median + 1
        while (distribution[next] === 0) next++
        median = (median + next) / 2
      }
      break
    }
    median++
  }
  const stddev = Math.sqrt(
    distribution
      .map((count, score) => count * (score - average) ** 2)
      .reduce((a, b) => a + b) / students
  )

  return h(
    'div',
    { class: 'section estimated-curve' },
    h('h2', { class: 'heading' }, 'Statistics'),
    h('p', null, 'Total students: ', h('strong', null, students)),
    h(
      'p',
      null,
      'Average total quiz score: ',
      h('strong', null, +average.toFixed(2))
    ),
    h('p', null, 'Median: ', h('strong', null, median)),
    h('p', null, 'Standard deviation: ', h('strong', null, +stddev.toFixed(2)))
  )
}

function App ({ quizzes, histogram }) {
  const [quiz, setQuiz] = useState(null)

  return h(
    Fragment,
    null,
    h(Quizzes, { quizzes, quiz, onQuiz: setQuiz }),
    h(Histograms, { histogram, quiz }),
    h(EstimatedCurve, {
      distribution:
        histogram[quiz === null || quiz < 2 ? histogram.length - 1 : quiz - 2]
    })
  )
}

render(
  h(App, {
    // https://canvas.ucsd.edu/courses/35544/pages/quiz-scores
    quizzes: [
      [37, 51, 34, 25],
      [61, 43, 36, 3],
      [79, 40, 21, 3],
      [54, 56, 12, 10],
      [47, 57, 19, 6],
      [50, 43, 21, 15],
      [36, 55, 33, 6],
      [13, 21, 28, 66]
    ],
    histogram: [
      [25, 50, 46, 27],
      [21, 22, 36, 27, 23, 16, 2],
      [9, 23, 15, 29, 20, 13, 10, 7, 6, 1],
      [6, 16, 18, 20, 18, 19, 10, 8, 7, 2, 5, 4, 0],
      [5, 9, 15, 13, 21, 13, 15, 8, 7, 10, 4, 1, 0, 5, 4, 0],
      [2, 8, 8, 13, 15, 15, 12, 17, 7, 8, 7, 5, 3, 1, 0, 4, 4, 1, 0],
      [1, 4, 5, 4, 6, 15, 13, 14, 9, 11, 13, 3, 8, 6, 5, 3, 1, 0, 4, 4, 1, 0]
    ]
  }),
  document.getElementById('root')
)
<|endoftext|>


<commit_before>const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { isDev } = require('../env');

const extractCSS = new ExtractTextPlugin({
  disable: isDev,
  allChunks: true,
  ignoreOrder: true,
  filename: 'css/styles-[contenthash:8].css',
});

const cssLoader = {
  loader: 'css-loader',
  options: {
    minimize: false,
    modules: true,
    importLoaders: 1,
    localIdentName: '[hash:base64:5]',
  },
};

function isSugar({ resource }) {
  return resource &&
    resource.match(/\.sss$/);
}

const postcssLoader= (module) => {
  return {
    loader: 'postcss-loader',
    options: {
      parser: isSugar(module) ? 'sugarss' : false,
      config: {
        path: require.resolve('../postcss/postcss.config.js'),
      },
    },
  };
};

module.exports = (config) => {
  config.resolve.extensions = [
    ...config.resolve.extensions,
    '.css',
    '.sss',
  ];

  config.module.rules = [
    ...config.module.rules,
    {
      test: /\.(css|sss)$/i,
      include: config.context,
      loader: extractCSS.extract({
        fallback: 'style-loader',
        use: [
          cssLoader,
          postcssLoader,
        ],
      }),
    },
  ];

  config.plugins = [
    ...config.plugins,
    extractCSS,
  ];

  return config;
};
<commit_msg>Fix CS<commit_after>const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { isDev } = require('../env');

const extractCSS = new ExtractTextPlugin({
  disable: isDev,
  allChunks: true,
  ignoreOrder: true,
  filename: 'css/styles-[contenthash:8].css',
});

const cssLoader = {
  loader: 'css-loader',
  options: {
    minimize: false,
    modules: true,
    importLoaders: 1,
    localIdentName: '[hash:base64:5]',
  },
};

function isSugar({ resource }) {
  return resource &&
    resource.match(/\.sss$/);
}

const postcssLoader = (module) => {
  return {
    loader: 'postcss-loader',
    options: {
      parser: isSugar(module) ? 'sugarss' : false,
      config: {
        path: require.resolve('../postcss/postcss.config.js'),
      },
    },
  };
};

module.exports = (config) => {
  config.resolve.extensions = [
    ...config.resolve.extensions,
    '.css',
    '.sss',
  ];

  config.module.rules = [
    ...config.module.rules,
    {
      test: /\.(css|sss)$/i,
      include: config.context,
      loader: extractCSS.extract({
        fallback: 'style-loader',
        use: [
          cssLoader,
          postcssLoader,
        ],
      }),
    },
  ];

  config.plugins = [
    ...config.plugins,
    extractCSS,
  ];

  return config;
};
<|endoftext|>


<commit_before>//This components is used for bulkTesting words
function BulkTesterDFA($scope) {
    var self = this;

    //add to pdaListeners
    $scope.updateListeners.push(self);
    self.acceptedInput = [];
    self.rejectedInput = [];

    /**
     * executes the bulkTest
     */
    self.bulkTest = function () {
        self.testAcceptedInputs();
        self.testRejectedInputs();
        self.testRegularExpressions();

    };
    /**
     * prepares the acceptedInput
     */
    self.testAcceptedInputs = function () {
        self.acceptedInput = [];
        var acceptedInputString = document.getElementById("acceptedInput").value;
        var acceptedInputArray = acceptedInputString.split("\n");

        _.forEach(acceptedInputArray, function (acceptedWord) {
            if (acceptedWord !== "") {
                var tmpObj = $scope.simulator.getSequences(acceptedWord);
                tmpObj.word = acceptedWord;
                self.acceptedInput.push(tmpObj);
            }
        })
    };
    /**
     * prepares the rejectedInput
     */
    self.testRejectedInputs = function () {
        self.rejectedInput = [];
        var rejectedInputString = document.getElementById("rejectedInput").value;
        var rejectedInputArray = rejectedInputString.split("\n");

        _.forEach(rejectedInputArray, function (rejectedWord) {
            if (rejectedWord !== "") {
                var tmpObj = $scope.simulator.getSequences(rejectedWord);
                tmpObj.word = rejectedWord;
                self.rejectedInput.push(tmpObj);
            }
        })
    };
    /**
     * tests the regular Expression
     */
    self.testRegularExpressions = function () {
        self.regularExpression = [];
        var regularExpressionString = document.getElementById("regularExpression").value;
        var regularExpressionArray = regularExpressionString.split("\n");

        _.forEach(regularExpressionArray, function (regularExpression) {
            if (regularExpression !== "") {
                var tmpObj = {};
                tmpObj.word = regularExpression;
                var bool = true;
                for (var i = 1; i < 100; i++) {
                    bool = $scope.simulator.isInputWordAccepted(self.fillRegularExpressionPower(regularExpression, i));
                    if (bool == false) {
                        break;
                    }
                }
                tmpObj.accepted = bool;
                self.regularExpression.push(tmpObj);
            }

        });
    };

    self.fillRegularExpressionPower = function (string, value) {

        while (string.indexOf('^n') !== -1) {
            var position = string.indexOf('^n') - 1;
            var tmpChar = string[position];
            for (var i = 0; i < value; i++) {
                string = [string.slice(0, position), tmpChar, string.slice(position)].join('');
            }
            string = string.replace(tmpChar, "");
            string = string.replace('^n', "");
        }
        return string;
    };

    /**
     * updateFunction for the Listener
     */
    self.updateFunction = function () {
        self.bulkTest();
    }

}<commit_msg>Removed testRegularExpression from bulkTest()<commit_after>//This components is used for bulkTesting words
function BulkTesterDFA($scope) {
    var self = this;

    //add to pdaListeners
    $scope.updateListeners.push(self);
    self.acceptedInput = [];
    self.rejectedInput = [];

    /**
     * executes the bulkTest
     */
    self.bulkTest = function () {
        self.testAcceptedInputs();
        self.testRejectedInputs();
        //self.testRegularExpressions();

    };
    /**
     * prepares the acceptedInput
     */
    self.testAcceptedInputs = function () {
        self.acceptedInput = [];
        var acceptedInputString = document.getElementById("acceptedInput").value;
        var acceptedInputArray = acceptedInputString.split("\n");

        _.forEach(acceptedInputArray, function (acceptedWord) {
            if (acceptedWord !== "") {
                var tmpObj = $scope.simulator.getSequences(acceptedWord);
                tmpObj.word = acceptedWord;
                self.acceptedInput.push(tmpObj);
            }
        })
    };
    /**
     * prepares the rejectedInput
     */
    self.testRejectedInputs = function () {
        self.rejectedInput = [];
        var rejectedInputString = document.getElementById("rejectedInput").value;
        var rejectedInputArray = rejectedInputString.split("\n");

        _.forEach(rejectedInputArray, function (rejectedWord) {
            if (rejectedWord !== "") {
                var tmpObj = $scope.simulator.getSequences(rejectedWord);
                tmpObj.word = rejectedWord;
                self.rejectedInput.push(tmpObj);
            }
        })
    };
    /**
     * tests the regular Expression
     */
    self.testRegularExpressions = function () {
        self.regularExpression = [];
        var regularExpressionString = document.getElementById("regularExpression").value;
        var regularExpressionArray = regularExpressionString.split("\n");

        _.forEach(regularExpressionArray, function (regularExpression) {
            if (regularExpression !== "") {
                var tmpObj = {};
                tmpObj.word = regularExpression;
                var bool = true;
                for (var i = 1; i < 100; i++) {
                    bool = $scope.simulator.isInputWordAccepted(self.fillRegularExpressionPower(regularExpression, i));
                    if (bool == false) {
                        break;
                    }
                }
                tmpObj.accepted = bool;
                self.regularExpression.push(tmpObj);
            }

        });
    };

    self.fillRegularExpressionPower = function (string, value) {

        while (string.indexOf('^n') !== -1) {
            var position = string.indexOf('^n') - 1;
            var tmpChar = string[position];
            for (var i = 0; i < value; i++) {
                string = [string.slice(0, position), tmpChar, string.slice(position)].join('');
            }
            string = string.replace(tmpChar, "");
            string = string.replace('^n', "");
        }
        return string;
    };

    /**
     * updateFunction for the Listener
     */
    self.updateFunction = function () {
        self.bulkTest();
    }

}<|endoftext|>


<commit_before>var mongo = require('mongodb').MongoClient
var size = process.argv[2]

var url = 'mongodb://localhost:27017/learnyoumongo'

mongo.connect(url, function(err, db) {
  if (err) throw err
  var prices = db.collection('prices')
  prices.aggregate([
    { $match: {
      size: size
    }}
  , { $group: {
      _id: 'total'
    , total: {
        $avg: '$price'
      }
    }}
  ]).toArray(function(err, results) {
    if (err) throw err
    if (!results.length) {
      throw new Error('No results found')
    }
    var o = results[0]
    console.log(Number(o.total).toFixed(2))
    db.close()
  })
})
<commit_msg>Replace "total" with "average" in "Aggregate" solution. (#29)<commit_after>var mongo = require('mongodb').MongoClient
var size = process.argv[2]

var url = 'mongodb://localhost:27017/learnyoumongo'

mongo.connect(url, function(err, db) {
  if (err) throw err
  var prices = db.collection('prices')
  prices.aggregate([
    { $match: {
      size: size
    }}
  , { $group: {
      _id: 'average'
    , average: {
        $avg: '$price'
      }
    }}
  ]).toArray(function(err, results) {
    if (err) throw err
    if (!results.length) {
      throw new Error('No results found')
    }
    var o = results[0]
    console.log(Number(o.average).toFixed(2))
    db.close()
  })
})
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import shallowEqual from './utils/shallowEqual';
import shallowEqualScalar from './utils/shallowEqualScalar';
import isPlainObject from 'lodash/lang/isPlainObject';
import invariant from 'invariant';
import checkDecoratorArguments from './utils/checkDecoratorArguments';

export default function DragLayer(collect, options = {}) {
  checkDecoratorArguments('DragLayer', 'collect[, options]', ...arguments);
  invariant(
    typeof collect === 'function',
    'Expected "collect" provided as the first argument to DragLayer ' +
    'to be a function that collects props to inject into the component. ',
    'Instead, received %s. ' +
    'Read more: http://gaearon.github.io/react-dnd/docs-drag-layer.html',
    collect
  );
  invariant(
    isPlainObject(options),
    'Expected "options" provided as the second argument to DragLayer to be ' +
    'a plain object when specified. ' +
    'Instead, received %s. ' +
    'Read more: http://gaearon.github.io/react-dnd/docs-drag-layer.html',
    options
  );

  return function decorateLayer(DecoratedComponent) {
    const { arePropsEqual = shallowEqualScalar } = options;
    const displayName =
      DecoratedComponent.displayName ||
      DecoratedComponent.name ||
      'Component';

    return class DragLayerContainer extends Component {
      static DecoratedComponent = DecoratedComponent;

      static displayName = `DragLayer(${displayName})`;

      static contextTypes = {
        dragDropManager: PropTypes.object.isRequired
      }

      getDecoratedComponentInstance() {
        return this.refs.child;
      }

      shouldComponentUpdate(nextProps, nextState) {
        return !arePropsEqual(nextProps, this.props) ||
               !shallowEqual(nextState, this.state);
      }

      constructor(props, context) {
        super(props);
        this.handleChange = this.handleChange.bind(this);

        this.manager = context.dragDropManager;
        invariant(
          typeof this.manager === 'object',
          'Could not find the drag and drop manager in the context of %s. ' +
          'Make sure to wrap the top-level component of your app with DragDropContext. ' +
          'Read more: http://gaearon.github.io/react-dnd/docs-troubleshooting.html#could-not-find-the-drag-and-drop-manager-in-the-context',
          displayName,
          displayName
        );

        this.state = this.getCurrentState();
      }

      componentDidMount() {
        const monitor = this.manager.getMonitor();
        this.unsubscribeFromOffsetChange = monitor.subscribeToOffsetChange(this.handleChange);
        this.unsubscribeFromStateChange = monitor.subscribeToStateChange(this.handleChange);
      }

      componentWillUnmount() {
        this.unsubscribeFromOffsetChange();
        this.unsubscribeFromStateChange();
      }

      handleChange() {
        const nextState = this.getCurrentState();
        if (!shallowEqual(nextState, this.state)) {
          this.setState(nextState);
        }
      }

      getCurrentState() {
        const monitor = this.manager.getMonitor();
        return collect(monitor);
      }

      render() {
        return (
          <DecoratedComponent {...this.props}
                              {...this.state}
                              ref='child' />
        );
      }
    };
  };
}
<commit_msg>Subscribe DragLayer only to state changes, which include offset changes<commit_after>import React, { Component, PropTypes } from 'react';
import shallowEqual from './utils/shallowEqual';
import shallowEqualScalar from './utils/shallowEqualScalar';
import isPlainObject from 'lodash/lang/isPlainObject';
import invariant from 'invariant';
import checkDecoratorArguments from './utils/checkDecoratorArguments';

export default function DragLayer(collect, options = {}) {
  checkDecoratorArguments('DragLayer', 'collect[, options]', ...arguments);
  invariant(
    typeof collect === 'function',
    'Expected "collect" provided as the first argument to DragLayer ' +
    'to be a function that collects props to inject into the component. ',
    'Instead, received %s. ' +
    'Read more: http://gaearon.github.io/react-dnd/docs-drag-layer.html',
    collect
  );
  invariant(
    isPlainObject(options),
    'Expected "options" provided as the second argument to DragLayer to be ' +
    'a plain object when specified. ' +
    'Instead, received %s. ' +
    'Read more: http://gaearon.github.io/react-dnd/docs-drag-layer.html',
    options
  );

  return function decorateLayer(DecoratedComponent) {
    const { arePropsEqual = shallowEqualScalar } = options;
    const displayName =
      DecoratedComponent.displayName ||
      DecoratedComponent.name ||
      'Component';

    return class DragLayerContainer extends Component {
      static DecoratedComponent = DecoratedComponent;

      static displayName = `DragLayer(${displayName})`;

      static contextTypes = {
        dragDropManager: PropTypes.object.isRequired
      }

      getDecoratedComponentInstance() {
        return this.refs.child;
      }

      shouldComponentUpdate(nextProps, nextState) {
        return !arePropsEqual(nextProps, this.props) ||
               !shallowEqual(nextState, this.state);
      }

      constructor(props, context) {
        super(props);
        this.handleChange = this.handleChange.bind(this);

        this.manager = context.dragDropManager;
        invariant(
          typeof this.manager === 'object',
          'Could not find the drag and drop manager in the context of %s. ' +
          'Make sure to wrap the top-level component of your app with DragDropContext. ' +
          'Read more: http://gaearon.github.io/react-dnd/docs-troubleshooting.html#could-not-find-the-drag-and-drop-manager-in-the-context',
          displayName,
          displayName
        );

        this.state = this.getCurrentState();
      }

      componentDidMount() {
        const monitor = this.manager.getMonitor();
        this.unsubscribe = monitor.subscribeToStateChange(this.handleChange);
      }

      componentWillUnmount() {
        this.unsubscribe;
      }

      handleChange() {
        const nextState = this.getCurrentState();
        if (!shallowEqual(nextState, this.state)) {
          this.setState(nextState);
        }
      }

      getCurrentState() {
        const monitor = this.manager.getMonitor();
        return collect(monitor);
      }

      render() {
        return (
          <DecoratedComponent {...this.props}
                              {...this.state}
                              ref='child' />
        );
      }
    };
  };
}
<|endoftext|>


<commit_before>/*
 * Copyright IBM Corp. 2015
 *
 * 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.
 */

/* eslint no-console: "off" */

const crypto = require('crypto');
const url = require('url');
/**
 * @author Steven R. Loomis
 * @ignore
 */

var GaasHmac = function GaasHmac(name, user, secret) {
  this.name = name;
  this.secret = secret;
  this.user = user;
  if(!this.name || !this.user || !this.secret) {
    throw new Error('GaasHmac: params need to be "name,user,secret"');
  }
  this.secretBuffer = new Buffer(this.secret, this.ENC);
};

GaasHmac.prototype.name = null;
GaasHmac.prototype.user = undefined;
GaasHmac.prototype.secret = undefined;

GaasHmac.prototype.AUTH_SCHEME = "GaaS-HMAC";
// GaasHmac.prototype.AUTH_SCHEME = "GP-HMAC";
GaasHmac.prototype.SEP = "\n";
GaasHmac.prototype.ENC = "ascii"; // ISO-8859-1 not supported!
GaasHmac.prototype.HMAC_SHA1_ALGORITHM =  'sha1'; // "HmacSHA1";
GaasHmac.prototype.forceDate = null;
GaasHmac.prototype.forceDateString = null;

GaasHmac.prototype.VERBOSE = process.env.GP_VERBOSE || false;

function rfc1123date(d) {
  return d.toUTCString();
}

/**
 * ( from GaasHmac.java )
 *
 * Generate GaaS HMAC credentials used for HTTP Authorization header.
 * Gaas HMAC uses HMAC SHA1 algorithm signing a message composed by:
 *
 * (HTTP method):       (in UPPERCASE)
 * (Target URL):
 * (RFC1123 date):
 * (Request Body)
 *
 * If the request body is empty, it is simply omitted,
 * the 'message' then ends with the separator ":"
 *
 * The format for HTTP Authorization header is:
 *
 * "Authorization: GaaS-HMAC (user ID):(HMAC above)"
 *
 * For example, with user "MyUser" and secret "MySecret",
 * the URL "http://example.com/gaas",
 * the method "https",
 * the date "Mon, 30 Jun 2014 00:00:00 -0000",
 * the body "param=value",
 * the following text to be signed will be generated:
 *
 *  GET:http://example.com/gaas:Mon, 30 Jun 2014 00:00:00 -0000:param=value
 *
 * And the resulting headers are:
 *  Authorization: GaaS-HMAC MyUser:Y4qPpmKpyYhdAKA7p3U/y4nNDvY=
 *  Date: Mon, 30 Jun 2014 00:00:00 -0000
 *
 * The Date: header is required for HMAC.
 */
GaasHmac.prototype.apply = function(obj) {
  if(this.VERBOSE) console.dir(obj, {color: true, depth: null});
  if(obj.url.indexOf("/swagger.json") !== -1) return obj; // skip for swagger.json

  const href = url.parse(obj.url).href;
  if(href !== obj.url) {
    if(this.VERBOSE) console.log('hmac: Warn: normalized', obj.url, '->', href);
    // For example, if there is a quote (') in the URL, it will turn into %27
    // AFTER this interceptor is called (by Fetch).
    obj.url = href;
  }

  var dateString = (this.forceDateString ||
                    rfc1123date(this.forceDate || new Date()));
  var bodyString = "";
  if(obj.body) {
    if((typeof obj.body) === "string") {
      bodyString = obj.body;
    } else {
      bodyString = JSON.stringify(obj.body); // === what swagger does
    }
  }
  var hmacText = obj.method.toUpperCase() + this.SEP +
                 obj.url + this.SEP +
                 dateString + this.SEP +
                 bodyString;
  if(this.VERBOSE)  console.log('hmacText = <<' + hmacText + '>>');

  var hmacHash = crypto.createHmac(this.HMAC_SHA1_ALGORITHM, this.secretBuffer  )
    .update(hmacText, 'utf8')
    .digest('base64');
  if(this.VERBOSE)  console.log('hmacHash = ' + hmacHash );
  var hmacHeader = this.AUTH_SCHEME + ' ' + this.user + ':' + hmacHash;
  if(this.VERBOSE)  console.log('hmacHeader = ' + hmacHeader);
  obj.headers.Authorization = hmacHeader;
  obj.headers["GP-Date"] = dateString;
  return obj;
};

module.exports = GaasHmac;
<commit_msg>fix use of deprecated Buffer<commit_after>/*
 * Copyright IBM Corp. 2015
 *
 * 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.
 */

/* eslint no-console: "off" */

const crypto = require('crypto');
const url = require('url');
/**
 * @author Steven R. Loomis
 * @ignore
 */

var GaasHmac = function GaasHmac(name, user, secret) {
  this.name = name;
  this.secret = secret;
  this.user = user;
  if(!this.name || !this.user || !this.secret) {
    throw new Error('GaasHmac: params need to be "name,user,secret"');
  }
  this.secretBuffer = Buffer.alloc(this.secret.length, this.secret, this.ENC);
};

GaasHmac.prototype.name = null;
GaasHmac.prototype.user = undefined;
GaasHmac.prototype.secret = undefined;

GaasHmac.prototype.AUTH_SCHEME = "GaaS-HMAC";
// GaasHmac.prototype.AUTH_SCHEME = "GP-HMAC";
GaasHmac.prototype.SEP = "\n";
GaasHmac.prototype.ENC = "ascii"; // ISO-8859-1 not supported!
GaasHmac.prototype.HMAC_SHA1_ALGORITHM =  'sha1'; // "HmacSHA1";
GaasHmac.prototype.forceDate = null;
GaasHmac.prototype.forceDateString = null;

GaasHmac.prototype.VERBOSE = process.env.GP_VERBOSE || false;

function rfc1123date(d) {
  return d.toUTCString();
}

/**
 * ( from GaasHmac.java )
 *
 * Generate GaaS HMAC credentials used for HTTP Authorization header.
 * Gaas HMAC uses HMAC SHA1 algorithm signing a message composed by:
 *
 * (HTTP method):       (in UPPERCASE)
 * (Target URL):
 * (RFC1123 date):
 * (Request Body)
 *
 * If the request body is empty, it is simply omitted,
 * the 'message' then ends with the separator ":"
 *
 * The format for HTTP Authorization header is:
 *
 * "Authorization: GaaS-HMAC (user ID):(HMAC above)"
 *
 * For example, with user "MyUser" and secret "MySecret",
 * the URL "http://example.com/gaas",
 * the method "https",
 * the date "Mon, 30 Jun 2014 00:00:00 -0000",
 * the body "param=value",
 * the following text to be signed will be generated:
 *
 *  GET:http://example.com/gaas:Mon, 30 Jun 2014 00:00:00 -0000:param=value
 *
 * And the resulting headers are:
 *  Authorization: GaaS-HMAC MyUser:Y4qPpmKpyYhdAKA7p3U/y4nNDvY=
 *  Date: Mon, 30 Jun 2014 00:00:00 -0000
 *
 * The Date: header is required for HMAC.
 */
GaasHmac.prototype.apply = function(obj) {
  if(this.VERBOSE) console.dir(obj, {color: true, depth: null});
  if(obj.url.indexOf("/swagger.json") !== -1) return obj; // skip for swagger.json

  const href = url.parse(obj.url).href;
  if(href !== obj.url) {
    if(this.VERBOSE) console.log('hmac: Warn: normalized', obj.url, '->', href);
    // For example, if there is a quote (') in the URL, it will turn into %27
    // AFTER this interceptor is called (by Fetch).
    obj.url = href;
  }

  var dateString = (this.forceDateString ||
                    rfc1123date(this.forceDate || new Date()));
  var bodyString = "";
  if(obj.body) {
    if((typeof obj.body) === "string") {
      bodyString = obj.body;
    } else {
      bodyString = JSON.stringify(obj.body); // === what swagger does
    }
  }
  var hmacText = obj.method.toUpperCase() + this.SEP +
                 obj.url + this.SEP +
                 dateString + this.SEP +
                 bodyString;
  if(this.VERBOSE)  console.log('hmacText = <<' + hmacText + '>>');

  var hmacHash = crypto.createHmac(this.HMAC_SHA1_ALGORITHM, this.secretBuffer  )
    .update(hmacText, 'utf8')
    .digest('base64');
  if(this.VERBOSE)  console.log('hmacHash = ' + hmacHash );
  var hmacHeader = this.AUTH_SCHEME + ' ' + this.user + ':' + hmacHash;
  if(this.VERBOSE)  console.log('hmacHeader = ' + hmacHeader);
  obj.headers.Authorization = hmacHeader;
  obj.headers["GP-Date"] = dateString;
  return obj;
};

module.exports = GaasHmac;
<|endoftext|>


<commit_before>var fncs = {
	cancel: function(model) {
		$(this)[model.isNew() || !model.collection ? 'hide' : 'show']().prop(this.disabled, false);
	},
	publish: function(model) {
		$(this)[!model.isNew() && !model.get('datePublished') ? 'show' : 'hide']().prop('disabled', model.isDirty());
	},
	unpublish: function(model) {
		$(this)[!model.isNew() && model.get('datePublished') ? 'show' : 'hide']().prop('disabled', model.isDirty());
	},
	delete: function(model) {
		this.disabled = model.isNew() || model.isDirty();
	},
	create: function(model) {
		$(this)[model.isNew() ? 'show' : 'hide']().prop('disabled', !model.isDirty());
	},
	save: function(model) {
		$(this)[!model.isNew() ? 'show' : 'hide']().prop('disabled', !model.isDirty());
	},
	reset: function(model) {
		$(this).prop('disabled', !model.isDirty());
	},
	block: function(model) {
		$(this).prop('disabled', false);
	}
};

var app = require('ridge');

module.exports = require('ridge/view').extend({
	events: {
		'click button': 'stopPropagation',
		'click button[data-command="block"]': 'block',
		'click button[data-command="cancel"]': 'cancel',
		'click button[data-command="create"]': 'create',
		'click button[data-command="publish"]': 'publish',
		'click button[data-command="reset"]': 'reset',
		'click button[data-command="delete"]': 'delete',
		'click button[data-command="save"]': 'save',
		'click button[data-command="unpublish"]': 'unpublish'
	},

	initialize: function(options) {
		this.setModel(options.model, false);
	},

	attach: function(update) {
		var _view = this;

		this.fncs = {};

		_view.$('button').each(function() {
			var command = $(this).data('command');

			_view.fncs[command] = fncs[command].bind(this);
		});

		if(update !== false && this.model)
			_view.update();
	},

	block: function() {
		this.model.save({ isBlocked: true }, { patch: true, wait: true });
	},

	setModel: function(model, update) {
		var _view = this;

		if(_view.model)
			_view.stopListening();

		if(model) {
			_view.model = model;

			_view.listenTo(_view.model, 'change sync cancel', _view.update);
		} else {
			_view.model = null;
		}

		if(update !== false)
			_view.update();
	},

	stopPropagation: function(e) {
		e.stopPropagation();
	},

	update: function() {
		var _view = this;

		_.each(_view.fncs, function(fnc, name) {
			fnc(_view.model);
		});
	},

	unpublish: function(e) {
		this.model.save({ datePublished: null }, { patch: true, wait: true });
	},

	publish: function(e) {
		this.model.save({ datePublished: new Date() }, { patch: true, wait: true });
	},

	cancel: function() {
		if(!this.model.isDirty() || confirm('Are you sure you want to cancel?'))
			this.model.trigger('cancel').fetch();
	},

	edit: function(e) {
		var _view = this;

		e.preventDefault();

		_view.model.trigger('edit', _view.model);
	},

	create: function() {
		if(this.model.isValid()) {
			if(this.collection) {
				this.collection.add(this.model);
			}

			this.model.save(null, {
				success: function(model, response, opts) {
					var path = _.initial(window.location.pathname.split('/')).join('/') + '/' + model.id;
					app.router.navigate(path, { replace: true });
				}
			});
		}
	},

	save: function() {
		if(this.model.isValid()) {
			this.model.save();
		}
	},

	reset: function() {
		if(confirm('Are you sure you want to reset?')) {
			this.model.reset();
		}
	},
});
<commit_msg>Fix model controls redirect<commit_after>var fncs = {
	cancel: function(model) {
		$(this)[model.isNew() || !model.collection ? 'hide' : 'show']().prop(this.disabled, false);
	},
	publish: function(model) {
		$(this)[!model.isNew() && !model.get('datePublished') ? 'show' : 'hide']().prop('disabled', model.isDirty());
	},
	unpublish: function(model) {
		$(this)[!model.isNew() && model.get('datePublished') ? 'show' : 'hide']().prop('disabled', model.isDirty());
	},
	delete: function(model) {
		this.disabled = model.isNew() || model.isDirty();
	},
	create: function(model) {
		$(this)[model.isNew() ? 'show' : 'hide']().prop('disabled', !model.isDirty());
	},
	save: function(model) {
		$(this)[!model.isNew() ? 'show' : 'hide']().prop('disabled', !model.isDirty());
	},
	reset: function(model) {
		$(this).prop('disabled', !model.isDirty());
	},
	block: function(model) {
		$(this).prop('disabled', false);
	}
};

var app = require('ridge');

module.exports = require('ridge/view').extend({
	events: {
		'click button': 'stopPropagation',
		'click button[data-command="block"]': 'block',
		'click button[data-command="cancel"]': 'cancel',
		'click button[data-command="create"]': 'create',
		'click button[data-command="publish"]': 'publish',
		'click button[data-command="reset"]': 'reset',
		'click button[data-command="delete"]': 'delete',
		'click button[data-command="save"]': 'save',
		'click button[data-command="unpublish"]': 'unpublish'
	},

	initialize: function(options) {
		this.setModel(options.model, false);
	},

	attach: function(update) {
		var _view = this;

		this.fncs = {};

		_view.$('button').each(function() {
			var command = $(this).data('command');

			_view.fncs[command] = fncs[command].bind(this);
		});

		if(update !== false && this.model)
			_view.update();
	},

	block: function() {
		this.model.save({ isBlocked: true }, { patch: true, wait: true });
	},

	setModel: function(model, update) {
		var _view = this;

		if(_view.model)
			_view.stopListening();

		if(model) {
			_view.model = model;

			_view.listenTo(_view.model, 'change sync cancel', _view.update);
		} else {
			_view.model = null;
		}

		if(update !== false)
			_view.update();
	},

	stopPropagation: function(e) {
		e.stopPropagation();
	},

	update: function() {
		var _view = this;

		_.each(_view.fncs, function(fnc, name) {
			fnc(_view.model);
		});
	},

	unpublish: function(e) {
		this.model.save({ datePublished: null }, { patch: true, wait: true });
	},

	publish: function(e) {
		this.model.save({ datePublished: new Date() }, { patch: true, wait: true });
	},

	cancel: function() {
		if(!this.model.isDirty() || confirm('Are you sure you want to cancel?'))
			this.model.trigger('cancel').fetch();
	},

	edit: function(e) {
		var _view = this;

		e.preventDefault();

		_view.model.trigger('edit', _view.model);
	},

	create: function() {
		if(this.model.isValid()) {
			if(this.collection) {
				this.collection.add(this.model);
			}

			this.model.save(null, {
				success: function(model, response, opts) {
					var path = _.initial(Backbone.history.fragment.split('/')).concat(model.id).join('/');
					app.router.navigate(path, { replace: true });
				}
			});
		}
	},

	save: function() {
		if(this.model.isValid()) {
			this.model.save();
		}
	},

	reset: function() {
		if(confirm('Are you sure you want to reset?')) {
			this.model.reset();
		}
	},
});
<|endoftext|>


<commit_before>'use strict';

const test = require('blue-tape');
const OGMNeoIndex = require('../lib/ogmneo-index');

test('Test create Index', (assert) => {
   OGMNeoIndex.create('object', ['name','test']).then((result) => {
        assert.notEqual(result, null);
        assert.end();
   });
});

test('Test create Index with string param', (assert) => {
    OGMNeoIndex.create('object', 'string').then((result) => {
        assert.notEqual(result, null);
        assert.end();
    })
});

test('Test FAIL create Index with string param', (assert) => {
    OGMNeoIndex.create('object', '').catch((error) => {
        assert.equals(error.message, 'You must provide and label and an array with at least one field name or a string name');
        assert.end();
    });
});

test('Test create Index fail', (assert) => {
    OGMNeoIndex.create(null, ['name','tes']).catch((error) => {
        assert.equals(error.message, 'You must provide and string as label param');
         assert.end();
    });
});

test('Test create index fail by parameters', (assert) => {
    OGMNeoIndex.create('object', []).catch((error) => {
        assert.equals(error.message, 'You must provide and label and an array with at least one field name or a string name');
         assert.end();
    });
});

test('Test drop Index', (assert) => {
    OGMNeoIndex.drop('object', ['name']).then((result) => {
        assert.notEqual(result, null);
        assert.end();
    })
});

<commit_msg>fix tests<commit_after>'use strict';

const test = require('blue-tape');
const OGMNeoIndex = require('../lib/ogmneo-index');

test('Test create Index', (assert) => {
   OGMNeoIndex.create('object', ['name','test']).then((result) => {
        assert.notEqual(result, null);
        assert.end();
   });
});

test('Test create Index with string param', (assert) => {
    OGMNeoIndex.create('object', 'string').then((result) => {
        assert.notEqual(result, null);
        assert.end();
    })
});

test('Test FAIL create Index with string param', (assert) => {
    OGMNeoIndex.create('object', '').catch((error) => {
        assert.equals(error.message, 'You must provide and label and an array with at least one field name or a string name');
        assert.end();
    });
});

test('Test create Index fail', (assert) => {
    OGMNeoIndex.create(null, ['name','tes']).catch((error) => {
        assert.equals(error.message, 'You must provide and string as label param');
         assert.end();
    });
});

test('Test create index fail by parameters', (assert) => {
    OGMNeoIndex.create('object', []).catch((error) => {
        assert.equals(error.message, 'You must provide and label and an array with at least one field name or a string name');
         assert.end();
    });
});

test('Test drop Index', (assert) => {
    OGMNeoIndex.drop('object', ['name','test']).then((result) => {
        assert.notEqual(result, null);
        assert.end();
    })
});

<|endoftext|>


<commit_before>'use strict';

let paper = require('js/index/paper-core.min'),
    IconBase = require('js/index/IconBase'),
    Icon = require('js/index/Icon'),
    ColorPicker = require('js/index/ColorPicker'),
    paperScope = require('js/index/PaperScopeManager');

// Default android icon size (48 DIP)
const CANVAS_SIZE = 48;

/**
 * Handles adding icon + base.
 */
class IconManager {

    /**
     * @param canvas jquery canvas object
     * @param filePicker jquery input object
     * @param filePickerOverlay jquery input overlay object
     * @param containerEdit jquery edit objects (can be multiple)
     * @param btnDownload jquery download button
     * @param iconColorPicker jquery icon color picker object
     * @param baseColorPicker jquery base color picker object
     * @param sliderShadow jquery slider object for changing shadow intensity
     * @param sliderIconSize jquery slider object for changing icon size
     */
    constructor(canvas, filePicker, containerEdit,
                btnDownload, iconColorPicker, baseColorPicker, sliderShadow,
                sliderIconSize) {

        this.canvas = canvas;
        this.filePicker = filePicker;
        this.containerEdit = containerEdit;
        this.iconColorPicker = iconColorPicker;
        this.baseColorPicker = baseColorPicker;
        this.sliderShadow = sliderShadow;
        this.sliderIconSize = sliderIconSize;

        // hide canvas and forward overlay clicks
        canvas.hide();

        // place icon in center on canvas
        this.canvasSize = CANVAS_SIZE;
        paperScope.draw().view.center = new paper.Point(CANVAS_SIZE / 2, CANVAS_SIZE / 2);
        paperScope.draw().view.zoom = canvas.width() / CANVAS_SIZE;
        this.center = new paper.Point(this.canvasSize / 2, this.canvasSize / 2);

        filePicker.setSvgLoadedCallback(function(svgData) {
            this.onSvgFileLoaded(svgData);
        }.bind(this));

        // setup download
        btnDownload.click(function() {
            this.exportAsSvgFile();
        }.bind(this));
    }

    /**
     * Handles the svg file loaded callback.
     * @param svgData either raw svg data or a URL pointing to a svg file.
     */
    onSvgFileLoaded(svgData) {
        // remove any previous icons
        if (this.icon) this.icon.remove();

        paperScope.draw().project.importSVG(svgData, {
            applyMatrix: true,
            expandShapes: true,
            onLoad: function (importedItem) {
                // check svg paths
                let importedPath = this.getPathFromImport(importedItem);
                if (!importedPath) {
                    window.alert('Sorry, no path found in SVG file :(');
                    return;
                }
                importedPath.strokeWidth = 0;

                // one time base setup
                this.setupBase();

                // create icon and shadow
                this.setupIcon(importedPath);
            }.bind(this)
        });
    }

    setupBase() {
        let defaultBaseColor = '#512DA8';
        this.baseRadius = this.canvasSize / 2 * 0.9;
        this.iconBase = new IconBase(this.center, this.baseRadius);
        this.iconBase.setColor(defaultBaseColor);

        new ColorPicker(this.baseColorPicker, defaultBaseColor, function(newColor) {
            this.iconBase.setColor(newColor);
        }.bind(this));
    }

    setupIcon(importedPath) {
        // create icon + shadow
        let defaultIconColor = '#ffffff';
        this.icon = new Icon(this.center, 'white', importedPath, this.iconBase);
        this.icon.setSize(this.baseRadius * 2 * 0.60);

        // setup icon color picker
        new ColorPicker(this.iconColorPicker, defaultIconColor, function(newColor) {
            this.icon.setColor(newColor);
        }.bind(this));

        // setup shadow intensity picker
        let setIntensityFunction = function() {
            let intensity = this.sliderShadowData.getValue();
            this.icon.getIconShadow().setIntensity(intensity[1], intensity[0]);
        }.bind(this);
        this.sliderShadowData = this.sliderShadow.slider()
            .on('slide', function () {
                setIntensityFunction();
            }.bind(this))
            .data('slider');
        setIntensityFunction();

        // setup icon size picker
        let setSizeFunction = function () {
            let size = this.sliderIconSizeData.getValue();
            let scale = 0.0954548 * Math.exp(0.465169 * size);
            this.icon.setScale(scale);
        }.bind(this);
        this.sliderIconSizeData = this.sliderIconSize.slider()
            .on('slide', function () {
                setSizeFunction();
            }.bind(this))
            .data('slider');
        this.icon.getIconShadow().applyShadow();

        // show canvas + remove loading msg
        this.filePicker.hide(300);
        this.canvas.delay(300).fadeIn(300);
        this.containerEdit.delay(300).fadeIn(300);
    }

    /**
     * Exports the whole project as one svg file.
     */
    exportAsSvgFile() {
        paperScope.activateExpo();
        let drawProject = paperScope.draw().project;
        let exportProject = paperScope.expo().project;

        // copy draw layer over to export canvas
        exportProject.clear();
        let layer = new paper.Layer();
        for (let i = 0; i < drawProject.layers[0].children.length; ++i) {
            layer.addChild(drawProject.layers[0].children[i].clone(false));
        }

        // generate final svg
        var svg = exportProject.exportSVG({ asString: true });
		var data = 'data:image/svg+xml;base64,' + btoa(svg);
		var fileName = 'icon.svg';

        // create download link
        var anchor = $('Download')
            .css('display', 'none')
            .appendTo('body');
        anchor.get(0).click();
        anchor.remove();

        // reactivate draw scope
        paperScope.activateDraw();
    }

    getPathFromImport(importedItem) {
        // recursive search for paths in group
        if (importedItem instanceof paper.Group) {
            let possiblePaths = [];
            for (let i = 0; i < importedItem.children.length; ++i) {
                let path = this.getPathFromImport(importedItem.children[i]);
                if (path) possiblePaths.push(path);
            }

            // if only one path, return that one
            if (possiblePaths.length == 0) return null;
            if (possiblePaths.length == 1) return possiblePaths[0];

            // if multiple paths, try finding one with fill color
            // (helps importing Google material icons, which always have a second 'invisible' path)
            for (let i = 0; i < possiblePaths.length; ++i) {
                if (possiblePaths[i].fillColor) return possiblePaths[i];
            }
            // return first match
            return possiblePaths[0];
        }

        if (importedItem instanceof paper.PathItem) {
            return importedItem;
        }

        return null;
    }

}

module.exports = IconManager;
<commit_msg>Combine seperated import paths to single CompoundPath<commit_after>'use strict';

let paper = require('js/index/paper-core.min'),
    IconBase = require('js/index/IconBase'),
    Icon = require('js/index/Icon'),
    ColorPicker = require('js/index/ColorPicker'),
    paperScope = require('js/index/PaperScopeManager');

// Default android icon size (48 DIP)
const CANVAS_SIZE = 48;

/**
 * Handles adding icon + base.
 */
class IconManager {

    /**
     * @param canvas jquery canvas object
     * @param filePicker jquery input object
     * @param filePickerOverlay jquery input overlay object
     * @param containerEdit jquery edit objects (can be multiple)
     * @param btnDownload jquery download button
     * @param iconColorPicker jquery icon color picker object
     * @param baseColorPicker jquery base color picker object
     * @param sliderShadow jquery slider object for changing shadow intensity
     * @param sliderIconSize jquery slider object for changing icon size
     */
    constructor(canvas, filePicker, containerEdit,
                btnDownload, iconColorPicker, baseColorPicker, sliderShadow,
                sliderIconSize) {

        this.canvas = canvas;
        this.filePicker = filePicker;
        this.containerEdit = containerEdit;
        this.iconColorPicker = iconColorPicker;
        this.baseColorPicker = baseColorPicker;
        this.sliderShadow = sliderShadow;
        this.sliderIconSize = sliderIconSize;

        // hide canvas and forward overlay clicks
        canvas.hide();

        // place icon in center on canvas
        this.canvasSize = CANVAS_SIZE;
        paperScope.draw().view.center = new paper.Point(CANVAS_SIZE / 2, CANVAS_SIZE / 2);
        paperScope.draw().view.zoom = canvas.width() / CANVAS_SIZE;
        this.center = new paper.Point(this.canvasSize / 2, this.canvasSize / 2);

        filePicker.setSvgLoadedCallback(function(svgData) {
            this.onSvgFileLoaded(svgData);
        }.bind(this));

        // setup download
        btnDownload.click(function() {
            this.exportAsSvgFile();
        }.bind(this));
    }

    /**
     * Handles the svg file loaded callback.
     * @param svgData either raw svg data or a URL pointing to a svg file.
     */
    onSvgFileLoaded(svgData) {
        // remove any previous icons
        if (this.icon) this.icon.remove();

        paperScope.draw().project.importSVG(svgData, {
            applyMatrix: true,
            expandShapes: true,
            onLoad: function (importedItem) {
                // check svg paths
                let importedPath = this.getPathFromImport(importedItem);
                if (!importedPath) {
                    window.alert('Sorry, no path found in SVG file :(');
                    return;
                }
                importedPath.strokeWidth = 0;

                // one time base setup
                this.setupBase();

                // create icon and shadow
                this.setupIcon(importedPath);
            }.bind(this)
        });
    }

    setupBase() {
        let defaultBaseColor = '#512DA8';
        this.baseRadius = this.canvasSize / 2 * 0.9;
        this.iconBase = new IconBase(this.center, this.baseRadius);
        this.iconBase.setColor(defaultBaseColor);

        new ColorPicker(this.baseColorPicker, defaultBaseColor, function(newColor) {
            this.iconBase.setColor(newColor);
        }.bind(this));
    }

    setupIcon(importedPath) {
        // create icon + shadow
        let defaultIconColor = '#ffffff';
        this.icon = new Icon(this.center, 'white', importedPath, this.iconBase);
        this.icon.setSize(this.baseRadius * 2 * 0.60);

        // setup icon color picker
        new ColorPicker(this.iconColorPicker, defaultIconColor, function(newColor) {
            this.icon.setColor(newColor);
        }.bind(this));

        // setup shadow intensity picker
        let setIntensityFunction = function() {
            let intensity = this.sliderShadowData.getValue();
            this.icon.getIconShadow().setIntensity(intensity[1], intensity[0]);
        }.bind(this);
        this.sliderShadowData = this.sliderShadow.slider()
            .on('slide', function () {
                setIntensityFunction();
            }.bind(this))
            .data('slider');
        setIntensityFunction();

        // setup icon size picker
        let setSizeFunction = function () {
            let size = this.sliderIconSizeData.getValue();
            let scale = 0.0954548 * Math.exp(0.465169 * size);
            this.icon.setScale(scale);
        }.bind(this);
        this.sliderIconSizeData = this.sliderIconSize.slider()
            .on('slide', function () {
                setSizeFunction();
            }.bind(this))
            .data('slider');
        this.icon.getIconShadow().applyShadow();

        // show canvas + remove loading msg
        this.filePicker.hide(300);
        this.canvas.delay(300).fadeIn(300);
        this.containerEdit.delay(300).fadeIn(300);
    }

    /**
     * Exports the whole project as one svg file.
     */
    exportAsSvgFile() {
        paperScope.activateExpo();
        let drawProject = paperScope.draw().project;
        let exportProject = paperScope.expo().project;

        // copy draw layer over to export canvas
        exportProject.clear();
        let layer = new paper.Layer();
        for (let i = 0; i < drawProject.layers[0].children.length; ++i) {
            layer.addChild(drawProject.layers[0].children[i].clone(false));
        }

        // generate final svg
        var svg = exportProject.exportSVG({ asString: true });
		var data = 'data:image/svg+xml;base64,' + btoa(svg);
		var fileName = 'icon.svg';

        // create download link
        var anchor = $('Download')
            .css('display', 'none')
            .appendTo('body');
        anchor.get(0).click();
        anchor.remove();

        // reactivate draw scope
        paperScope.activateDraw();
    }

    getPathFromImport(importedItem) {
        // recursive search for paths in group
        if (importedItem instanceof paper.Group) {
            let possiblePaths = [];
            for (let i = 0; i < importedItem.children.length; ++i) {
                let path = this.getPathFromImport(importedItem.children[i]);
                if (path) possiblePaths.push(path);
            }

            // if only one path, return that one
            if (possiblePaths.length == 0) return null;
            if (possiblePaths.length == 1) return possiblePaths[0];

            // if multiple paths, select all with fill color
            // (helps importing Google material icons, which always have a second 'invisible' path)
            let filledPaths = [];
            for (let i = 0; i < possiblePaths.length; ++i) {
                let path = possiblePaths[i];
                if (path.fillColor) filledPaths.push(possiblePaths[i]);
                path.remove();
            }

            // create new CompoundPath from single paths
            let simplePaths = [];
            for (let i = 0; i < filledPaths.length; ++i) {
                let path = filledPaths[i];
                if (path instanceof paper.Path) {
                    simplePaths.push(path);
                } else if (path instanceof paper.CompoundPath) {
                    for (let j = 0; j < path.children.length; ++j) {
                        simplePaths.push(path.children[j]);
                    }
                }
                simplePaths[simplePaths.length - 1].fillColor = new paper.Color(0, 0, 0, 0);
            }
            // sorting paths by area seems to be necessary to properly determine inside / outside of paths
            // (yes, it shouldn't, but ic_child_care_* seems to do just this)
            simplePaths.sort(function(a , b) {
                return a.area - b.area;
            });
            return new paper.CompoundPath({ children: simplePaths });
        }

        if (importedItem instanceof paper.PathItem) {
            return importedItem;
        }

        return null;
    }

}

module.exports = IconManager;
<|endoftext|>


<commit_before>var _ = require('underscore');

var Growing = module.exports = function(blocks, options) {
    var defaults = {
        maxWidth: null,
        maxHeight: null
    };

    this.options = _.extend({}, defaults, options || {});

    _.extend(this, {
        width: 0,
        height: 0,
        blocks: blocks || [],
        nodes: [],
        list: [],
        excludedBlocks: [],
        nodeIndex: 0,
        growRightLast: 0
    });

    this.init();
};

_.extend(Growing.prototype, {
    init: function() {
        this.blocks.sort(function(a, b) {
            return b.height - a.height;
        });

        _.each(this.blocks, this.fit.bind(this));
    },

    pushList: function(block, x, y) {
        this.list.push(_.extend({}, block, { x: x, y: y }));
    },

    createNode: function(x, y, height) {
        this.nodes.push({
            x: x,
            y: y,
            height: height,
            index: this.nodeIndex++
        });
    },

    fit: function(block) {
        if (!this.findNode(block))
            this.grow(block);
    },

    findNode: function(block) {
        if (!this.nodes.length) return false;

        var self = this, elite,
            matches = _.filter(this.nodes, function(node) {
                var nodeWidth = self.width - node.x;

                return block.width <= nodeWidth && block.height <= node.height;
            });

        if (!matches.length) {
            elite = _.filter(matches, function(node) {
                var nodeWidth = self.width - node.x;

                return block.width === nodeWidth || block.height === node.height;
            });

            if (elite.length) matches = elite;
        }

        matches.sort(function(a, b) {
            var aWidth = self.width - a.x,
                bWidth = self.width - b.x;

            return bWidth + b.height - aWidth - a.height;
        });

        if (!matches.length) return false;

        this.pasteToNode(matches[0], block);

        return true;
    },

    grow: function(block) {
        var targetWidth = this.width + block.width,
            targetHeight = this.height + block.height,
            canGrowRight = !(this.options.maxWidth && this.options.maxWidth < targetWidth),
            canGrowDown = !(this.options.maxHeight && this.options.maxHeight < targetHeight);

        if (targetWidth <= targetHeight && canGrowRight)
            this.growRight(block);
        else if (canGrowDown)
            this.growDown(block);
        else
            this.excludedBlocks.push(block);
    },

    growRight: function(block) {
        var x = this.width,
            y = 0;

        if (x > 0 && block.height < this.growRightLast)
            this.createNode(x, block.height, this.growRightLast - block.height);

        this.width += block.width;
        this.height = this.height < block.height ? block.height : this.height;
        this.growRightLast = block.height;

        this.pushList(block, x, y);
    },

    growDown: function(block) {
        var x = 0,
            y = this.height;

        this.createNode(block.width, this.height, block.height);

        this.height += block.height;
        this.width = this.width < block.width ? block.width : this.width;

        this.pushList(block, x, y);
    },

    pasteToNode: function(node, block) {
        var nodeWidth = this.width - node.x,
            dw = nodeWidth - block.width,
            dh = node.height - block.height;

        this.nodes = _.filter(this.nodes, function(a) {
            return a.index !== node.index;
        });

        if (dw > 0)
            this.createNode(node.x + block.width, node.y, block.height);

        if (dh > 0)
            this.createNode(node.x, node.y + block.height, dh);

        this.pushList(block, node.x, node.y);
    }
});
<commit_msg>added yet one sort blocks<commit_after>var _ = require('underscore');

var Growing = module.exports = function(blocks, options) {
    var defaults = {
        maxWidth: null,
        maxHeight: null
    };

    this.options = _.extend({}, defaults, options || {});

    _.extend(this, {
        width: 0,
        height: 0,
        blocks: blocks || [],
        nodes: [],
        list: [],
        excludedBlocks: [],
        nodeIndex: 0,
        growRightLast: 0
    });

    this.init();
};

_.extend(Growing.prototype, {
    init: function() {
        this.blocks.sort(function(a, b) {
            return b.width * b.height - a.width * a.height;
        });

        this.blocks.sort(function(a, b) {
            return b.height - a.height;
        });

        _.each(this.blocks, this.fit.bind(this));
    },

    pushList: function(block, x, y) {
        this.list.push(_.extend({}, block, { x: x, y: y }));
    },

    createNode: function(x, y, height) {
        this.nodes.push({
            x: x,
            y: y,
            height: height,
            index: this.nodeIndex++
        });
    },

    fit: function(block) {
        if (!this.findNode(block))
            this.grow(block);
    },

    findNode: function(block) {
        if (!this.nodes.length) return false;

        var self = this, elite,
            matches = _.filter(this.nodes, function(node) {
                var nodeWidth = self.width - node.x;

                return block.width <= nodeWidth && block.height <= node.height;
            });

        if (!matches.length) {
            elite = _.filter(matches, function(node) {
                var nodeWidth = self.width - node.x;

                return block.width === nodeWidth || block.height === node.height;
            });

            if (elite.length) matches = elite;
        }

        matches.sort(function(a, b) {
            var aWidth = self.width - a.x,
                bWidth = self.width - b.x;

            return bWidth + b.height - aWidth - a.height;
        });

        if (!matches.length) return false;

        this.pasteToNode(matches[0], block);

        return true;
    },

    grow: function(block) {
        var targetWidth = this.width + block.width,
            targetHeight = this.height + block.height,
            canGrowRight = !(this.options.maxWidth && this.options.maxWidth < targetWidth),
            canGrowDown = !(this.options.maxHeight && this.options.maxHeight < targetHeight);

        if (targetWidth <= targetHeight && canGrowRight)
            this.growRight(block);
        else if (canGrowDown)
            this.growDown(block);
        else
            this.excludedBlocks.push(block);
    },

    growRight: function(block) {
        var x = this.width,
            y = 0;

        if (x > 0 && block.height < this.growRightLast)
            this.createNode(x, block.height, this.growRightLast - block.height);

        this.width += block.width;
        this.height = this.height < block.height ? block.height : this.height;
        this.growRightLast = block.height;

        this.pushList(block, x, y);
    },

    growDown: function(block) {
        var x = 0,
            y = this.height;

        this.createNode(block.width, this.height, block.height);

        this.height += block.height;
        this.width = this.width < block.width ? block.width : this.width;

        this.pushList(block, x, y);
    },

    pasteToNode: function(node, block) {
        var nodeWidth = this.width - node.x,
            dw = nodeWidth - block.width,
            dh = node.height - block.height;

        this.nodes = _.filter(this.nodes, function(a) {
            return a.index !== node.index;
        });

        if (dw > 0)
            this.createNode(node.x + block.width, node.y, block.height);

        if (dh > 0)
            this.createNode(node.x, node.y + block.height, dh);

        this.pushList(block, node.x, node.y);
    }
});
<|endoftext|>


<commit_before>twttr.anywhere(function (T) {
	if(T.isConnected()){
		var user=T.currentUser;
		var p=user.data('profile_image_url');
		var a=p.split('_');
		p=a[0]+"_"+a[1]+"_"+"mini.jpeg";
		$("#peepin").html('
 '+user.data("screen_name")+'

Home

Discussions

Files

Log out!

').hide().fadeIn('fast');
	}
	else{
		$("#peepin").html('Login »').show();
	}
  $("#login").live("click",function(){
  	if(T.isConnected()){
  		$("#peepin").html('Tweet »').hide().fadeIn(500);
  	}
  	else{
  		T.signIn();
  	}
  });
  $("#logout").live("click",function(){
  	twttr.anywhere.signOut();
  	window.location="index.html";
  });
});
<commit_msg>if user logged in display user dropdown menu<commit_after>twttr.anywhere(function (T) {
	if(T.isConnected()){
		var user=T.currentUser;
		var p=user.data('profile_image_url');
		var a=p.split('_');
		p=a[0]+"_"+a[1]+"_"+"mini.jpeg";
		$("#peepin").html('
 '+user.data("screen_name")+'

Home

Discussions

Files

Log out!

').hide().fadeIn('fast');
	}
	else{
		$("#peepin").html('Login »').show();
	}
  $("#login").live("click",function(){
  	if(T.isConnected()){
  		var user=T.currentUser;
		var p=user.data('profile_image_url');
		var a=p.split('_');
		p=a[0]+"_"+a[1]+"_"+"mini.jpeg";
		$("#peepin").html('
 '+user.data("screen_name")+'

Home

Discussions

Files

Log out!

').hide().fadeIn('fast');
  	}
  	else{
  		T.signIn();
  	}
  });
  $("#logout").live("click",function(){
  	twttr.anywhere.signOut();
  	window.location="index.html";
  });
});
<|endoftext|>