/* Copyright (c) 2009- Boreal - Information Strategies, published under the BSD license. See http://geoprisma.org/license for the full text of the license. */ /** * @requires OpenLayers/Handler/Click.js */ /** * Class: OpenLayers.Control.QueryOnClick * * Inherits From: * - */ OpenLayers.Control.QueryOnClick = OpenLayers.Class(OpenLayers.Control, { /** * Constant: EVENT_TYPES * * Supported event types: * afterqueries - Triggered after all queries were completed. The event * object is an array of feature properties of the returned features. */ EVENT_TYPES: ["afterqueries"], /** * Constant: DEFAULT_PARAMS * {Object} Hashtable of default parameter key/value pairs */ DEFAULT_PARAMS: { VERSION: "1.0.0", REQUEST: "GetFeatureInfo", EXCEPTIONS: "application/vnd.ogc.se_xml", FORMAT: "image/jpeg", INFO_FORMAT: 'application/vnd.ogc.gml', STYLES: "", FEATURE_COUNT: 1000 }, /* const: i18n_wait_options_msg {String} Wait msg */ i18n_wait_options_msg : "Query in progress, please wait...", /* const: i18n_wait_options_progress_text {String} Wait progress text */ i18n_wait_options_progress_text : "Loading...", /* const: i18n_wait_options_completed_text {String} Completed : */ i18n_wait_options_completed_text : "Completed : ", /* const: i18n_wait_options_of_text {String} of */ i18n_wait_options_of_text : " of ", /* const: i18n_no_layer_queryable {String} No layer is queryable */ i18n_no_layer_queryable : "No layer currently queryable.", /* const: i18n_warning {String} Warning text */ i18n_warning : "Warning", /* const: i18n_message_no_result_msg {String} No result message */ i18n_message_no_result_msg : "Your search did not match any records.", /* const: i18n_message_no_result_title {String} No result title */ i18n_message_no_result_title : "No record found", /** * Property: APIProperty: drawMode * {string} */ drawMode: null, /** * Property: queryablelayers * {Array(String)} Layers that are queryable with GetFeatureInfo requests */ queryablelayertypes : ["OpenLayers.Layer.WMS", "OpenLayers.Layer.WMS.Untiled", "OpenLayers.Layer.MapServer"], /** * Property: markerLayer * {} Layer used to point a marker where the user * clicked. */ markerLayer: null, /** * Property: marker * {} Point feature created/updated on click */ marker: null, /** * APIProperty: resources * {Array()} Array of queryable resource objects. */ resources: null, /** * APIProperty: resources * {Array()} Array resource objects ready to be queried. */ resourcestoquery: null, /** * APIProperty: lastEvt * {Event} Last event queried. */ lastEvt: null, /** * Property: results * {Array()} An array of Result objects used to render * the results of the query. */ results: null, /** * Property: queries * {Integer} The number of queries received. As soon as this number is * equal to the length of the resourcestoquery array, that means * all responses were received. */ queries: 0, /** * Property: errors * {Integer} When an error occurs on the response of a query, this number is * incremented. */ errors: 0, /** * Property: features * {Array()} Array of features created from the * responses received. */ features: null, /** * Property: features * {Array(String)} Array of html results returned by queries using * 'text/html' info_format parameter. */ htmlResults: null, /** * Property: featurepanels * {Array()} Array of FeaturePanel objects used to * render the results of the query. */ featurepanels: null, /** * Property: getFeaturesResource * {Array()} Array of functions to forward the resource * to getFeatures. */ getFeaturesResource: null, /** * APIProperty: resetOnDeactivation * {String} Defines what to reset when this widget is deactivated. */ resetOnDeactivation: null, /** * APIProperty: markerStyle * {Object} Used for the StyleMap for the markerLayer. If none is providen, * DEFAULT_MARKER_STYLE is used. */ markerStyle: null, /** * Property: DEFAULT_MARKER_STYLE * {Object} Used for the StyleMap for the markerLayer if no markerStyle is * providen. */ DEFAULT_MARKER_STYLE : { graphicWidth: 21, graphicHeight: 25, graphicYOffset: -25, externalGraphic: OpenLayers.ImgPath+"marker.png" }, /** * APIProperty: noMarker * {Boolean} If set to true, no marker layer is created. */ noMarker: false, /** * Property: progressBar * {Ext.ProgressBar} */ progressBar: null, /** * APIProperty: multipleKey * {String} An event modifier ('altKey', 'shiftKey' or 'ctrlKey') that * temporarily sets the property to true. Default is null. */ multipleKey: null, /** * APIProperty: toggleKey * {String} An event modifier ('altKey', 'shiftKey' or 'ctrlKey') that * temporarily sets the property to true. Default is null. */ toggleKey: null, /** * Property: modifiers * {Object} The event modifiers to use, according to the current event * being handled by this control's handlers */ modifiers: null, /** * APIProperty: multiQueryResource * {String} when in 'multiple' mode, query this resource only if this * property is set. Defaults to null. */ multiQueryResource: null, /** * APIProperty: multiple * {Boolean} Allow selection of multiple features. Default is false. */ multiple: false, /** * APIProperty: toggle * {Boolean} Unselect a selected feature on click. Default is false. */ toggle: false, /** * Constructor: OpenLayers.Control.QueryOnClick * Create a new QueryOnClick control. * * Parameters: * options - {Object} Optional object whose properties will be set on the * control. */ initialize: function(options) { OpenLayers.Control.prototype.initialize.apply(this, [options]); this.resourcestoquery = []; this.features = []; this.htmlResults = []; this.resources = this.resources || []; this.results = []; this.featurepanels = []; this.getFeaturesResource = []; if(this.noMarker !== true) { // markerStyle var markerStyle; if(this.markerStyle || this.markerStyle != null) { markerStyle = this.markerStyle; } else { markerStyle = this.DEFAULT_MARKER_STYLE; } var styleMap = new OpenLayers.StyleMap({ "default": markerStyle }); this.markerLayer = new OpenLayers.Layer.Vector( "QueryOnClick_Marker", { displayInLayerSwitcher: false, styleMap: styleMap } ); } // Handler.Click var callbacks = { click: this.onClick }; var options = { delay: 0 }; this.handler = new OpenLayers.Handler.Click(this, callbacks, options); // resetOnDeactivation events listeners switch(this.resetOnDeactivation) { case "marker": this.events.register("deactivate", this, this.removeMarker); break; case "all": this.events.register("deactivate", this, function() { this.resetQueryData({"modifiers": {"multiple": false}}); this.resetFeatures(); }); break; } }, /** * Method: getResourceNameByLayer * Returns the resource name of a layer given a service type. * * Parameters: * szLayer - {String} The server-side layer name * szServiceType - {String} The service type (i.e. "wms") * * Returns: * {String} The resource name */ getResourceNameByLayer: function(szLayer, szServiceType){ for(var i=0; i} The result object to add */ addResult: function(result){ this.results.push(result); }, /** * APIMethod: addResults * Add the results to this.results array. * * Parameters: * results - {Array()} The result object to add */ addResults: function(results){ for(var i=0, len=results.length; i} The featurepanel object to add */ addFeaturePanel: function(featurepanel){ this.featurepanels.push(featurepanel); }, /** * Method: onClick * Called by this click handler when the user click the map. * * First, the current query data is reset and all result panels are reset * too. Second, each resources are validated : is there a layer currently * visible that has the resource ? Third, all queryable resource builds a * query and send it. */ onClick: function(evt) { this.setModifiers(evt); // always reset all results before making any query this.resetQueryData(); // Reset the query data and all results panels if (!this.modifiers.multiple) { this.resetFeatures(); } this.lastEvt = evt; var lonlat = this.map.getLonLatFromPixel(evt.xy); /** * RESOURCE VALIDATION * First, browse each resource. If a layer that has the resource is * queryable, add it to the resources to query. */ for (var i=0, len = this.resources.length; i= 1.3) { objParams['EXCEPTIONS'] = "INIMAGE"; } var strParams = OpenLayers.Util.getParameterString(objParams); if(strParams.length > 0) { var strSeparator = (szURL.indexOf('?') > -1) ? '&' : '?'; szURL += strSeparator + strParams; } this.getFeaturesResource[oResource.resource] = new Function("response","this.getFeatures(response,'"+oResource.resource+"');"); OpenLayers.loadURL(szURL, '', this, this.getFeaturesResource[oResource.resource], this.onError); } }, /** * Method: getFeatures * Retreive the features from the query response and add them to * this.features. The number of result received is incremented * (this.queries). When the last result is received, the method showResult * is called. * * Parameters: * response - {AJAX} Ajax response * resource - {String} Name of the resource */ getFeatures: function(response, resource){ var oResource = this.getResourceByName(resource); if (oResource['wms']['info_format'] != "text/html") { var oFormat = new OpenLayers.Format.WMSGetFeatureInfo(); var oFeatures = oFormat.read(response.responseXML || response.responseText); var feature; for (var i=0, nbFeatures=oFeatures.length; i} Hash of options. Possible keys are : * - modifiers : the query modifiers */ resetResults: function(options) { options = options || {}; for(var i=0, len=this.results.length; i} Hash of options. Possible keys are : * - modifiers : the query modifiers */ resetQueryData: function(options) { options = options || {"modifiers": this.modifiers}; this.resourcestoquery = []; this.queries = 0; this.errors = 0; this.resetResults(options); }, /** * Method: resetQueryData * Reset 'feature-related' properties, such as : removing markers, reseting * features and htmlResults */ resetFeatures: function() { for (var i=this.features.length; i>0; i--) { this.features[i-1].destroy(); } this.features = []; this.htmlResults = []; this.removeMarker(); }, /** * Method: showResult * If results were found, add a marker where the user clicked and call each * result "showResult" function. */ showResult: function(){ // if no records were found if (this.features.length == 0 && this.htmlResults.length == 0) { this.hideWaitMessageBox(); // TODO : this is HARDCODED var szMessage = this.i18n_message_no_result_msg; var szTitle = this.i18n_message_no_result_title; if(this.errors == 1){ szMessage += " "+this.errors+" occured."; szTitle += " and error"; } else if (this.errors > 1){ szMessage += " "+this.errors+" occured."; szTitle += " and errors"; } this.showMessage(szTitle, szMessage); return; } if(this.noMarker !== true) { this.markerLayer.addFeatures([this.marker]); } // execute each results (using features and htmlResults returned) for(var i=0, len=this.results.length; i 0){ // TODO this is HARDCODED var szMessage = this.errors+" error"; var szTitle = "Error"; if(this.errors == 1){ szMessage += " occured."; } else { szMessage += "s occured"; szTitle += "s"; } this.showMessage(szTitle, szMessage); } }, /** * Method: showWaitMessageBox * Shows a "wait message" in a Ext.Window with a ProgressBar. */ showWaitMessageBox: function() { this.waitmessagebox = new Ext.Window({ title: this.i18n_wait_options_msg, width: '200', modal: true, closable: false, closeAction: 'hide', items:[ new Ext.ProgressBar({ text: this.i18n_wait_options_progress_text, id:'queryonclick-pbar', xtype: 'progress', cls:'left-align' }) ] }); this.updateProgressBar(); this.waitmessagebox.show(); }, /** * Method: hideWaitMessageBox * Hides the "wait message" Ext.Window. */ hideWaitMessageBox: function() { this.waitmessagebox.hide(); }, /** * Method: updateProgressBar * Update the "wait message" window with the current queries completed. */ updateProgressBar: function() { var nCurrent = this.queries; var nCount = this.resourcestoquery.length; var szMessage = this.i18n_wait_options_completed_text + nCurrent + this.i18n_wait_options_of_text + nCount + '...'; var oProgressBar = Ext.getCmp('queryonclick-pbar'); oProgressBar.updateProgress(nCurrent/nCount, szMessage); }, /** * Method: setMap * Set the map property for the control and all handlers. * * Parameters: * map - {} The control's map. */ setMap: function(map) { if(this.noMarker !== true) { map.addLayer(this.markerLayer); } this.handler.setMap(map); OpenLayers.Control.prototype.setMap.apply(this, arguments); }, /** * Method: getResourceByName * Returns the resource object inside this widget using its name. If not * found, returns false. * * Parameters: * resourceName - {String} The name of the resource to look for * * Return: * {Object} The resource object contained in this widget or false if not * found. */ getResourceByName: function(resourceName) { for (var i=0, len=this.resources.length; i} */ setModifiers: function(evt) { this.modifiers = { multiple: this.multiple || (this.multipleKey && evt[this.multipleKey]), toggle: this.toggle || (this.toggleKey && evt[this.toggleKey]) }; }, /** * APIMethod: getFeatureByResourceAndFid * Given a feature resource and fid, return the feature if it exists in the * features array * * Parameters: * resource - {String} The feature resource name * fid - {String} The feature fid * * Returns: * {} A feature corresponding to the given * fid and resource or null if there is no such feature. */ getFeatureByResourceAndFid: function(resource, fid) { var feature = null; for (var i=0, len=this.features.length; i