More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Control / SelectFeature.js
blob:a/labs/openlayers/lib/OpenLayers/Control/SelectFeature.js -> blob:b/labs/openlayers/lib/OpenLayers/Control/SelectFeature.js
  /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the Clear BSD license.
  * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
   
   
  /**
  * @requires OpenLayers/Control.js
  * @requires OpenLayers/Feature/Vector.js
  * @requires OpenLayers/Handler/Feature.js
  * @requires OpenLayers/Layer/Vector/RootContainer.js
  */
   
  /**
  * Class: OpenLayers.Control.SelectFeature
  * The SelectFeature control selects vector features from a given layer on
  * click or hover.
  *
  * Inherits from:
  * - <OpenLayers.Control>
  */
  OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
   
  /**
  * Constant: EVENT_TYPES
  *
  * Supported event types:
  * - *beforefeaturehighlighted* Triggered before a feature is highlighted
  * - *featurehighlighted* Triggered when a feature is highlighted
  * - *featureunhighlighted* Triggered when a feature is unhighlighted
  */
  EVENT_TYPES: ["beforefeaturehighlighted", "featurehighlighted", "featureunhighlighted"],
   
  /**
  * Property: multipleKey
  * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
  * the <multiple> property to true. Default is null.
  */
  multipleKey: null,
   
  /**
  * Property: toggleKey
  * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
  * the <toggle> property to true. Default is null.
  */
  toggleKey: null,
   
  /**
  * APIProperty: multiple
  * {Boolean} Allow selection of multiple geometries. Default is false.
  */
  multiple: false,
   
  /**
  * APIProperty: clickout
  * {Boolean} Unselect features when clicking outside any feature.
  * Default is true.
  */
  clickout: true,
   
  /**
  * APIProperty: toggle
  * {Boolean} Unselect a selected feature on click. Default is false. Only
  * has meaning if hover is false.
  */
  toggle: false,
   
  /**
  * APIProperty: hover
  * {Boolean} Select on mouse over and deselect on mouse out. If true, this
  * ignores clicks and only listens to mouse moves.
  */
  hover: false,
   
  /**
  * APIProperty: highlightOnly
  * {Boolean} If true do not actually select features (i.e. place them in the
  * layer's selected features array), just highlight them. This property has
  * no effect if hover is false. Defaults to false.
  */
  highlightOnly: false,
   
  /**
  * APIProperty: box
  * {Boolean} Allow feature selection by drawing a box.
  */
  box: false,
   
  /**
  * Property: onBeforeSelect
  * {Function} Optional function to be called before a feature is selected.
  * The function should expect to be called with a feature.
  */
  onBeforeSelect: function() {},
   
  /**
  * APIProperty: onSelect
  * {Function} Optional function to be called when a feature is selected.
  * The function should expect to be called with a feature.
  */
  onSelect: function() {},
   
  /**
  * APIProperty: onUnselect
  * {Function} Optional function to be called when a feature is unselected.
  * The function should expect to be called with a feature.
  */
  onUnselect: function() {},
   
  /**
  * Property: scope
  * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect
  * callbacks. If null the scope will be this control.
  */
  scope: null,
   
  /**
  * APIProperty: geometryTypes
  * {Array(String)} To restrict selecting to a limited set of geometry types,
  * send a list of strings corresponding to the geometry class names.
  */
  geometryTypes: null,
   
  /**
  * Property: layer
  * {<OpenLayers.Layer.Vector>} The vector layer with a common renderer
  * root for all layers this control is configured with (if an array of
  * layers was passed to the constructor), or the vector layer the control
  * was configured with (if a single layer was passed to the constructor).
  */
  layer: null,
   
  /**
  * Property: layers
  * {Array(<OpenLayers.Layer.Vector>} The layers this control will work on,
  * or null if the control was configured with a single layer
  */
  layers: null,
   
  /**
  * APIProperty: callbacks
  * {Object} The functions that are sent to the handlers.feature for callback
  */
  callbacks: null,
   
  /**
  * APIProperty: selectStyle
  * {Object} Hash of styles
  */
  selectStyle: null,
   
  /**
  * Property: renderIntent
  * {String} key used to retrieve the select style from the layer's
  * style map.
  */
  renderIntent: "select",
   
  /**
  * Property: handlers
  * {Object} Object with references to multiple <OpenLayers.Handler>
  * instances.
  */
  handlers: null,
   
  /**
  * Constructor: OpenLayers.Control.SelectFeature
  * Create a new control for selecting features.
  *
  * Parameters:
  * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. The
  * layer(s) this control will select features from.
  * options - {Object}
  */
  initialize: function(layers, options) {
  // concatenate events specific to this control with those from the base
  this.EVENT_TYPES =
  OpenLayers.Control.SelectFeature.prototype.EVENT_TYPES.concat(
  OpenLayers.Control.prototype.EVENT_TYPES
  );
  OpenLayers.Control.prototype.initialize.apply(this, [options]);
   
  if(this.scope === null) {
  this.scope = this;
  }
  this.initLayer(layers);
  var callbacks = {
  click: this.clickFeature,
  clickout: this.clickoutFeature
  };
  if (this.hover) {
  callbacks.over = this.overFeature;
  callbacks.out = this.outFeature;
  }
   
  this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks);
  this.handlers = {
  feature: new OpenLayers.Handler.Feature(
  this, this.layer, this.callbacks,
  {geometryTypes: this.geometryTypes}
  )
  };
   
  if (this.box) {
  this.handlers.box = new OpenLayers.Handler.Box(
  this, {done: this.selectBox},
  {boxDivClassName: "olHandlerBoxSelectFeature"}
  );
  }
  },
   
  /**
  * Method: initLayer
  * Assign the layer property. If layers is an array, we need to use
  * a RootContainer.
  *
  * Parameters:
  * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers.
  */
  initLayer: function(layers) {
  if(layers instanceof Array) {
  this.layers = layers;
  this.layer = new OpenLayers.Layer.Vector.RootContainer(
  this.id + "_container", {
  layers: layers
  }
  );
  } else {
  this.layer = layers;
  }
  },
   
  /**
  * Method: destroy
  */
  destroy: function() {
  if(this.active && this.layers) {
  this.map.removeLayer(this.layer);
  }
  OpenLayers.Control.prototype.destroy.apply(this, arguments);
  if(this.layers) {
  this.layer.destroy();
  }
  },
   
  /**
  * Method: activate
  * Activates the control.
  *
  * Returns:
  * {Boolean} The control was effectively activated.
  */
  activate: function () {
  if (!this.active) {
  if(this.layers) {
  this.map.addLayer(this.layer);
  }
  this.handlers.feature.activate();
  if(this.box && this.handlers.box) {
  this.handlers.box.activate();
  }
  }
  return OpenLayers.Control.prototype.activate.apply(
  this, arguments
  );
  },
   
  /**
  * Method: deactivate
  * Deactivates the control.
  *
  * Returns:
  * {Boolean} The control was effectively deactivated.
  */
  deactivate: function () {
  if (this.active) {
  this.handlers.feature.deactivate();
  if(this.handlers.box) {
  this.handlers.box.deactivate();
  }
  if(this.layers) {
  this.map.removeLayer(this.layer);
  }
  }
  return OpenLayers.Control.prototype.deactivate.apply(
  this, arguments
  );
  },
   
  /**
  * Method: unselectAll
  * Unselect all selected features. To unselect all except for a single
  * feature, set the options.except property to the feature.
  *
  * Parameters:
  * options - {Object} Optional configuration object.
  */
  unselectAll: function(options) {
  // we'll want an option to supress notification here
  var layers = this.layers || [this.layer];
  var layer, feature;
  for(var l=0; l<layers.length; ++l) {
  layer = layers[l];
  for(var i=layer.selectedFeatures.length-1; i>=0; --i) {
  feature = layer.selectedFeatures[i];
  if(!options || options.except != feature) {
  this.unselect(feature);
  }
  }
  }
  },
   
  /**
  * Method: clickFeature
  * Called on click in a feature
  * Only responds if this.hover is false.
  *
  * Parameters:
  * feature - {<OpenLayers.Feature.Vector>}
  */
  clickFeature: function(feature) {
  if(!this.hover) {
  var selected = (OpenLayers.Util.indexOf(
  feature.layer.selectedFeatures, feature) > -1);
  if(selected) {
  if(this.toggleSelect()) {
  this.unselect(feature);
  } else if(!this.multipleSelect()) {
  this.unselectAll({except: feature});
  }
  } else {
  if(!this.multipleSelect()) {
  this.unselectAll({except: feature});
  }
  this.select(feature);
  }
  }
  },
   
  /**
  * Method: multipleSelect
  * Allow for multiple selected features based on <multiple> property and
  * <multipleKey> event modifier.
  *
  * Returns:
  * {Boolean} Allow for multiple selected features.
  */
  multipleSelect: function() {
  return this.multiple || (this.handlers.feature.evt &&
  this.handlers.feature.evt[this.multipleKey]);
  },
   
  /**
  * Method: toggleSelect
  * Event should toggle the selected state of a feature based on <toggle>
  * property and <toggleKey> event modifier.
  *
  * Returns:
  * {Boolean} Toggle the selected state of a feature.
  */
  toggleSelect: function() {
  return this.toggle || (this.handlers.feature.evt &&
  this.handlers.feature.evt[this.toggleKey]);
  },
   
  /**
  * Method: clickoutFeature
  * Called on click outside a previously clicked (selected) feature.
  * Only responds if this.hover is false.
  *
  * Parameters:
  * feature - {<OpenLayers.Vector.Feature>}
  */
  clickoutFeature: function(feature) {
  if(!this.hover && this.clickout) {
  this.unselectAll();
  }
  },
   
  /**
  * Method: overFeature
  * Called on over a feature.
  * Only responds if this.hover i