More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Protocol / HTTP.js
blob:a/labs/openlayers/lib/OpenLayers/Protocol/HTTP.js -> blob:b/labs/openlayers/lib/OpenLayers/Protocol/HTTP.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/Protocol.js
  * @requires OpenLayers/Feature/Vector.js
  * @requires OpenLayers/Filter/Spatial.js
  * @requires OpenLayers/Filter/Comparison.js
  * @requires OpenLayers/Filter/Logical.js
  * @requires OpenLayers/Request/XMLHttpRequest.js
  */
   
  /**
  * Class: OpenLayers.Protocol.HTTP
  * A basic HTTP protocol for vector layers. Create a new instance with the
  * <OpenLayers.Protocol.HTTP> constructor.
  *
  * Inherits from:
  * - <OpenLayers.Protocol>
  */
  OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
   
  /**
  * Property: url
  * {String} Service URL, read-only, set through the options
  * passed to constructor.
  */
  url: null,
   
  /**
  * Property: headers
  * {Object} HTTP request headers, read-only, set through the options
  * passed to the constructor,
  * Example: {'Content-Type': 'plain/text'}
  */
  headers: null,
   
  /**
  * Property: params
  * {Object} Parameters of GET requests, read-only, set through the options
  * passed to the constructor,
  * Example: {'bbox': '5,5,5,5'}
  */
  params: null,
   
  /**
  * Property: callback
  * {Object} Function to be called when the <read>, <create>,
  * <update>, <delete> or <commit> operation completes, read-only,
  * set through the options passed to the constructor.
  */
  callback: null,
   
  /**
  * Property: scope
  * {Object} Callback execution scope, read-only, set through the
  * options passed to the constructor.
  */
  scope: null,
   
  /**
  * Property: readWithPOST
  * {Boolean} true if read operations are done with POST requests
  * instead of GET, defaults to false.
  */
  readWithPOST: false,
   
  /**
  * Property: wildcarded.
  * {Boolean} If true percent signs are added around values
  * read from LIKE filters, for example if the protocol
  * read method is passed a LIKE filter whose property
  * is "foo" and whose value is "bar" the string
  * "foo__ilike=%bar%" will be sent in the query string;
  * defaults to false.
  */
  wildcarded: false,
   
  /**
  * Constructor: OpenLayers.Protocol.HTTP
  * A class for giving layers generic HTTP protocol.
  *
  * Parameters:
  * options - {Object} Optional object whose properties will be set on the
  * instance.
  *
  * Valid options include:
  * url - {String}
  * headers - {Object}
  * params - {Object}
  * format - {<OpenLayers.Format>}
  * callback - {Function}
  * scope - {Object}
  */
  initialize: function(options) {
  options = options || {};
  this.params = {};
  this.headers = {};
  OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
  },
   
  /**
  * APIMethod: destroy
  * Clean up the protocol.
  */
  destroy: function() {
  this.params = null;
  this.headers = null;
  OpenLayers.Protocol.prototype.destroy.apply(this);
  },
   
  /**
  * APIMethod: read
  * Construct a request for reading new features.
  *
  * Parameters:
  * options - {Object} Optional object for configuring the request.
  * This object is modified and should not be reused.
  *
  * Valid options:
  * url - {String} Url for the request.
  * params - {Object} Parameters to get serialized as a query string.
  * headers - {Object} Headers to be set on the request.
  * filter - {<OpenLayers.Filter>} Filter to get serialized as a
  * query string.
  * readWithPOST - {Boolean} If the request should be done with POST.
  *
  * Returns:
  * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
  * references the HTTP request, this object is also passed to the
  * callback function when the request completes, its "features" property
  * is then populated with the the features received from the server.
  */
  read: function(options) {
  OpenLayers.Protocol.prototype.read.apply(this, arguments);
  options = OpenLayers.Util.applyDefaults(options, this.options);
  options.params = OpenLayers.Util.applyDefaults(
  options.params, this.options.params);
  if(options.filter) {
  options.params = this.filterToParams(
  options.filter, options.params);
  }
  var readWithPOST = (options.readWithPOST !== undefined) ?
  options.readWithPOST : this.readWithPOST;
  var resp = new OpenLayers.Protocol.Response({requestType: "read"});
  if(readWithPOST) {
  resp.priv = OpenLayers.Request.POST({
  url: options.url,
  callback: this.createCallback(this.handleRead, resp, options),
  data: OpenLayers.Util.getParameterString(options.params),
  headers: {
  "Content-Type": "application/x-www-form-urlencoded"
  }
  });
  } else {
  resp.priv = OpenLayers.Request.GET({
  url: options.url,
  callback: this.createCallback(this.handleRead, resp, options),
  params: options.params,
  headers: options.headers
  });
  }
  return resp;
  },
   
  /**
  * Method: handleRead
  * Individual callbacks are created for read, create and update, should
  * a subclass need to override each one separately.
  *
  * Parameters:
  * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
  * the user callback.
  * options - {Object} The user options passed to the read call.
  */
  handleRead: function(resp, options) {
  this.handleResponse(resp, options);
  },
   
  /**
  * Method: filterToParams
  * Convert an <OpenLayers.Filter> object to parameters.
  *
  * Parameters:
  * filter - {OpenLayers.Filter} filter to convert.
  * params - {Object} The parameters object.
  *
  * Returns:
  * {Object} The resulting parameters object.
  */
  filterToParams: function(filter, params) {
  params = params || {};
  var className = filter.CLASS_NAME;
  var filterType = className.substring(className.lastIndexOf(".") + 1);
  switch(filterType) {
  case "Spatial":
  switch(filter.type) {
  case OpenLayers.Filter.Spatial.BBOX:
  params.bbox = filter.value.toArray();
  break;
  case OpenLayers.Filter.Spatial.DWITHIN:
  params.tolerance = filter.distance;
  // no break here
  case OpenLayers.Filter.Spatial.WITHIN:
  params.lon = filter.value.x;
  params.lat = filter.value.y;
  break;
  default:
  OpenLayers.Console.warn(
  "Unknown spatial filter type " + filter.type);
  }
  break;
  case "Comparison":
  var op = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR[filter.type];
  if(op !== undefined) {
  var value = filter.value;
  if(filter.type == OpenLayers.Filter.Comparison.LIKE) {
  value = this.regex2value(value);
  if(this.wildcarded) {
  value = "%" + value + "%";
  }
  }
  params[filter.property + "__" + op] = value;
  params.queryable = params.queryable || [];
  params.queryable.push(filter.property);
  } else {
  OpenLayers.Console.warn(
  "Unknown comparison filter type " + filter.type);
  }
  break;
  case "Logical":
  if(filter.type === OpenLayers.Filter.Logical.AND) {
  for(var i=0,len=filter.filters.length; i<len; i++) {
  params = this.filterToParams(filter.filters[i], params);
  }
  } else {
  OpenLayers.Console.warn(
  "Unsupported logical filter type " + filter.type);
  }
  break;
  default:
  OpenLayers.Console.warn("Unknown filter type " + filterType);
  }
  return params;
  },
   
  /**
  * Method: regex2value
  * Convert the value from a regular expression string to a LIKE/ILIKE
  * string known to the web service.
  *
  * Parameters:
  * value - {String} The regex string.
  *
  * Returns:
  * {String} The converted string.
  */
  regex2value: function(value) {
   
  // highly sensitive!! Do not change this without running the
  // Protocol/HTTP.html unit tests
   
  // convert % to \%
  value = value.replace(/%/g, "\\%");
   
  // convert \\. to \\_ (\\.* occurences converted later)
  value = value.replace(/\\\\\.(\*)?/g, function($0, $1) {
  return $1 ? $0 : "\\\\_";
  });
   
  // convert \\.* to \\%
  value = value.replace(/\\\\\.\*/g, "\\\\%");
   
  // convert . to _ (\. and .* occurences converted later)
  value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) {
  return $1 || $2 ? $0 : "_";
  });
   
  // convert .* to % (\.* occurnces converted later)
  value = value.replace(/(\\)?\.\*/g, function($0, $1) {
  return $1 ? $0 : "%";
  });
   
  // convert \. to .
  value = value.replace(/\\\./g, ".");
   
  // replace \* with * (watching out for \\*)
  value = value.replace(/(\\)?\\\*/g, function($0, $1) {
  return $1 ? $0 : "*";
  });
   
  return value;
  },
   
  /**
  * APIMethod: create
  * Construct a request for writing newly created features.
  *
  * Parameters:
  * features - {Array({<OpenLayers.Feature.Vector>})} or
  * {<OpenLayers.Feature.Vector>}
  * options - {Object} Optional object for configuring the request.
  * This object is modified and should not be reused.
  *
  * Returns:
  * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
  * object, whose "priv" property references the HTTP request, this
  * object is also passed to the callback function when the request
  * completes, its "features" property is then populated with the
  * the features received from the server.
  */
  create: function(features, options) {
  options = OpenLayers.Util.applyDefaults(options, this.options);
   
  var resp = new OpenLayers.Protocol.Response({
  reqFeatures: features,
  requestType: "create"
  });
   
  resp.priv = OpenLayers.Request.POST({
  url: options.url,
  callback: this.createCallback(this.handleCreate, resp, options),
  headers: options.headers,
  data: this.format.write(features)
  });
   
  return resp;
  },
   
  /**
  * Method: handleCreate
  * Called the the request issued by <create> is complete. May be overridden
  * by subclasses.
  *
  * Parameters:
  * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
  * any user callback.
  * options - {Object} The user options passed to the create call.
  */
  handleCreate: function(resp, options) {
  this.handleResponse(resp, options);
  },
   
  /**
  * APIMethod: update
  * Construct a request updating modified feature.
  *
  * Parameters:
  * feature - {<OpenLayers.Feature.Vector>}
  * options - {Object} Optional object for configuring the request.
  * This object is modified and should not be reused.
  *
  * Returns:
  * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
  * object, whose "priv" property references the HTTP request, this
  * object is also passed to the callback function when the request
  * completes, its "features" property is then populated with the
  * the feature received from the server.
  */
  update: function(feature, options) {
  options = options || {};
  var url = options.url ||
  feature.url ||
  this.options.url + "/" + feature.fid;
  options = OpenLayers.Util.applyDefaults(options, this.options);
   
  var resp = new OpenLayers.Protocol.Response({