Source: widgets/SpwWriterQueryForm.js

Retour à la documentation
/**
 * @class spw.widgets.SpwWriterQueryForm
 */
define(["dojo/_base/declare","spw/api/SpwBaseWidget", "dojo/on", "dojo/_base/lang",
        "esri/tasks/IdentifyTask", "esri/tasks/IdentifyParameters", "esri/geometry/Point",
        "spw/api/Utils", "dojo/_base/array", "esri/tasks/QueryTask", "esri/tasks/query",
        "esri/tasks/BufferParameters", "dojo/dom-construct", "dgrid/OnDemandGrid",
        "dgrid/extensions/ColumnHider", "dgrid/extensions/ColumnResizer", "dojo/store/Memory",
        "dojo/dom-class", "dgrid/Selection", "dgrid/util/mouse", "spw/api/MessageManager", "dojo/Evented",
        "dojo/date/locale", "dojo/i18n!./nls/SpwWriterQueryForm", "dijit/form/Button"],
		function(declare, SpwBaseWidget, on, lang, IdentifyTask, IdentifyParameters, Point,
				Utils, array, QueryTask, Query, BufferParameters, domConstruct, OnDemandGrid,
				ColumnHider, ColumnResizer, Memory, domClass, Selection, mouseUtil, MessageManager,
				Evented, locale, labels, Button){

	var QueryFormConnector = null;

	QueryFormConnector = declare("spw.widgets.SpwWriterQueryForm", [SpwBaseWidget, Evented], /** @lends spw.widgets.SpwWriterQueryForm.prototype */{


		/**
         * Url du service de base utilisé pour récupérer les géométries sur base desquelles lancer l'identification des services
         * @type String
         */
		baseService:null,
		/**
         * Alias du(des) champs du service de base à afficher dans le tableau présentant la sélection de l'utilisateur
         * @type string | Array.<String>
         */
		serviceFieldAlias:null,
		/**
         * Nom du(des) champs du service de base à afficher dans le tableau présentant la sélection de l'utilisateur. Cette propriété est prioritaire par rapport à "serviceFieldAlias".
         * @type string | Array.<String>
         */
		serviceFieldName:null,
		/**
         * Identifiant du(des) champs du formulaire HTML qui seront remplis sur base des valeurs retournées par l'identification du service de base "baseService".
         * Ce paramètre doit correspondre au type du paramètre "serviceFieldName" (ou "serviceFieldAlias") : si un tableau est utilisé, le matching field-value s'effectue via l'index de l'élément dans le tableau.
         * @type string | Array.<String>
         */
		formField:null,
		/**
		 * Nombre maximum d'éléments autorisés lors de la sélection préalable de l'utilisateur. (venant du baseService)
		 */
		maxItemSelection:null,
		/**
		 * Information permettant au viewer de zoomer lors de l'activation du widget.
         * @property zoomInfo.x {Number} coordonnée x
         * @property zoomInfo.y {Number} coordonnée y
         * @property zoomInfo.radius {Number} rayon à appliquer à la coordonnée x,y lors du zoom, en mètres.
		 * @type Object
		 */
		zoomInfo: null,/*{
			"x":150000,
			"y":150000,
			"radius":100
		},*/
		/**
		 * Indique si la sélection de l'utilisateur doit être consolidée (UNION) avant de lancer l'identification sur les services définis.
		 * Si vrai, le système vérifiera que le polygone formé est valide et n'est pas un multipart polygon
		 * @type Boolean
		 */
        unionServiceQuery: false,
        /**
         * Séparateur utilisé pour séparer les différents appels d'identification (plusieurs géométries dans la sélection utilisateur).
         * @type String
         */
        serviceSeparator: "|#|",
        /**
         * Définition des services à interroger ainsi que le mapping service field - form field.
         * @property Object.serviceUrl {String} Url du layer à interroger (layer d'un MapService esri)
         * @property Object.serviceFieldName {String | Array.<String>} Nom du(des) champs du service à utiliser pour remplir le(les) champs correspondants du formulaire HTML.
         * @property Object.formField {String | Array.<String>} Identifiant du(des) champs du formulaire HTML qui seront remplis sur base des valeurs retournées par l'identification du service.
         * @property Object.queryBuffer {Number} Buffer de proximité à appliquer sur la sélection utilisateur lors de l'identification de cette couche.
         * @property Object.queryType {String} Type de requête spatiale à effectuer : PARTIAL = polygone contenu partiellement dans l'objet identifié ou TOTAL = le polygone est entièrement contenu dans l'objet identifié.
         * @type Array.<Object>
         */
    	services: null,/*[
      		{
    			serviceUrl: "http://webgisdgo4.spw.wallonie.be/ArcGIS/rest/services/DGO4/PDS_5000/MapServer/19",
    			serviceFieldName:"DESCRIPTION",
    			formField:"myFormField2",
    			queryBuffer: 0,
    			queryType:"PARTIAL"
    		},
    		{
				serviceUrl: "http://geoservices.wallonie.be/arcgis/rest/services/NATURA2000/NATURA2000_EP/MapServer/1",
				serviceFieldName:["NOM", "CODE_SITE"],
				formField:["myFormField3", "myFormField3_2"],
				queryBuffer: 2000,
				queryType:"PARTIAL"
			}],*/

    	
		/**
         * Identifiant du champs du formualire HTML. Si précisé, ce champs est rempli avec les coordonnées x et y du point cliqué sur la carte.
         * @type string
         */
    	xyField:null,

    	valueSeparator:",",
    	noResultValue: "|$|NO_RESULT|$|",
    	serviceErrorValue: "|$|SERVICE_ERROR|$|",
    	unavailableErrorValue: "|$|UNAVAILABLE_ERROR|$|",

    	instructionMessage:"Veuillez sélectionner une ou plusieurs parçelles adjaçentes.",
    	maxSelectionMessage:"Le nombre maximum de sélection est atteint.",
    	invalidSelectionMessage:"La sélection n'est pas valide. Veuillez sélectionner des éléments adjaçents.",
    	noSelectionMessage:"Aucun élément sélectionné. Veuillez sélectionner au minimum un élément.",
    	processingMessage:"Traitement en cours. Veuillez patienter.",
    	validateButtonMessage:"Sauver et revenir au formulaire",

    	dateFormat:null,

    	globalConfigObjectName: "geoviewerQueryFormTransfert",

    	_baseServiceOIDFieldName: null,
        _mapClickHandler: null,
        _features: null,
        _selectionGrid: null,
        _containerDiv: null,
        _btnValidate: null,
        _xy: null,

        queryCount: 0,

        events: { QueriesCompleted: "QueryFormConnector_QueriesCompleted" },

        /**
         * @constructs
         * @param config
         */
		constructor: function (config) {
			this._features = [];

			lang.mixin(this, labels);
		},

		postCreate: function() {
			this.inherited(arguments);
			this._containerDiv = domConstruct.create("div", {innerHTML:this.instructionMessage, class: "spwWriterQueryForm", style:"padding:8px;"}, this.domNode);
			this._xy = [];
		},

		onActivate: function(){
			this.inherited(arguments);

			if(window && window[this.globalConfigObjectName]){
				lang.mixin(this, window[this.globalConfigObjectName]);
			}

			if(this.zoomInfo){
				this.spwViewer.get('spwMap').zoomToPoint(this.zoomInfo.x, this.zoomInfo.y, this.zoomInfo.radius);
			}

			this._mapClickHandler = this.spwViewer.get('spwMap').on("MapClicked", lang.hitch(this, this.identifyBaseService));
		},

		onDeactivate: function(){
			this.inherited(arguments);
			if(this._mapClickHandler){
				this._mapClickHandler.remove();
			}
			if(this._btnValidate){
				this._btnValidate.destroy();
				this._btnValidate = null;
			}
			if(this._features && this._features.length > 0){
				while (this._features.length > 0){
					this.deselectFeature(this._features[0]);
				}
			}
			if(this._selectionGrid){
				this._selectionGrid.destroy();
				this._selectionGrid = null;
			}
		},

		identifyBaseService: function(x, y){
			this._xy.push(x+","+y);
			if(this.xyField){
				var formField = document.getElementById(this.xyField);
				if(formField){
					formField.value = this._xy.join(this.serviceSeparator);
				}
			}
			var query = new Query();
			query.geometry = new Point(x, y, this.spwViewer.get('spatialReference'));
			query.outFields = ["*"];
			query.returnGeometry = true;

			return new QueryTask(this.baseService).execute(query, lang.hitch(this, function(queryResult) {
				if(queryResult && queryResult.features && queryResult.features.length > 0){
					this._baseServiceOIDFieldName = this.getEsriOIDFieldName(queryResult);
					if(!this.serviceFieldName){
						this.serviceFieldName = this.aliasesToNames(queryResult);
					}
					if(this.dateFormat){
						this.formatResultsDates(queryResult);
					}
	            	var selectedFeature = this.getSelectedFeature(queryResult.features[0].attributes[this._baseServiceOIDFieldName]);
	            	if(selectedFeature){
	        			this.deselectFeature(selectedFeature);
	            	} else {
	        			if(this._features && this.maxItemSelection && this._features.length >= this.maxItemSelection){
	        				MessageManager.getInstance().notifyInfo(this.maxSelectionMessage);
	        			} else {
	        				this.selectFeature(queryResult.features[0]);
	        			}
	            	}
				}
			}));
		},

		formatResultsDates: function(queryResult) {
			array.forEach(queryResult.fields, function(field){
				if(field.type == "esriFieldTypeDate"){
					array.forEach(queryResult.features, function(feature){
						feature.attributes[field.name] = locale.format(new Date(feature.attributes[field.name]), {datePattern: this.dateFormat});
					});
				}
			});
		},

		aliasesToNames: function(queryResults) {
			if(typeof(this.serviceFieldAlias) == 'string'){
				var f = "";
				array.some(queryResults.fields, function(field){
					if(field.alias == this.serviceFieldAlias){
						f = field.name;
						return true;
					}
					return false;
				});
				return f;
			} else {
				var f = [];
				array.forEach(this.serviceFieldAlias, function(alias){
					array.some(queryResults.fields, function(field){
						if(field.alias == alias){
							f.push(field.name);
							return true;
						}
						return false;
					});
				});
				return f;
			}
		},

		baseServiceRedefined: function(){
			var serviceDef = null;
			array.some(this.services, lang.hitch(this, function(service){
				var serviceUrl = service.serviceUrl;
				if(serviceUrl[serviceUrl.length-1] == '/'){
					serviceUrl = serviceUrl.substring(0, serviceUrl.length-1);
				}
				var baseServiceUrl = this.baseService;
				if(baseServiceUrl[baseServiceUrl.length-1] == '/'){
					baseServiceUrl = baseServiceUrl.substring(0, baseServiceUrl.length-1);
				}

				if(baseServiceUrl == serviceUrl){
					serviceDef = service;
					return true;
				};
				return false;
			}));
			return serviceDef;
		},

		getEsriOIDFieldName: function(queryResults){
			var f = "";
			array.forEach(queryResults.fields, lang.hitch(this, function(field){
				if(field.type == "esriFieldTypeOID"){
					f = field.name;
				}
			}));
			return f;
		},

		getSelectedFeature: function(objectid){
        	for(var i=0; i < this._features.length; i++){
        		if(this._features[i].attributes[this._baseServiceOIDFieldName] == objectid){
        			return this._features[i];
        		}
        	}
        	return null;
		},

		deselectFeature: function(feature){
        	this.spwViewer.get('spwMap').removeFeature(feature);
        	this._features.splice(this._features.indexOf(feature), 1);
        	this._buildSelectionArray();
		},

		selectFeature: function(feature){
			feature.geometry.spatialReference = this.spwViewer.get('spatialReference');
        	this.spwViewer.get('spwMap').showFeature(feature);
        	this._features.push(feature);
        	this._buildSelectionArray();
		},

		resize: function(){
			if(this._selectionGrid) {
				this._selectionGrid.resize();
			}
		},

		_buildSelectionArray: function(){
			if(!this._selectionGrid) {
				var columns = {};
				for(var key in this._features[0].attributes){
					columns[key.replace(' ', '')] = {};
					lang.mixin(columns[key.replace(' ', '')], {
						label:key,
						hidden: ((typeof(this.serviceFieldName) === 'string') ? (key != this.serviceFieldName) : (this.serviceFieldName.indexOf(key) < 0))
					});
				}
				columns.editorbtn = {
						label:"",
						sortable:false,
						hidden:false,
						unhidable:true,
						resizable: false,
						width:40,
						renderCell: lang.hitch(this, function(object, value, node, options){
							var lnk = domConstruct.create("img", {src:this.imagesPath + "icon-delete.png", title:labels.deleteImg, alt:labels.deleteImg, style:"cursor:pointer;"}, domConstruct.create("div", {style:"text-align:center;"}, node));
							on(lnk, "click", lang.hitch(this, function(){
								var selectedFeature = this.getSelectedFeature(object[this._baseServiceOIDFieldName]);
								if(selectedFeature){
									this.deselectFeature(selectedFeature);
								}
							}));
						})
				};

				this._selectionGrid = new (declare([OnDemandGrid, Selection, ColumnHider, ColumnResizer]))({
					className: "dgrid-autoheight",
					addUiClasses: false,
					columns: columns
			    }, domConstruct.create("div", {style:"height:190px;overflow-y:auto;"}, this._containerDiv));

				this._selectionGrid.on(mouseUtil.enterRow, lang.hitch(this, this.gridRowEntered));
		        this._selectionGrid.on(mouseUtil.leaveRow, lang.hitch(this, this.gridRowLeaved));

		        this._btnValidate = new Button({
                    style: 'float: right;',
                    label: this.validateButtonMessage
                }, domConstruct.create("button", null, this._containerDiv));

				on(this._btnValidate, "click", lang.hitch(this, this.validateSelection));
			}
			this.refreshGrid();
		},

		gridRowEntered: function(event){
			var data = this._selectionGrid.row(event);
			if(data){
				var selectedFeature = this.getSelectedFeature(data.data[this._baseServiceOIDFieldName]);
				if(selectedFeature){
					this.spwViewer.get('spwMap').highlightFeature(selectedFeature);
				}
			}
		},

		gridRowLeaved: function(event){
			var data = this._selectionGrid.row(event);
			if(data){
				var selectedFeature = this.getSelectedFeature(data.data[this._baseServiceOIDFieldName]);
				if(selectedFeature){
					this.spwViewer.get('spwMap').unhighlightFeature(selectedFeature);
				}
			}
		},

		refreshGrid: function() {
			if(this._selectionGrid){
				var store = new Memory({idProperty: this._baseServiceOIDFieldName, data:array.map(this._features, function(feature){
					for(var key in feature.attributes){
						if(key.indexOf(' ') > -1){
							feature.attributes[key.replace(' ', '')] = feature.attributes[key];
						}
					}
					return feature.attributes;
				})});
				this._selectionGrid.set('store', store);
			}
		},

        validateSelection: function(){
        	if(this._features && this._features.length > 1 && this.unionServiceQuery){
	        	this.spwViewer.get('geometryService').union(array.map(this._features, function(feature){return feature.geometry;}), lang.hitch(this, function(geometry){
	        		if(!geometry || !geometry.rings || this.isMultipartPolygon(geometry)){
	        			MessageManager.getInstance().notifyWarning(this.invalidSelectionMessage);
	        		} else {
	        			geometry.spatialReference = this._features[0].geometry.spatialReference;
	        			this.fillBaseServiceFields();
	            		this.queryServices(geometry);
	        		}
	        	}), function(){
	        		MessageManager.getInstance().notifyError(labels.constraintError);
	        	});
        	} else if (this._features && this._features.length == 1){
    			this.fillBaseServiceFields();
        		this.queryServices(this._features[0].geometry);
        	} else if(this._features && this._features.length > 1 && !this.unionServiceQuery){
    			this.fillBaseServiceFields();
    			array.forEach(this._features, lang.hitch(this, function(feature){
            		this.queryServices(feature.geometry);
    			}));
        	}
    		else {
        		MessageManager.getInstance().notifyWarning(this.noSelectionMessage);
        	}
        },

        fillBaseServiceFields: function() {
			var formFields = this.formField;
			var fieldsToFetch = this.serviceFieldName;

			var serviceRedef = this.baseServiceRedefined();
			if(serviceRedef){
				fieldsToFetch = serviceRedef.serviceFieldName;
				formFields = serviceRedef.formField;
			}

			if(typeof(fieldsToFetch) === 'string'){
				fieldsToFetch = [fieldsToFetch];
			}
			if(typeof(formFields) === 'string'){
				formFields = [formFields];
			}
			array.forEach(fieldsToFetch, lang.hitch(this, function(field, idx){
				var fieldValue = this._features && this._features.length > 0 ? this.joinBaseFeatureValues(this._features, field) : this.noResultValue;
				var formField = document.getElementById(formFields[idx]);
				if(formField){
					formField.value = fieldValue;
				}
			}));
        },

        isMultipartPolygon: function(geometry){
        	var clockwiseCount = 0;
        	for(var i =0; i < geometry.rings.length; i++){
        		if(geometry.isClockwise(geometry.rings[i]) && ++clockwiseCount > 1){
        			return true;
        		}
        	}
        	return false;
        },

        queryServices: function(geometry) {
        	MessageManager.getInstance().displayModalMessage("<div>"+this.processingMessage+"</div>");
        	this.set("queryCount", this.get("queryCount") + this.services.length);
        	var watchHandler = this.watch("queryCount", lang.hitch(this, function(name, oldVal, newVal){
        		if(newVal <= 0){
            		watchHandler.remove();
                	MessageManager.getInstance().hideModalMessage();
    				this.emit("QueryFormConnector_QueriesCompleted");
        		}
        	}));
			array.forEach(this.services, lang.hitch(this, function(service, idx){
				if(service != this.baseServiceRedefined()){
					try {
						if(service.queryBuffer){
							var params = new BufferParameters();
							params.geometries  = [ geometry ];
							params.distances = [ service.queryBuffer ];
							params.bufferSpatialReference = this.spwViewer.get('spatialReference');
							params.outSpatialReference = this.spwViewer.get('spatialReference');
							this.spwViewer.get('geometryService').buffer(params, lang.hitch(this, function(bufferedGeometry){
								this.executeQuery(bufferedGeometry[0], service);
							}), lang.hitch(this, function(error){
								console.info(error);
								this.fillQueryServiceFields(service, null, this.unavailableErrorValue);
								this.set('queryCount', this.queryCount-1);
							}));
						} else {
							this.executeQuery(geometry, service);
						}
					} catch(err) {
						this.fillQueryServiceFields(service, null, this.unavailableErrorValue);
						this.set('queryCount', this.queryCount-1);
					}
				} else {
					this.set('queryCount', this.queryCount-1);
				}
			}));
        },

        fillQueryServiceFields: function(service, queryResult, errorText) {
        	console.log("========================");
        	console.log("Résultat query : ");
        	console.log("--- Service : ",service);
        	console.log("--- queryResult : ",queryResult);
        	console.log("--- errorText : ",errorText);
        	console.log("========================");

			var fieldsToFetch = service.serviceFieldName;
			var formFields = service.formField;
			if(typeof(fieldsToFetch) === 'string'){
				fieldsToFetch = [fieldsToFetch];
			}
			if(typeof(formFields) === 'string'){
				formFields = [formFields];
			}
			array.forEach(fieldsToFetch, lang.hitch(this, function(field, idx){
				if(errorText){
					var formField = document.getElementById(formFields[idx]);
					if(formField){
						formField.value = formField.value != '' ? (formField.value + this.serviceSeparator + errorText) : errorText;
					}
				} else {
					var fieldValue = queryResult && queryResult.features.length > 0 ? this.joinFeatureValues(queryResult.features, field) : this.noResultValue;
					var formField = document.getElementById(formFields[idx]);
					if(formField){
						formField.value = formField.value != '' ? (formField.value + this.serviceSeparator + fieldValue) : fieldValue;
					}
				}
			}));
        },

        executeQuery: function(geometry, service){
			var query = new Query();
			query.geometry = geometry;
			query.spatialRelationship = (service.queryType != "TOTAL") ? Query.SPATIAL_REL_INTERSECTS : Query.SPATIAL_REL_WITHIN;
			query.outFields = ["*"];
			query.returnGeometry = false;
			query.outSpatialReference = this.spwViewer.get('spatialReference');

			return new QueryTask(service.serviceUrl).execute(query, lang.hitch(this, function(queryResult) {
				if(this.dateFormat){
					this.formatResultsDates(queryResult);
				}
				this.fillQueryServiceFields(service, queryResult);
				this.set('queryCount', this.queryCount-1);
			}), lang.hitch(this, function(){
				this.fillQueryServiceFields(service, null, this.unavailableErrorValue);
				this.set('queryCount', this.queryCount-1);
			}));
        },

        joinFeatureValues: function(features, field){
        	return this.joinValues(features, field, this.valueSeparator);
        },

        joinBaseFeatureValues: function(features, field){
        	return this.joinValues(features, field, this.serviceSeparator);
        },

        joinValues: function(features, field, separator){
        	if(features[0] && typeof(features[0].attributes[field]) != 'undefined'){
            	var values = array.map(features, function(feature){return feature.attributes[field];});
            	return values.join(separator);
        	}
        	return this.serviceErrorValue;
        }
	});

	return QueryFormConnector;
});