diff --git a/src/app/core/layers/filter/expression.js b/src/app/core/layers/filter/expression.js index 983ef81b8..870f6f42a 100644 --- a/src/app/core/layers/filter/expression.js +++ b/src/app/core/layers/filter/expression.js @@ -10,11 +10,11 @@ function Expression(options={}) { const proto = Expression.prototype; proto.and = function(field, value) { - this._expression = this._expression ? this._expression + ' AND ': this._expression; - if (field && value) { - this.eq(field, value); - } - return this; + this._expression = this._expression ? this._expression + ' AND ': this._expression; + if (field && value) { + this.eq(field, value); + } + return this; }; proto.or = function() { @@ -89,9 +89,9 @@ proto.createSingleExpressionElement = function({value, attribute, operator, logi const filterValue = `( ${_value.map(value => `'${value}'`).join(',').replace(/,/g, ' , ')} )`; filterElement = `"${attribute}" ${filterOp} ${filterValue}${filterLogicOperator}`; } else if ( - (value !== null && value !== undefined) - && !(Number.isNaN(value) || !value.toString().trim()) //check if a valid number (not a NaN and not an empty string) - ) { + (value !== null && value !== undefined) + && !(Number.isNaN(value) || !value.toString().trim()) //check if a valid number (not a NaN and not an empty string) + ) { const singolequote = Array.isArray(value) ? value : typeof value !== 'number' ? value.split("'") : []; if (singolequote.length > 1) { @@ -100,12 +100,11 @@ proto.createSingleExpressionElement = function({value, attribute, operator, logi const value = singolequote[i]; if (!value) continue; - const filterOp = 'ILIKE'; const filterValue = `%${value}%`.trim(); const filterElement = `"${attribute}" ${filterOp} '${filterValue}'`; _filterElements.push(filterElement) } - filterElement = `${_filterElements.join(' AND ')}${filterLogicOperator}`; + filterElement = `${_filterElements.join(` ${logicop} `)}${filterLogicOperator}`; } else filterElement = `"${attribute}" ${filterOp} '${valueExtra}${value}${valueExtra}'${filterLogicOperator}`; } return filterElement; diff --git a/src/app/core/layers/layer.js b/src/app/core/layers/layer.js index a01e29877..b54934d79 100644 --- a/src/app/core/layers/layer.js +++ b/src/app/core/layers/layer.js @@ -76,7 +76,7 @@ function Layer(config={}, options={}) { /** * Store feature count url to get features count of a layer - * + * * @since 3.8.0 */ this.config.urls.featurecount = project.getUrl('featurecount'); @@ -150,7 +150,7 @@ function Layer(config={}, options={}) { /** * @type { Array<{{ id: string, name: string }}> } array of saved filters - * + * * @since 3.9.0 */ filters: config.filters || [], @@ -240,7 +240,7 @@ proto.getProxyData = function(type) { /** * Set proxy data - * + * * @param type * @param data */ @@ -250,7 +250,7 @@ proto.setProxyData= function(type, data = {}) { /** * Clear proxy data - * + * * @param type */ proto.clearProxyData = function(type) { @@ -259,10 +259,10 @@ proto.clearProxyData = function(type) { /** * Get a proxy request - * + * * @param type * @param proxyParams - * + * * @returns {Promise<*>} */ proto.getDataProxyFromServer = async function(type = 'wms', proxyParams = {}) { @@ -280,10 +280,10 @@ proto.getDataProxyFromServer = async function(type = 'wms', proxyParams = {}) { /** * @TODO Add description - * + * * @param type * @param changes - * + * * @returns {Promise<*>} */ proto.changeProxyDataAndReloadFromServer = function(type = 'wms', changes = {}) { @@ -297,7 +297,7 @@ proto.changeProxyDataAndReloadFromServer = function(type = 'wms', changes = {}) /** * [EDITING PLUGIN] Check if layer is in editing - * + * * @returns { boolean } */ proto.isInEditing = function() { @@ -306,7 +306,7 @@ proto.isInEditing = function() { /** * [EDITING PLUGIN] Set editing state - * + * * @param {boolean} bool */ proto.setInEditing = function(bool=false) { @@ -315,7 +315,7 @@ proto.setInEditing = function(bool=false) { /** * @TODO Add description here - * + * * @returns {*} */ proto.getSearchParams = function() { @@ -324,7 +324,7 @@ proto.getSearchParams = function() { /** * Return search_endpoint - * + * * @returns {*} */ proto.getSearchEndPoint = function() { @@ -333,7 +333,7 @@ proto.getSearchEndPoint = function() { /** * @TODO Add description - * + * * @param pageLength */ proto.setAttributeTablePageLength = function(pageLength) { @@ -342,7 +342,7 @@ proto.setAttributeTablePageLength = function(pageLength) { /** * @TODO add description - * + * * @returns {null} */ proto.getAttributeTablePageLength = function() { @@ -379,7 +379,7 @@ proto.isGeoLayer = function() { /** * @TODO Add description - * + * * @param { Object } opts * @param opts.page * @param opts.page_size @@ -390,7 +390,7 @@ proto.isGeoLayer = function() { * @param opts.custom_params * @param opts.field * @param opts.in_bbox - * + * * @returns {*} */ proto.getDataTable = function({ @@ -439,7 +439,7 @@ proto.getDataTable = function({ /** * Search layer feature by fids - * + * * @param fids formatter */ proto.getFeatureByFids = async function({ @@ -501,7 +501,7 @@ proto.searchFeatures = function(options = {}, params = {}) { ordering: options.ordering, unique: options.unique, raw: undefined !== options.raw ? options.raw : false, - suggest: undefined !== options.suggest ? options.suggest : {}, + suggest: options.suggest, /** @since 3.9.0 */ formatter: undefined !== options.formatter ? options.formatter : 1, }) @@ -523,18 +523,20 @@ proto.searchFeatures = function(options = {}, params = {}) { * @param { 0 | 1 } opts.formatter * @param { Array } opts.field - Array of object with type of suggest (see above) * @param opts.unique + * @param opts.fformatter * @param opts.queryUrl * @param opts.ordering */ proto.getFilterData = async function({ raw = false, - suggest = {}, - formatter = 1, + suggest, field, unique, + fformatter, //@since v3.9 + formatter = 1, queryUrl, - ordering + ordering, } = {}) { return await this .getProvider('data') @@ -546,6 +548,7 @@ proto.getFilterData = async function({ suggest, formatter, unique, + fformatter, }); }; @@ -606,7 +609,7 @@ proto.getFields = function() { * Get field by name * * @param fieldName - * + * * @returns {*} */ proto.getFieldByName = function(fieldName) { @@ -650,7 +653,7 @@ proto.getConfig = function() { /** * @param fields - * + * * @returns { Array } form structure to show on form editing */ proto.getLayerEditingFormStructure = function(fields) { @@ -659,7 +662,7 @@ proto.getLayerEditingFormStructure = function(fields) { /** * @TODO Add description - * + * * @returns {*|*[]} */ proto.getFieldsOutOfFormStructure = function() { @@ -674,7 +677,7 @@ proto.hasFormStructure = function() { }; /** - * @returns custom style (for future implementation) + * @returns custom style (for future implementation) */ proto.getCustomStyle = function() { return this.config.customstyle; @@ -682,7 +685,7 @@ proto.getCustomStyle = function() { /** * Get state layer - * + * * @returns {*|{metadata, downloadable: *, attributetable: {pageLength: null}, defaultstyle: *, source, title: *, infoformats: ((function(): *)|*|*[]), tochighlightable: boolean, featurecount: number, stylesfeaturecount: (number|string|*|{[p: number]: *}), projectLayer: boolean, infoformat: (string|default.watch.infoformat|*), geolayer: boolean, inediting: boolean, disabled: boolean, id: (*|string), selected: boolean, openattributetable: (boolean|boolean), metadata_querable: (boolean|boolean), visible: boolean, filters: *[], filter: {current: null, active: boolean}, selection: {active: boolean}, removable: (boolean|*), styles}} */ proto.getState = function() { @@ -705,7 +708,7 @@ proto.getEditingLayer = function() { /** * Set editing layer - * + * * @param editingLayer */ proto.setEditingLayer = function(editingLayer) { @@ -721,7 +724,7 @@ proto.isHidden = function() { /** * Set hidden - * + * * @param bool */ proto.setHidden = function(bool=true) { @@ -772,7 +775,7 @@ proto.getOrigName = function() { /** * Get Server type - * + * * @returns {*|string|{wmst: {filter: Providers.WFSDataProvider, search: null, data: null, query: Providers.WMSDataProvider}, virtual: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}, oracle: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}, delimitedtext: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}, wfs: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider}, wcs: {filter: Providers.WFSDataProvider, search: null, data: null, query: Providers.WMSDataProvider}, arcgismapserver: {filter: null, search: null, data: null, query: Providers.WMSDataProvider}, mdal: {filter: null, search: null, data: null, query: Providers.WMSDataProvider}, vectortile: {filter: null, search: null, data: null, query: Providers.WMSDataProvider}, "vector-tile": {filter: null, search: null, data: null, query: Providers.WMSDataProvider}, gdal: {filter: null, search: null, data: null, query: Providers.WMSDataProvider}, ogr: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}, wms: {filter: Providers.WFSDataProvider, search: null, data: null, query: Providers.WMSDataProvider}, postgres: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}, mssql: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}, spatialite: {filter: Providers.WFSDataProvider, search: Providers.QGISProvider, data: Providers.QGISProvider, query: Providers.WMSDataProvider, filtertoken: Providers.QGISProvider}}} */ proto.getServerType = function() { @@ -790,7 +793,7 @@ proto.getType = function() { /** * Set Type - * + * * @param type */ proto.setType = function(type) { @@ -799,9 +802,9 @@ proto.setType = function(type) { /** * Check if layer is a type passed - * + * * @param type - * + * * @returns {boolean} */ proto.isType = function(type) { @@ -810,7 +813,7 @@ proto.isType = function(type) { /** * Set disabled - * + * * @param bool */ proto.setDisabled = function(bool) { @@ -833,7 +836,7 @@ proto.isVisible = function() { /** * Set visibility - * + * * @param bool */ proto.setVisible = function(bool) { @@ -858,7 +861,7 @@ proto.isQueryable = function({ onMap } = { onMap: false }) { /** * @TODO Add description - * + * * @returns {string|string|*} */ proto.getOws = function() { @@ -867,7 +870,7 @@ proto.getOws = function() { /** * @TODO Description - * + * * @returns {boolean} */ proto.getTocHighlightable = function() { @@ -876,7 +879,7 @@ proto.getTocHighlightable = function() { /** * @TODO Description - * + * * @param bool */ proto.setTocHighlightable = function(bool=false) { @@ -923,7 +926,7 @@ proto.isBaseLayer = function() { }; /** - * @param type get url by type (data, shp, csv, xls, editing, ...) + * @param type get url by type (data, shp, csv, xls, editing, ...) */ proto.getUrl = function(type) { return this.config.urls[type]; @@ -963,7 +966,7 @@ proto.getQueryUrl = function() { /** * Set query url - * + * * @param queryUrl */ proto.setQueryUrl = function(queryUrl) { @@ -979,7 +982,7 @@ proto.getQueryLayerName = function() { /** * @TODO Description - * + * * @returns {*} */ proto.getQueryLayerOrigName = function() { @@ -988,9 +991,9 @@ proto.getQueryLayerOrigName = function() { /** * @TODO Description - * + * * @param ogcService - * + * * @returns { default.watch.infoformat | * | string } */ proto.getInfoFormat = function(ogcService) { @@ -1006,7 +1009,7 @@ proto.getInfoFormat = function(ogcService) { /** * @TODO Description - * + * * @returns {(function(): *)|*|*[]} */ proto.getInfoFormats = function() { @@ -1015,7 +1018,7 @@ proto.getInfoFormats = function() { /** * @TODO Description - * + * * @returns {*} */ proto.getInfoUrl = function() { @@ -1024,7 +1027,7 @@ proto.getInfoUrl = function() { /** * @TODO Description - * + * * @param infoFormat */ proto.setInfoFormat = function(infoFormat) { @@ -1033,7 +1036,7 @@ proto.setInfoFormat = function(infoFormat) { /** * @TODO Description - * + * * @returns {*|{}} */ proto.getAttributes = function() { @@ -1042,7 +1045,7 @@ proto.getAttributes = function() { /** * @TODO Description - * + * * @param attribute * @param type * @param options @@ -1059,9 +1062,9 @@ proto.changeAttribute = function(attribute, type, options) { /** * @TODO Description - * + * * @param name - * + * * @returns {*} */ proto.getAttributeLabel = function(name) { @@ -1071,9 +1074,9 @@ proto.getAttributeLabel = function(name) { /** * Return provider by type - * + * * @param type - * + * * @returns {*} */ proto.getProvider = function(type) { @@ -1082,7 +1085,7 @@ proto.getProvider = function(type) { /** * Return all providers - * + * * @returns {*|{filter: null, search: null, data: null, query: null, filtertoken: null}} */ proto.getProviders = function() { @@ -1091,7 +1094,7 @@ proto.getProviders = function() { /** * @TODO Description - * + * * @returns {*} */ proto.getLayersStore = function() { @@ -1100,7 +1103,7 @@ proto.getLayersStore = function() { /** * @TODO Description - * + * * @param layerstore */ proto.setLayersStore = function(layerstore) { @@ -1109,7 +1112,7 @@ proto.setLayersStore = function(layerstore) { /** * Return if it is possible to show table of attribute - * + * * @returns {boolean} */ proto.canShowTable = function() { @@ -1141,13 +1144,13 @@ proto.canShowTable = function() { /** * @TODO Description - * + * * @param { Object } field * @param field.name * @param field.type * @param field.options * @param field.reset - * + * * @returns {*} */ proto.changeFieldType = function({ @@ -1176,13 +1179,13 @@ proto.changeFieldType = function({ /** * @TODO Description - * + * * @param { Object } config * @param config.name * @param config.type * @param config.options * @param config.reset - * + * * @returns {*} */ proto.changeConfigFieldType = function({ @@ -1196,7 +1199,7 @@ proto.changeConfigFieldType = function({ /** * @TODO Description - * + * * @param name */ proto.resetConfigField = function({name}) { @@ -1254,14 +1257,14 @@ proto.getStyleFeatureCount = async function(style) { /** * [LAYER SELECTION] - * + * * Base on boolean value create a filter token from server * based on selection or delete current filtertoken - * + * * @param bool - * + * * @returns {Promise} - * + * * @deprecated since 3.9.0. Will be removed in 4.x. Use Layer::createFilterToken() and deleteFilterToken(fid) instead */ proto.activeFilterToken = deprecate(async function(bool) { await this[bool ? 'createFilterToken' : 'deleteFilterToken'](); }, '[G3W-CLIENT] Layer::activeFilterToken(bool) is deprecated'); @@ -1323,7 +1326,9 @@ Layer.SourceTypes = { "VECTOR-TILE": "vector-tile", VECTORTILE: "vectortile", ARCGISMAPSERVER: 'arcgismapserver', - GEOJSON: "geojson" + GEOJSON: "geojson", + /** @since 3.9.0 */ + POSTGRESRASTER: 'postgresraster', /** * ADD TO PROVIDER FACTORY (@TODO or already done?) */ diff --git a/src/app/core/layers/layerfactory.js b/src/app/core/layers/layerfactory.js index 9ebbfb4e3..41311b16e 100644 --- a/src/app/core/layers/layerfactory.js +++ b/src/app/core/layers/layerfactory.js @@ -30,6 +30,8 @@ const NO_GEOMETRY = [ Layer.SourceTypes.MDAL, /** @since 3.8.7 */ Layer.SourceTypes.ARCGISMAPSERVER, + /** @since 3.9.0 */ + Layer.SourceTypes.POSTGRESRASTER, ]; const BASE_LAYERS = { @@ -160,14 +162,15 @@ class LayerFactory { const source = config.source || {}; // Check Server Type - const is_qgis = Layer.ServerTypes.QGIS === config.servertype; - const is_ogc = Layer.ServerTypes.OGC === config.servertype; - const is_g3w = Layer.ServerTypes.G3WSUITE === config.servertype - const is_local = Layer.ServerTypes.LOCAL === config.servertype; + const is_qgis = Layer.ServerTypes.QGIS === config.servertype; + const is_ogc = Layer.ServerTypes.OGC === config.servertype; + const is_g3w = Layer.ServerTypes.G3WSUITE === config.servertype + const is_local = Layer.ServerTypes.LOCAL === config.servertype; - const is_wms = is_ogc && Layer.SourceTypes.WMS === source.type; - const is_wfs = is_ogc && Layer.SourceTypes.WFS === source.type; - const is_geojson = is_g3w && Layer.SourceTypes.GEOJSON === source.type; + const is_wms = is_ogc && Layer.SourceTypes.WMS === source.type; + const is_wfs = is_ogc && Layer.SourceTypes.WFS === source.type; + const is_geojson = is_g3w && Layer.SourceTypes.GEOJSON === source.type; + const is_pgraster = is_qgis && Layer.SourceTypes.POSTGRESRASTER === source.type; // Check Geometry Type const is_tabular = config.geometrytype === 'NoGeometry'; @@ -177,7 +180,7 @@ class LayerFactory { // Check Layer Type const is_base_layer = config.servertype in BASE_LAYERS; const is_table_layer = is_qgis && has_geom && is_tabular; - const is_image_layer = is_wms || is_qgis && (no_geom || (has_geom && !is_tabular)); + const is_image_layer = is_wms || is_qgis && (no_geom || (has_geom && !is_tabular) || is_pgraster); const is_vector_layer = is_local || is_wfs || (is_g3w && !is_geojson); const is_geojson_layer = is_geojson; diff --git a/src/app/core/layers/map/wmslayer.js b/src/app/core/layers/map/wmslayer.js index 7db8b4897..0073660c0 100644 --- a/src/app/core/layers/map/wmslayer.js +++ b/src/app/core/layers/map/wmslayer.js @@ -1,4 +1,5 @@ import ApplicationState from 'store/application-state'; +import ProjectsRegistry from 'store/projects'; const { base, inherit } = require('utils'); const MapLayer = require('core/layers/map/maplayer'); @@ -87,7 +88,7 @@ proto._makeOlLayer = function(withLayers) { iframe_internal: this.iframe_internal, layers: (withLayers) ? this.layers.map(layer => layer.getWMSLayerName()) : this.layers, /** @since 3.7.11 */ - format: this.config.format + format: this.config.format || ProjectsRegistry.getCurrentProject().getWmsGetmapFormat(), }, this.extraParams, this._method diff --git a/src/app/core/layers/providersfactory.js b/src/app/core/layers/providersfactory.js index 465406a77..f1ce776c9 100644 --- a/src/app/core/layers/providersfactory.js +++ b/src/app/core/layers/providersfactory.js @@ -182,36 +182,62 @@ const Providers = { this.getFilterToken = QgsFilterToken.getToken.bind(null, this._filtertokenUrl); } + /** + * @param { Object } opts + * @param opts.field + * @param opts.raw + * @param opts.suggest + * @param opts.unique + * @param opts.formatter + * @param opts.queryUrl + * @param opts.ordering + * @param opts.fformatter since 3.9.0 + * + * @returns {Promise} + */ async getFilterData({ field, raw = false, - suggest = {}, + suggest, unique, formatter = 1, queryUrl, ordering, + fformatter, } = {}) { + const params = { + field, + suggest, + ordering, + formatter, + unique, + fformatter, + filtertoken: ApplicationState.tokens.filtertoken + }; try { - let response = await XHR.get({ - url: `${queryUrl ? queryUrl : this._layer.getUrl('data')}`, - params: { - field, - suggest, - ordering, - formatter, - unique, - filtertoken: ApplicationState.tokens.filtertoken - }, - }); + const url = queryUrl ? queryUrl : this._layer.getUrl('data'); + const response = field // check `field` parameter + ? await XHR.post({ url, contentType: 'application/json', data: JSON.stringify(params)}) // since g3w-admin@v3.7 + : await XHR.get({ url, params }); // BACKCOMP (`unique` and `ordering` were only GET parameters) // vector layer if ('table' !== this._layer.getType()) { this.setProjections(); } - if (raw) return response; - if (unique && response.result) return response.data; - if (response.result) return { data: Parsers.response.get('application/json')({ layers: [this._layer], response: response.vector.data, projections: this._projections }) }; + if (raw) return response; + if (unique && response.result) return response.data; + if (fformatter && response.result) return response; + + if (response.result) { + return { + data: Parsers.response.get('application/json')({ + layers: [this._layer], + response: response.vector.data, + projections: this._projections, + }) + }; + } } catch(e) { return Promise.reject(e); @@ -900,6 +926,13 @@ class ProviderFactory { data: null, search: null, }, + /** @since 3.9.0 */ + 'postgresraster': { + query: Providers.wms, + filter: null, + data: null, + search: null, + }, 'vector-tile': { query: Providers.wms, filter: null, diff --git a/src/app/core/project/project.js b/src/app/core/project/project.js index 3025a8567..15d3f4b81 100644 --- a/src/app/core/project/project.js +++ b/src/app/core/project/project.js @@ -104,6 +104,16 @@ inherit(Project, G3WObject); const proto = Project.prototype; +/** + * @returns `wms_getmap_format` attribute from server (project settings) + * + * @since 3.9.0 + */ + +proto.getWmsGetmapFormat = function() { + return this.state.wms_getmap_format; +} + /** * Get search end point value (ows or api) */ diff --git a/src/app/gui/map/mapservice.js b/src/app/gui/map/mapservice.js index 1fa14258d..5baf4e554 100644 --- a/src/app/gui/map/mapservice.js +++ b/src/app/gui/map/mapservice.js @@ -1417,7 +1417,11 @@ proto.addControl = function(id, type, control, addToMapControls=true, visible=tr const buttonControl = $(control.element).find('button'); - buttonControl.tooltip({ placement: 'bottom', trigger: GUI.isMobile() ? 'click': 'hover' }); + buttonControl.tooltip({ + placement: 'bottom', + container: 'body', + trigger: GUI.isMobile() ? 'click': 'hover' + }); // in case of mobile hide tooltip after click if (GUI.isMobile()) { diff --git a/src/app/gui/queryresults/queryresultsservice.js b/src/app/gui/queryresults/queryresultsservice.js index 27bce207c..83a0047fa 100644 --- a/src/app/gui/queryresults/queryresultsservice.js +++ b/src/app/gui/queryresults/queryresultsservice.js @@ -1226,6 +1226,8 @@ class QueryResultsService extends G3WObject { Layer.SourceTypes.WMS, Layer.SourceTypes.WCS, Layer.SourceTypes.WMST, + /** @since 3.9.0 */ + Layer.SourceTypes.POSTGRESRASTER, ]; return featureAttributesNames.map(featureAttr => ({ name: featureAttr, diff --git a/src/app/gui/search/vue/panel/searchservice.js b/src/app/gui/search/vue/panel/searchservice.js index a2f168764..9497b7a1d 100644 --- a/src/app/gui/search/vue/panel/searchservice.js +++ b/src/app/gui/search/vue/panel/searchservice.js @@ -38,41 +38,82 @@ function SearchService(config = {}) { base(this); - // reactivity data + /** + * reactivity data + */ this.state = { title: null, forminputs: [], loading: {}, - searching: false + searching: false, }; - this.config = config; + /** + * @FIXME add description + */ + this.config = config; const { options = {} } = this.config; const layerid = options.querylayerid || options.layerid || null; + /** + * @FIXME add description + */ this.inputdependance = {}; + /** + * @FIXME add description + */ this.inputdependencies = {}; + /** + * @FIXME add description + */ this.cachedependencies = {}; + /** + * @FIXME add description + */ this.project = ProjectsRegistry.getCurrentProject(); + /** + * @FIXME add description + */ this.mapService = GUI.getService('map'); + /** + * @FIXME add description + */ this.searchLayer = null; + /** + * @FIXME add description + */ this.filter = null; + /** + * @FIXME add description + */ this.inputs = []; + /** + * @FIXME add description + */ this.state.title = config.name; + /** + * @FIXME add description + */ this.search_endpoint = config.search_endpoint; + /** + * @FIXME add description + */ this.url = options.queryurl; + /** + * @FIXME add description + */ this.filter = options.filter; /** @@ -80,26 +121,32 @@ function SearchService(config = {}) { */ this.type = this.config.type || 'search'; + /** + * @FIXME add description + */ this.return = options.return || 'data'; - this.show = this.return === 'data' && this.type === 'search'; + /** + * @FIXME add description + */ + this.show = 'data' === this.return && 'search' === this.type; + /** + * @FIXME add description + */ this.searchLayer = CatalogLayersStoresRegistry.getLayerById(layerid); /** * Store layers that will be searchable for that search form. * First one is layer owner of the search setted on admin. */ - this.searchLayers = [ - layerid, - ...(options.otherquerylayerids || []) - ].map(layerid => CatalogLayersStoresRegistry.getLayerById(layerid)); - + this.searchLayers = [ layerid, ...(options.otherquerylayerids || []) ].map(id => CatalogLayersStoresRegistry.getLayerById(id)); /** * Create the form search structure */ this.createInputsFormFromFilter({ filter: (options.filter || []) }); + } inherit(SearchService, G3WObject); @@ -109,107 +156,97 @@ const proto = SearchService.prototype; /** * @TODO slim down and refactor * - * Start Method to create right search structure for search form + * Create right search structure for search form * - * @param filter + * @param { Object } opts + * @param { Array } opts.filter input * - * @returns {Promise} + * @returns { Promise } form input */ -proto.createInputsFormFromFilter = async function({filter=[]}={}) { - const filterLenght = filter.length - 1; - for (let index = 0; index <= filterLenght; index ++) { - const input = filter[index]; - const forminput = { - label: input.label, - attribute: input.attribute, - type: input.input.type || 'textfield', - options: {...input.input.options}, - value: null, - operator: input.op, - logicop: index === filterLenght ? null : input.logicop, - id: input.id || getUniqueDomId(), - loading: false, - widget: null +proto.createInputsFormFromFilter = async function({ + filter = [], +} = {}) { + for (let i = 0; i <= filter.length - 1; i++) { + + const input = { + label: filter[i].label, + attribute: filter[i].attribute, + type: filter[i].input.type || 'textfield', + options: { ...filter[i].input.options }, + value: null, + operator: filter[i].op, + logicop: i === (filter.length - 1) ? null : filter[i].logicop, + id: filter[i].id || getUniqueDomId(), + loading: false, + widget: null, }; - //check if has a dependance - const {options:{ dependance, dependance_strict } } = forminput; - if (forminput.type === 'selectfield' || forminput.type === 'autocompletefield') { - // to be sure set values options to empty array if undefined - forminput.loading = forminput.type !== 'autocompletefield'; - const promise = new Promise((resolve, reject) =>{ - if (forminput.options.values === undefined) { - forminput.options.values = []; - } else if (dependance) { // in case of dependence load right now - if (!dependance_strict) { - this.getValuesFromField(forminput) - .then(values => { // return array of values - values = this.valuesToKeysValues(values); // set values for select - forminput.options.values = values; - }) - .catch(()=> forminput.options.values = [])// in case of error - .finally(()=> { - forminput.loading = false; - resolve(); - }); - } else { - forminput.loading = false; - resolve(); - } - } else { - // no dependence - this.getValuesFromField(forminput) - .then(values => { // return array of values - values = this.valuesToKeysValues(values); // set values for select - forminput.options.values = values; - }) - .catch((err) => { - forminput.options.values = []; - })// in case of error - .finally(() => { - forminput.loading = false; - resolve(); - }) + // check if it has a dependance + const dependance_strict = undefined !== input.options.dependance_strict ? input.options.dependance_strict : false; + const dependance = undefined !== input.options.dependance ? input.options.dependance : false; + const GIVE_ME_A_NAME_1 = ['selectfield', 'autocompletefield'].includes(input.type); + const GIVE_ME_A_NAME_2 = GIVE_ME_A_NAME_1 && dependance; + + input.options.values = undefined !== input.options.values ? input.options.values : []; + const { values } = input.options; + + let promise; + + /** @FIXME add description */ + if (GIVE_ME_A_NAME_1) { + // ensure seting values options to empty array when undefined + input.loading = input.type !== 'autocompletefield'; + + promise = new Promise((resolve, reject) => { + + // in case of dependence load right now + if (dependance && dependance_strict) { + input.loading = false; + return resolve(); } - }); - if (dependance) { - //set dependence of input - this.inputdependance[forminput.attribute] = dependance; - this.state.loading[dependance] = false; - // set disabled false for back compatibility - forminput.options.disabled = dependance_strict; - /** - * Set dependence between input - */ - this.setInputDependencies({ - master: dependance, - slave: forminput - }); - /** - * Set widget type for fill dependency - */ - if (forminput.options.values.length) { - forminput.widget = 'valuemap'; - forminput.options._values = [...forminput.options.values]; - } else if (forminput.options.layer_id) { - forminput.widget = 'valuerelation'; + // set array of values for select + if (!dependance_strict) { + this + .getValuesFromField(input) + .then(_values => { values.splice(0, values.length).concat(this.valuesToKeysValues(_values)); }) + .catch((err) => { console.warn(err); values.length = 0 }) + .finally(() => { input.loading = false; resolve(); }) } - } + }); + } + + // there is a dependence + if (GIVE_ME_A_NAME_2) { + this.inputdependance[input.attribute] = dependance; // set dependence of input + this.state.loading[dependance] = false; + input.options.disabled = dependance_strict; // disabled for BACKCOMP + this.setInputDependencies({ master: dependance, slave: input }); // set dependence between input + + } + + // set widget type for fill dependency + if (GIVE_ME_A_NAME_2 && values.length) { + input.widget = 'valuemap'; + input.options._values = [...values]; + } + + /** @TODO add description */ + if (GIVE_ME_A_NAME_2 && !values.length && input.options.layer_id) { + input.widget = 'valuerelation'; + } + + /** @TODO add description */ + if (GIVE_ME_A_NAME_1 && 'autocompletefield' !== input.type) { promise .then(() => { - if (forminput.type !== 'autocompletefield') { - if (forminput.options.values.length) { - forminput.options.values[0].value !== ALLVALUE && forminput.options.values.unshift({value:ALLVALUE}); - } else { - forminput.options.values.push({value:ALLVALUE}); - } - forminput.value = ALLVALUE; - } + values[values.length && ALLVALUE !== values[0].value ? 'unshift' : 'push']({ value:ALLVALUE }); + input.value = ALLVALUE; }); } - // ad form inputs to list of search input - this.state.forminputs.push(forminput); + + // add form inputs to list of search input + this.state.forminputs.push(input); } }; @@ -228,6 +265,11 @@ proto.setReturnType = function(returnType='data') { this.show = ('data' === returnType); }; +/** + * @param field + * + * @returns {*} + */ proto.getAutoFieldDependeciesParamField = function(field) { const fieldDependency = this.getCurrentFieldDependance(field); if (fieldDependency) { @@ -236,8 +278,21 @@ proto.getAutoFieldDependeciesParamField = function(field) { } }; -proto.createFieldsDependenciesAutocompleteParameter = function({ fields = [], field, value }={}) { +/** + * @param { Object } opts + * @param opts.fields + * @param opts.field + * @param opts.value + * + * @returns { string | undefined | * } + */ +proto.createFieldsDependenciesAutocompleteParameter = function({ + fields = [], + field, + value, +} = {}) { const dependendency = this.getCurrentFieldDependance(field); + if (undefined !== value) { fields.push(createSingleFieldParameter({ field, value, operator: this.getFilterInputFromField(field).op })); } @@ -259,9 +314,10 @@ proto.createFieldsDependenciesAutocompleteParameter = function({ fields = [], fi * * @param field form input * - * @returns {Promise<[]>} + * @returns { Promise<[]> } */ proto.getValuesFromField = async function(field) { + //if defined layer_id dependence if (field.options.layer_id) { //array of unique values const uniqueValues = await this.getUniqueValuesFromField({ field: field.attribute }); @@ -276,12 +332,33 @@ proto.getValuesFromField = async function(field) { ); } - if (field.options.values.length) { + // Relation reference + if (field.options.relation_reference) { + try { + //call filter data with fformatter + const response = await this.searchLayer.getFilterData({ fformatter: field.attribute }); + //check response + if (response && response.result && response.data) { + field.options.values = response.data.map(([value, key]) => ({ key, value })); + } + } catch(err) { + throw Error(err); + } + } + + if (field.options.values.length > 0) { return this.getValueMapValues(field); } - return this.getUniqueValuesFromField({ field:field.attribute }) + + return this.getUniqueValuesFromField({ field: field.attribute }) }; +/** + * @param field + * @param filter + * + * @returns { Promise<[]> } + */ proto.getValueRelationValues = async function(field, filter) { try { const { data = [] } = await DataRouterService.getData('search:features', { @@ -297,7 +374,7 @@ proto.getValueRelationValues = async function(field, filter) { (data && data[0] && data[0].features || []) .forEach(feature => { values.push({ key: feature.get(field.options.key), value: feature.get(field.options.value) }) - }); + }); return values; } catch(err) { return []; @@ -309,27 +386,42 @@ proto.getValueRelationValues = async function(field, filter) { * * @param field * - * @returns {Promise<*>} + * @returns { Promise<*> } */ proto.getValueMapValues = async function(field) { return field.options.values.filter(value => ALLVALUE !== value); }; + /** * @param layers * @param options.field * @param options.suggest * @param options.unique + * @param options.fformatter since 3.9.0 * @param options.ordering * - * @returns {Promise<*>} + * @returns { Promise<*> } * * @since 3.8.0 */ proto.getLayersFilterData = async function(layers, options = {}) { - const { field, suggest, unique, ordering } = options; + const { + field, + suggest, + unique, + ordering, + fformatter, + } = options; // get unique value from each layers - const promisesData = await Promise.allSettled(layers.map(layer => layer.getFilterData({ field, suggest, unique, ordering }))); + const promisesData = await Promise + .allSettled(layers.map(layer => layer.getFilterData({ + field, + suggest, + unique, + ordering, + fformatter, + }))); const data = Array.from( promisesData @@ -347,11 +439,12 @@ proto.getLayersFilterData = async function(layers, options = {}) { /** * Get unique values from field * + * @param { Object } options * @param options.field * @param options.value * @param options.unique * - * @returns {Promise<[]>} + * @returns { Promise<[]> } */ proto.getUniqueValuesFromField = async function({field, value, output}) { let data = []; @@ -375,20 +468,21 @@ proto.getUniqueValuesFromField = async function({field, value, output}) { /** * Perform search * - * @param filter - * @param search_endpoint - * @param queryUrl - * @param feature_count - * @param show + * @param { Object } opts + * @param opts.filter + * @param opts.search_endpoint + * @param opts.queryUrl + * @param opts.feature_count + * @param opts.show * - * @returns {Promise} + * @returns { Promise } */ proto.doSearch = async function({ filter, search_endpoint = this.getSearchEndPoint(), queryUrl = this.url, feature_count = 10000, - show = this.show + show = this.show, } = {}) { //get or create request filter @@ -437,42 +531,55 @@ proto.doSearch = async function({ }; /** - * Method that filter input base on NONVALIDVALUES - * @returns {*[]} + * Filter input by NONVALIDVALUES + * + * @returns { Array } */ proto.filterValidFormInputs = function() { - return this.state.forminputs.filter(input => -1 === NONVALIDVALUES.indexOf(input.value) && '' !== input.value.toString().trim()); + return this.state + .forminputs + .filter(input => -1 === NONVALIDVALUES.indexOf(input.value) && '' !== input.value.toString().trim()); }; /** - * - * @returns {string|*|string} + * @returns { string | * } */ proto.getSearchEndPoint = function() { return this.search_endpoint || this.searchLayer.getSearchEndPoint() }; -/* -* type wms, vector (for vector api) -* */ +/** + * type wms, vector (for vector api) + */ proto.createFilter = function(search_endpoint = this.getSearchEndPoint()) { return createFilterFormInputs({ layer: this.searchLayers, inputs: this.filterValidFormInputs(), search_endpoint }); }; +/** + * @private + */ proto._run = function() { this.doSearch(); }; /** - * Method called when input search change - * @param id - * @param value + * Called on search input change + * + * @param { Object } opts + * @param opts.id + * @param opts.value */ proto.changeInput = function({id, value} = {}) { this.state.forminputs.find(input => id == input.id).value = value; }; -proto.createQueryFilterFromConfig = function({filter}) { +/** + * @param { Object } opts + * @param opts.filter + * + * @returns { Object } + */ +proto.createQueryFilterFromConfig = function({ filter }) { let queryFilter; for (const operator in filter) { queryFilter = create_boolean_filter(operator, filter[operator]); @@ -480,10 +587,22 @@ proto.createQueryFilterFromConfig = function({filter}) { return queryFilter; }; +/** + * @param field + * + * @returns {*} + */ proto.getFilterInputFromField = function(field) { return this.filter.find(input => input.attribute === field); }; +/** + * @param field + * + * @returns { * | null } + * + * @private + */ proto._getExpressionOperatorFromInput = function(field) { const dependanceCascadeField = this.getFilterInputFromField(field); return dependanceCascadeField ? dependanceCascadeField.op : null; @@ -500,8 +619,10 @@ proto._getCascadeDependanciesFilter = function(field, dependencies = []) { /** * Check if a field has a dependance + * * @param field - * @returns {{}} + * + * @returns { Object } */ proto.getCurrentFieldDependance = function(field) { const dependance = this.inputdependance[field]; @@ -517,7 +638,9 @@ proto.getCurrentFieldDependance = function(field) { * Check the current value of dependance */ proto.getDependanceCurrentValue = function(field) { - return this.inputdependance[field] ? this.cachedependencies[this.inputdependance[field]]._currentValue : this.state.forminputs.find(forminput => forminput.attribute === field).value; + return this.inputdependance[field] ? + this.cachedependencies[this.inputdependance[field]]._currentValue : + this.state.forminputs.find(forminput => forminput.attribute === field).value; }; /** @@ -533,20 +656,25 @@ proto.fillDependencyInputs = function({field, subscribers=[], value=ALLVALUE}={} //loop over dependencies fields inputs subscribers.forEach(subscribe => { // in case of autocomplete reset values to empty array - if (subscribe.type === 'autocompletefield') subscribe.options.values.splice(0); - else { + if (subscribe.type === 'autocompletefield') { + subscribe.options.values.splice(0); + } else { //set starting all values - if (subscribe.options._allvalues === undefined) subscribe.options._allvalues = [...subscribe.options.values]; + if (subscribe.options._allvalues === undefined) { + subscribe.options._allvalues = [...subscribe.options.values]; + } //case of father is set an empty invalid value (all value example) if (invalidValue) { //subscribe has to set all valaues subscribe.options.values.splice(0); setTimeout(()=>subscribe.options.values = [...subscribe.options._allvalues]); - } else subscribe.options.values.splice(1); //otherwise has to get first __ALL_VALUE + } else { + subscribe.options.values.splice(1); + } //otherwise has to get first __ALL_VALUE } subscribe.value = subscribe.type !== 'selectfield' ? ALLVALUE : null; }); - // check i cache field values are set + // check if cache field values are set this.cachedependencies[field] = this.cachedependencies[field] || {}; this.cachedependencies[field]._currentValue = value; const notAutocompleteSubscribers = subscribers.filter(subscribe => subscribe.type !== 'autocompletefield'); @@ -580,8 +708,9 @@ proto.fillDependencyInputs = function({field, subscribers=[], value=ALLVALUE}={} } } else { this.state.loading[field] = true; - if (isRoot) this.cachedependencies[field][value] = this.cachedependencies[field][value] || {}; - else { + if (isRoot) { + this.cachedependencies[field][value] = this.cachedependencies[field][value] || {}; + } else { const dependenceValue = this.getDependanceCurrentValue(field); this.cachedependencies[field][dependenceValue] = this.cachedependencies[field][dependenceValue] || {}; this.cachedependencies[field][dependenceValue][value] = this.cachedependencies[field][dependenceValue][value] || {} @@ -614,20 +743,22 @@ proto.fillDependencyInputs = function({field, subscribers=[], value=ALLVALUE}={} values.forEach(value => subscribe.options.values.push(value)); } else if (widget === 'valuerelation') { - parentData.forEach(feature =>{ - const value = feature.get(attribute); - value && uniqueValues.add(value); + parentData.forEach(feature => { + const value = feature.get(attribute); + value && uniqueValues.add(value); + }); + if (uniqueValues.size > 0) { + const filter = createSingleFieldParameter({ + layer: CatalogLayersStoresRegistry.getLayerById(subscribe.options.layer_id), + search_endpoint: this.getSearchEndPoint(), + field: subscribe.options.key, + value: [...uniqueValues] }); - if (uniqueValues.size > 0) { - const filter = createSingleFieldParameter({ - field: subscribe.options.key, - value: [...uniqueValues] - }); - try { - const values = await this.getValueRelationValues(subscribe, filter); - values.forEach(value => subscribe.options.values.push(value)); - } catch(err) {console.log(err)} - } + try { + const values = await this.getValueRelationValues(subscribe, filter); + values.forEach(value => subscribe.options.values.push(value)); + } catch(err) {console.log(err)} + } } else { parentData.forEach(feature => { @@ -651,37 +782,69 @@ proto.fillDependencyInputs = function({field, subscribers=[], value=ALLVALUE}={} } else { //set disable subscribers.forEach(subscribe => { - if (subscribe.options.dependance_strict) subscribe.options.disabled = false; + if (subscribe.options.dependance_strict) { + subscribe.options.disabled = false; + } }); this.state.loading[field] = false; resolve(); } } } else { - subscribers.forEach(subscribe => subscribe.options.disabled = subscribe.options.dependance_strict); + subscribers + .forEach(subscribe => subscribe.options.disabled = subscribe.options.dependance_strict); resolve(); } }) }; +/** + * @param field + * + * @returns { Array | * } + */ proto.getDependencies = function(field) { return this.inputdependencies[field] || []; }; +/** + * @param { Object } opts + * @param opts.master + * @param opts.slave + */ proto.setInputDependencies = function({ master, slave }={}) { this.inputdependencies[master] = (undefined !== this.inputdependencies[master] ? this.inputdependencies[master] : []); this.inputdependencies[master].push(slave); }; -//set key value for select +/** + * set key value for select + */ proto.valuesToKeysValues = function(values) { - return values.length ? ('Object' !== toRawType(values[0]) ? values.map(value => ({ key: value, value })) : values) : values; + return values.length ? + ('Object' !== toRawType(values[0]) ? values.map(value => ({ key: value, value })) : values) : + values; }; -proto.createQueryFilterObject = function({ogcService='wms', filter={}}={}) { +/** + * @param { Object } opts + * @param opts.ogcService + * @param opts.filter + * + * @returns {{infoFormat: *, crs: *, serverType, layers: [], url: *} & {filter: {}, ogcService: string}} + */ +proto.createQueryFilterObject = function({ + ogcService = 'wms', + filter = {}, +} = {}) { return Object.assign(this.getInfoFromLayer(ogcService), { ogcService, filter }); }; +/** + * @param ogcService + * + * @returns {{infoFormat: *, crs: *, serverType, layers: [], url: *}} + */ proto.getInfoFromLayer = function(ogcService) { return { url: ('wfs' === ogcService ? this.searchLayer.getProject().getWmsUrl() : this.searchLayer.getQueryUrl()), @@ -692,42 +855,47 @@ proto.getInfoFromLayer = function(ogcService) { }; }; +/** + * @param layer + */ proto.setSearchLayer = function(layer) { this.searchLayer = layer; }; +/** + * @returns { null | * } + */ proto.getSearchLayer = function() { - return this.searchLayer + return this.searchLayer; }; +/** + * + */ proto.clear = function() { this.state = null; }; -/** - * @private - */ function create_boolean_filter(operator, inputs = []) { const boolean = { [operator]: [] }; - inputs.forEach((input) => { - for (const operator in input) { - if (Array.isArray(input[operator])) { - create_boolean_filter(operator, input[operator]); // recursion step. - break; + inputs + .forEach((input) => { + for (const operator in input) { + if (Array.isArray(input[operator])) { + create_boolean_filter(operator, input[operator]); // recursion step. + break; + } } - } - boolean[operator].push({ - [input.op] : { + boolean[operator].push({ + [input.op] : { [input.attribute]: null - } - }); + }}); }); return boolean; } /** * Search father layer id based on result of child layer - * @private */ async function parse_search_1n(data, options) { const { search_endpoint, feature_count, relation_id, output_title } = options; @@ -806,9 +974,6 @@ async function parse_search_1n(data, options) { return data; } -/** - * @private - */ function parse_search_by_returnType(data, returnType) { if ('search' === returnType) { GUI.closeContent(); diff --git a/src/assets/style/less/admin-lte2-less/skins/g3w-skin-blue.less b/src/assets/style/less/admin-lte2-less/skins/g3w-skin-blue.less index 241585021..78b714268 100644 --- a/src/assets/style/less/admin-lte2-less/skins/g3w-skin-blue.less +++ b/src/assets/style/less/admin-lte2-less/skins/g3w-skin-blue.less @@ -6,8 +6,3 @@ @import "../../bootstrap-less/variables.less"; @import "../variables.less"; @import "../mixins.less"; - -.skin-blue { - .g3w-tooltip + .tooltip > .tooltip-inner {background-color: @light-blue;} - .g3w-tooltip + .tooltip > .tooltip-arrow { border-bottom-color: @light-blue; } -} diff --git a/src/assets/style/less/app.less b/src/assets/style/less/app.less index 61def73c6..ecc1fc56d 100644 --- a/src/assets/style/less/app.less +++ b/src/assets/style/less/app.less @@ -134,7 +134,6 @@ table.dataTable > tbody > tr.child ul.dtr-details > li { @import "g3w-error-page"; @import "g3w-querybuilder"; @import "g3w-tabs"; -@import "g3w-relations-table"; @import "g3w-print"; @import "g3w-table-attribute"; @@ -244,3 +243,9 @@ table.dataTable > tbody > tr.child ul.dtr-details > li { @import "g3w-dark/g3w-viewport"; +.tooltip .tooltip-inner { + font-weight: 700; + font-size: 1.25rem; + padding: 8px; + background-color: #222; +} \ No newline at end of file diff --git a/src/assets/style/less/g3w-form.less b/src/assets/style/less/g3w-form.less index 1e017093a..7971b8663 100644 --- a/src/assets/style/less/g3w-form.less +++ b/src/assets/style/less/g3w-form.less @@ -23,10 +23,6 @@ max-width: 40%; font-weight: bold } - .attr-value {} - .tooltip.bottom .tooltip-inner { - font-weight:bold; - } .relation-editbtn { padding: 3px 3px 3px 3px; diff --git a/src/assets/style/less/g3w-mapcontrols.less b/src/assets/style/less/g3w-mapcontrols.less index 8095667f6..0b29792a9 100644 --- a/src/assets/style/less/g3w-mapcontrols.less +++ b/src/assets/style/less/g3w-mapcontrols.less @@ -534,10 +534,6 @@ flex-wrap: wrap; z-index: 1; display: flex; - .tooltip { - font-weight: bold; - font-size: 1em; - } .ol-zoom-extent { top:0; left:0; diff --git a/src/assets/style/less/g3w-queryresults.less b/src/assets/style/less/g3w-queryresults.less index 493dbbdb8..b92a010a2 100644 --- a/src/assets/style/less/g3w-queryresults.less +++ b/src/assets/style/less/g3w-queryresults.less @@ -146,7 +146,6 @@ } .tooltip.top .tooltip-inner { margin-left: 100px; - font-weight:bold; } .divider { display: block; diff --git a/src/assets/style/less/g3w-relations-table.less b/src/assets/style/less/g3w-relations-table.less deleted file mode 100644 index 0787f5ebb..000000000 --- a/src/assets/style/less/g3w-relations-table.less +++ /dev/null @@ -1,32 +0,0 @@ -.query-relation { - .header { - margin: 0 !important;; - } - &.mobile { - #relationtable_filter { - &.dataTables_filter{ - display: flex !important; - justify-content: flex-end !important; - } - } - .relations-download { - display: flex; - } - } -} -.relationtable { - &.dataTable tbody { - td span.action-button:hover{ - background-color: transparent; - } - tr.selected { - background-color: #e4e4e4 !important; - .row-wrap-tabs { - .tabs-wrapper { - background-color: #FFFFFF !important; - } - } - } - } -} - diff --git a/src/assets/style/less/g3w-skins/blue/g3w-form.less b/src/assets/style/less/g3w-skins/blue/g3w-form.less index ec4bf9802..ecee64486 100644 --- a/src/assets/style/less/g3w-skins/blue/g3w-form.less +++ b/src/assets/style/less/g3w-skins/blue/g3w-form.less @@ -45,15 +45,6 @@ .g3w-icon { color: @light-blue; } - .tooltip-inner { - background-color:@light-blue; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @light-blue; - } - .tooltip.left .tooltip-arrow { - border-left-color: @light-blue; - } .relation-editbtn { border: 2px solid @light-blue; color: @light-blue; diff --git a/src/assets/style/less/g3w-skins/blue/g3w-mapcontrols.less b/src/assets/style/less/g3w-skins/blue/g3w-mapcontrols.less index 16e75ae67..9736938a5 100644 --- a/src/assets/style/less/g3w-skins/blue/g3w-mapcontrols.less +++ b/src/assets/style/less/g3w-skins/blue/g3w-mapcontrols.less @@ -1,15 +1,5 @@ .skin-blue { - .g3w-map-controls { - .tooltip-inner { - background-color:@light-blue; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @light-blue; - } - .tooltip.left .tooltip-arrow { - border-left-color: @light-blue; - } - } + .ol-control, .ol-custom-overviewmap { button { color: #fff; diff --git a/src/assets/style/less/g3w-skins/blue/g3w-queryresults.less b/src/assets/style/less/g3w-skins/blue/g3w-queryresults.less index 385ca1695..97305d591 100644 --- a/src/assets/style/less/g3w-skins/blue/g3w-queryresults.less +++ b/src/assets/style/less/g3w-skins/blue/g3w-queryresults.less @@ -23,12 +23,6 @@ } } } - .tooltip.top .tooltip-inner { - background-color:@light-blue; - } - .tooltip.top .tooltip-arrow { - border-top-color: @light-blue; - } table.feature_attributes tr:nth-child(even), table.fieldsoutofstructure tr:nth-child(even) { background: fade(@light-blue, 10%) !important; @@ -81,12 +75,5 @@ } } } - - .query-relations-page { - td { - //color: @light-blue; - } - } - } diff --git a/src/assets/style/less/g3w-skins/blue/g3w-skin.less b/src/assets/style/less/g3w-skins/blue/g3w-skin.less index 2f3889447..186df223e 100644 --- a/src/assets/style/less/g3w-skins/blue/g3w-skin.less +++ b/src/assets/style/less/g3w-skins/blue/g3w-skin.less @@ -34,33 +34,4 @@ color: darken(@light-blue,20%) !important; } - .skin-tooltip-top + .tooltip.top, .skin-tooltip-left + .tooltip.left, .skin-tooltip-right + .tooltip.right, .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-inner { - background-color:@light-blue !important; - font-weight: bold; - } - - } - .skin-tooltip-top + .tooltip.top { - .tooltip-arrow { - border-top-color: @light-blue !important; - } - } - .skin-tooltip-left + .tooltip.left { - .tooltip-arrow { - border-left-color: @light-blue !important; - } - } - - .skin-tooltip-right + .tooltip.right { - .tooltip-arrow { - border-right-color: @light-blue !important; - } - } - - .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-arrow { - border-bottom-color: @light-blue !important; - } - } } diff --git a/src/assets/style/less/g3w-skins/green/g3w-form.less b/src/assets/style/less/g3w-skins/green/g3w-form.less index 59c95c3a0..f506e8fa8 100644 --- a/src/assets/style/less/g3w-skins/green/g3w-form.less +++ b/src/assets/style/less/g3w-skins/green/g3w-form.less @@ -43,16 +43,6 @@ .g3w-icon { color: @green; } - .tooltip-inner { - background-color:@green; - font-weight: bold; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @green; - } - .tooltip.left .tooltip-arrow { - border-left-color: @green; - } .relation-editbtn { border: 2px solid @green; color: @green; diff --git a/src/assets/style/less/g3w-skins/green/g3w-mapcontrols.less b/src/assets/style/less/g3w-skins/green/g3w-mapcontrols.less index 0614c7aea..0537c5a42 100644 --- a/src/assets/style/less/g3w-skins/green/g3w-mapcontrols.less +++ b/src/assets/style/less/g3w-skins/green/g3w-mapcontrols.less @@ -1,15 +1,5 @@ .skin-green { - .g3w-map-controls { - .tooltip-inner { - background-color:@green; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @green; - } - .tooltip.left .tooltip-arrow { - border-left-color: @green; - } - } + .ol-control, .ol-custom-overviewmap { button { color: #fff; diff --git a/src/assets/style/less/g3w-skins/green/g3w-queryresults.less b/src/assets/style/less/g3w-skins/green/g3w-queryresults.less index 3b49da18d..3a53beadb 100644 --- a/src/assets/style/less/g3w-skins/green/g3w-queryresults.less +++ b/src/assets/style/less/g3w-skins/green/g3w-queryresults.less @@ -25,12 +25,6 @@ } } } - .tooltip.top .tooltip-inner { - background-color:@green; - } - .tooltip.top .tooltip-arrow { - border-top-color: @green; - } table.feature_attributes tr:nth-child(even), table.fieldsoutofstructure tr:nth-child(even) { background: @light-green-48 !important; @@ -83,11 +77,5 @@ } } } - - .query-relations-page { - td { - //color: @green; - } - } } diff --git a/src/assets/style/less/g3w-skins/green/g3w-skin.less b/src/assets/style/less/g3w-skins/green/g3w-skin.less index d59bd0a58..10a224fc4 100644 --- a/src/assets/style/less/g3w-skins/green/g3w-skin.less +++ b/src/assets/style/less/g3w-skins/green/g3w-skin.less @@ -33,31 +33,4 @@ color: darken(@green,20%) !important; } - .skin-tooltip-top + .tooltip.top, .skin-tooltip-left + .tooltip.left, .skin-tooltip-right + .tooltip.right, .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-inner { - background-color:@green !important; - font-weight: bold; - } - } - .skin-tooltip-left + .tooltip.left { - .tooltip-arrow { - border-left-color: @green !important; - } - } - - .skin-tooltip-top + .tooltip.top .tooltip-arrow { - border-top-color: @green !important; - } - - .skin-tooltip-right + .tooltip.right { - .tooltip-arrow { - border-right-color: @green !important; - } - } - - .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-arrow { - border-bottom-color: @green !important; - } - } } diff --git a/src/assets/style/less/g3w-skins/purple/g3w-form.less b/src/assets/style/less/g3w-skins/purple/g3w-form.less index 031c24de9..8c946a350 100644 --- a/src/assets/style/less/g3w-skins/purple/g3w-form.less +++ b/src/assets/style/less/g3w-skins/purple/g3w-form.less @@ -47,12 +47,6 @@ background-color:@purple; font-weight: bold; } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @purple; - } - .tooltip.left .tooltip-arrow { - border-left-color: @purple; - } .relation-editbtn { border: 2px solid @purple; color: @purple; diff --git a/src/assets/style/less/g3w-skins/purple/g3w-mapcontrols.less b/src/assets/style/less/g3w-skins/purple/g3w-mapcontrols.less index 93bc90535..f37f09e18 100644 --- a/src/assets/style/less/g3w-skins/purple/g3w-mapcontrols.less +++ b/src/assets/style/less/g3w-skins/purple/g3w-mapcontrols.less @@ -1,15 +1,5 @@ .skin-purple { - .g3w-map-controls { - .tooltip-inner { - background-color:@purple; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @purple; - } - .tooltip.left .tooltip-arrow { - border-left-color: @purple; - } - } + .ol-control, .ol-custom-overviewmap { button { color: #fff; diff --git a/src/assets/style/less/g3w-skins/purple/g3w-queryresults.less b/src/assets/style/less/g3w-skins/purple/g3w-queryresults.less index 190009b9a..00dfa1a3f 100644 --- a/src/assets/style/less/g3w-skins/purple/g3w-queryresults.less +++ b/src/assets/style/less/g3w-skins/purple/g3w-queryresults.less @@ -22,12 +22,6 @@ } } } - .tooltip.top .tooltip-inner { - background-color:@purple; - } - .tooltip.top .tooltip-arrow { - border-top-color: @purple; - } table.feature_attributes tr:nth-child(even), table.fieldsoutofstructure tr:nth-child(even) { background: fade(@purple, 10%) !important; diff --git a/src/assets/style/less/g3w-skins/purple/g3w-skin.less b/src/assets/style/less/g3w-skins/purple/g3w-skin.less index 96d052f11..49829f107 100644 --- a/src/assets/style/less/g3w-skins/purple/g3w-skin.less +++ b/src/assets/style/less/g3w-skins/purple/g3w-skin.less @@ -32,32 +32,5 @@ .skin-color-dark { color: darken(@purple,20%) !important; } - .skin-tooltip-top + .tooltip.top, .skin-tooltip-left + .tooltip.left, .skin-tooltip-right + .tooltip.right, .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-inner { - background-color: @purple !important; - font-weight: bold; - } - } - .skin-tooltip-top + .tooltip.top { - .tooltip-arrow { - border-top-color: @purple !important; - } - } - .skin-tooltip-left + .tooltip.left { - .tooltip-arrow { - border-left-color: @purple !important; - } - } - .skin-tooltip-right + .tooltip.right { - .tooltip-arrow { - border-right-color: @purple !important; - } - } - - .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-arrow { - border-bottom-color: @purple !important; - } - } } diff --git a/src/assets/style/less/g3w-skins/red/g3w-form.less b/src/assets/style/less/g3w-skins/red/g3w-form.less index f21c896c6..b1f4604b5 100644 --- a/src/assets/style/less/g3w-skins/red/g3w-form.less +++ b/src/assets/style/less/g3w-skins/red/g3w-form.less @@ -42,16 +42,7 @@ .g3w-icon { color: @red; } - .tooltip-inner { - background-color:@red; - font-weight: bold; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @red; - } - .tooltip.left .tooltip-arrow { - border-left-color: @red; - } + .relation-editbtn { border: 2px solid @red; color: @red; diff --git a/src/assets/style/less/g3w-skins/red/g3w-mapcontrols.less b/src/assets/style/less/g3w-skins/red/g3w-mapcontrols.less index da3f7fe01..d7144e7fc 100644 --- a/src/assets/style/less/g3w-skins/red/g3w-mapcontrols.less +++ b/src/assets/style/less/g3w-skins/red/g3w-mapcontrols.less @@ -1,15 +1,4 @@ .skin-red { - .g3w-map-controls { - .tooltip-inner { - background-color:@red; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @red; - } - .tooltip.left .tooltip-arrow { - border-left-color: @red; - } - } .ol-control, .ol-custom-overviewmap { button { color: #fff; diff --git a/src/assets/style/less/g3w-skins/red/g3w-queryresults.less b/src/assets/style/less/g3w-skins/red/g3w-queryresults.less index 70c05818b..23dcf3a18 100644 --- a/src/assets/style/less/g3w-skins/red/g3w-queryresults.less +++ b/src/assets/style/less/g3w-skins/red/g3w-queryresults.less @@ -22,12 +22,6 @@ } } } - .tooltip.top .tooltip-inner { - background-color:@red; - } - .tooltip.top .tooltip-arrow { - border-top-color: @red; - } table.feature_attributes tr:nth-child(even), table.fieldsoutofstructure tr:nth-child(even) { background: fade(@red, 10%) !important; @@ -83,11 +77,5 @@ } } - .query-relations-page { - td { - //color: @red; - } - } - } diff --git a/src/assets/style/less/g3w-skins/red/g3w-skin.less b/src/assets/style/less/g3w-skins/red/g3w-skin.less index 67494d1be..7db60b03c 100644 --- a/src/assets/style/less/g3w-skins/red/g3w-skin.less +++ b/src/assets/style/less/g3w-skins/red/g3w-skin.less @@ -33,33 +33,4 @@ color: darken(@red,20%) !important; } - .skin-tooltip-top + .tooltip.top, .skin-tooltip-left + .tooltip.left, .skin-tooltip-right + .tooltip.right, .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-inner { - background-color: @red !important; - font-weight: bold; - } - - } - .skin-tooltip-top + .tooltip.top { - .tooltip-arrow { - border-top-color: @red !important; - } - } - .skin-tooltip-left + .tooltip.left { - .tooltip-arrow { - border-left-color: @red !important; - } - } - - .skin-tooltip-right + .tooltip.right { - .tooltip-arrow { - border-right-color: @red !important; - } - } - - .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-arrow { - border-bottom-color: @red !important; - } - } } diff --git a/src/assets/style/less/g3w-skins/yellow/g3w-form.less b/src/assets/style/less/g3w-skins/yellow/g3w-form.less index 4fc460d56..18470c086 100644 --- a/src/assets/style/less/g3w-skins/yellow/g3w-form.less +++ b/src/assets/style/less/g3w-skins/yellow/g3w-form.less @@ -43,16 +43,6 @@ .g3w-icon { color: @yellow; } - .tooltip-inner { - background-color:@yellow; - font-weight: bold; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @yellow; - } - .tooltip.left .tooltip-arrow { - border-left-color: @yellow; - } .relation-editbtn { border: 2px solid @yellow; color: @yellow; diff --git a/src/assets/style/less/g3w-skins/yellow/g3w-mapcontrols.less b/src/assets/style/less/g3w-skins/yellow/g3w-mapcontrols.less index 9d19f8802..4a77b444c 100644 --- a/src/assets/style/less/g3w-skins/yellow/g3w-mapcontrols.less +++ b/src/assets/style/less/g3w-skins/yellow/g3w-mapcontrols.less @@ -1,15 +1,5 @@ .skin-yellow { - .g3w-map-controls { - .tooltip-inner { - background-color:@yellow; - } - .tooltip.bottom .tooltip-arrow { - border-bottom-color: @yellow; - } - .tooltip.left .tooltip-arrow { - border-left-color: @yellow; - } - } + .ol-control, .ol-custom-overviewmap { button { color: #fff; diff --git a/src/assets/style/less/g3w-skins/yellow/g3w-queryresults.less b/src/assets/style/less/g3w-skins/yellow/g3w-queryresults.less index a100efe1b..33dfed4fe 100644 --- a/src/assets/style/less/g3w-skins/yellow/g3w-queryresults.less +++ b/src/assets/style/less/g3w-skins/yellow/g3w-queryresults.less @@ -22,12 +22,6 @@ } } } - .tooltip.top .tooltip-inner { - background-color:@yellow; - } - .tooltip.top .tooltip-arrow { - border-top-color: @yellow; - } table.feature_attributes tr:nth-child(even), table.fieldsoutofstructure tr:nth-child(even) { background: fade(@yellow, 10%) !important; @@ -83,11 +77,5 @@ } } - .query-relations-page { - td { - //color: @yellow; - } - } - } diff --git a/src/assets/style/less/g3w-skins/yellow/g3w-skin.less b/src/assets/style/less/g3w-skins/yellow/g3w-skin.less index a7fe059f0..b0446fda7 100644 --- a/src/assets/style/less/g3w-skins/yellow/g3w-skin.less +++ b/src/assets/style/less/g3w-skins/yellow/g3w-skin.less @@ -33,33 +33,4 @@ color: darken(@yellow,20%) !important; } - .skin-tooltip-top + .tooltip.top, .skin-tooltip-left + .tooltip.left, .skin-tooltip-right + .tooltip.right, .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-inner { - background-color: @yellow !important; - font-weight: bold; - } - - } - .skin-tooltip-top + .tooltip.top { - .tooltip-arrow { - border-top-color: @yellow !important; - } - } - .skin-tooltip-left + .tooltip.left { - .tooltip-arrow { - border-left-color: @yellow !important; - } - } - - .skin-tooltip-right + .tooltip.right { - .tooltip-arrow { - border-right-color: @yellow !important; - } - } - - .skin-tooltip-bottom + .tooltip.bottom { - .tooltip-arrow { - border-bottom-color: @yellow !important; - } - } } diff --git a/src/components/App.vue b/src/components/App.vue index 98821988e..9d75e68bf 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -1396,6 +1396,8 @@ export default { $('#g3w-modal-overlay').css('height',$(window).height()); }); + document.body.classList.toggle('is-mobile', this.isMobile()); + }, }; diff --git a/src/components/CatalogLayerContextMenu.vue b/src/components/CatalogLayerContextMenu.vue index e4be52f06..6471ee927 100644 --- a/src/components/CatalogLayerContextMenu.vue +++ b/src/components/CatalogLayerContextMenu.vue @@ -240,11 +240,20 @@
- WMS URL - + WMS URL + +
@@ -254,11 +263,20 @@
- WFS URL - + WFS URL + +
@@ -740,7 +758,7 @@ * Set current filter * * @param filter - * + * * @since 3.9.0 */ async setCurrentLayerFilter(filter) { @@ -760,11 +778,11 @@ /** * Delete filter from saved filters - * + * * @param fid - * + * * @returns { Promise } - * + * * @since 3.9.0 */ async deleteFilter(fid) { @@ -860,7 +878,7 @@ /** * @returns { boolean } whether it can show filters menu - * + * * @since 3.9.0 */ canShowFiltersMenu(layer) { diff --git a/src/components/CatalogTristateTree.vue b/src/components/CatalogTristateTree.vue index 34db60035..80445796c 100644 --- a/src/components/CatalogTristateTree.vue +++ b/src/components/CatalogTristateTree.vue @@ -153,6 +153,7 @@ class = "action-button skin-tooltip-left selection-filter-icon" data-placement = "left" data-toggle = "tooltip" + data-container="body" :class = "g3wtemplate.getFontClass('clear')" @click.caputure.prevent.stop = "clearSelection" v-t-tooltip.create = "'layer_selection_filter.tools.clear'" @@ -164,6 +165,7 @@ class = "action-button skin-tooltip-left selection-filter-icon" data-placement = "left" data-toggle = "tooltip" + data-container="body" :class = "[ g3wtemplate.getFontClass('filter'), layerstree.filter.active ? 'active' : '', @@ -381,7 +383,7 @@ export default { /** * Remove current active filter - * + * * @since 3.9.0 */ async removeCurrentFilter() { @@ -502,7 +504,7 @@ export default { /** * Save layer filter - * + * * @since 3.9.0 */ saveFilter(layerstree) { diff --git a/src/components/InputLonLat.vue b/src/components/InputLonLat.vue index 27d142d24..400b74f8b 100644 --- a/src/components/InputLonLat.vue +++ b/src/components/InputLonLat.vue @@ -6,8 +6,14 @@