From 2900823eb2688ca21b241a4a53e66af8dc9ef0ba Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Thu, 10 Nov 2011 08:47:53 +0100 Subject: [PATCH] Move deprecated Layer.WFS and Tile.WFS into deprecated.js. --- lib/OpenLayers.js | 2 - lib/OpenLayers/Layer/WFS.js | 610 -------------------- lib/OpenLayers/Tile/WFS.js | 192 ------- lib/deprecated.js | 785 ++++++++++++++++++++++++++ tests/{ => deprecated}/Layer/WFS.html | 3 +- tests/{ => deprecated}/Tile/WFS.html | 3 +- tests/list-tests.html | 4 +- 7 files changed, 791 insertions(+), 808 deletions(-) delete mode 100644 lib/OpenLayers/Layer/WFS.js delete mode 100644 lib/OpenLayers/Tile/WFS.js rename tests/{ => deprecated}/Layer/WFS.html (98%) rename tests/{ => deprecated}/Tile/WFS.html (98%) diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 933407c4ec..19b1da3ca6 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -122,7 +122,6 @@ "OpenLayers/Tile.js", "OpenLayers/Tile/Image.js", "OpenLayers/Tile/Image/IFrame.js", - "OpenLayers/Tile/WFS.js", "OpenLayers/Layer/Image.js", "OpenLayers/Layer/SphericalMercator.js", "OpenLayers/Layer/EventPane.js", @@ -337,7 +336,6 @@ "OpenLayers/Format/XLS/v1.js", "OpenLayers/Format/XLS/v1_1_0.js", "OpenLayers/Format/OGCExceptionReport.js", - "OpenLayers/Layer/WFS.js", "OpenLayers/Control/GetFeature.js", "OpenLayers/Control/NavToolbar.js", "OpenLayers/Control/PanPanel.js", diff --git a/lib/OpenLayers/Layer/WFS.js b/lib/OpenLayers/Layer/WFS.js deleted file mode 100644 index af9ef0376b..0000000000 --- a/lib/OpenLayers/Layer/WFS.js +++ /dev/null @@ -1,610 +0,0 @@ -/* Copyright (c) 2006-2011 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/Tile/WFS.js - * @requires OpenLayers/Layer/Vector.js - * @requires OpenLayers/Layer/Markers.js - * @requires OpenLayers/Console.js - * @requires OpenLayers/Lang.js - */ - -/** - * Class: OpenLayers.Layer.WFS - * *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.Vector - * with a Protocol.WFS and one or more Strategies. - * - * Inherits from: - * - - * - - */ -OpenLayers.Layer.WFS = OpenLayers.Class( - OpenLayers.Layer.Vector, OpenLayers.Layer.Markers, { - - /** - * APIProperty: isBaseLayer - * {Boolean} WFS layer is not a base layer by default. - */ - isBaseLayer: false, - - /** - * Property: tile - * {} - */ - tile: null, - - /** - * APIProperty: ratio - * {Float} The ratio property determines the size of the serverside query - * relative to the map viewport size. By default, we load an area twice - * as big as the map, to allow for panning without immediately reload. - * Setting this to 1 will cause the area of the WFS request to match - * the map area exactly. It is recommended to set this to some number - * at least slightly larger than 1, otherwise accidental clicks can - * cause a data reload, by moving the map only 1 pixel. - */ - ratio: 2, - - /** - * Property: DEFAULT_PARAMS - * {Object} Hashtable of default key/value parameters - */ - DEFAULT_PARAMS: { service: "WFS", - version: "1.0.0", - request: "GetFeature" - }, - - /** - * APIProperty: featureClass - * {} If featureClass is defined, an old-style markers - * based WFS layer is created instead of a new-style vector layer. If - * sent, this should be a subclass of OpenLayers.Feature - */ - featureClass: null, - - /** - * APIProperty: format - * {} The format you want the data to be parsed with. - * Must be passed in the constructor. Should be a class, not an instance. - * This option can only be used if no featureClass is passed / vectorMode - * is false: if a featureClass is passed, then this parameter is ignored. - */ - format: null, - - /** - * Property: formatObject - * {} Internally created/managed format object, used by - * the Tile to parse data. - */ - formatObject: null, - - /** - * APIProperty: formatOptions - * {Object} Hash of options which should be passed to the format when it is - * created. Must be passed in the constructor. - */ - formatOptions: null, - - /** - * Property: vectorMode - * {Boolean} Should be calculated automatically. Determines whether the - * layer is in vector mode or marker mode. - */ - vectorMode: true, - - /** - * APIProperty: encodeBBOX - * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', - * but some services want it that way. Default false. - */ - encodeBBOX: false, - - /** - * APIProperty: extractAttributes - * {Boolean} Should the WFS layer parse attributes from the retrieved - * GML? Defaults to false. If enabled, parsing is slower, but - * attributes are available in the attributes property of - * layer features. - */ - extractAttributes: false, - - /** - * Constructor: OpenLayers.Layer.WFS - * - * Parameters: - * name - {String} - * url - {String} - * params - {Object} - * options - {Object} Hashtable of extra options to tag onto the layer - */ - initialize: function(name, url, params, options) { - if (options == undefined) { options = {}; } - - if (options.featureClass || - !OpenLayers.Layer.Vector || - !OpenLayers.Feature.Vector) { - this.vectorMode = false; - } - - // Uppercase params - params = OpenLayers.Util.upperCaseObject(params); - - // Turn off error reporting, browsers like Safari may work - // depending on the setup, and we don't want an unneccesary alert. - OpenLayers.Util.extend(options, {'reportError': false}); - var newArguments = []; - newArguments.push(name, options); - OpenLayers.Layer.Vector.prototype.initialize.apply(this, newArguments); - if (!this.renderer || !this.vectorMode) { - this.vectorMode = false; - if (!options.featureClass) { - options.featureClass = OpenLayers.Feature.WFS; - } - OpenLayers.Layer.Markers.prototype.initialize.apply(this, - newArguments); - } - - if (this.params && this.params.typename && !this.options.typename) { - this.options.typename = this.params.typename; - } - - if (!this.options.geometry_column) { - this.options.geometry_column = "the_geom"; - } - - this.params = OpenLayers.Util.applyDefaults( - params, - OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS) - ); - this.url = url; - }, - - - /** - * APIMethod: destroy - */ - destroy: function() { - if (this.vectorMode) { - OpenLayers.Layer.Vector.prototype.destroy.apply(this, arguments); - } else { - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); - } - if (this.tile) { - this.tile.destroy(); - } - this.tile = null; - - this.ratio = null; - this.featureClass = null; - this.format = null; - - if (this.formatObject && this.formatObject.destroy) { - this.formatObject.destroy(); - } - this.formatObject = null; - - this.formatOptions = null; - this.vectorMode = null; - this.encodeBBOX = null; - this.extractAttributes = null; - }, - - /** - * Method: setMap - * - * Parameters: - * map - {} - */ - setMap: function(map) { - if (this.vectorMode) { - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); - - var options = { - 'extractAttributes': this.extractAttributes - }; - - OpenLayers.Util.extend(options, this.formatOptions); - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { - options.externalProjection = this.projection; - options.internalProjection = this.map.getProjectionObject(); - } - - this.formatObject = this.format ? new this.format(options) : new OpenLayers.Format.GML(options); - } else { - OpenLayers.Layer.Markers.prototype.setMap.apply(this, arguments); - } - }, - - /** - * Method: moveTo - * - * Parameters: - * bounds - {} - * zoomChanged - {Boolean} - * dragging - {Boolean} - */ - moveTo:function(bounds, zoomChanged, dragging) { - if (this.vectorMode) { - OpenLayers.Layer.Vector.prototype.moveTo.apply(this, arguments); - } else { - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); - } - - // don't load wfs features while dragging, wait for drag end - if (dragging) { - // TBD try to hide the vector layer while dragging - // this.setVisibility(false); - // this will probably help for panning performances - return false; - } - - if ( zoomChanged ) { - if (this.vectorMode) { - this.renderer.clear(); - } - } - - //DEPRECATED - REMOVE IN 3.0 - // don't load data if current zoom level doesn't match - if (this.options.minZoomLevel) { - OpenLayers.Console.warn(OpenLayers.i18n('minZoomLevelError')); - - if (this.map.getZoom() < this.options.minZoomLevel) { - return null; - } - } - - if (bounds == null) { - bounds = this.map.getExtent(); - } - - var firstRendering = (this.tile == null); - - //does the new bounds to which we need to move fall outside of the - // current tile's bounds? - var outOfBounds = (!firstRendering && - !this.tile.bounds.containsBounds(bounds)); - - if (zoomChanged || firstRendering || (!dragging && outOfBounds)) { - //determine new tile bounds - var center = bounds.getCenterLonLat(); - var tileWidth = bounds.getWidth() * this.ratio; - var tileHeight = bounds.getHeight() * this.ratio; - var tileBounds = - new OpenLayers.Bounds(center.lon - (tileWidth / 2), - center.lat - (tileHeight / 2), - center.lon + (tileWidth / 2), - center.lat + (tileHeight / 2)); - - //determine new tile size - var tileSize = this.map.getSize(); - tileSize.w = tileSize.w * this.ratio; - tileSize.h = tileSize.h * this.ratio; - - //determine new position (upper left corner of new bounds) - var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top); - var pos = this.map.getLayerPxFromLonLat(ul); - - //formulate request url string - var url = this.getFullRequestString(); - - var params = null; - - // Cant combine "filter" and "BBOX". This is a cheap hack to help - // people out who can't migrate to the WFS protocol immediately. - var filter = this.params.filter || this.params.FILTER; - if (filter) { - params = {FILTER: filter}; - } - else { - params = {BBOX: this.encodeBBOX ? tileBounds.toBBOX() - : tileBounds.toArray()}; - } - - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { - var projectedBounds = tileBounds.clone(); - projectedBounds.transform(this.map.getProjectionObject(), - this.projection); - if (!filter){ - params.BBOX = this.encodeBBOX ? projectedBounds.toBBOX() - : projectedBounds.toArray(); - } - } - - url += "&" + OpenLayers.Util.getParameterString(params); - - if (!this.tile) { - this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds, - url, tileSize); - this.addTileMonitoringHooks(this.tile); - this.tile.draw(); - } else { - if (this.vectorMode) { - this.destroyFeatures(); - this.renderer.clear(); - } else { - this.clearMarkers(); - } - this.removeTileMonitoringHooks(this.tile); - this.tile.destroy(); - - this.tile = null; - this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds, - url, tileSize); - this.addTileMonitoringHooks(this.tile); - this.tile.draw(); - } - } - }, - - /** - * Method: addTileMonitoringHooks - * This function takes a tile as input and adds the appropriate hooks to - * the tile so that the layer can keep track of the loading tile - * (making sure to check that the tile is always the layer's current - * tile before taking any action). - * - * Parameters: - * tile - {} - */ - addTileMonitoringHooks: function(tile) { - tile.onLoadStart = function() { - //if this is the the layer's current tile, then trigger - // a 'loadstart' - if (this == this.layer.tile) { - this.layer.events.triggerEvent("loadstart"); - } - }; - tile.events.register("loadstart", tile, tile.onLoadStart); - - tile.onLoadEnd = function() { - //if this is the the layer's current tile, then trigger - // a 'tileloaded' and 'loadend' - if (this == this.layer.tile) { - this.layer.events.triggerEvent("tileloaded"); - this.layer.events.triggerEvent("loadend"); - } - }; - tile.events.register("loadend", tile, tile.onLoadEnd); - tile.events.register("unload", tile, tile.onLoadEnd); - }, - - /** - * Method: removeTileMonitoringHooks - * This function takes a tile as input and removes the tile hooks - * that were added in addTileMonitoringHooks() - * - * Parameters: - * tile - {} - */ - removeTileMonitoringHooks: function(tile) { - tile.unload(); - tile.events.un({ - "loadstart": tile.onLoadStart, - "loadend": tile.onLoadEnd, - "unload": tile.onLoadEnd, - scope: tile - }); - }, - - /** - * Method: onMapResize - * Call the onMapResize method of the appropriate parent class. - */ - onMapResize: function() { - if(this.vectorMode) { - OpenLayers.Layer.Vector.prototype.onMapResize.apply(this, - arguments); - } else { - OpenLayers.Layer.Markers.prototype.onMapResize.apply(this, - arguments); - } - }, - - /** - * Method: display - * Call the display method of the appropriate parent class. - */ - display: function() { - if(this.vectorMode) { - OpenLayers.Layer.Vector.prototype.display.apply(this, - arguments); - } else { - OpenLayers.Layer.Markers.prototype.display.apply(this, - arguments); - } - }, - - /** - * APIMethod: mergeNewParams - * Modify parameters for the layer and redraw. - * - * Parameters: - * newParams - {Object} - */ - mergeNewParams:function(newParams) { - var upperParams = OpenLayers.Util.upperCaseObject(newParams); - var newArguments = [upperParams]; - return OpenLayers.Layer.HTTPRequest.prototype.mergeNewParams.apply(this, - newArguments); - }, - - /** - * APIMethod: clone - * - * Parameters: - * obj - {Object} - * - * Returns: - * {} An exact clone of this OpenLayers.Layer.WFS - */ - clone: function (obj) { - - if (obj == null) { - obj = new OpenLayers.Layer.WFS(this.name, - this.url, - this.params, - this.getOptions()); - } - - //get all additions from superclasses - if (this.vectorMode) { - obj = OpenLayers.Layer.Vector.prototype.clone.apply(this, [obj]); - } else { - obj = OpenLayers.Layer.Markers.prototype.clone.apply(this, [obj]); - } - - // copy/set any non-init, non-simple values here - - return obj; - }, - - /** - * APIMethod: getFullRequestString - * combine the layer's url with its params and these newParams. - * - * Add the SRS parameter from 'projection' -- this is probably - * more eloquently done via a setProjection() method, but this - * works for now and always. - * - * Parameters: - * newParams - {Object} - * altUrl - {String} Use this as the url instead of the layer's url - */ - getFullRequestString:function(newParams, altUrl) { - var projectionCode = this.projection.getCode() || this.map.getProjection(); - this.params.SRS = (projectionCode == "none") ? null : projectionCode; - - return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply( - this, arguments); - }, - - /** - * APIMethod: commit - * Write out the data to a WFS server. - */ - commit: function() { - if (!this.writer) { - var options = {}; - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { - options.externalProjection = this.projection; - options.internalProjection = this.map.getProjectionObject(); - } - - this.writer = new OpenLayers.Format.WFS(options,this); - } - - var data = this.writer.write(this.features); - - OpenLayers.Request.POST({ - url: this.url, - data: data, - success: this.commitSuccess, - failure: this.commitFailure, - scope: this - }); - }, - - /** - * Method: commitSuccess - * Called when the Ajax request returns a response - * - * Parameters: - * response - {XmlNode} from server - */ - commitSuccess: function(request) { - var response = request.responseText; - if (response.indexOf('SUCCESS') != -1) { - this.commitReport(OpenLayers.i18n("commitSuccess", {'response':response})); - - for(var i = 0; i < this.features.length; i++) { - this.features[i].state = null; - } - // TBD redraw the layer or reset the state of features - // foreach features: set state to null - } else if (response.indexOf('FAILED') != -1 || - response.indexOf('Exception') != -1) { - this.commitReport(OpenLayers.i18n("commitFailed", {'response':response})); - } - }, - - /** - * Method: commitFailure - * Called when the Ajax request fails - * - * Parameters: - * response - {XmlNode} from server - */ - commitFailure: function(request) {}, - - /** - * APIMethod: commitReport - * Called with a 'success' message if the commit succeeded, otherwise - * a failure message, and the full request text as a second parameter. - * Override this function to provide custom transaction reporting. - * - * string - {String} reporting string - * response - {String} full XML response - */ - commitReport: function(string, response) { - OpenLayers.Console.userError(string); - }, - - - /** - * APIMethod: refresh - * Refreshes all the features of the layer - */ - refresh: function() { - if (this.tile) { - if (this.vectorMode) { - this.renderer.clear(); - this.features.length = 0; - } else { - this.clearMarkers(); - this.markers.length = 0; - } - this.tile.draw(); - } - }, - - /** - * APIMethod: getDataExtent - * Calculates the max extent which includes all of the layer data. - * - * Returns: - * {} - */ - getDataExtent: function () { - var extent; - //get all additions from superclasses - if (this.vectorMode) { - extent = OpenLayers.Layer.Vector.prototype.getDataExtent.apply(this); - } else { - extent = OpenLayers.Layer.Markers.prototype.getDataExtent.apply(this); - } - - return extent; - }, - - /** - * APIMethod: setOpacity - * Call the setOpacity method of the appropriate parent class to set the - * opacity. - * - * Parameter: - * opacity - {Float} - */ - setOpacity: function (opacity) { - if (this.vectorMode) { - OpenLayers.Layer.Vector.prototype.setOpacity.apply(this, [opacity]); - } else { - OpenLayers.Layer.Markers.prototype.setOpacity.apply(this, [opacity]); - } - }, - - CLASS_NAME: "OpenLayers.Layer.WFS" -}); diff --git a/lib/OpenLayers/Tile/WFS.js b/lib/OpenLayers/Tile/WFS.js deleted file mode 100644 index d892a08f99..0000000000 --- a/lib/OpenLayers/Tile/WFS.js +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright (c) 2006-2011 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/Tile.js - * @requires OpenLayers/Request/XMLHttpRequest.js - */ - -/** - * Class: OpenLayers.Tile.WFS - * Instances of OpenLayers.Tile.WFS are used to manage the image tiles - * used by various layers. Create a new image tile with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Tile.WFS = OpenLayers.Class(OpenLayers.Tile, { - - /** - * Property: features - * {Array()} list of features in this tile - */ - features: null, - - /** - * Property: url - * {String} - */ - url: null, - - /** - * Property: request - * {} - */ - request: null, - - /** TBD 3.0 - reorder the parameters to the init function to put URL - * as last, so we can continue to call tile.initialize() - * without changing the arguments. - * - * Constructor: OpenLayers.Tile.WFS - * Constructor for a new instance. - * - * Parameters: - * layer - {} layer that the tile will go in. - * position - {} - * bounds - {} - * url - {} - * size - {} - */ - initialize: function(layer, position, bounds, url, size) { - OpenLayers.Tile.prototype.initialize.apply(this, arguments); - this.url = url; - this.features = []; - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - OpenLayers.Tile.prototype.destroy.apply(this, arguments); - this.destroyAllFeatures(); - this.features = null; - this.url = null; - if(this.request) { - this.request.abort(); - //this.request.destroy(); - this.request = null; - } - }, - - /** - * Method: clear - * Clear the tile of any bounds/position-related data so that it can - * be reused in a new location. - */ - clear: function() { - this.destroyAllFeatures(); - }, - - /** - * Method: draw - * Check that a tile should be drawn, and load features for it. - */ - draw:function() { - if (OpenLayers.Tile.prototype.draw.apply(this, arguments)) { - if (this.isLoading) { - //if already loading, send 'reload' instead of 'loadstart'. - this.events.triggerEvent("reload"); - } else { - this.isLoading = true; - this.events.triggerEvent("loadstart"); - } - this.loadFeaturesForRegion(this.requestSuccess); - } - }, - - /** - * Method: loadFeaturesForRegion - * Abort any pending requests and issue another request for data. - * - * Input are function pointers for what to do on success and failure. - * - * Parameters: - * success - {function} - * failure - {function} - */ - loadFeaturesForRegion:function(success, failure) { - if(this.request) { - this.request.abort(); - } - this.request = OpenLayers.Request.GET({ - url: this.url, - success: success, - failure: failure, - scope: this - }); - }, - - /** - * Method: requestSuccess - * Called on return from request succcess. Adds results via - * layer.addFeatures in vector mode, addResults otherwise. - * - * Parameters: - * request - {} - */ - requestSuccess:function(request) { - if (this.features) { - var doc = request.responseXML; - if (!doc || !doc.documentElement) { - doc = request.responseText; - } - if (this.layer.vectorMode) { - this.layer.addFeatures(this.layer.formatObject.read(doc)); - } else { - var xml = new OpenLayers.Format.XML(); - if (typeof doc == "string") { - doc = xml.read(doc); - } - var resultFeatures = xml.getElementsByTagNameNS( - doc, "http://www.opengis.net/gml", "featureMember" - ); - this.addResults(resultFeatures); - } - } - if (this.events) { - this.events.triggerEvent("loadend"); - } - - //request produced with success, we can delete the request object. - //this.request.destroy(); - this.request = null; - }, - - /** - * Method: addResults - * Construct new feature via layer featureClass constructor, and add to - * this.features. - * - * Parameters: - * results - {Object} - */ - addResults: function(results) { - for (var i=0; i < results.length; i++) { - var feature = new this.layer.featureClass(this.layer, - results[i]); - this.features.push(feature); - } - }, - - - /** - * Method: destroyAllFeatures - * Iterate through and call destroy() on each feature, removing it from - * the local array - */ - destroyAllFeatures: function() { - while(this.features.length > 0) { - var feature = this.features.shift(); - feature.destroy(); - } - }, - - CLASS_NAME: "OpenLayers.Tile.WFS" - } -); diff --git a/lib/deprecated.js b/lib/deprecated.js index 11a80ed00c..20243ea459 100644 --- a/lib/deprecated.js +++ b/lib/deprecated.js @@ -6,6 +6,12 @@ * @requires OpenLayers/Request.js * @requires OpenLayers/Layer/WMS.js * @requires OpenLayers/Layer/MapServer.js + * @requires OpenLayers/Tile.js + * @requires OpenLayers/Request/XMLHttpRequest.js + * @requires OpenLayers/Layer/Vector.js + * @requires OpenLayers/Layer/Markers.js + * @requires OpenLayers/Console.js + * @requires OpenLayers/Lang.js */ /** @@ -1969,3 +1975,782 @@ OpenLayers.Layer.MapServer.Untiled = OpenLayers.Class(OpenLayers.Layer.MapServer CLASS_NAME: "OpenLayers.Layer.MapServer.Untiled" }); + +/** + * Class: OpenLayers.Tile.WFS + * Instances of OpenLayers.Tile.WFS are used to manage the image tiles + * used by various layers. Create a new image tile with the + * constructor. + * + * Inherits from: + * - + */ +OpenLayers.Tile.WFS = OpenLayers.Class(OpenLayers.Tile, { + + /** + * Property: features + * {Array()} list of features in this tile + */ + features: null, + + /** + * Property: url + * {String} + */ + url: null, + + /** + * Property: request + * {} + */ + request: null, + + /** TBD 3.0 - reorder the parameters to the init function to put URL + * as last, so we can continue to call tile.initialize() + * without changing the arguments. + * + * Constructor: OpenLayers.Tile.WFS + * Constructor for a new instance. + * + * Parameters: + * layer - {} layer that the tile will go in. + * position - {} + * bounds - {} + * url - {} + * size - {} + */ + initialize: function(layer, position, bounds, url, size) { + OpenLayers.Tile.prototype.initialize.apply(this, arguments); + this.url = url; + this.features = []; + }, + + /** + * APIMethod: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + OpenLayers.Tile.prototype.destroy.apply(this, arguments); + this.destroyAllFeatures(); + this.features = null; + this.url = null; + if(this.request) { + this.request.abort(); + //this.request.destroy(); + this.request = null; + } + }, + + /** + * Method: clear + * Clear the tile of any bounds/position-related data so that it can + * be reused in a new location. + */ + clear: function() { + this.destroyAllFeatures(); + }, + + /** + * Method: draw + * Check that a tile should be drawn, and load features for it. + */ + draw:function() { + if (OpenLayers.Tile.prototype.draw.apply(this, arguments)) { + if (this.isLoading) { + //if already loading, send 'reload' instead of 'loadstart'. + this.events.triggerEvent("reload"); + } else { + this.isLoading = true; + this.events.triggerEvent("loadstart"); + } + this.loadFeaturesForRegion(this.requestSuccess); + } + }, + + /** + * Method: loadFeaturesForRegion + * Abort any pending requests and issue another request for data. + * + * Input are function pointers for what to do on success and failure. + * + * Parameters: + * success - {function} + * failure - {function} + */ + loadFeaturesForRegion:function(success, failure) { + if(this.request) { + this.request.abort(); + } + this.request = OpenLayers.Request.GET({ + url: this.url, + success: success, + failure: failure, + scope: this + }); + }, + + /** + * Method: requestSuccess + * Called on return from request succcess. Adds results via + * layer.addFeatures in vector mode, addResults otherwise. + * + * Parameters: + * request - {} + */ + requestSuccess:function(request) { + if (this.features) { + var doc = request.responseXML; + if (!doc || !doc.documentElement) { + doc = request.responseText; + } + if (this.layer.vectorMode) { + this.layer.addFeatures(this.layer.formatObject.read(doc)); + } else { + var xml = new OpenLayers.Format.XML(); + if (typeof doc == "string") { + doc = xml.read(doc); + } + var resultFeatures = xml.getElementsByTagNameNS( + doc, "http://www.opengis.net/gml", "featureMember" + ); + this.addResults(resultFeatures); + } + } + if (this.events) { + this.events.triggerEvent("loadend"); + } + + //request produced with success, we can delete the request object. + //this.request.destroy(); + this.request = null; + }, + + /** + * Method: addResults + * Construct new feature via layer featureClass constructor, and add to + * this.features. + * + * Parameters: + * results - {Object} + */ + addResults: function(results) { + for (var i=0; i < results.length; i++) { + var feature = new this.layer.featureClass(this.layer, + results[i]); + this.features.push(feature); + } + }, + + + /** + * Method: destroyAllFeatures + * Iterate through and call destroy() on each feature, removing it from + * the local array + */ + destroyAllFeatures: function() { + while(this.features.length > 0) { + var feature = this.features.shift(); + feature.destroy(); + } + }, + + CLASS_NAME: "OpenLayers.Tile.WFS" + } +); + +/** + * Class: OpenLayers.Layer.WFS + * *Deprecated*. To be removed in 3.0. Instead use OpenLayers.Layer.Vector + * with a Protocol.WFS and one or more Strategies. + * + * Inherits from: + * - + * - + */ +OpenLayers.Layer.WFS = OpenLayers.Class( + OpenLayers.Layer.Vector, OpenLayers.Layer.Markers, { + + /** + * APIProperty: isBaseLayer + * {Boolean} WFS layer is not a base layer by default. + */ + isBaseLayer: false, + + /** + * Property: tile + * {} + */ + tile: null, + + /** + * APIProperty: ratio + * {Float} The ratio property determines the size of the serverside query + * relative to the map viewport size. By default, we load an area twice + * as big as the map, to allow for panning without immediately reload. + * Setting this to 1 will cause the area of the WFS request to match + * the map area exactly. It is recommended to set this to some number + * at least slightly larger than 1, otherwise accidental clicks can + * cause a data reload, by moving the map only 1 pixel. + */ + ratio: 2, + + /** + * Property: DEFAULT_PARAMS + * {Object} Hashtable of default key/value parameters + */ + DEFAULT_PARAMS: { service: "WFS", + version: "1.0.0", + request: "GetFeature" + }, + + /** + * APIProperty: featureClass + * {} If featureClass is defined, an old-style markers + * based WFS layer is created instead of a new-style vector layer. If + * sent, this should be a subclass of OpenLayers.Feature + */ + featureClass: null, + + /** + * APIProperty: format + * {} The format you want the data to be parsed with. + * Must be passed in the constructor. Should be a class, not an instance. + * This option can only be used if no featureClass is passed / vectorMode + * is false: if a featureClass is passed, then this parameter is ignored. + */ + format: null, + + /** + * Property: formatObject + * {} Internally created/managed format object, used by + * the Tile to parse data. + */ + formatObject: null, + + /** + * APIProperty: formatOptions + * {Object} Hash of options which should be passed to the format when it is + * created. Must be passed in the constructor. + */ + formatOptions: null, + + /** + * Property: vectorMode + * {Boolean} Should be calculated automatically. Determines whether the + * layer is in vector mode or marker mode. + */ + vectorMode: true, + + /** + * APIProperty: encodeBBOX + * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no', + * but some services want it that way. Default false. + */ + encodeBBOX: false, + + /** + * APIProperty: extractAttributes + * {Boolean} Should the WFS layer parse attributes from the retrieved + * GML? Defaults to false. If enabled, parsing is slower, but + * attributes are available in the attributes property of + * layer features. + */ + extractAttributes: false, + + /** + * Constructor: OpenLayers.Layer.WFS + * + * Parameters: + * name - {String} + * url - {String} + * params - {Object} + * options - {Object} Hashtable of extra options to tag onto the layer + */ + initialize: function(name, url, params, options) { + if (options == undefined) { options = {}; } + + if (options.featureClass || + !OpenLayers.Layer.Vector || + !OpenLayers.Feature.Vector) { + this.vectorMode = false; + } + + // Uppercase params + params = OpenLayers.Util.upperCaseObject(params); + + // Turn off error reporting, browsers like Safari may work + // depending on the setup, and we don't want an unneccesary alert. + OpenLayers.Util.extend(options, {'reportError': false}); + var newArguments = []; + newArguments.push(name, options); + OpenLayers.Layer.Vector.prototype.initialize.apply(this, newArguments); + if (!this.renderer || !this.vectorMode) { + this.vectorMode = false; + if (!options.featureClass) { + options.featureClass = OpenLayers.Feature.WFS; + } + OpenLayers.Layer.Markers.prototype.initialize.apply(this, + newArguments); + } + + if (this.params && this.params.typename && !this.options.typename) { + this.options.typename = this.params.typename; + } + + if (!this.options.geometry_column) { + this.options.geometry_column = "the_geom"; + } + + this.params = OpenLayers.Util.applyDefaults( + params, + OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS) + ); + this.url = url; + }, + + + /** + * APIMethod: destroy + */ + destroy: function() { + if (this.vectorMode) { + OpenLayers.Layer.Vector.prototype.destroy.apply(this, arguments); + } else { + OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); + } + if (this.tile) { + this.tile.destroy(); + } + this.tile = null; + + this.ratio = null; + this.featureClass = null; + this.format = null; + + if (this.formatObject && this.formatObject.destroy) { + this.formatObject.destroy(); + } + this.formatObject = null; + + this.formatOptions = null; + this.vectorMode = null; + this.encodeBBOX = null; + this.extractAttributes = null; + }, + + /** + * Method: setMap + * + * Parameters: + * map - {} + */ + setMap: function(map) { + if (this.vectorMode) { + OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); + + var options = { + 'extractAttributes': this.extractAttributes + }; + + OpenLayers.Util.extend(options, this.formatOptions); + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { + options.externalProjection = this.projection; + options.internalProjection = this.map.getProjectionObject(); + } + + this.formatObject = this.format ? new this.format(options) : new OpenLayers.Format.GML(options); + } else { + OpenLayers.Layer.Markers.prototype.setMap.apply(this, arguments); + } + }, + + /** + * Method: moveTo + * + * Parameters: + * bounds - {} + * zoomChanged - {Boolean} + * dragging - {Boolean} + */ + moveTo:function(bounds, zoomChanged, dragging) { + if (this.vectorMode) { + OpenLayers.Layer.Vector.prototype.moveTo.apply(this, arguments); + } else { + OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); + } + + // don't load wfs features while dragging, wait for drag end + if (dragging) { + // TBD try to hide the vector layer while dragging + // this.setVisibility(false); + // this will probably help for panning performances + return false; + } + + if ( zoomChanged ) { + if (this.vectorMode) { + this.renderer.clear(); + } + } + + //DEPRECATED - REMOVE IN 3.0 + // don't load data if current zoom level doesn't match + if (this.options.minZoomLevel) { + OpenLayers.Console.warn(OpenLayers.i18n('minZoomLevelError')); + + if (this.map.getZoom() < this.options.minZoomLevel) { + return null; + } + } + + if (bounds == null) { + bounds = this.map.getExtent(); + } + + var firstRendering = (this.tile == null); + + //does the new bounds to which we need to move fall outside of the + // current tile's bounds? + var outOfBounds = (!firstRendering && + !this.tile.bounds.containsBounds(bounds)); + + if (zoomChanged || firstRendering || (!dragging && outOfBounds)) { + //determine new tile bounds + var center = bounds.getCenterLonLat(); + var tileWidth = bounds.getWidth() * this.ratio; + var tileHeight = bounds.getHeight() * this.ratio; + var tileBounds = + new OpenLayers.Bounds(center.lon - (tileWidth / 2), + center.lat - (tileHeight / 2), + center.lon + (tileWidth / 2), + center.lat + (tileHeight / 2)); + + //determine new tile size + var tileSize = this.map.getSize(); + tileSize.w = tileSize.w * this.ratio; + tileSize.h = tileSize.h * this.ratio; + + //determine new position (upper left corner of new bounds) + var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top); + var pos = this.map.getLayerPxFromLonLat(ul); + + //formulate request url string + var url = this.getFullRequestString(); + + var params = null; + + // Cant combine "filter" and "BBOX". This is a cheap hack to help + // people out who can't migrate to the WFS protocol immediately. + var filter = this.params.filter || this.params.FILTER; + if (filter) { + params = {FILTER: filter}; + } + else { + params = {BBOX: this.encodeBBOX ? tileBounds.toBBOX() + : tileBounds.toArray()}; + } + + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { + var projectedBounds = tileBounds.clone(); + projectedBounds.transform(this.map.getProjectionObject(), + this.projection); + if (!filter){ + params.BBOX = this.encodeBBOX ? projectedBounds.toBBOX() + : projectedBounds.toArray(); + } + } + + url += "&" + OpenLayers.Util.getParameterString(params); + + if (!this.tile) { + this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds, + url, tileSize); + this.addTileMonitoringHooks(this.tile); + this.tile.draw(); + } else { + if (this.vectorMode) { + this.destroyFeatures(); + this.renderer.clear(); + } else { + this.clearMarkers(); + } + this.removeTileMonitoringHooks(this.tile); + this.tile.destroy(); + + this.tile = null; + this.tile = new OpenLayers.Tile.WFS(this, pos, tileBounds, + url, tileSize); + this.addTileMonitoringHooks(this.tile); + this.tile.draw(); + } + } + }, + + /** + * Method: addTileMonitoringHooks + * This function takes a tile as input and adds the appropriate hooks to + * the tile so that the layer can keep track of the loading tile + * (making sure to check that the tile is always the layer's current + * tile before taking any action). + * + * Parameters: + * tile - {} + */ + addTileMonitoringHooks: function(tile) { + tile.onLoadStart = function() { + //if this is the the layer's current tile, then trigger + // a 'loadstart' + if (this == this.layer.tile) { + this.layer.events.triggerEvent("loadstart"); + } + }; + tile.events.register("loadstart", tile, tile.onLoadStart); + + tile.onLoadEnd = function() { + //if this is the the layer's current tile, then trigger + // a 'tileloaded' and 'loadend' + if (this == this.layer.tile) { + this.layer.events.triggerEvent("tileloaded"); + this.layer.events.triggerEvent("loadend"); + } + }; + tile.events.register("loadend", tile, tile.onLoadEnd); + tile.events.register("unload", tile, tile.onLoadEnd); + }, + + /** + * Method: removeTileMonitoringHooks + * This function takes a tile as input and removes the tile hooks + * that were added in addTileMonitoringHooks() + * + * Parameters: + * tile - {} + */ + removeTileMonitoringHooks: function(tile) { + tile.unload(); + tile.events.un({ + "loadstart": tile.onLoadStart, + "loadend": tile.onLoadEnd, + "unload": tile.onLoadEnd, + scope: tile + }); + }, + + /** + * Method: onMapResize + * Call the onMapResize method of the appropriate parent class. + */ + onMapResize: function() { + if(this.vectorMode) { + OpenLayers.Layer.Vector.prototype.onMapResize.apply(this, + arguments); + } else { + OpenLayers.Layer.Markers.prototype.onMapResize.apply(this, + arguments); + } + }, + + /** + * Method: display + * Call the display method of the appropriate parent class. + */ + display: function() { + if(this.vectorMode) { + OpenLayers.Layer.Vector.prototype.display.apply(this, + arguments); + } else { + OpenLayers.Layer.Markers.prototype.display.apply(this, + arguments); + } + }, + + /** + * APIMethod: mergeNewParams + * Modify parameters for the layer and redraw. + * + * Parameters: + * newParams - {Object} + */ + mergeNewParams:function(newParams) { + var upperParams = OpenLayers.Util.upperCaseObject(newParams); + var newArguments = [upperParams]; + return OpenLayers.Layer.HTTPRequest.prototype.mergeNewParams.apply(this, + newArguments); + }, + + /** + * APIMethod: clone + * + * Parameters: + * obj - {Object} + * + * Returns: + * {} An exact clone of this OpenLayers.Layer.WFS + */ + clone: function (obj) { + + if (obj == null) { + obj = new OpenLayers.Layer.WFS(this.name, + this.url, + this.params, + this.getOptions()); + } + + //get all additions from superclasses + if (this.vectorMode) { + obj = OpenLayers.Layer.Vector.prototype.clone.apply(this, [obj]); + } else { + obj = OpenLayers.Layer.Markers.prototype.clone.apply(this, [obj]); + } + + // copy/set any non-init, non-simple values here + + return obj; + }, + + /** + * APIMethod: getFullRequestString + * combine the layer's url with its params and these newParams. + * + * Add the SRS parameter from 'projection' -- this is probably + * more eloquently done via a setProjection() method, but this + * works for now and always. + * + * Parameters: + * newParams - {Object} + * altUrl - {String} Use this as the url instead of the layer's url + */ + getFullRequestString:function(newParams, altUrl) { + var projectionCode = this.projection.getCode() || this.map.getProjection(); + this.params.SRS = (projectionCode == "none") ? null : projectionCode; + + return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply( + this, arguments); + }, + + /** + * APIMethod: commit + * Write out the data to a WFS server. + */ + commit: function() { + if (!this.writer) { + var options = {}; + if (this.map && !this.projection.equals(this.map.getProjectionObject())) { + options.externalProjection = this.projection; + options.internalProjection = this.map.getProjectionObject(); + } + + this.writer = new OpenLayers.Format.WFS(options,this); + } + + var data = this.writer.write(this.features); + + OpenLayers.Request.POST({ + url: this.url, + data: data, + success: this.commitSuccess, + failure: this.commitFailure, + scope: this + }); + }, + + /** + * Method: commitSuccess + * Called when the Ajax request returns a response + * + * Parameters: + * response - {XmlNode} from server + */ + commitSuccess: function(request) { + var response = request.responseText; + if (response.indexOf('SUCCESS') != -1) { + this.commitReport(OpenLayers.i18n("commitSuccess", {'response':response})); + + for(var i = 0; i < this.features.length; i++) { + this.features[i].state = null; + } + // TBD redraw the layer or reset the state of features + // foreach features: set state to null + } else if (response.indexOf('FAILED') != -1 || + response.indexOf('Exception') != -1) { + this.commitReport(OpenLayers.i18n("commitFailed", {'response':response})); + } + }, + + /** + * Method: commitFailure + * Called when the Ajax request fails + * + * Parameters: + * response - {XmlNode} from server + */ + commitFailure: function(request) {}, + + /** + * APIMethod: commitReport + * Called with a 'success' message if the commit succeeded, otherwise + * a failure message, and the full request text as a second parameter. + * Override this function to provide custom transaction reporting. + * + * string - {String} reporting string + * response - {String} full XML response + */ + commitReport: function(string, response) { + OpenLayers.Console.userError(string); + }, + + + /** + * APIMethod: refresh + * Refreshes all the features of the layer + */ + refresh: function() { + if (this.tile) { + if (this.vectorMode) { + this.renderer.clear(); + this.features.length = 0; + } else { + this.clearMarkers(); + this.markers.length = 0; + } + this.tile.draw(); + } + }, + + /** + * APIMethod: getDataExtent + * Calculates the max extent which includes all of the layer data. + * + * Returns: + * {} + */ + getDataExtent: function () { + var extent; + //get all additions from superclasses + if (this.vectorMode) { + extent = OpenLayers.Layer.Vector.prototype.getDataExtent.apply(this); + } else { + extent = OpenLayers.Layer.Markers.prototype.getDataExtent.apply(this); + } + + return extent; + }, + + /** + * APIMethod: setOpacity + * Call the setOpacity method of the appropriate parent class to set the + * opacity. + * + * Parameter: + * opacity - {Float} + */ + setOpacity: function (opacity) { + if (this.vectorMode) { + OpenLayers.Layer.Vector.prototype.setOpacity.apply(this, [opacity]); + } else { + OpenLayers.Layer.Markers.prototype.setOpacity.apply(this, [opacity]); + } + }, + + CLASS_NAME: "OpenLayers.Layer.WFS" +}); diff --git a/tests/Layer/WFS.html b/tests/deprecated/Layer/WFS.html similarity index 98% rename from tests/Layer/WFS.html rename to tests/deprecated/Layer/WFS.html index 42b566acfe..09b6a541dc 100644 --- a/tests/Layer/WFS.html +++ b/tests/deprecated/Layer/WFS.html @@ -1,6 +1,7 @@ - + + + +