diff --git a/gulpfile.js b/gulpfile.js index dcaab6f2d..c633e1e79 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -90,7 +90,7 @@ const dev_plugins = Array.from( */ function get_version(pluginName) { const src = (pluginName ? `${g3w.pluginsFolder}/${pluginName}` : '.'); - // delete cache of require otherwise no package.json version rest the old (cache) one + // delete cache of require otherwise no package.json version rests the old (cache) one delete require.cache[require.resolve(`${src}/package.json`)]; try { return require(`${src}/package.json`).version; @@ -131,7 +131,7 @@ function get_branch(pluginName) { } /** - * Create standard version format for app and plugins + * Create a standard version format for app and plugins * * @param { string } pluginName * @@ -178,12 +178,12 @@ const browserify_plugin = (pluginName, watch = true) => { console.log(INFO__ + `Building plugin:` + __RESET + ' → ' + outputFolder); let bundler = browserify(`./${pluginName}/index.js`, { - basedir: `${g3w.pluginsFolder}`, - paths: [`${g3w.pluginsFolder}`], - debug: !production, - cache: {}, + basedir: `${g3w.pluginsFolder}`, + paths: [`${g3w.pluginsFolder}`], + debug: !production, + cache: {}, packageCache: {}, - plugin: [ + plugin: [ watch && !production ? watchify : undefined, /* Uncomment the following in next ESM release (v4.x) */ // esmify @@ -206,26 +206,26 @@ const browserify_plugin = (pluginName, watch = true) => { const branch = get_branch(pluginName); return merge( - gulp - .src(`./src/plugins/_version.js`), // NB: hardcoded file, do not use `g3w.pluginsFolder`! - bundler - .bundle() - .on('error', (err) => { gutil.log(err); process.exit(); }) - .pipe(source(`${src}/build.js`)) - .pipe(buffer()) - .pipe(rename('plugin.js')) - ) - .pipe(concat('plugin.js')) - .pipe(replace('process.env.g3w_plugin_name', `"${pluginName}"`)) - .pipe(replace('process.env.g3w_plugin_version', `"${is_prod_branch(branch) ? version : version.split('-')[0] + '-' + branch }"`)) - .pipe(replace('process.env.g3w_plugin_hash', `"${hash}"`)) - .pipe(replace('process.env.g3w_plugin_branch', `"${branch}"`)) - .pipe(gulpif(production, sourcemaps.init())) - .pipe(gulpif(production, uglify({ compress: { drop_console: true } }).on('error', gutil.log))) - .pipe(gulpif(production, sourcemaps.write(src))) - .pipe(gulp.dest(src)) // put plugin.js to plugin folder (git source) - .pipe(gulp.dest(outputFolder)) // put plugin.js to static folder (PROD | DEV env) - .pipe(gulpif(!production, browserSync.reload({ stream: true }))); // refresh browser after changing local files (dev mode) + gulp + .src(`./src/plugins/_version.js`), // NB: hardcoded file, do not use `g3w.pluginsFolder`! + bundler + .bundle() + .on('error', (err) => { gutil.log(err); process.exit(); }) + .pipe(source(`${src}/build.js`)) + .pipe(buffer()) + .pipe(rename('plugin.js')) + ) + .pipe(concat('plugin.js')) + .pipe(replace('process.env.g3w_plugin_name', `"${pluginName}"`)) + .pipe(replace('process.env.g3w_plugin_version', `"${is_prod_branch(branch) ? version : version.split('-')[0] + '-' + branch }"`)) + .pipe(replace('process.env.g3w_plugin_hash', `"${hash}"`)) + .pipe(replace('process.env.g3w_plugin_branch', `"${branch}"`)) + .pipe(gulpif(production, sourcemaps.init())) + .pipe(gulpif(production, uglify({ compress: { drop_console: true } }).on('error', gutil.log))) + .pipe(gulpif(production, sourcemaps.write(src))) + .pipe(gulp.dest(src)) // put plugin.js to plugin folder (git source) + .pipe(gulp.dest(outputFolder)) // put plugin.js to static folder (PROD | DEV env) + .pipe(gulpif(!production, browserSync.reload({ stream: true }))); // refresh browser after changing local files (dev mode) }; return rebundle(); @@ -393,12 +393,12 @@ gulp.task('browserify:app', function() { */ gulp.task('images', function () { return gulp.src([ - `${g3w.assetsFolder}/images/**/*.{png,jpg,gif,svg}`, - `${g3w.pluginsFolder}/**/*.{png,jpg,gif,svg}`, - '!./src/**/node_modules/**/' - ]) - .pipe(flatten()) - .pipe(gulp.dest(`${outputFolder}/static/client/images/`)) + `${g3w.assetsFolder}/images/**/*.{png,jpg,gif,svg}`, + `${g3w.pluginsFolder}/**/*.{png,jpg,gif,svg}`, + '!./src/**/node_modules/**/' + ]) + .pipe(flatten()) + .pipe(gulp.dest(`${outputFolder}/static/client/images/`)) }); /** @@ -415,14 +415,14 @@ gulp.task('datatable-images', function () { */ gulp.task('fonts', function () { return gulp.src([ - `${g3w.assetsFolder}/fonts/**/*.{eot,ttf,woff,woff2}`, - `${g3w.assetsFolder}/vendors/bootstrap/fonts/**/*.{eot,ttf,woff,woff2}`, - `${g3w.assetsFolder}/vendors/font-awesome-5.15.4/webfonts/**/*.{eot,ttf,woff,woff2}`, - `${g3w.pluginsFolder}/**/*.{eot,ttf,woff,woff2}`, - '!./src/**/node_modules/**/' - ]) - .pipe(flatten()) - .pipe(gulp.dest(`${outputFolder}/static/client/fonts/`)) + `${g3w.assetsFolder}/fonts/**/*.{eot,ttf,woff,woff2}`, + `${g3w.assetsFolder}/vendors/bootstrap/fonts/**/*.{eot,ttf,woff,woff2}`, + `${g3w.assetsFolder}/vendors/font-awesome-5.15.4/webfonts/**/*.{eot,ttf,woff,woff2}`, + `${g3w.pluginsFolder}/**/*.{eot,ttf,woff,woff2}`, + '!./src/**/node_modules/**/' + ]) + .pipe(flatten()) + .pipe(gulp.dest(`${outputFolder}/static/client/fonts/`)) }); /** @@ -489,15 +489,11 @@ gulp.task('concatenate:vendor_css', function() { */ gulp.task('browser-sync', function() { browserSync.init({ - port: g3w.port, - open: false, + port: g3w.port, + open: false, startPath: '/', - proxy: { - target: g3w.proxy.url - }, - socket: { - domain: `${g3w.host}:${g3w.port}` - } + proxy: { target: g3w.proxy.url }, + socket: { domain: `${g3w.host}:${g3w.port}`} }); /* Uncomment the following in next Gulp Release (v4.x) */ @@ -531,15 +527,15 @@ gulp.task('clone:default_plugins', function() { }); /** - * Ask the developer which plugins wants to deploy + * Ask the developer which plugins want to deploy */ gulp.task('select-plugins', function() { return gulp .src('./package.json') .pipe( prompt.prompt({ - type: 'checkbox', - name: 'plugins', + type: 'checkbox', + name: 'plugins', message: 'Plugins', default: ['client'], // exclude from plugin list "client" and all "template_" plugins @@ -662,8 +658,8 @@ gulp.task('test', function() { * @see src\app\version */ gulp.task('version', function() { - set_version(); // client - dev_plugins.forEach(pluginName => set_version(pluginName)); // plugins + set_version(); // client + dev_plugins.forEach(name => set_version(name)); // plugins }); /** diff --git a/src/app/api.js b/src/app/api.js index 2d2e15dba..957d816ca 100644 --- a/src/app/api.js +++ b/src/app/api.js @@ -166,7 +166,6 @@ const FormComponent = require('gui/form/vue/form'); const FormService = require('gui/form/formservice'); const InputsComponents = require('gui/inputs/inputs'); const Fields = require('gui/fields/fields'); -const SearchPanelService = require('gui/search/vue/panel/searchservice'); /** * G3W-OL modules @@ -376,7 +375,6 @@ const g3wsdk = { Fields, Mixins, services: { - SearchPanel: SearchPanelService, FormService } } diff --git a/src/app/config.js b/src/app/config.js index 7b4430585..0de5d9d16 100644 --- a/src/app/config.js +++ b/src/app/config.js @@ -4,19 +4,16 @@ */ import translations from '../locales'; -const apptitle = "G3W Client"; + +const apptitle = "G3W Client"; const supportedLanguages = ['en', 'it']; export const plugins = {}; -export const tools = { - tools: [] -}; +export const tools = { tools: [] }; -// get message from internationalization -export const _i18n = { - resources: translations -}; +// get a message from internationalization +export const _i18n = { resources: translations }; export const client = { debug: true, @@ -25,19 +22,17 @@ export const client = { export const server = { urls: { - baseurl: '/', - ows: 'ows', - api: 'api', + baseurl: '/', + ows: 'ows', + api: 'api', initconfig: 'api/initconfig', - config: 'api/config' + config: 'api/config' } }; export const utils = { merge(type) { - if (type) { - console.log(CONFIG) - } + if (type) { console.log(type) } } }; diff --git a/src/app/constant.js b/src/app/constant.js index 9a6801785..a36468d71 100644 --- a/src/app/constant.js +++ b/src/app/constant.js @@ -36,27 +36,27 @@ export const DEFAULT_EDITING_CAPABILITIES = [ export const DOWNLOAD_FORMATS = { download: { format: 'shapefile', - url: 'shp' + url: 'shp' }, download_gpkg: { format: 'gpkg', - url: 'gpkg' + url: 'gpkg' }, download_gpx: { format: 'gpx', - url: 'gpx' + url: 'gpx' }, download_csv: { format: 'csv', - url: 'csv' + url: 'csv' }, download_xls: { format: 'xls', - url: 'xls' + url: 'xls' }, download_raster: { format: 'geotiff', - url: 'geotiff' + url: 'geotiff' } }; @@ -88,19 +88,19 @@ export const G3W_FID = 'g3w_fid'; * @type {Object} * @since v3.5 */ -export const FILTER_OPERATORS = { - gte: '>=', - lte: '<=', - NOT: '!=', - eq: '=', - gt: '>', - lt: '<', - IN: 'IN', +export const FILTER_OPERATORS = { + gte: '>=', + lte: '<=', + NOT: '!=', + eq: '=', + gt: '>', + lt: '<', + IN: 'IN', 'NOT IN': 'NOT IN', - LIKE: 'LIKE', - ILIKE: 'ILIKE', - AND: 'AND', - OR: 'OR', + LIKE: 'LIKE', + ILIKE: 'ILIKE', + AND: 'AND', + OR: 'OR', }; /** @@ -108,10 +108,10 @@ export const FILTER_OPERATORS = { * @since v3.5 */ export const FILTER_EXPRESSION_OPERATORS = { - lte: '<=', - ltgt: '!=', + lte: '<=', + ltgt: '!=', ilike: 'ILIKE', - like: 'LIKE', + like: 'LIKE', ...FILTER_OPERATORS, }; @@ -209,19 +209,12 @@ export const LOCALSTORAGE_EXTERNALWMS_ITEM = 'externalwms'; * @type {MapSettings} */ export const MAP_SETTINGS = { - ZOOM: { - maxScale: 1000, - }, - ANIMATION: { - duration: 2000 - }, + ZOOM: { maxScale: 1000, }, + ANIMATION: { duration: 2000, }, LAYER_POSITIONS: { default: 'top', - getPositions(){ - return [ - 'top', - 'bottom' - ] + getPositions() { + return [ 'top', 'bottom' ] } } }; @@ -253,96 +246,96 @@ export const PRINT_RESOLUTIONS = [150, 300]; */ export const PRINT_SCALES = [ { - value:100, - label:'1:100' + value: 100, + label: '1:100' }, { - value:200, - label:'1:200' + value: 200, + label: '1:200' }, { - value:500, - label:'1:500' + value: 500, + label: '1:500' }, { - value:1000, - label:'1:1.000' + value: 1000, + label: '1:1.000' }, { - value:2000, - label:'1:2.000' + value: 2000, + label: '1:2.000' }, { - value:2500, - label:'1:2.500' + value: 2500, + label: '1:2.500' }, { - value:5000, - label:'1:5.000' + value: 5000, + label: '1:5.000' }, { - value:10000, - label:'1:10.000' + value: 10000, + label: '1:10.000' }, { - value:20000, - label:'1:20.000' + value: 20000, + label: '1:20.000' }, { - value:25000, - label:'1:25.000' + value: 25000, + label: '1:25.000' }, { - value:50000, - label:'1:50.000' + value: 50000, + label: '1:50.000' }, { - value:100000, - label:'1:100.000' + value: 100000, + label: '1:100.000' }, { - value:250000, - label:'1:250.000' + value: 250000, + label: '1:250.000' }, { - value:500000, - label:'1:500.000' + value: 500000, + label: '1:500.000' }, { - value:1000000, - label:'1:1.000.000' + value: 1000000, + label: '1:1.000.000' }, { - value:2500000, - label:'1:2.500.000' + value: 2500000, + label: '1:2.500.000' }, { - value:5000000, - label:'1:5.000.000' + value: 5000000, + label: '1:5.000.000' }, { - value:10000000, - label:'1:10.000.000' + value: 10000000, + label: '1:10.000.000' }, { - value:20000000, - label:'1:20.000.000' + value: 20000000, + label: '1:20.000.000' }, { - value:50000000, - label:'1:50.000.000' + value: 50000000, + label: '1:50.000.000' }, { - value:100000000, - label:'1:100.000.000' + value: 100000000, + label: '1:100.000.000' }, { - value:250000000, - label:'1:250.000.000' + value: 250000000, + label: '1:250.000.000' }, { - value:500000000, - label:'1:500.000.000' + value: 500000000, + label: '1:500.000.000' } ]; @@ -352,7 +345,7 @@ export const PRINT_SCALES = [ * @type {{unit: string, value: number}} */ export const QUERY_POINT_TOLERANCE = { - unit: 'pixel', + unit: 'pixel', value: 10 }; @@ -404,9 +397,7 @@ export const VIEWPORT = { * @type {Object} */ export const ZINDEXES = { - usermessage: { - tool: 2 - } + usermessage: { tool: 2 } }; /** @@ -597,12 +588,12 @@ export const FONT_AWESOME_ICONS = { export const LOCAL_ITEM_IDS = { MESSAGES: { - id: 'MESSAGES', + id: 'MESSAGES', value: {} }, SPATIALBOOKMARKS: { - id: 'SPATIALBOOKMARKS', + id: 'SPATIALBOOKMARKS', value: {} }, @@ -633,7 +624,7 @@ export const DOTS_PER_INCH = 96; * @since 3.10.0 */ export const INCHES_PER_UNIT = { - m: 39.37, + m: 39.37, degrees: 4374754 }; diff --git a/src/app/core/data/service.js b/src/app/core/data/service.js deleted file mode 100644 index 604e5e683..000000000 --- a/src/app/core/data/service.js +++ /dev/null @@ -1,56 +0,0 @@ -import ProjectsRegistry from 'store/projects'; -import GUI from 'services/gui'; - -const { resolve } = require('utils'); - -function BaseService(){ - ProjectsRegistry.onbefore('setCurrentProject' , project => this.project = project); - this.project = ProjectsRegistry.getCurrentProject(); -} - -const proto = BaseService.prototype; -/** - * - * @param request is a Promise(jquery promise at moment - * @returns {Promise} - */ -proto.handleRequest = function(request){ - // OVERWRITE TO SERVICE -}; - -proto.handleResponse = async function(response){ - // OVERWRITE TO SERVICE -}; - -/** - * @param {{ type: 'vector' }} - * - * @returns { unknown[] } array of external layer add on project - * - * @since 3.8.0 - */ -proto.getSelectedExternalLayers = function({type = 'vector'}) { - return GUI.getService('catalog').getExternalSelectedLayers({ type }); -}; - -/** - * @returns {Promise<[]>} a resolved request (empty array) - * - * @since 3.8.0 - */ -proto.getEmptyRequest = function(){ - return resolve([]); -}; - -/** - * @param {{ type: 'vector' }} - * - * @returns {boolean} - * - * @since 3.8.0 - */ -proto.hasExternalLayerSelected = function({type = 'vector'}) { - return this.getSelectedExternalLayers({ type }).length > 0; -}; - -module.exports = BaseService; \ No newline at end of file diff --git a/src/app/core/g3w-barstack.js b/src/app/core/g3w-barstack.js new file mode 100644 index 000000000..611d7221d --- /dev/null +++ b/src/app/core/g3w-barstack.js @@ -0,0 +1,162 @@ +/** + * @file + * @since 3.10.0 + */ + +import Panel from 'core/g3w-panel'; +import Component from 'core/g3w-component'; +import G3WObject from 'core/g3wobject'; + +/** + * Barstack Class - used to mount panels stack on top of each parent + * + * ORIGINAL SOURCE src/app/gui/utils/barstack.js@v3.9.3 + * + */ +export class BarStack extends G3WObject { + + constructor() { + + super(); + + /** identify the DOM element where insert the component/panel */ + this._parent = null; + + /** barstack state. It stores the panel array */ + this.state = { + contentsdata: [] // Array<{ content, options }> + } + + } + + /** + * push componenet on top of parent + */ + push(content, options={}) { + this._parent = options.parent; + return this._mount(content, options); + } + + /** + * remove the last component from stack + */ + pop() { + const d = $.Deferred(); + const data = this.state.contentsdata; + if (data.length) { + this._unmount(data.slice(-1)[0].content).then(() => { d.resolve(data.pop()) }); + } else { + d.resolve(); + } + return d.promise(); + } + + /** + * clear all stacks + */ + clear() { + const d = $.Deferred(); + const data = this.state.contentsdata; + if (data.length) { + $ + .when(data.map(d => this._unmount(d.content))) + .then(() => { data.splice(0, data.length); d.resolve(); }); + } else { + d.resolve(); + } + this.emit('clear'); + return d.promise(); + } + + getContentData() { + return this.state.contentsdata; + } + + getCurrentContentData() { + return this.state.contentsdata[this.state.contentsdata.length - 1]; + } + + getPreviousContentData() { + return this.state.contentsdata[this.state.contentsdata.length - 2]; + } + + /** + * Mount component to parent + */ + _mount(content, options) { + const d = $.Deferred(); + const data = this.state.contentsdata; + + // check the type of content: + + // String or JQuery + if (content instanceof jQuery || _.isString(content)) { + let el = _.isString(content) ? ($(content).length ? $('
' + content + '
') : $(content)) : content + $(this._parent).append(el); + data.push({ content: el, options }); + console.warn('[G3W-CLIENT] jQuery components will be discontinued, please update your code as soon as possible', data[data.length - 1]); + d.resolve(); + } + + // Vue element + else if (content.mount && 'function' === typeof content.mount) { + // Check duplicate element by component id (if already exist) + let id = data.findIndex(d => d.content.getId && (d.content.getId() === content.getId())); + if (-1 !== id) { + data[id].content.unmount().then(() => data.splice(id, 1)); + } + // Mount vue component + content + .mount(this._parent, options.append || false) + .then(() => { + $(this._parent).localize(); + data.push({ content, options }); + d.resolve(content); + }); + + } + + // DOM element + else { + this._parent.appendChild(content); + data.push({ content, options }); + d.resolve(); + } + + return d.promise(); + + } + + /** + * unmount component + */ + _unmount(content) { + const d = $.Deferred(); + if (content instanceof Component || content instanceof Panel) { + content.unmount().then(() => d.resolve()); + } else { + $(this._parent).empty(); + d.resolve(); + } + return d.promise(); + } + + forEach(cbk) { + this.state.contentsdata.forEach(d => cbk(d.content)); + } + + /** + * @returns number of elements stored in stack + */ + getLength() { + return this.state.contentsdata.length; + } + + /** + * @since 3.10.0 + */ + getComponentById(id) { + return (this.getContentData().find(d => d.content.id == id) || {}).content; + } + +} \ No newline at end of file diff --git a/src/app/core/g3w-component.js b/src/app/core/g3w-component.js new file mode 100644 index 000000000..c7667d065 --- /dev/null +++ b/src/app/core/g3w-component.js @@ -0,0 +1,344 @@ +/** + * @file + * @since 3.10.0 + */ +import G3WObject from 'core/g3wobject'; +import { merge } from 'utils/merge'; +import { noop } from 'utils/noop'; +import { capitalize_first_letter } from 'utils/capitalize_first_letter'; +import { resolve } from 'utils/resolve'; +import GUI from 'services/gui'; + +/** @deprecated */ +const _cloneDeep = require('lodash.clonedeep'); + +const deprecate = require('util-deprecate'); + +const çç = (a, b) => undefined !== a ? a : b; // like a ?? (coalesce operator) + +/** + * Component class + * + * ORIGINAL SOURCE src/app/gui/component/component.js@v3.9.3 + * + * @param { Object} opts + * @param { number } opts.id + * @param { string } opts.title + * @param { boolean } opts.visible + * @param { boolean } opts.open + * @param { boolean } opts.resizable + * @param { null | unknown } opts.info + * @param { boolean } opts.loading + * @param { boolean } opts.disabled + * @param { boolean } opts.closewhenshowviewportcontent + * @param opts.events + * @param opts.internalComponent since 3.10.0 + * @param opts.service since 3.10.0 + */ +export default class Component extends G3WObject { + + constructor(opts = {}) { + + // BACKOMP v3.x + if (opts.iconConfig) { + opts.iconColor = opts.iconConfig.color; + opts.icon = opts.iconConfig.icon; + delete opts.iconConfig; + } + + // TODO: check why `GUI.getFontClass` is undefined + opts.icon = GUI.getFontClass(opts.icon) || opts.icon; + + super({ + setters: { + + setOpen(bool) { + this.state.open = bool; + if (this._setOpen) { + this._setOpen(bool); + } + }, + + setVisible(bool) { + this.state.visible = bool; + if (this._setVisible) { + this._setVisible(bool); + } + }, + + setLoading(bool = false) { + this.state.loading = bool; + }, + + setDisabled(bool = false) { + this.state.disabled = bool; + }, + + reload() { + console.warn('[G3W-CLIENT] reloading of components will be discontinued, please update your code as soon as possible', this.getId()) + if (this._reload) { + this._reload(); + } + }, + } + + }); + + this._firstLayout = true; + + /** internal VUE component */ + this.internalComponent = çç(opts.internalComponent, null); + + /** @type { Array } */ + this._components = []; + + /** @type { string } */ + this.id = çç(opts.id, Math.random() * 1000); + + /** @type { string } */ + this.title = çç(opts.title, ''); + + this.state = { + sizes: { width: 0, height:0 }, + info: çç(opts.info, null), + open: çç(opts.open, false), + visible: çç(opts.visible, true), + loading: çç(opts.loading, false), + disabled: çç(opts.disabled, false), + resizable: çç(opts.resizable, false), + closewhenshowviewportcontent: çç(opts.closewhenshowviewportcontent, true), + }; + + this.setService(opts.service || this); + + if (opts.internalComponent) { + this.setInternalComponent(opts.internalComponent); + } + + merge(this, opts); + + // add events options + this.events = çç(opts.events, {}); + + if (this.events.open) { + const { when = "after", cb = () => {} } = this.events.open; + this[`on${when}`]('setOpen', bool => cb(bool)); + } + + if (opts.vueComponentObject) { + this.init(opts); + } + } + + /** + * @param { Object } opts + * @param { Array } opts.components + * @param { Object } opts.service + * @param { Function } opts.service.init + * @param opts.vueComponentObject + * @param opts.template + * @param opts.propsData + */ + init(opts = {}) { + this.vueComponent = _cloneDeep(opts.vueComponentObject); + this._components = opts.components || []; + + this.setService(opts.service || this._service || noop); + + if (this._service.init && this.init !== this._service.init) { + this._service.init(opts); + } + + if (opts.template) { + this.vueComponent.template = opts.template; + } + + this.setInternalComponent = function() { + this.internalComponent = new (Vue.extend(this.vueComponent))({ + service: this._service, + template: opts.template, + propsData: opts.propsData + }); + this.internalComponent.state = this.getService().state; + }; + + this.setInternalComponent(); + + return this; + } + + getId() { + return this.id; + } + + setId(id) { + this.id = id; + } + + getOpen() { + return this.state.open; + } + + closeWhenViewportContentIsOpen() { + return this.getOpen() && this.state.closewhenshowviewportcontent; + } + + getVisible() { + return this.state.visible; + } + + getTitle() { + return this.state.title; + } + + setTitle(title) { + this.state.title = title; + } + + getService() { + return this._service; + } + + setService(service) { + this._service = service; + } + addComponent(Component) { + this._components.push(Component); + } + + removeComponent(Component) { + this._components.find((c, i) => { + if (c === Component) { + this.splice(i, 1); + return true; + } + }) + } + + getInternalComponent() { + return this.internalComponent; + } + + setInternalComponent(internalComponent, options={}) { + this.internalComponent = undefined === internalComponent && this.internalComponentClass ? new this.internalComponentClass : internalComponent; + (options.events || []) + .forEach(e => this.internalComponent.$on(e.name, data => e.handler && e.handler(data) || this[`set${capitalize_first_letter(e.name)}`](data))); + if (this._service && this._service.state) { + this.internalComponent.state = this._service.state; + } + } + + /** + * @param { Element | 'string' } parent DOM element + * @param { boolean } append + * + * @returns jquery promise + * + * @fires internalComponent~ready + * @fires mount event + */ + mount(parent, append) { + const d = $.Deferred(); + + if (!this.internalComponent) { + this.setInternalComponent(); + } + + if (append) { + $(parent).append(this.internalComponent.$mount().$el); + } + + if (!append){ + this.internalComponent.$mount(parent); + } + + this.internalComponent.$nextTick(() => { + $(parent).localize(); + this.emit('ready'); + d.resolve(true); + }); + + // emit mount event + this.emit('mount'); + + return d.promise(); + } + + /** + * @returns jquery promise + * + * @fires unmount + */ + unmount() { + if (!this.internalComponent) { + return resolve(); + } + if (this.state.resizable) { + this.internalComponent.$off('resize-component', this.internalComponent.layout); + } + this.state.open = false; + this.internalComponent.$destroy(true); // destroy vue component + $(this.internalComponent.$el).remove(); // remove dom element + this.internalComponent = null; // set internal componet to null (for GC) + this.emit('unmount'); // emit unmount event + return resolve(); + } + + /** + * @returns { Element } DOM element + */ + ismount() { + return this.internalComponent && this.internalComponent.$el; + } + + /** + * @param { number } width + * @param { number } height + * + * @listens internalComponent~resize-component + * @fires internalComponent~resize-component + * @fires layout + */ + layout(width, height) { + if (this.state.resizable && this._firstLayout) { + this.internalComponent.$on('resize-component', this.internalComponent.layout); + this._firstLayout = false; + } + this.internalComponent.$nextTick(() => { this.internalComponent.$emit('resize-component', { width, height }); }); + this.emit('layout'); + } + +} + +/** + * @deprecated since 3.10.0 Will be deleted in 4.x. + */ +Object.assign(Component.prototype, { + _setOpen: noop, + _setVisible: noop, + _reload: noop, + destroy: noop, + click: noop, + show: noop, + setComponents: deprecate(function(c) { this._components = Array.isArray(c) ? c: []; }, '[G3W-CLIENT] Component::setComponents(components) is deprecated'), + setInternalComponentTemplate: deprecate(function(t) { t && (this.vueComponent.template = t); }, '[G3W-CLIENT] Component::setInternalComponentTemplate(template) is deprecated'), + getInternalTemplate: deprecate(function() { return this.vueComponent.template; }, '[G3W-CLIENT] Component::getInternalTemplate() is deprecated'), + insertComponentAt: deprecate(function(i, c) { this._components.splice(i, 0, c); }, '[G3W-CLIENT] Component::insertComponentAt(index, Component) is deprecated'), + removeCompomentAt: deprecate(function(i) { this._components.splice(i, 1); }, '[G3W-CLIENT] Component::removeCompomentAt(index) is deprecated'), + exendComponents: deprecate(function(c) { _.merge(this._components, c); }, '[G3W-CLIENT] Component::exendComponents(components) is deprecated'), + addInternalComponentData: deprecate(function(d) { _.merge(this.internalComponent, d) }, '[G3W-CLIENT] Component::addInternalComponentData(data) is deprecated'), + handleEventsComponent: deprecate(function() { this.events.open && this['on' + (this.events.open || 'after')]('setOpen', b => (this.events.open.cb || (() => {}))(b)); }, '[G3W-CLIENT] Component::handleEventsComponent() is deprecated'), + popComponent: deprecate(function() { return this._components.pop(); }, '[G3W-CLIENT] Component::popComponent() is deprecated'), + overwriteServiceMethod: deprecate(function(n, m) { this._service[n] = m; }, '[G3W-CLIENT] Component::overwriteServiceMethod(methodName, method) is deprecated'), + extendInternalComponentMethods: deprecate(function(m) { m && Object.entries(m).forEach(([k, v]) => (!(v instanceof Function)) && delete m[k]); merge(this.vueComponent.methods, m); }, '[G3W-CLIENT] Component::extendInternalComponentMethods(methods) is deprecated'), + extendInternalComponentComponents: deprecate(function(c) { c && merge(this.vueComponent.components, c); }, '[G3W-CLIENT] Component::extendInternalComponentComponents(components) is deprecated'), + extendComponents: deprecate(function(c) { this.extendInternalComponentComponents(c); }, '[G3W-CLIENT] Component::extendComponents(components) is deprecated'), + extendInternalComponentComputed: deprecate(function(c) { c && Object.entries(c).forEach(([k, v]) => (!(v instanceof Function)) && delete c[k]); merge(this.vueComponent.computed, c); }, '[G3W-CLIENT] Component::extendInternalComponentComputed(computed) is deprecated'), + extendService: deprecate(function(o) { this._service && merge(this._service, serviceOptions); }, '[G3W-CLIENT] Component::extendService(serviceOptions) is deprecated'), + createVueComponent: deprecate(function(o) { return _cloneDeep(o); }, '[G3W-CLIENT] Component::createVueComponent(vueObjOptions) is deprecated'), + closeWhenViewportContentIsOpen: deprecate(function() { return this.getOpen() && this.state.closewhenshowviewportcontent; }, '[G3W-CLIENT] Component::closeWhenViewportContentIsOpen() is deprecated'), + /** used by the following plugins: "cadastre", "iternet" */ + overwriteServiceMethods: deprecate(function(o) { Object.entries(o).forEach(([n, m]) => this._service[n] = m) }, '[G3W-CLIENT] Component::overwriteServiceMethods(methodsOptions) is deprecated'), + /** used by the following plugins: "cadastre" */ + extendInternalComponent: deprecate(function(o) { this.vueComponent ? Object.entries(o).forEach(([k, v]) => { switch (k) { case 'methods': this.extendInternalComponentMethods(v); break; case 'components': this.extendInternalComponentComponents(v); break; case 'computed': merge(this.vueComponent[k], v); break; case 'data': merge(this.vueComponent[k], v); break; } }): (this.vueComponent = o); }, '[G3W-CLIENT] Component::extendInternalComponent(internalComponentOptions) is deprecated'), +}); \ No newline at end of file diff --git a/src/app/core/g3w-object.js b/src/app/core/g3w-object.js new file mode 100644 index 000000000..7c22c26a2 --- /dev/null +++ b/src/app/core/g3w-object.js @@ -0,0 +1,265 @@ +import { noop } from 'utils/noop'; +import { debounce } from 'utils/debounce'; +import { throttle } from 'utils/throttle'; + +/** + * Mimics the behavior of child class fields in parent class, + * which is the only way to define a property (eg `this.setters = { ... }`) + * before invoking the `super()` constructor. + * + * @TODO upgrade babel version in order to declare `setters`, `throttles` `debounces` as class fields + * + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields + */ +function defineClassField(obj, key, cb, initVal) { + // The Field is already available within parent constructor + // in case of ES5 inheritance (i.e. `inherit(ChildClass, G3WObject);`) + if (initVal) { + return cb.call(obj, initVal); + } + // The Field is not available within parent constructor + // in case ES6 inheritance (i.e. `class ChildClass extends G3WObject { };`); + // I.e + // class A extends G3WObject { + // constructor() { + // super(); + // this.setters = { + // foo() {}, + // bar() {}, + // }; + // } + // } + let currVal = initVal; + return Object.defineProperty(obj, key, { + get() { return currVal; }, + set(value) { + currVal = value; + if (value) { cb.call(obj, value); } + }, + }); +} + +/** + * Base object to handle a setter and its listeners. + */ +export default class G3WObject extends EventEmitter { + + constructor(opts) { + super(opts); + + opts = opts || {}; + + // Register the chain of events + + defineClassField(this, 'setters', this._setupListenersChain, opts.setters || this.setters); + defineClassField(this, 'throttles', this._setupThrottles, opts.throttles || this.throttles); + defineClassField(this, 'debounces', this._setupDebounces, opts.debounces || this.debounces); + } + + /** + * Attach an event listener after executing a setter method + * + * @param {string} setter - function name to listen for + * @param {function} listener - event listener (sync) + * @param {number} priority - priority (lowest value executes first) + */ + onafter(setter, listener, priority) { + return this._onsetter('after', setter, listener, false, priority); + } + + /** + * Attach an event listener after executing a setter method (once) + * + * @param {string} setter - function name to listen for + * @param {function} listener - event listener (sync) + * @param {number} priority - priority (lowest value executes first) + */ + onceafter(setter, listener, priority) { + return this._onsetter('after', setter, listener, false, priority, true); + } + + /** + * Attach an event listener before executing a setter method + * + * @param {string} setter - function name to listen for + * @param {function} listener - event listener (sync) + * @param {number} priority - priority (lowest value executes first) + */ + onbefore(setter, listener, priority) { + return this._onsetter('before', setter, listener, false, priority); + } + + /** + * Attach an event listener before executing a setter method (once) + * + * @param {string} setter - function name to listen for + * @param {function} listener - event listener (sync) + * @param {number} priority - priority (lowest value executes first) + */ + oncebefore(setter, listener, priority) { + return this._onsetter('before', setter, listener, false, priority, true); + } + + /** + * Attatch an event listener before executing a setter method (once) + * + * @param {string} setter - function name to listen for + * @param {function} listener - event listener (async) + * @param {number} priority - priority (lowest value executes first) + */ + onbeforeasync(setter, listener, priority) { + return this._onsetter('before', setter, listener, true, priority); + } + + /** + * Loop each settersListeners (array) and find a setter key (before/after) to be removed + */ + un(setter, key) { + Object.entries(this.settersListeners) + .forEach(([_key, setters]) => { + if (undefined === key) { + setters[setter].splice(0); + } else { + setters[setter].forEach((listener, idx) => { listener.key === key && setters[setter].splice(idx, 1); }) + } + }); + }; + +/** + * Register and handle listeners + * + * @param { 'before' | 'after' } when + * @param { Function } setter + * @param { Object } listener + * @param { Boolean } async + * @param { Number } priority + * @param { Boolean } once + */ + _onsetter(when, setter, listener, async, priority = 0, once = false) { + // unique listenerKey + let key; + // check if setter function is registered + // and then add an info object to setter listeners + // (sorted based on priority) + if (this.settersListeners && undefined !== this.settersListeners[when][setter]) { + key = `${Math.floor(Math.random() * 1000000) + Date.now()}`; + this.settersListeners[when][setter].push({ key, fnc: listener, async, priority, once}); + this.settersListeners[when][setter] = _.sortBy(this.settersListeners[when][setter], listener => listener.priority); + } + return key // in case of no setter register return undefined listenerKey + } + + /** + * @returns {Promise} + */ + _setupListenersChain(setters) { + + // all methods inside object "setters" of child class. + this.settersListeners = { + after: {}, + before: {}, + }; + + for (const setter in setters) { + + // Array to push before and after subscribers + this.settersListeners.after[setter] = []; + this.settersListeners.before[setter] = []; + + // assign the property setter name to the object as own method + this[setter] = function(...args) { + + // listener count + let count = 0; + + const deferred = $.Deferred(); + + /** + * + * @param {undefined | Boolean} bool + */ + const next = (bool) => { + //check if it needs to skip (exit) + const skip = _.isBoolean(bool) ? !bool : false; + //get count of before subscribers on setter function + const len = this.settersListeners.before[setter].length; + + // abort in case of error bool false, + // or we reached the end of onbefore subscriber + if (skip) { + (_.isFunction(setters[setter]) ? noop : (setters[setter].fallback || noop)).apply(this, args); + deferred.reject(); + return; + } + + // call complete method methods and check what returns + if (count === len) { + // run setter function (resolve promise) + deferred.resolve((_.isFunction(setters[setter]) ? setters[setter] : setters[setter].fnc).apply(this, args)); + // call all subscribed methods after setter + const onceListeners = []; + this + .settersListeners + .after[setter] + .forEach(listener => { + listener.fnc.apply(this, args); + if (listener.once) { + onceListeners.push(listener.key); + } + }); + onceListeners.forEach(key => this.un(setter, key)); + this.emitEvent(`set:${setter}`, args); + } + // still call an onbefore listener subscribers + if (count < len) { + //get on before listener subscribes and increment count to 1 + const listener = this.settersListeners.before[setter][count++]; + //check if it is async + if (listener.async) { + // add function next to argument of listener function + args.push(next); + listener.fnc.apply(this, args) + } else { + // return or undefined or a boolean to tell if ok(true) can continue or not (false) + next(listener.fnc.apply(this, args)); + } + //in case of listener subscribe function need to run just one time + // after call remove it from listeners + if (listener.once) { + this.settersListeners.before[setter].splice(count - 1, 1); + } + } + + }; + + // run all the subscribers and setters + next(true); + + return deferred.promise(); + } + + } + return this.settersListeners; + } + + _setupDebounces(debounces) { + for (const name in debounces) { + this[name] = debounce(debounces[name].fnc, debounces[name].delay); + } + } + + _setupThrottles(throttles) { + for (const name in throttles) { + this[name] = throttle(throttles[name].fnc, throttles[name].delay); + } + } + + get(key) { + return this[key] && !(this[key] instanceof Function) ? this[key] : null; + } + + set(key, value) { + this[key] = value; + } + +}; \ No newline at end of file diff --git a/src/app/core/g3w-panel.js b/src/app/core/g3w-panel.js new file mode 100644 index 000000000..aef2f3ef3 --- /dev/null +++ b/src/app/core/g3w-panel.js @@ -0,0 +1,92 @@ +/** + * @file + * @since 3.10.0 + */ + +import GUI from 'services/gui'; +import G3WObject from 'core/g3w-object'; +import { resolve } from 'utils/resolve'; + +/** + * ORIGINAL SOURCE: src/app/gui/panel.js@v3.9.3 + */ +export default class Panel extends G3WObject { + + constructor (opts = {}) { + super(); + + this.id = opts.id || null; + + this.title = opts.title || ''; + + this.service = opts.service; + + if (opts.vueComponentObject) { + this.internalPanel = new (Vue.extend(opts.vueComponentObject))({ service: this.service }); + } else { + this.internalPanel = opts.panel || opts.internalPanel || null; + } + + if (true === opts.show && this.internalPanel) { + this.show(); + } + } + + getId() { + return this.id; + } + + getTitle() { + return this.title; + } + + getService() { + return this.service; + } + + setService(service) { + this.service = service; + } + + getInternalPanel() { + return this.internalPanel; + } + + setInternalPanel(internalPanel) { + this.internalPanel = internalPanel; + } + + show() { + GUI.showPanel(this); + } + + close() { + GUI.closePanel(); + } + + mount(parent) { + const panel = this.internalPanel; + const vueComp = panel.$mount(); + $(parent).append(vueComp.$el); + vueComp.$nextTick(() => { + $(parent).localize(); + if (panel.onShow) { panel.onShow();} + }); + return resolve(true); + } + + unmount() { + const panel = this.internalPanel; + panel.$destroy(true); + $(panel.$el).remove(); + if (panel.onClose) { panel.onClose();} + this.internalComponent = null; + if (this.service && this.service.clear) { + this.service.clear(); + } + return resolve(); + } + + onResize(parentWidth,parentHeight) {} + +} \ No newline at end of file diff --git a/src/app/core/g3wobject.js b/src/app/core/g3wobject.js index fd30742c6..4fb4c686e 100644 --- a/src/app/core/g3wobject.js +++ b/src/app/core/g3wobject.js @@ -1,214 +1,7 @@ -const { inherit, noop, debounce, throttle } = require('utils'); - -/** - * Base object to handle a setter and its listeners. - * @constructor - */ -const G3WObject = function() { - //check if setters property is set. Register the chain of events - this.setters && this._setupListenersChain(this.setters); - // check debounces - this.debounces && this._setupDebounces(this.debounces); - //check throttles - this.throttles && this._setupThrottles(this.throttles); -}; - -inherit(G3WObject, EventEmitter); - -const proto = G3WObject.prototype; - /** - * Insert a listener on afeter setter was executed - * @param {string} setter - IMethod name to register a listener function - * @param {function} listener - listener function (only syncron) - * @param {number} priority - Priorità di esecuzione: valore minore viene eseuito prima + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 */ -proto.onafter = function(setter, listener, priority){ - return this._onsetter('after', setter, listener, false, priority); -}; - -proto.onceafter = function(setter, listener, priority){ - return this._onsetter('after', setter, listener, false, priority, true); -}; - -/** - * Listern before cal sesster - * @param {string} setter - Method name setter - * @param {function} listener - function to call - * @param {number} priority - Priority - */ -proto.onbefore = function(setter, listener, priority) { - return this._onsetter('before', setter, listener, false, priority); -}; - -// once before -proto.oncebefore = function(setter, listener, priority){ - return this._onsetter('before', setter, listener, false, priority, true); -}; - -/** - * @param {string} setter - Method name setter - * @param {function} listener - function to call - * @param {number} priority - Priority - */ -proto.onbeforeasync = function(setter, listener, priority) { - return this._onsetter('before', setter, listener, true, priority); -}; - -proto.un = function(setter, key) { - // cicle on after before (key) and for each settersListeners (array) find key - Object.entries(this.settersListeners).forEach(([_key, settersListeners]) => { - if (key === undefined) settersListeners[setter].splice(0); - else settersListeners[setter].forEach((setterListener, idx) => { - if (setterListener.key === key) { - settersListeners[setter].splice(idx, 1); - } - }) - }); -}; - -// base function to register and handle on setter listeners -/* - when=before|after, - type=sync|async -*/ -proto._onsetter = function(when, setter, listener, async, priority=0, once=false) { - let listenerKey; - // check if setter function is register. - if (typeof this.settersListeners[when][setter] !== "undefined") { - // set unique listenerKey value - listenerKey = `${Math.floor(Math.random()*1000000) + Date.now()}`; - // add info object to setters listeners - this.settersListeners[when][setter].push({ - key: listenerKey, - fnc: listener, - async, - priority, - once - }); - // set lineners base on priority - this.settersListeners[when][setter] = _.sortBy(this.settersListeners[when][setter], setterListener => setterListener.priority); - } - // return key - return listenerKey // in case of no setter register return undefined listerKey -}; - -proto._setupListenersChain = function(setters) { - // initialize all methods inside object "setters" of child class. - this.settersListeners = { - after: {}, - before: {} - }; - for (const setter in setters) { - const setterOption = setters[setter]; - let setterFnc = noop; - let setterFallback = noop; - if (_.isFunction(setterOption)) setterFnc = setterOption; - else { - setterFnc = setterOption.fnc; - setterFallback = setterOption.fallback || noop; // method called in case of error - } - // create array to push before and after subscribers - this.settersListeners.after[setter] = []; - this.settersListeners.before[setter] = []; - // assign the property settern name to the object as own method - this[setter] = function(...args) { - const deferred = $.Deferred(); - let returnVal = null; - let counter = 0; - // function to call original function(setter function) - const callSetter = () => { - // run setter function - returnVal = setterFnc.apply(this, args); - // resolve promise - deferred.resolve(returnVal); - //call all subscribed methods afet setter - const onceListenerKeys = []; - const afterListeners = this.settersListeners.after[setter]; - afterListeners.forEach(listener => { - listener.fnc.apply(this, args); - listener.once && onceListenerKeys.push(listener.key); - }); - onceListenerKeys.forEach(key => this.un(setter, key)); - }; - // abort function - const abort = () => { - setterFallback.apply(this, args); - deferred.reject(); - }; - // get all before listeners functions of setter - const beforeListeners = this.settersListeners['before'][setter]; - // listener counter - counter = 0; - const next = bool => { - // initilize cont to true (continue) - let cont = true; - // check if bool is Boolean - if (_.isBoolean(bool)) cont = bool; - // check if count is false or we are arrived to the end of onbefore subscriber - if (cont === false) { - // found an error so we can abort - abort.apply(this, args); - } else if (counter === beforeListeners.length) { - // call complete method methods - const completed = callSetter(); - //verifico che cosa ritorna - if (completed === undefined || completed === true) { - this.emitEvent(`set:${setter}`,args); - } - } else if (cont) { - const listenerObj = beforeListeners[counter]; - const currentCounter = counter; - // if is async functtion - if (beforeListeners[counter].async) { - //add function next to argument of listnerFunction - args.push(next); - // update counter - counter += 1; - listenerObj.fnc.apply(this, args) - } else { - // return or undefine or a boolen to tell if ok(true) can conitnue or not (false) - const bool = listenerObj.fnc.apply(this, args); - //update counter - counter += 1; - next(bool); - } - listenerObj.once && beforeListeners.splice(currentCounter, 1); - } - }; - // run next to start to run all the subscribers and setrer its self - next(); - // retun a promise - return deferred.promise(); - } - } - return this.settersListeners -}; - -proto._setupDebounces = function(debounces) { - for (const name in debounces) { - const delay = debounces[name].delay; - const fnc = debounces[name].fnc; - this[name] = debounce(fnc, delay); - } -}; - -proto._setupThrottles = function(throttles) { - for (const name in throttles) { - const delay = throttles[name].delay; - const fnc = throttles[name].fnc; - this[name] = throttle(fnc, delay); - } -}; - -//method get -proto.get = function(key) { - return this[key] && !(this[key] instanceof Function) ? this[key] : null; -}; - -//method set -proto.set = function(key, value) { - this[key] = value; -}; -module.exports = G3WObject; +import G3WObject from 'core/g3w-object'; +module.exports = G3WObject; \ No newline at end of file diff --git a/src/app/core/i18n/i18n.service.js b/src/app/core/i18n/i18n.service.js index 2c1788a0b..6a62c3191 100755 --- a/src/app/core/i18n/i18n.service.js +++ b/src/app/core/i18n/i18n.service.js @@ -34,8 +34,7 @@ function init(config) { } const getAppLanguage = function() { - const config = ApplicationService.getConfig(); - return config.user.i18n || "en"; + return ApplicationService.getConfig().user.i18n || "en"; }; @@ -50,9 +49,7 @@ const tPlugin = function(text) { }; const tPrefix = function(filter) { - return function(text) { - return i18next.t(`${filter}.${text}`); - } + return (text) => i18next.t(`${filter}.${text}`); }; const addI18nPlugin = function({name, config}) { diff --git a/src/app/core/layers/features/featuresstore.js b/src/app/core/layers/features/featuresstore.js index c7e519805..dab3cf0d9 100644 --- a/src/app/core/layers/features/featuresstore.js +++ b/src/app/core/layers/features/featuresstore.js @@ -1,11 +1,11 @@ const { base, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); +const G3WObject = require('core/g3wobject'); /** @deprecated */ -const _cloneDeep = require('lodash.clonedeep'); +const _cloneDeep = require('lodash.clonedeep'); // Object to store and handle features of layer -function FeaturesStore(options={}) { +function FeaturesStore(options = {}) { this._features = options.features || []; this._provider = options.provider || null; this._loadedIds = []; // store locked ids @@ -13,9 +13,7 @@ function FeaturesStore(options={}) { //setters this.setters = { addFeatures(features) { - features.forEach(feature => { - this._addFeature(feature); - }) + features.forEach(feature => this._addFeature(feature)) }, addFeature(feature) { this._addFeature(feature); @@ -64,9 +62,7 @@ proto.getProvider = function() { proto.unlock = function() { const d = $.Deferred(); this._provider.unlock() - .then(response => { - d.resolve(response) - }) + .then(response => d.resolve(response)) .fail(err => d.reject(err)); return d.promise(); }; @@ -94,13 +90,13 @@ proto._getFeatures = function(options={}) { proto._filterFeaturesResponse = function(options={}) { /** * get features returned from server and feature that are currently locked. - * If featurelocks are less that a features, it means that other user is editing these feature + * If featurelocks are less than features, it means that another user is editing these features * @type {*[]} */ - const {features=[], featurelocks=[]} = options; + const { features = [], featurelocks = [] } = options; - //if no features locks mean all feature request are locked by another user - if (featurelocks.length === 0) { + //if no features locks mean all feature requests are locked by another user + if (0 === featurelocks.length) { //if there are feature on response are locked if (features.length > 0) { this.featuresLockedByOtherUser(features); @@ -144,7 +140,7 @@ proto._filterFeaturesResponse = function(options={}) { * {featureid: "1", lockid: "6bbab1c1c03332fb39b8ffae35e557ba"} * @private */ -proto._filterLockIds = function(featurelocks=[]) { +proto._filterLockIds = function(featurelocks = []) { const _lockIds = this._lockIds.map(lockid => lockid.featureid); const toAddLockId = featurelocks.filter(featurelock => _lockIds.indexOf(featurelock.featureid) === -1); this._lockIds = [...this._lockIds, ...toAddLockId]; @@ -177,7 +173,8 @@ proto._commit = function(commitItems) { const d = $.Deferred(); if (commitItems && this._provider) { commitItems.lockids = this._lockIds; - this._provider.commit(commitItems) + this._provider + .commit(commitItems) .then(response => d.resolve(response)) .fail(err => d.reject(err)) } else d.reject(); @@ -186,11 +183,11 @@ proto._commit = function(commitItems) { // get feature from id proto.getFeatureById = function(featureId) { - return this._features.find(feature => feature.getId() == featureId); + return this._features.find(feature => featureId == feature.getId()); }; proto.getFeatureByUid = function(uid) { - return this._features.find(feature => feature.getUid() === uid); + return this._features.find(feature => uid === feature.getUid()); }; proto._addFeature = function(feature) { diff --git a/src/app/core/layers/features/olfeaturesstore.js b/src/app/core/layers/features/olfeaturesstore.js index d53b2ba4d..e0b983313 100644 --- a/src/app/core/layers/features/olfeaturesstore.js +++ b/src/app/core/layers/features/olfeaturesstore.js @@ -1,5 +1,5 @@ const { inherit, base } = require('utils'); -const FeaturesStore = require('core/layers/features/featuresstore'); +const FeaturesStore = require('core/layers/features/featuresstore'); // Storage of the feature in vector layer function OlFeaturesStore(options={}) { @@ -29,11 +29,11 @@ proto.getFeaturesCollection = function() { }; proto.getFeatureById = function(featureId) { - return this._features.getArray().find(feature => feature.getId() == featureId); + return this._features.getArray().find(feature => featureId == feature.getId()); }; proto.getFeatureByUid = function(uid) { - return this._features.getArray().find(feature => feature.getUid() === uid); + return this._features.getArray().find(feature => uid === feature.getUid()); }; proto._addFeature = function(feature) { @@ -42,7 +42,7 @@ proto._addFeature = function(feature) { this._features.dispatchEvent('change') }; -//sobtitute the feature after modify +//substitute the feature after modifying proto._updateFeature = function(feature) { // set index at -1 let index = -1; diff --git a/src/app/core/layers/filter/expression.js b/src/app/core/layers/filter/expression.js index 870f6f42a..7042a9560 100644 --- a/src/app/core/layers/filter/expression.js +++ b/src/app/core/layers/filter/expression.js @@ -1,170 +1,141 @@ -import { FILTER_EXPRESSION_OPERATORS as OPERATORS } from 'app/constant'; +import { FILTER_EXPRESSION_OPERATORS } from 'app/constant'; //Expression -function Expression(options={}) { - this._layerName = options.layerName; - const filter = options.filter; - this._expression = filter && filter || ''; -} - -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; -}; - -proto.or = function() { - if (field && value) { - this._expression = this._expression ? this._expression + ' OR ' : this._expression; - this.eq(field, value); - } - return this; -}; - -proto.eq = function (field, value) { - this._expression = this._expression + this._build('eq', field, value); - return this; -}; - -proto.like = function(field, value) { - this._expression = this._expression + this._build('LIKE', field, value); - return this; -}; - -proto.ilike = function(field, value) { - this._expression = this._expression + this._build('ILIKE', field, value); - return this; -}; - -proto.not = function(field, value) { - this._expression = this._expression + this._build('NOT', field, value); - return this; -}; - -proto.gt = function(field, value) { - this._expression = this._expression + this._build('gt', field, value); - return this; -}; - -proto.gte = function(field, value) { - this._expression = this._expression + this._build('gte', field, value); - return this; -}; - -proto.lt = function(field, value) { - this._expression = this._expression + this._build('lt', field, value); - return this; -}; - -proto.lte = function(field, value) { - this._expression = this._expression + this._build('lte', field, value); - return this; -}; - -proto.clear = function() { - this._expression = ''; - return this; -}; - -// get expression method to get the realt value of the expression -proto.get = function() { - return this._layerName ? `${this._layerName}: ${this._expression}`: this._expression; -}; - -proto._build = function(operator, field, value) { - return [`"${field}"`, OPERATORS[operator], `${value}`].join(' '); -}; - -proto.createSingleExpressionElement = function({value, attribute, operator, logicop}={}){ - let filterElement; - const valueExtra = (operator === 'LIKE' || operator === 'ILIKE') ? "%": ""; - const filterOp = OPERATORS[operator]; - const filterLogicOperator = logicop && ` ${logicop} ` || ''; - if (operator === 'IN') { - const _value = Array.isArray(value) ? value : [value]; - 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) - ) { - const singolequote = Array.isArray(value) ? value : - typeof value !== 'number' ? value.split("'") : []; - if (singolequote.length > 1) { - const _filterElements = []; - for (let i = 0; i < singolequote.length; i++) { - const value = singolequote[i]; - if (!value) - continue; - const filterValue = `%${value}%`.trim(); - const filterElement = `"${attribute}" ${filterOp} '${filterValue}'`; - _filterElements.push(filterElement) - } - filterElement = `${_filterElements.join(` ${logicop} `)}${filterLogicOperator}`; - } else filterElement = `"${attribute}" ${filterOp} '${valueExtra}${value}${valueExtra}'${filterLogicOperator}`; - } - return filterElement; -}; - -proto.createExpressionFromFilterObject = function(filter={}){ - let filterElements = []; - let rootFilter; - for (const operator in filter) { - rootFilter = OPERATORS[operator]; - const inputs = filter[operator]; - inputs.forEach((input) => { - for (const operator in input) { - const value = input[operator]; - if (Array.isArray(value)) { - this.createExpressionFromFilterObject(input); - } else { - const field = input[operator]; - for (const attribute in field) { - const value = field[attribute]; - const fieldElement = this.createSingleExpressionElement({ - value, - operator, - attribute - }); - filterElements.push(fieldElement); +module.exports = class Expression { + + constructor(options={}) { + this._layerName = options.layerName; + this._expression = options.filter || ''; + } + + and(field, value) { + this._expression = this._expression ? this._expression + ' AND ': this._expression; + if (field && value) { + this.eq(field, value); + } + return this; + } + + or(field, value) { + if (field && value) { + this._expression = this._expression ? this._expression + ' OR ' : this._expression; + this.eq(field, value); + } + return this; + } + + eq(field, value) { + this._expression = this._expression + this._build('eq', field, value); + return this; + } + + like(field, value) { + this._expression = this._expression + this._build('LIKE', field, value); + return this; + }; + + ilike(field, value) { + this._expression = this._expression + this._build('ILIKE', field, value); + return this; + } + + not(field, value) { + this._expression = this._expression + this._build('NOT', field, value); + return this; + } + + gt(field, value) { + this._expression = this._expression + this._build('gt', field, value); + return this; + } + + gte(field, value) { + this._expression = this._expression + this._build('gte', field, value); + return this; + } + + lt(field, value) { + this._expression = this._expression + this._build('lt', field, value); + return this; + } + + lte(field, value) { + this._expression = this._expression + this._build('lte', field, value); + return this; + } + + clear() { + this._expression = ''; + return this; + } + + // get expression method to get the realt value of the expression + get() { + return this._layerName ? `${this._layerName}: ${this._expression}`: this._expression; + } + + _build(operator, field, value) { + return [`"${field}"`, FILTER_EXPRESSION_OPERATORS[operator], `${value}`].join(' '); + } + + createSingleExpressionElement({ value, attribute, operator, logicop } = {}) { + const op = FILTER_EXPRESSION_OPERATORS[operator]; + const logic = logicop && ` ${logicop} ` || ''; + + if ('IN' === operator) { + return `"${attribute}" ${op} ( ${ [].concat(value).map(v => `'${v}'`).join(',').replace(/,/g, ' , ') } )${logic}`; + } + + const is_num = ![null, undefined].includes(value) && !(Number.isNaN(value) || !value.toString().trim()) //check if a valid number (not a NaN and not an empty string) + const vals = (Array.isArray(value) ? value : ('number' !== typeof value ? value.split("'") : [])); + + if (is_num && vals.length > 1) { + return `${vals.filter(v => v).map(v => `"${attribute}" ${op} '%${v}%'`).join(` ${logicop} `)}${logic}`; + } + + if (is_num) { + const like = ['LIKE', 'ILIKE'].includes(operator) ? "%": "" + return `"${attribute}" ${op} '${like}${value}${like}'${logic}`; + } + } + + createExpressionFromFilterObject(filter={}) { + let filters = []; + let rootFilter; + for (const operator in filter) { + rootFilter = FILTER_EXPRESSION_OPERATORS[operator]; + filter[operator].forEach((input) => { + for (const operator in input) { + if (Array.isArray(input[operator])) { + this.createExpressionFromFilterObject(input); + } else { + for (const attribute in input[operator]) { + filters.push(this.createSingleExpressionElement({ value: input[operator][attribute], operator, attribute })); + } } } - } - }); - rootFilter = (filterElements.length > 0) ? filterElements.join(" "+ rootFilter + " ") : false; - } - return rootFilter; -}; - -proto.createExpressionFromField = function({layerName, field, value, operator='eq'}){ - const filter = this.createSingleExpressionElement({ - attribute: field, - value, - operator - }); - this._expression = `${layerName}:${filter}`; - return this; -}; - -proto.createExpressionFromFilterArray = function(inputs=[]){ - let filter = ''; - // set logicop of last element to null - const inputsLength = inputs.length ? inputs.length - 1 : inputs.length; - inputs.forEach((input, index) => { - const filterElement = this.createSingleExpressionElement(input); - filter = `${filter}${(input.logicop && index === inputsLength) ? filterElement.substring(0, filterElement.length - (input.logicop.length+1)): filterElement}`; - }); - return filter || undefined; -}; - -proto.createExpressionFromFilter = function(filter, layerName) { - const filterParam = Array.isArray(filter) ? this.createExpressionFromFilterArray(filter) : this.createExpressionFromFilterObject(filter); - if (filterParam) this._expression = `${layerName}:${filterParam}`; - return this -}; - -module.exports = Expression; + }); + rootFilter = filters.join(' ' + rootFilter + ' ') || false; + } + return rootFilter; + } + + createExpressionFromField({layerName, field, value, operator='eq'}) { + this._expression = `${layerName}:${this.createSingleExpressionElement({ attribute: field, value, operator })}`; + return this; + } + + createExpressionFromFilterArray(inputs=[]) { + return inputs.reduce((acc, input, i) => { + const filter = this.createSingleExpressionElement(input); + // set logicop of last element to null + return `${acc}${(input.logicop && i === inputs.length - 1) ? filter.substring(0, filter.length - (input.logicop.length + 1)) : filter}`; + }, '') || undefined; + } + + createExpressionFromFilter(filter, layerName) { + const fparam = Array.isArray(filter) ? this.createExpressionFromFilterArray(filter) : this.createExpressionFromFilterObject(filter); + if (fparam) this._expression = `${layerName}:${fparam}`; + return this + } +}; \ No newline at end of file diff --git a/src/app/core/layers/filter/filter.js b/src/app/core/layers/filter/filter.js index d0da46c85..e5632fc1c 100644 --- a/src/app/core/layers/filter/filter.js +++ b/src/app/core/layers/filter/filter.js @@ -1,78 +1,73 @@ // class Filter to build filter // useful by provider providers to get data -function Filter(config={}) { - this._filter = null; - this._type = null; - this.config = config; -} - -const proto = Filter.prototype; - -/** - * Config methods - */ - -proto.getConfig = function(){ - return this.config; -}; - -proto.setConfig = function(config = {}){ - this.config = config; -}; - -proto.mergeConfig = function(config={}){ - this.config = {...this.config, ...config}; -}; - -/*** - * end config methods - */ - -proto.getAll = function() { - this._type = Filter.TYPES.all; - this._filter = null -}; - -// to create complex filter -proto.setExpression = function(expression) { - this._type = Filter.TYPES.expression; - this._filter = expression; -}; +class Filter { + + constructor(config = {}) { + this._filter = null; + this._type = null; + this.config = config; + } + + getConfig() { + return this.config; + } + + setConfig(config = {}) { + this.config = config; + }; + + mergeConfig(config={}) { + this.config = {...this.config, ...config}; + } + + getAll() { + this._type = Filter.TYPES.all; + this._filter = null + }; + + // to create complex filter + setExpression(expression) { + this._type = Filter.TYPES.expression; + this._filter = expression; + return this; + } + + setGeometry(geometry) { + this._type = Filter.TYPES.geometry; + this._filter = geometry; + return this; + } + + setBBOX(bbox) { + this._type = Filter.TYPES.bbox; + this._filter = bbox; + return this; + }; + + setFids(ids) { + this._type = Filter.TYPES.fids; + this._filter = ids; + return this; + } + + serialize() { + return JSON.stringify(this); + } + + // get filter value + get() { + return this._filter; + }; + + getType() { + return this._type; + } + + clear() { + this._filter = null; + } -proto.setGeometry = function(geometry) { - this._type = Filter.TYPES.geometry; - this._filter = geometry; - return this; -}; - -proto.setBBOX = function(bbox) { - this._type = Filter.TYPES.bbox; - this._filter = bbox; - return this; -}; - -proto.setFids = function(ids) { - this._type = Filter.TYPES.fids; - this._filter = ids; - return this; -}; - -proto.serialize = function() { - return JSON.stringify(this); -}; - -// get filter value -proto.get = function() { - return this._filter; -}; - -proto.getType = function() { - return this._type; -}; - -proto.clear = function() { - this._filter = null; -}; +} Filter.TYPES = { bbox: 'bbox', diff --git a/src/app/core/layers/layer.js b/src/app/core/layers/layer.js index 178ff0854..48d62e141 100644 --- a/src/app/core/layers/layer.js +++ b/src/app/core/layers/layer.js @@ -40,8 +40,8 @@ function Layer(config={}, options={}) { project = ProjectsRegistry.getCurrentProject() } = options; - //get search_end point value (api, ows) - this.config.search_endpoint = project.getSearchEndPoint(); + /** @deprecated since 3.10.0. Will be removed in v.4.x. */ + this.config.search_endpoint = 'api'; // create relations this._relations = this._createRelations(project.getRelations()); @@ -320,12 +320,10 @@ proto.getSearchParams = function() { }; /** - * Return search_endpoint - * - * @returns {*} + * @deprecated since 3.10.0. Will be removed in v.4.x. */ proto.getSearchEndPoint = function() { - return this.getType() !== Layer.LayerTypes.TABLE ? this.config.search_endpoint : 'api'; + return 'api'; }; /** @@ -459,6 +457,8 @@ proto.getFeatureByFids = async function({ }; /** + * @TODO deprecate `search_endpoint = 'ows'` + * * Search Features * * @param { Object } opts diff --git a/src/app/core/layers/layersstoresregistry.js b/src/app/core/layers/layersstoresregistry.js index 3bb1f47ab..e28782627 100644 --- a/src/app/core/layers/layersstoresregistry.js +++ b/src/app/core/layers/layersstoresregistry.js @@ -1,70 +1,62 @@ -const { base, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); +import G3WObject from 'core/g3w-object'; // Registy Layers -function LayersStoresRegistry() { - this.stores = {}; - this.storesArray = []; - // to react some application components that are binding to Layerstore - this.setters = { - addLayersStore: this._addLayersStore.bind(this), - removeLayersStore: this._removeLayersStore.bind(this), - removeLayersStores: this._removeLayersStores.bind(this), - }; - - base(this); -} - -inherit(LayersStoresRegistry, G3WObject); - -const proto = LayersStoresRegistry.prototype; - -proto.getLayerById = function(layerId) { - let layer; - for (const storeId in this.stores) { - const layerStore = this.stores[storeId]; - layer = layerStore.getLayerById(layerId); - if (layer) break; +module.exports = (class LayersStoresRegistry extends G3WObject { + + constructor() { + super(); + + this.stores = {}; + + this.storesArray = []; + + // to react some application components that are binding to Layerstore + this.setters = { + + addLayersStore(store, idx) { + const id = store.getId(); + this.stores[id] = store; + if (null !== idx && undefined !== idx) { + this.storesArray.splice(idx, 0, id); + } else { + this.storesArray.push(id); + } + }, + + removeLayersStore(store) { + if (store) { + const id = store.getId(); + this.storesArray = this.storesArray.filter(i => i != id); + delete this.stores[id]; + } + }, + + removeLayersStores() { + this.storesArray = []; + this.stores = {}; + }, + + }; } - return layer -}; - -proto.getLayers = function(filter) { - return Object.values(this.stores).flatMap(store => store.getLayers(filter)); -}; - -proto.getQuerableLayersStores = function() { - return this.getLayersStores().filter(store => store.isQueryable()); -}; -proto.getLayersStore = function(id) { - return this.stores[id]; -}; - -proto.getLayersStores = function() { - return this.storesArray.map(storeId => this.stores[storeId]); -}; - -proto._addLayersStore = function(layersStore, idx) { - const storeId = layersStore.getId(); - this.stores[storeId] = layersStore; - if (!_.isNil(idx)) this.storesArray.splice(idx,0, storeId); - else this.storesArray.push(storeId); + getLayerById(id) { + return Object.values(this.stores).map(store => store.getLayerById(id)).find(layer => layer); + } -}; + getLayers(filter) { + return Object.values(this.stores).flatMap(store => store.getLayers(filter)); + } -proto._removeLayersStore = function(layerStore) { - if (layerStore) { - const storeId = layerStore.getId(); - this.storesArray = this.storesArray.filter((_storeId) => _storeId != storeId); - delete this.stores[storeId]; + getQuerableLayersStores() { + return this.getLayersStores().filter(store => store.isQueryable()); } -}; -proto._removeLayersStores = function() { - this.storesArray = []; - this.stores = {}; -}; + getLayersStore(id) { + return this.stores[id]; + } + getLayersStores() { + return this.storesArray.map(id => this.stores[id]); + } -module.exports = LayersStoresRegistry; +}); \ No newline at end of file diff --git a/src/app/core/layers/providersfactory.js b/src/app/core/layers/providersfactory.js index 4044a47f3..dc38bb32c 100644 --- a/src/app/core/layers/providersfactory.js +++ b/src/app/core/layers/providersfactory.js @@ -145,7 +145,7 @@ const Providers = { } /** - * @TODO check if deprecated (broken and unusued code ?) + * @TODO check if deprecated (broken and unused code ?) */ digestFeaturesForTable() { return { diff --git a/src/app/core/plugin/plugin.js b/src/app/core/plugin/plugin.js index c40a05882..9e3e72648 100644 --- a/src/app/core/plugin/plugin.js +++ b/src/app/core/plugin/plugin.js @@ -1,20 +1,18 @@ +import G3WObject from 'core/g3w-object'; +import Component from 'core/g3w-component'; import PluginsRegistry from 'store/plugins'; import ProjectsRegistry from 'store/projects'; import ApplicationService from 'services/application'; import GUI from 'services/gui'; +import { toRawType } from 'utils/toRawType'; -const { - base, - inherit, - toRawType -} = require('utils'); -const G3WObject = require('core/g3wobject'); -const Component = require('gui/component/component'); const { addI18nPlugin } = require('core/i18n/i18n.service'); const TIMEOUT = 10000; -const Plugin = function({ +module.exports = class Plugin extends G3WObject { + + constructor({ name = null, config = PluginsRegistry.getPluginConfig(name), service = null, @@ -24,422 +22,396 @@ const Plugin = function({ api = {}, } = {}) { - base(this); - - this.setName(name); - this.setConfig(config); - this.setLocale(i18n); - this.setService(service); - this.setDependencies(dependencies); - this.addFontClasses(fontClasses); - this.setApi(api); - this.setHookService(null); - - this._ready = false; - - // List of sidebar services that usually plugin need to interact with (hook = place/name of component) - this.hookservices = { - 'search': GUI.getService('search'), - 'tools': GUI.getService('tools') - }; + super(); + + this.setName(name); + this.setConfig(config); + this.setLocale(i18n); + this.setService(service); + this.setDependencies(dependencies); + this.addFontClasses(fontClasses); + this.setApi(api); + this.setHookService(null); + + this._ready = false; + + // List of sidebar services that usually plugin need to interact with (hook = place/name of component) + this.hookservices = { + 'search': GUI.getService('search'), + 'tools': GUI.getService('tools') + }; + + // Automatically remove the loading plugin indicator after timeout + this._timeout = setTimeout(() => { + PluginsRegistry.removeLoadingPlugin(this.name, this._ready); + this.removeLayout(); + }, TIMEOUT) + + } + + /** + * @FIXME add description + */ + setName(name) { + this.name = name; + } + + /** + * @FIXME add description + */ + getName() { + return this.name; + } + + /** + * @FIXME add description + */ + setConfig(config) { + this.config = toRawType(config) === 'Object' ? config : null; + } + + /** + * @FIXME add description + */ + getConfig(name = this.name) { + return this.config || PluginsRegistry.getPluginConfig(name); + } + + /** + * @FIXME add description + */ + setLocale(i18n) { + if (i18n && this.name) { + addI18nPlugin({ name: this.name, config: i18n}); + } + } + + /** + * @FIXME add description + */ + setService(service) { + this.service = service; + if (service) { + service.setPlugin(this); + } + } + + /** + * @FIXME add description + */ + getService() { + return this.service + } + + /** + * @FIXME add description + */ + setDependencies(dependencies) { + this.dependencies = dependencies; + } + + /** + * @FIXME add description + */ + setApi(api = {}) { + this._api = api; + /** + * @FIXME useless assignment ? + */ + api.getConfig = this._api.getConfig; // add alias for "api.getConfig()" method + } + + /** + * @FIXME add description + */ + getApi() { + return this._api; + } + + /** + * @FIXME add description + */ + setHookService(hook) { + this._hook = hook; + } + + /** + * @FIXME add description + */ + getHookService(hook = "tools") { + return this.hookservices[hook]; + } - // Automatically remove the loading plugin indicator after timeout - this._timeout = setTimeout(() => { - PluginsRegistry.removeLoadingPlugin(this.name, this._ready); - this.removeLayout(); - }, TIMEOUT) - -}; - -inherit(Plugin, G3WObject); - -const proto = Plugin.prototype; - -/** - * @FIXME add description - */ -proto.setName = function(name) { - this.name = name; -}; - -/** - * @FIXME add description - */ -proto.getName = function() { - return this.name; -}; - -/** - * @FIXME add description - */ -proto.setConfig = function(config) { - this.config = toRawType(config) === 'Object' ? config : null; -}; - -/** - * @FIXME add description - */ -proto.getConfig = function(name = this.name) { - return this.config || PluginsRegistry.getPluginConfig(name); -}; - -/* - * @FIXME add description - */ -proto.setLocale = function(i18n) { - if (i18n && this.name) { - addI18nPlugin({ name: this.name, config: i18n}); - } -}; - -/** - * @FIXME add description - */ -proto.setService = function(service) { - this.service = service; - if (service) { - service.setPlugin(this); - } -}; - -/** - * @FIXME add description - */ -proto.getService = function() { - return this.service -}; - -/** - * @FIXME add description - */ -proto.setDependencies = function(dependencies) { - this.dependencies = dependencies; -}; - -/** - * @FIXME add description - */ -proto.setApi = function(api = {}) { - this._api = api; - /** - * @FIXME useless assignment ? - */ - api.getConfig = this._api.getConfig; // add alias for "api.getConfig()" method -}; - -/** - * @FIXME add description - */ -proto.getApi = function() { - return this._api; -}; - -/** - * @FIXME add description - */ -proto.setHookService = function(hook) { - this._hook = hook; -}; - -/** - * @FIXME add description - */ -proto.getHookService = function(hook = "tools") { - return this.hookservices[hook]; -}; - -/** - * Override plugin's content default layout (eg. default panel width, height, ...) - * - * @see g3wsdk.core.ApplicationState.gui.layout - */ -proto.setLayout = function(config = ApplicationService.cloneLayout('app')) { - ApplicationService.setLayout(this.name, config); -}; - -/** - * @FIXME add description - * - * @see g3wsdk.core.ApplicationState.gui.layout.__current - */ -proto.setCurrentLayout = function() { - ApplicationService.setCurrentLayout(this.name); -}; - -/** - * @FIXME add description - * - * @see g3wsdk.core.ApplicationState.gui.layout - */ -proto.removeLayout = function() { - ApplicationService.removeLayout(this.name) -}; - -/** - * @FIXME add description - */ -proto.setReady = function(isReady) { - this._ready = isReady; - if (this._ready) { - this.setLayout(); - } - this.emit('set-ready', isReady, this.name); - /** - * @FIXME empty delay ? - */ - setTimeout(() => { - clearTimeout(this._timeout); - PluginsRegistry.removeLoadingPlugin(this.name, this._ready); - }, 0 /* 0 = allow any previously "setTimeout" to execute */) -}; - -/** - * @FIXME add description - */ -proto.isReady = function() { - return new Promise((resolve) => { - this._ready - ? resolve(this._ready) - : this.once('set-ready', (isReady) => { this._ready = isReady; resolve(this._ready); }) - }); -}; - -/** - * Check if plugin is compatible with current projectId - */ -proto.isCurrentProjectCompatible = function(projectId) { - return projectId === ProjectsRegistry.getCurrentProject().getGid(); -}; - -/** - * Check and register plugin only when compatible with current projectId (eg: qdjango:1) - */ -proto.registerPlugin = function(projectId) { - const iscompatible = this.isCurrentProjectCompatible(projectId); - if (iscompatible) { - PluginsRegistry.registerPlugin(this); - } else { - PluginsRegistry.removeLoadingPlugin(this.name, false); - clearTimeout(this._timeout); - } - return iscompatible; -}; - -/** - * @FIXME explain better what it does - * - * Get plugin dependencies - */ -proto.getDependencyPlugins = function(pluginsName) { - this.dependencies = pluginsName || this.dependencies; - return Promise.all(this.dependencies.map(pluginName => this.getDependencyPlugin(pluginName))) -}; - -/** - * @FIXME explain better what it does - * - * Create to not replace above plugin method used by non changed old plugin - */ -proto.getDependencyPluginsObject = async function(pluginsName) { - const pluginsApiObject = {}; - const promises = await this.getDependencyPlugins(pluginsName); - this.dependencies.forEach((pluginName, index) => pluginsApiObject[pluginName] = promises[index]); - return pluginsApiObject -}; - -/** - * @FIXME explain better what it does - * - * Get plugin dependency - */ -proto.getDependencyPlugin = function(pluginName) { - if (PluginsRegistry.isTherePlugin(pluginName)) { + /** + * Override plugin's content default layout (eg. default panel width, height, ...) + * + * @see g3wsdk.core.ApplicationState.gui.layout + */ + setLayout(config = ApplicationService.cloneLayout('app')) { + ApplicationService.setLayout(this.name, config); + } + + /** + * @FIXME add description + * + * @see g3wsdk.core.ApplicationState.gui.layout.__current + */ + setCurrentLayout() { + ApplicationService.setCurrentLayout(this.name); + } + + /** + * @FIXME add description + * + * @see g3wsdk.core.ApplicationState.gui.layout + */ + removeLayout() { + ApplicationService.removeLayout(this.name) + } + + /** + * @FIXME add description + */ + setReady(isReady) { + this._ready = isReady; + if (this._ready) { + this.setLayout(); + } + this.emit('set-ready', isReady, this.name); + setTimeout(() => { + clearTimeout(this._timeout); + PluginsRegistry.removeLoadingPlugin(this.name, this._ready); + }, 0 /* 0 = allow any previously "setTimeout" to execute */) + } + + /** + * @FIXME add description + */ + isReady() { return new Promise((resolve) => { - const plugin = PluginsRegistry.getPlugin(pluginName); - /** - * @TODO refactor weird shortcircuiting logic - */ - plugin - && plugin.isReady().then(() => resolve(plugin.getApi())) - || PluginsRegistry.onafter('registerPlugin', plugin => { - (plugin.name === pluginName) && plugin.isReady().then(() => {resolve(plugin.getApi())}) + this._ready + ? resolve(this._ready) + : this.once('set-ready', (isReady) => { this._ready = isReady; resolve(this._ready); }) + }); + } + + /** + * @returns whether plugin is compatible with current projectId + */ + isCurrentProjectCompatible(projectId) { + return projectId === ProjectsRegistry.getCurrentProject().getGid(); + } + + /** + * Check and register plugin only when compatible with current projectId (eg: qdjango:1) + */ + registerPlugin(projectId) { + const iscompatible = this.isCurrentProjectCompatible(projectId); + if (iscompatible) { + PluginsRegistry.registerPlugin(this); + } else { + PluginsRegistry.removeLoadingPlugin(this.name, false); + clearTimeout(this._timeout); + } + return iscompatible; + } + + /** + * @FIXME explain better what it does + * + * Get plugin dependencies + */ + getDependencyPlugins(pluginsName) { + this.dependencies = pluginsName || this.dependencies; + return Promise.all(this.dependencies.map(pluginName => this.getDependencyPlugin(pluginName))) + } + + /** + * @FIXME explain better what it does + * + * Create to not replace above plugin method used by non changed old plugin + */ + async getDependencyPluginsObject(pluginsName) { + const api = {}; + const promises = await this.getDependencyPlugins(pluginsName); + this.dependencies.forEach((pluginName, index) => api[pluginName] = promises[index]); + return api; + } + + /** + * @FIXME explain better what it does + * + * Get plugin dependency + */ + getDependencyPlugin(pluginName) { + if (PluginsRegistry.isTherePlugin(pluginName)) { + return new Promise((resolve) => { + const plugin = PluginsRegistry.getPlugin(pluginName); + /** + * @TODO refactor weird shortcircuiting logic + */ + plugin + && plugin.isReady().then(() => resolve(plugin.getApi())) + || PluginsRegistry.onafter('registerPlugin', plugin => { + (plugin.name === pluginName) && plugin.isReady().then(() => {resolve(plugin.getApi())}) + }); + }) + } + return Promise.reject({ error: 'no plugin' }); + } + + /** + * Handle loading process of a specific hook service (eg. "tools" interface on the left sidebar) + */ + setHookLoading({ hook = "tools", loading = false } = {}) { + this.getHookService(hook).setLoading(loading); + } + + /** + * @FIXME add description + */ + addToolGroup({ hook = "tools", position:order, title:group } = {}) { + this.getHookService(hook).addToolGroup(order, group); + } + + /** + * @FIXME add description + */ + removeToolGroup({ hook, group } = {}) { + this.getHookService(hook).removeToolGroup(group.title); + } + + /** + * @param tool + * @param group tools group + */ + addTools(tool, group) { + const hook = tool.hook || 'tools'; + let tools = []; + + if (!tool.action && !tool.type) { + this.removeToolGroup({ hook, group }); + } else { + this.setHookService(hook); + tools = (this.config.configs || [this.config]).map(config => { + return { + icon: tool.icon, + type: tool.type, + name: config.name || tool.name, + html: tool.html, + options: tool.options || {}, + action: tool.action && tool.action.bind(this, config), + loading: undefined !== tool.loading ? tool.loading : false, + disabled: undefined !== tool.disabled ? tool.disabled : false, + offline: undefined !== tool.offline ? tool.offline : true, + state: undefined !== tool.state ? tool.state : ({ type: null, message: null }) + }; }); - }) - } - return Promise.reject({ error: 'no plugin' }); -}; - -/** - * Handle loading process of a specific hook service (eg. "tools" interface on the left sidebar) - */ -proto.setHookLoading = function({ hook = "tools", loading = false } = {}) { - this.getHookService(hook).setLoading(loading); -}; - -/** - * @FIXME add description - */ -proto.addToolGroup = function({ hook = "tools", position:order, title:group } = {}) { - this.getHookService(hook).addToolGroup(order, group); -}; - -/** - * @FIXME add description - */ -proto.removeToolGroup = function({ hook, group } = {}) { - this.getHookService(hook).removeToolGroup(group.title); -}; - -/** - * @FIXME add description - */ -proto.addTools = function( - { - hook = "tools", - action, - html, - offline = true, - icon, - name, - type, - options = {}, - loading = false, - disabled = false, - state = { - type:null, - message:null + this.getHookService(hook).addTools(tools, group); } - } = {}, - groupTools - ) { - if (!action && !type) { - this.removeToolGroup({ hook, group: groupTools }); - return []; - } else { - this.setHookService(hook); - const tools = (this.config.configs || [this.config]).map(config => { - return { - icon, - type, - name: config.name || name, - html, - loading, - disabled, - options, - offline, - action: action && action.bind(this, config), - state - }; - }); - this.getHookService(hook).addTools(tools, groupTools); + return tools; } -}; - -/** - * @FIXME add description - */ -proto.setToolState = function({ id, state = { type:null, message: null } } = {}) { - this.hookservices[this._hook].setToolState({ id, state }); -}; - -/** - * @FIXME add description - */ -proto.removeTools = function() { - this.hookservices[this._hook].removeTools(); -}; - -/** - * Helper method to create and add a custom component item on the left sidebar - * - * @param vue vue component object (SFC) - * @param { Object } options - * @param { string } options.id - * @param { string } options.title textual description on left sidebar (eg. "metadata") - * @param { boolean } options.open true = collapsible button; false = button - * @param { boolean } options.collapsible whether expand the button when plugin is loaded - * @param { boolean } options.isolate whether propagate click event to all sidebar item - * @param { boolean } options.closewhenshowviewportcontent - * @param { Object } options.iconConfig - * @param { string } options.iconConfig.color color of icon - * @param { string } options.iconConfig.icon see gui\vue\vueappplugin.js font list - * @param { Object } options.events eg. events = { open: { when: 'before', cb: () => { } } - * @param { Object } options.sidebarOptions - * @param { number | string } options.sidebarOptions.position - * - * @returns component - * - * @listens unload - * - */ -proto.createSideBarComponent = function(vue, options = {}) { - - const çç = (a, b) => undefined !== a ? a : b; // like a ?? (coalesce operator) - - options.open = çç(options.open, false); - options.collapsible = çç(options.collapsible, true); - options.mobile = çç(options.mobile, true); - options.isolate = çç(options.isolate, false); - options.closewhenshowviewportcontent = çç(options.closewhenshowviewportcontent, true); - options.iconConfig = çç(options.iconConfig, {}); - options.events = çç(options.events, {}); - options.sidebarOptions = çç(options.sidebarOptions, { position: 1 }); - const { iconConfig, ...opts } = Object.assign({}, options, { iconColor: options.iconConfig.color, icon: GUI.getFontClass(options.iconConfig.icon) }); - - const component = (new Component(opts)).init({ vueComponentObject: vue }); - - GUI.addComponent(component, 'sidebar', options.sidebarOptions); - - this.once('unload', () => GUI.removeComponent(options.id, 'sidebar', options.sidebarOptions)); - - return component; -}; - -/** - * @deprecated since v3.4. - */ -proto.unload = function() { - if (this.service) { - this.service.clearAllEvents(); - } - this.emit('unload'); - //console.log('UNLOAD can be overwritten by plugin'); -}; - -/** - * @deprecated since v3.4. - */ -proto.load = function() { - //console.log('LOAD need to be overwrite by plugin'); -}; - -/** - * @TODO it could be depecrated after v3.4 ? - */ -proto.getProject = function() { - return ProjectsRegistry.getCurrentProject(); -}; - -/** - * @TODO it could be depecrated after v3.4 ? - */ -proto.addDependency = function(dependency) { - this.dependencies.push(dependency); -}; - -/** - * @TODO it could be depecrated after v3.4 ? - */ -proto.addFontClass = function({ name, className }) { - Vue.prototype.g3wtemplate.addFontClass({ name, className }); -}; - -/** - * @TODO it could be depecrated after v3.4 ? - */ -proto.addFontClasses = function(fonClasses = []) { - fonClasses.forEach(fontClass => this.addFontClass(fontClass)); -}; - -module.exports = Plugin; + + /** + * @FIXME add description + */ + setToolState({ id, state = { type:null, message: null } } = {}) { + this.hookservices[this._hook].setToolState({ id, state }); + } + + /** + * @FIXME add description + */ + removeTools() { + this.hookservices[this._hook].removeTools(); + } + + /** + * Helper method to create and add a custom component item on the left sidebar + * + * @param vue vue component object (SFC) + * @param { Object } opts + * @param { string } opts.id + * @param { string } opts.title textual description on left sidebar (eg. "metadata") + * @param { boolean } opts.open true = collapsible button; false = button + * @param { boolean } opts.collapsible whether expand the button when plugin is loaded + * @param { boolean } opts.isolate whether propagate click event to all sidebar item + * @param { boolean } opts.closewhenshowviewportcontent + * @param { Object } opts.iconConfig + * @param { string } opts.iconConfig.color color of icon + * @param { string } opts.iconConfig.icon see gui\vue\vueappplugin.js font list + * @param { Object } opts.events eg. events = { open: { when: 'before', cb: () => { } } + * @param { Object } opts.sidebarOptions + * @param { number | string } opts.sidebarOptions.position + * + * @returns component + * + * @listens unload + * + */ + createSideBarComponent(vue, opts = {}) { + + const çç = (a, b) => undefined !== a ? a : b; // like a ?? (coalesce operator) + + opts.vueComponentObject = vue; + opts.collapsible = çç(opts.collapsible, true); + opts.mobile = çç(opts.mobile, true); + opts.isolate = çç(opts.isolate, false); + opts.sidebarOptions = çç(opts.sidebarOptions, { position: 1 }); + + GUI.addComponent(new Component(opts), 'sidebar', opts.sidebarOptions); + + this.once('unload', () => GUI.removeComponent(opts.id, 'sidebar', opts.sidebarOptions)); + + return GUI.getComponent(opts.id) ; + } + + /** + * @deprecated since v3.4. + * + * @virtual method need to be implemented by subclasses + */ + unload() { + if (this.service) { + this.service.clearAllEvents(); + } + this.emit('unload'); + } + + /** + * @deprecated since v3.4. + * + * @virtual method need to be implemented by subclasses + */ + load() { } + + /** + * @TODO it could be depecrated after v3.4 ? + */ + getProject() { + return ProjectsRegistry.getCurrentProject(); + } + + /** + * @TODO it could be depecrated after v3.4 ? + */ + addDependency(dependency) { + this.dependencies.push(dependency); + }; + + /** + * @TODO it could be depecrated after v3.4 ? + */ + addFontClass({ name, className }) { + Vue.prototype.g3wtemplate.addFontClass({ name, className }); + } + + /** + * @TODO it could be depecrated after v3.4 ? + */ + addFontClasses(fonClasses = []) { + fonClasses.forEach(fontClass => this.addFontClass(fontClass)); + } + +}; \ No newline at end of file diff --git a/src/app/core/plugin/pluginservice.js b/src/app/core/plugin/pluginservice.js index 4ef1b5f34..636b609f6 100644 --- a/src/app/core/plugin/pluginservice.js +++ b/src/app/core/plugin/pluginservice.js @@ -1,147 +1,143 @@ +import G3WObject from 'core/g3w-object'; import ApplicationState from 'store/application-state'; import ApplicationService from 'services/application'; -const { base, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); - -function PluginService(options={}) { - base(this, options); - this.plugin; - this._api = { - own: null, - dependencies: {} - }; - this._pluginEvents = {}; - this._appEvents = []; - this.currentLayout = ApplicationService.getCurrentLayoutName(); - this.vm = new Vue(); - this.unwatch = this.vm.$watch(()=> ApplicationState.gui.layout.__current, - currentLayoutName => this.currentLayout = currentLayoutName !== this.getPlugin().getName() ? currentLayoutName : this.currentLayout); -} - -inherit(PluginService, G3WObject); - -const proto = PluginService.prototype; - -/** - * Set a default init method. Overwrite by each plugin - * @param config: plugin configuration object - */ -proto.init = function(config={}) { - this.config = config; -}; +module.exports = class PluginService extends G3WObject { + + constructor(options = {}) { + super(options); + this.plugin; + this._api = { + own: null, + dependencies: {} + }; + this._pluginEvents = {}; + this._appEvents = []; + this.currentLayout = ApplicationService.getCurrentLayoutName(); + this.vm = new Vue(); + this.unwatch = this.vm.$watch( + ()=> ApplicationState.gui.layout.__current, + layoutName => this.currentLayout = layoutName !== this.getPlugin().getName() ? layoutName : this.currentLayout + ); + } -proto.setCurrentLayout = function() { - ApplicationService.setCurrentLayout(this.getPlugin().getName()); -}; + /** + * @param config: plugin configuration object + * + * @virtual method need to be implemented by subclasses + */ + init(config={}) { + this.config = config; + } -proto.resetCurrentLayout = function() { - ApplicationService.setCurrentLayout(this.currentLayout); -}; + setCurrentLayout() { + ApplicationService.setCurrentLayout(this.getPlugin().getName()); + } -// set owner plugin of the service -proto.setPlugin = function(plugin) { - this.plugin = plugin; -}; + resetCurrentLayout() { + ApplicationService.setCurrentLayout(this.currentLayout); + } -// return the instance of the plugin owner of the service -proto.getPlugin = function() { - return this.plugin; -}; + // set owner plugin of the service + setPlugin(plugin) { + this.plugin = plugin; + } -proto.isIframe = function() { - return ApplicationService.isIframe(); -}; + // return the instance of the plugin owner of the service + getPlugin() { + return this.plugin; + } -/** - * Get Current Project - */ -proto.getCurrentProject = function() { - return ApplicationService.getCurrentProject(); -}; + isIframe() { + return ApplicationService.isIframe(); + } -proto.getGid = function() { - const { gid } = this.config; - return gid && gid.split(':')[1]; -}; + getCurrentProject() { + return ApplicationService.getCurrentProject(); + } -proto.getConfig = function() { - return this.config; -}; + getGid() { + return this.config.gid && this.config.gid.split(':')[1]; + } -proto.setConfig = function(config) { - this.config = config; -}; + getConfig() { + return this.config; + } -proto.setApi = function({dependency, api} = {}) { - if (!dependency) this._api.own = api; - else this._api.dependencies[dependency] = api; -}; + setConfig(config) { + this.config = config; + } -proto.getApi = function({dependency} = {}) { - return dependency && this._api.dependencies[dependency] || this._api.own; -}; + setApi({dependency, api} = {}) { + if (!dependency) this._api.own = api; + else this._api.dependencies[dependency] = api; + } -proto.initEvents = function(events=[]) { - for (let i in events) { - const name = events[i]; - this._pluginEvents[name] = {}; + getApi({dependency} = {}) { + return dependency && this._api.dependencies[dependency] || this._api.own; } -}; -proto.registerWindowEvent = function({evt, cb}={}) { - ApplicationService.registerWindowEvent({ - evt, - cb - }) -}; + initEvents(events=[]) { + for (let i in events) { + this._pluginEvents[events[i]] = {}; + } + } -proto.unregisterWindowEvent = function({evt, cb}) { - ApplicationService.unregisterWindowEvent({ - evt, - cb - }) -}; + registerWindowEvent({evt, cb}={}) { + ApplicationService.registerWindowEvent({ evt, cb }); + } -proto.subscribeEvent = function({name, once=false, owner, listener}) { - this._pluginEvents[name] = this._pluginEvents[name] ? this._pluginEvents[name] : {}; - this._pluginEvents[name][owner] = listener; - once ? this.once(name, listener): this.on(name, listener); -}; + unregisterWindowEvent({evt, cb}) { + ApplicationService.unregisterWindowEvent({ evt, cb }); + } -proto.triggerEvent = function({name, params={}}) { - this.emit(name, params); -}; + subscribeEvent({name, once=false, owner, listener}) { + this._pluginEvents[name] = this._pluginEvents[name] ? this._pluginEvents[name] : {}; + this._pluginEvents[name][owner] = listener; + if (once) { + this.once(name, listener); + } else { + this.on(name, listener); + } + } -proto.unsubscribeEvent = function({name, owner}) { - const listener = this._pluginEvents[name][owner]; - this.removeEvent(name, listener); - delete this._pluginEvents[name][owner]; -}; + triggerEvent({name, params={}}) { + this.emit(name, params); + } -proto.unsubscribeAllEvents = function() { - for (const name in this._pluginEvents) { - this.removeEvent(name); - delete this._pluginEvents[name]; + unsubscribeEvent({name, owner}) { + this.removeEvent(name, this._pluginEvents[name][owner]); + delete this._pluginEvents[name][owner]; } -}; -proto.clearAllEvents = function() { - this.unsubscribeAllEvents(); - this.unwatch(); - this.vm = null; - this._pluginEvents = null -}; + unsubscribeAllEvents() { + for (const name in this._pluginEvents) { + this.removeEvent(name); + delete this._pluginEvents[name]; + } + } -// to owerwrite if we need some condition to load or not the plugin -proto.loadPlugin = function() { - return true -}; + clearAllEvents() { + this.unsubscribeAllEvents(); + this.unwatch(); + this.vm = null; + this._pluginEvents = null + } -//Called when plugin is removed to clear events and memory -proto.clear = function() { - // to overwrite -}; + /** + * @returns need to load or not the plugin + * + * @virtual method need to be implemented by subclasses + */ + loadPlugin() { + return true + } + /** + * Called when plugin is removed to clear events and memory + * + * @virtual method need to be implemented by subclasses + */ + clear() {} -module.exports = PluginService; +}; diff --git a/src/app/core/project/project.js b/src/app/core/project/project.js index 1fb6cad87..6ec712e52 100644 --- a/src/app/core/project/project.js +++ b/src/app/core/project/project.js @@ -6,15 +6,15 @@ import { import ApplicationState from 'store/application-state'; import ApplicationService from 'services/application'; import { crsToCrsObject } from 'utils/crsToCrsObject'; +import G3WObject from 'core/g3wobject'; const { base, inherit, XHR } = require('utils'); -const G3WObject = require('core/g3wobject'); -const LayerFactory = require('core/layers/layerfactory'); -const LayersStore = require('core/layers/layersstore'); -const Projections = require('g3w-ol/projection/projections'); +const LayerFactory = require('core/layers/layerfactory'); +const LayersStore = require('core/layers/layersstore'); +const Projections = require('g3w-ol/projection/projections'); /** - * @FIXME options param appears to be unusued + * @FIXME options param appears to be unused * * @param config.id * @param config.type @@ -35,25 +35,24 @@ const Projections = require('g3w-ol/projection/projections'); * @param config.bookmarks array of bookmarks * @param { 'POST' | 'GET' } config.ows_method * @param { boolean } config.wms_use_layer_ids - * @param { 'ows' | 'api' } config.search_endpoint * @param { 'tab' | 'toc' } config.legend_position * @param { 'layers', 'baselayers', 'legend' } config.catalog_tab * * @param options */ -function Project(config={}, options={}) { +function Project(config = {}, options={}) { /** * For future implementation catalog tab actived */ - config.catalog_tab = config.toc_tab_default || config._catalog_tab || 'layers'; + config.catalog_tab = config.toc_tab_default || config._catalog_tab || 'layers'; - config.ows_method = config.ows_method || 'GET'; + config.ows_method = config.ows_method || 'GET'; config.toc_layers_init_status = config.toc_layers_init_status || TOC_LAYERS_INIT_STATUS; config.toc_themes_init_status = config.toc_themes_init_status || TOC_THEMES_INIT_STATUS; - config.query_point_tolerance = config.query_point_tolerance || QUERY_POINT_TOLERANCE; + config.query_point_tolerance = config.query_point_tolerance || QUERY_POINT_TOLERANCE; this.state = config; @@ -76,9 +75,9 @@ function Project(config={}, options={}) { /** * Set the project projection to object crs */ - this.state.crs = crsToCrsObject(this.state.crs); + this.state.crs = crsToCrsObject(this.state.crs); - this._projection = Projections.get(this.state.crs); + this._projection = Projections.get(this.state.crs); /** * Build a layersstore of the project @@ -119,14 +118,17 @@ proto.getWmsGetmapFormat = function() { } /** - * Get search end point value (ows or api) + * @deprecated since 3.10.0. Will be removed in v.4.x. */ proto.getSearchEndPoint = function() { - return this.state.search_endpoint; + return 'api'; }; +/** + * @deprecated since 3.10.0. Will be removed in v.4.x. + */ proto.setSearchEndPoint = function() { - (this.state.search || []).forEach(search => search.search_endpoint = this.state.search_endpoint); + (this.state.search || []).forEach(search => search.search_endpoint = 'api'); }; proto.getAliasUrl = function() { @@ -234,29 +236,27 @@ proto._buildLayersStore = function() { const overviewprojectgid = this.state.overviewprojectgid ? this.state.overviewprojectgid.gid : null; layersStore.setOptions({ - id: this.state.gid, + id: this.state.gid, projection: this._projection, - extent: this.state.extent, + extent: this.state.extent, initextent: this.state.initextent, - wmsUrl: this.state.WMSUrl, - catalog: this.state.gid !== overviewprojectgid + wmsUrl: this.state.WMSUrl, + catalog: overviewprojectgid !== this.state.gid, }); // instance each layer ad area added to layersstore const layers = this.getLayers(); layers.forEach(layerConfig => { - //check and set crs in objectformat - layerConfig.crs = crsToCrsObject(layerConfig.crs); + //check and set crs in object format + layerConfig.crs = crsToCrsObject(layerConfig.crs); // add projection - layerConfig.projection = layerConfig.crs ? Projections.get(layerConfig.crs) : this._projection; + layerConfig.projection = layerConfig.crs ? Projections.get(layerConfig.crs) : this._projection; //add ows_method - layerConfig.ows_method = this.getOwsMethod(); + layerConfig.ows_method = this.getOwsMethod(); layerConfig.wms_use_layer_ids = this.state.wms_use_layer_ids; - const layer = LayerFactory.build(layerConfig, { project: this }); - if (layer) { - layersStore.addLayer(layer); - } + const layer = LayerFactory.build(layerConfig, { project: this }); + if (layer) { layersStore.addLayer(layer)} }); // create layerstree from layerstore @@ -281,20 +281,20 @@ proto.getBaseLayers = function() { }; /** - * Get configuration layers array from server config + * Get configuration layers an array from server config * * @param filter property layer config to filter * @returns {*} */ -proto.getConfigLayers = function({key}={}) { - return key ? this.state.layers.filter(layer => layer[key] !== undefined) : this.state.layers; +proto.getConfigLayers = function({ key } = {}) { + return key ? this.state.layers.filter(layer => undefined !== layer[key] ) : this.state.layers; }; /** * Legend Position */ -proto.setLegendPosition = function(legend_position='tab') { +proto.setLegendPosition = function(legend_position = 'tab') { this.state.legend_position = legend_position; }; @@ -361,7 +361,7 @@ proto.getCrs = function() { /** * @param {'major' | 'minor' | 'patch' } qgis.type */ -proto.getQgisVersion = function({type}={}) { +proto.getQgisVersion = function({ type } = {}) { const index = ['major', 'minor', 'patch'].indexOf(type); return -1 === index ? this.state.qgis_version : +this.state.qgis_version.split('.')[index]; }; @@ -385,23 +385,24 @@ proto.getLayersStore = function() { /// Map Themes /** - * Set properties ( checked and visible) from view to layerstree + * Set properties (checked and visible) from view to layerstree * * @param map_theme map theme name * @param layerstree // current layerstree of TOC */ -proto.setLayersTreePropertiesFromMapTheme = async function({map_theme, layerstree=this.state.layerstree}) { +proto.setLayersTreePropertiesFromMapTheme = async function({ + map_theme, + layerstree = this.state.layerstree +}) { /** * mapThemeConfig contain map_theme attributes coming from project map_themes attribute config * plus layerstree of map_theme get from api map theme */ const mapThemeConfig = await this.getMapThemeFromThemeName(map_theme); // extract layerstree - const {layerstree:mapThemeLayersTree} = mapThemeConfig; + const { layerstree:mapThemeLayersTree } = mapThemeConfig; // create a chages need to apply map_theme changes to map and TOC - const changes = { - layers: {} // key is the layer id and object has style, visibility change (Boolean) - }; + const changes = {layers: {} }; // key is the layer id and object has style, visibility change (Boolean) const promises = []; /** * Function to traverse current layerstree of toc anche get changes with the new one related to map_theme choose @@ -409,54 +410,52 @@ proto.setLayersTreePropertiesFromMapTheme = async function({map_theme, layerstre * @param layerstree // current layerstree */ const groups = []; - const traverse = (mapThemeLayersTree, layerstree, checked) =>{ - mapThemeLayersTree.forEach((node, index) => { - if (node.nodes) { // case of group - groups.push({ - node, - group: layerstree[index] - }); - traverse(node.nodes, layerstree[index].nodes, checked && node.checked); - } else { - // case of layer - node.style = mapThemeConfig.styles[node.id]; // set style from map_theme - if (layerstree[index].checked !== node.visible) { - changes.layers[node.id] = { - visibility: true, - style: false - }; - } - layerstree[index].checked = node.visible; - // if has a style settled - if (node.style) { - const promise = new Promise((resolve, reject) =>{ - const setCurrentStyleAndResolvePromise = node => { - if (changes.layers[node.id] === undefined) changes.layers[node.id] = { - visibility: false, - style: false - }; - changes.layers[node.id].style = this.getLayerById(node.id).setCurrentStyle(node.style); - resolve(); - }; - if (this.getLayersStore()) setCurrentStyleAndResolvePromise(node); - else // case of starting project creation - node => setTimeout(() => { - setCurrentStyleAndResolvePromise(node); - })(node); + const traverse = (mapThemeLayersTree, layerstree, checked) => { + mapThemeLayersTree + .forEach((node, index) => { + if (node.nodes) { // case of a group + groups.push({ + node, + group: layerstree[index] }); - promises.push(promise); + traverse(node.nodes, layerstree[index].nodes, checked && node.checked); + } else { + // case of layer + node.style = mapThemeConfig.styles[node.id]; // set style from map_theme + if (layerstree[index].checked !== node.visible) { + changes.layers[node.id] = { + visibility: true, + style: false + }; + } + layerstree[index].checked = node.visible; + // if it has a style settled + if (node.style) { + const promise = new Promise((resolve, reject) =>{ + const setCurrentStyleAndResolvePromise = node => { + if (changes.layers[node.id] === undefined) changes.layers[node.id] = { + visibility: false, + style: false + }; + changes.layers[node.id].style = this.getLayerById(node.id).setCurrentStyle(node.style); + resolve(); + }; + if (this.getLayersStore()) { setCurrentStyleAndResolvePromise(node) } + else { (node => setTimeout(() => setCurrentStyleAndResolvePromise(node)))(node) }// case of starting project creation + }); + promises.push(promise); + } } - } }); }; traverse(mapThemeLayersTree, layerstree); await Promise.allSettled(promises); // all groups checked after layer checked so is set checked but not visible - groups.forEach(({group, node:{checked, expanded}}) => { + groups.forEach(({ group, node: { checked, expanded }}) => { group.checked = checked; group.expanded = expanded; }); - return changes // eventually information about changes (for example style etc..) + return changes // eventually, information about changes (for example style etc..) }; /** @@ -465,9 +464,9 @@ proto.setLayersTreePropertiesFromMapTheme = async function({map_theme, layerstre proto.getMapThemeFromThemeName = async function(map_theme) { // get map theme configuration from map_themes project config const mapThemeConfig = this.state.map_themes.find(map_theme_config => map_theme_config.theme === map_theme); - // check if mapThemeConfig exist and if has layerstree (property get from server with a specific api) + // check if mapThemeConfig exist and if it has layerstree (property gets from server with a specific api) if (mapThemeConfig && undefined === mapThemeConfig.layerstree ) { - mapThemeConfig.layerstree = await this.getMapThemeConfiguration(map_theme); + mapThemeConfig.layerstree = await this.getMapThemeConfiguration(map_theme); } return mapThemeConfig; }; @@ -482,9 +481,7 @@ proto.getMapThemeFromThemeName = async function(map_theme) { proto.getMapThemeConfiguration = async function(map_theme) { try { const response = await XHR.get({ url: `${this.urls.map_themes}${map_theme}/` }); - if (response.result) { - return response.data; - } + if (response.result) { return response.data } } catch(err) { console.warn('Error while retreiving map theme configuration', err); } diff --git a/src/app/g3w-ol/controls/streetviewcontrol.js b/src/app/g3w-ol/controls/streetviewcontrol.js index 731d54376..a4f3f4722 100644 --- a/src/app/g3w-ol/controls/streetviewcontrol.js +++ b/src/app/g3w-ol/controls/streetviewcontrol.js @@ -1,9 +1,10 @@ -import ApplicationState from 'store/application-state'; -import GUI from 'services/gui'; -import { mergeOptions } from 'utils/mergeOptions'; +import ApplicationState from 'store/application-state'; +import GUI from 'services/gui'; +import { mergeOptions } from 'utils/mergeOptions'; +import * as vueComp from 'components/StreetView.vue'; +import Component from 'core/g3w-component'; const { XHR } = require('utils'); -const StreetViewComponent = require('gui/streetview/vue/streetview'); const InteractionControl = require('g3w-ol/controls/interactioncontrol'); const PickCoordinatesInteraction = require('g3w-ol/interactions/pickcoordinatesinteraction'); @@ -120,7 +121,7 @@ proto.setPosition = function(position) { self._panorama.setPosition(data.location.latLng); } }).then(response => { - if (response === undefined) { + if (undefined === response) { GUI.closeContent(); } }).catch(() => this.toggle()) @@ -135,26 +136,26 @@ proto.setMap = function(map) { this._interaction.on('picked', ({coordinate}) => { this.showStreetView(coordinate); - this._autountoggle && this.toggle(); + if (this._autountoggle) { + this.toggle(); + } }); }; /** - * Method to show StreetView depending of key and keyError + * Method to show StreetView depending on a key and keyError * @param coordinate */ -proto.showStreetView = function(coordinate){ +proto.showStreetView = function(coordinate) { const [lng, lat] = ol.proj.transform(coordinate, this._map.getView().getProjection().getCode(), 'EPSG:4326'); if (this.key) { GUI.setContent({ - content: new StreetViewComponent({ - keyError: this.keyError - }), - title: 'StreetView' + title: 'StreetView', + content: new Component({ internalComponent: new (Vue.extend(vueComp))({ keyError: this.keyError }) }), }); - !this.keyError && this.setPosition({ - lng, lat - }) + if (!this.keyError) { + this.setPosition({ lng, lat }); + } } else { this._streetViewFeature.setGeometry( new ol.geom.Point(coordinate) @@ -178,8 +179,11 @@ proto.clear = function() { proto.toggle = function(toggle) { InteractionControl.prototype.toggle.call(this, toggle); - if (!this.isToggled()) this.clear(); - else this._layer.getSource().addFeatures([this._streetViewFeature]); + if (this.isToggled()) { + this._layer.getSource().addFeatures([this._streetViewFeature]); + } else { + this.clear(); + } }; module.exports = StreetViewControl; \ No newline at end of file diff --git a/src/app/g3w-ol/interactions/deletefeatureinteraction.js b/src/app/g3w-ol/interactions/deletefeatureinteraction.js index 82727fe03..90f65681d 100644 --- a/src/app/g3w-ol/interactions/deletefeatureinteraction.js +++ b/src/app/g3w-ol/interactions/deletefeatureinteraction.js @@ -27,11 +27,11 @@ DeleteInteraction.handleEvent_ = function(mapBrowserEvent) { if(this.features_.getArray().length && mapBrowserEvent.originalEvent.keyCode == 46) { // an event can be string or an object with attribute type this.dispatchEvent( - new DeleteInteractionEvent( - 'deleteend', - this.layer_, - this.features_, - event.coordinate)); + new DeleteInteractionEvent( + 'deleteend', + this.layer_, + this.features_, + event.coordinate)); return true; } } @@ -45,51 +45,46 @@ DeleteInteraction.handleDownEvent_ = function(event) { if (this.lastFeature_) { DeleteInteraction.handleMoveEvent_.call(this, event); this.dispatchEvent( - new DeleteInteractionEvent( - 'deleteend', - this.layer_, - this.features_, - event.coordinate)); + new DeleteInteractionEvent( + 'deleteend', + this.layer_, + this.features_, + event.coordinate)); return true; } return false; }; DeleteInteraction.handleMoveEvent_ = function(event) { - this.map_ = event.map; + this.map_ = event.map; const elem = this.map_.getTargetElement(); - if (this.startCursor_ === undefined) { - this.startCursor_ = elem.style.cursor; - } + if (undefined === this.startCursor_) { this.startCursor_ = elem.style.cursor } const intersectingFeature = this.map_.forEachFeatureAtPixel(event.pixel, (feature, layer) => { - ///check if is the same layero of editing - feature = (layer == this.layer_) ? feature : null; - return feature; - }); + ///check if is the same layer of editing + feature = (layer == this.layer_) ? feature : null; + return feature; + }); if (intersectingFeature) { this.previousCursor_ = elem.style.cursor; - elem.style.cursor = 'pointer'; + elem.style.cursor = 'pointer'; } else { - elem.style.cursor = this.previousCursor_ !== undefined ? - this.previousCursor_ : ''; + elem.style.cursor = undefined !== this.previousCursor_ + ? this.previousCursor_ + : ''; this.previousCursor_ = undefined; } }; DeleteInteraction.prototype.featuresAtPixel_ = function(pixel, map) { let found = null; - const intersectingFeature = map.forEachFeatureAtPixel(pixel, (feature) => { - return feature; - }); - if (this.features_ && - _.includes(this.features_.getArray(), intersectingFeature)) { + const intersectingFeature = map.forEachFeatureAtPixel(pixel, feature => feature); + if (this.features_ && this.features_.getArray().includes(intersectingFeature)) { found = intersectingFeature; } return found; }; - DeleteInteraction.prototype.clear = function() { let elem; if (this.map_) { @@ -98,5 +93,4 @@ DeleteInteraction.prototype.clear = function() { } }; - module.exports = DeleteInteraction; diff --git a/src/app/g3w-ol/interactions/measureinteraction.js b/src/app/g3w-ol/interactions/measureinteraction.js index 7b0a655f5..2456b9b04 100644 --- a/src/app/g3w-ol/interactions/measureinteraction.js +++ b/src/app/g3w-ol/interactions/measureinteraction.js @@ -12,12 +12,13 @@ const MeasureIteraction = function(options={}) { this._featureGeometryChangelistener; this._poinOnMapMoveListener; this.testTooltip; - this._helpMsg = options.help; - this._projection = options.projection; - this.feature = options.feature; - const drawColor = options.drawColor || 'rgba(0, 0, 0, 0.5)'; + this._helpTooltipElement; + this._helpMsg = options.help; + this._projection = options.projection; + this.feature = options.feature; + const drawColor = options.drawColor || 'rgba(0, 0, 0, 0.5)'; const useSphereMethods = needUseSphereMethods(this._projection); - const measureStyle = new ol.style.Style({ + const measureStyle = new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' }), @@ -37,14 +38,13 @@ const MeasureIteraction = function(options={}) { }) }); const geometryType = options.geometryType || 'LineString'; - const source = new ol.source.Vector(); - this._helpTooltipElement; - this._map = null; - this._feature = null; - this._layer = new ol.layer.Vector({ + const source = new ol.source.Vector(); + this._map = null; + this._feature = null; + this._layer = new ol.layer.Vector({ source, style() { - const styles = [ + return [ // linestring new ol.style.Style({ stroke: new ol.style.Stroke({ @@ -56,7 +56,6 @@ const MeasureIteraction = function(options={}) { }) }) ]; - return styles; } }); @@ -65,6 +64,7 @@ const MeasureIteraction = function(options={}) { type: geometryType, style: measureStyle }); + this.set('beforeRemove', this.clear); this.set('layer', this._layer); // register event on two action @@ -97,21 +97,24 @@ proto._clearMessagesAndListeners = function() { this._feature = null; // unset tooltip so that a new one can be created if (this._map) { - this._measureTooltipElement = null; + this._measureTooltipElement = null; this._helpTooltipElement.innerHTML = ''; + this._helpTooltipElement.classList.add('hidden'); + ol.Observable.unByKey(this._featureGeometryChangelistener); ol.Observable.unByKey(this._poinOnMapMoveListener); + $(document).off('keydown', this._keyDownEventHandler); } }; proto._removeLastPoint = function(event) { const geom = this._feature.getGeometry(); - if (event.keyCode === 46) { + if (46 === event.keyCode) { if( geom instanceof ol.geom.Polygon && geom.getCoordinates()[0].length > 2) { this.removeLastPoint(); - } else if(geom instanceof ol.geom.LineString && geom.getCoordinates().length > 1) { + } else if (geom instanceof ol.geom.LineString && geom.getCoordinates().length > 1) { this.removeLastPoint(); } } @@ -122,12 +125,12 @@ proto._drawStart = function(evt) { this._map = this.getMap(); this._map.removeLayer(this._layer); this._feature = evt.feature; - this.feature && this._feature.setGeometry(this.feature.getGeometry()); + if (this.feature) { this._feature.setGeometry(this.feature.getGeometry()) } this._keyDownEventHandler = this._removeLastPoint.bind(this); $(document).on('keydown', this._keyDownEventHandler); this._layer.getSource().clear(); this._poinOnMapMoveListener = this._map.on('pointermove', evt => { - if (evt.dragging) return; + if (evt.dragging) { return } if (this._feature && this._helpMsg) { const helpMsg = t(this._helpMsg); this._helpTooltipElement.innerHTML = helpMsg; @@ -140,8 +143,7 @@ proto._drawStart = function(evt) { }; proto._drawEnd = function() { - const {tooltip}= this.measureTooltip; - setMeasureTooltipStatic(tooltip); + setMeasureTooltipStatic(this.measureTooltip.tooltip); this._clearMessagesAndListeners(); this._map.addLayer(this._layer); }; @@ -150,15 +152,16 @@ proto._drawEnd = function() { * Creates a new help tooltip */ proto._createHelpTooltip = function() { - this._helpTooltipElement && this._helpTooltipElement.parentNode.removeChild(this._helpTooltipElement); - this._helpTooltip && this._map.removeOverlay(this._helpTooltip); - this._helpTooltipElement = document.createElement('div'); + if (this._helpTooltipElement) { this._helpTooltipElement.parentNode.removeChild(this._helpTooltipElement) } + if (this._helpTooltip) { this._map.removeOverlay(this._helpTooltip) } + this._helpTooltipElement = document.createElement('div'); this._helpTooltipElement.className = 'mtooltip hidden'; - this._helpTooltip = new ol.Overlay({ + this._helpTooltip = new ol.Overlay({ element: this._helpTooltipElement, offset: [15, 0], positioning: 'center-left' }); + this._map.addOverlay(this._helpTooltip); }; @@ -166,15 +169,8 @@ proto._createHelpTooltip = function() { * Creates a new measure tooltip */ proto._createMeasureTooltip = function() { - this.measureTooltip && removeMeasureTooltip({ - ...this.measureTooltip, - map: this._map - }); - this.measureTooltip = createMeasureTooltip({ - map: this._map, - feature: this._feature - }) - + if (this.measureTooltip) { removeMeasureTooltip({ ...this.measureTooltip, map: this._map }) } + this.measureTooltip = createMeasureTooltip({ map: this._map, feature: this._feature }); }; // END MEASURE CONTROLS // diff --git a/src/app/g3w-ol/interactions/pickcoordinatesinteraction.js b/src/app/g3w-ol/interactions/pickcoordinatesinteraction.js index 670aa5614..b874de132 100644 --- a/src/app/g3w-ol/interactions/pickcoordinatesinteraction.js +++ b/src/app/g3w-ol/interactions/pickcoordinatesinteraction.js @@ -1,19 +1,17 @@ -const PickCoordinatesEventType = { - PICKED: 'picked' -}; +const PickCoordinatesEventType = { PICKED: 'picked' }; const PickCoordinatesEvent = function(type, coordinate) { - this.type = type; + this.type = type; this.coordinate = coordinate; }; const PickCoordinatesInteraction = function(options) { this.previousCursor_ = null; - this._centerMap = null; + this._centerMap = null; ol.interaction.Pointer.call(this, { handleDownEvent: PickCoordinatesInteraction.handleDownEvent_, - handleUpEvent: PickCoordinatesInteraction.handleUpEvent_, + handleUpEvent: PickCoordinatesInteraction.handleUpEvent_, handleMoveEvent: PickCoordinatesInteraction.handleMoveEvent_ }); }; @@ -22,28 +20,26 @@ ol.inherits(PickCoordinatesInteraction, ol.interaction.Pointer); PickCoordinatesInteraction.handleDownEvent_ = function(event) { this._centerMap = event.map.getView().getCenter(); - // set timeout to avoid to block pan + // set timeout to avoid blocking pan setTimeout(() => { if (this._centerMap === event.map.getView().getCenter()) { PickCoordinatesInteraction.handleUpEvent_.call(this, event); } }, 300); - // return false to avoid start of drag event + // return false to avoid start of drag event return false }; PickCoordinatesInteraction.handleUpEvent_ = function(event) { this.dispatchEvent( - new PickCoordinatesEvent( - PickCoordinatesEventType.PICKED, - event.coordinate)); + new PickCoordinatesEvent( PickCoordinatesEventType.PICKED, event.coordinate ) + ); // it used to stop drag event return false; }; -PickCoordinatesInteraction.handleMoveEvent_ = function(event) { - const elem = event.map.getTargetElement(); - elem.style.cursor = 'pointer'; +PickCoordinatesInteraction.handleMoveEvent_ = function(e) { + e.map.getTargetElement().style.cursor = 'pointer'; return true; }; @@ -54,17 +50,14 @@ PickCoordinatesInteraction.prototype.shouldStopEvent = function() { PickCoordinatesInteraction.prototype.setActive = function(active) { const map = this.getMap(); if (map) { - const elem = map.getTargetElement(); + const elem = map.getTargetElement(); elem.style.cursor = ''; } ol.interaction.Pointer.prototype.setActive.call(this,active); }; -PickCoordinatesInteraction.prototype.setMap = function(map){ - if (!map) { - const elem = this.getMap().getTargetElement(); - elem.style.cursor = ''; - } +PickCoordinatesInteraction.prototype.setMap = function(map) { + if (!map) { this.getMap().getTargetElement().style.cursor = '' } ol.interaction.Pointer.prototype.setMap.call(this,map); }; diff --git a/src/app/g3w-ol/interactions/pickfeatureinteraction.js b/src/app/g3w-ol/interactions/pickfeatureinteraction.js index 1eed19d17..a2439fe2c 100644 --- a/src/app/g3w-ol/interactions/pickfeatureinteraction.js +++ b/src/app/g3w-ol/interactions/pickfeatureinteraction.js @@ -1,44 +1,42 @@ -const PickFeatureEventType = { - PICKED: 'picked' -}; +const PickFeatureEventType = { PICKED: 'picked' }; const PickFeatureEvent = function(type, coordinate, layer, feature) { - this.type = type; - this.feature = feature; + this.type = type; + this.feature = feature; this.coordinate = coordinate; - this.layer = layer; + this.layer = layer; }; -const PickFeatureInteraction = function(options={}) { +const PickFeatureInteraction = function(options = {}) { ol.interaction.Pointer.call(this, { handleDownEvent: PickFeatureInteraction.handleDownEvent_, - handleUpEvent: PickFeatureInteraction.handleUpEvent_, + handleUpEvent: PickFeatureInteraction.handleUpEvent_, handleMoveEvent: PickFeatureInteraction.handleMoveEvent_ }); - const {features} = options; - this.features_ = Array.isArray(features) && features.length && features || null; - this.layers_ = options.layers || null; + const { features } = options; + this.features_ = Array.isArray(features) && features.length && features || null; + this.layers_ = options.layers || null; this.pickedFeature_ = null; - this.pickedLayer_ = null; - this.layerFilter_ = (layer) => { - const include = _.includes(this.layers_, layer); + this.pickedLayer_ = null; + this.layerFilter_ = layer => { + const include = this.layers_.includes(layer); this.pickedLayer_ = include && layer; return include; }; }; ol.inherits(PickFeatureInteraction, ol.interaction.Pointer); -PickFeatureInteraction.handleDownEvent_ = function(event) { - this.pickedFeature_ = this.featuresAtPixel_(event.pixel, event.map); +PickFeatureInteraction.handleDownEvent_ = function(e) { + this.pickedFeature_ = this.featuresAtPixel_(e.pixel, e.map); return this.pickedFeature_; }; -PickFeatureInteraction.handleUpEvent_ = function(event) { - if(this.pickedFeature_){ +PickFeatureInteraction.handleUpEvent_ = function(e) { + if (this.pickedFeature_) { this.dispatchEvent( new PickFeatureEvent( PickFeatureEventType.PICKED, - event.coordinate, + e.coordinate, this.pickedLayer_, this.pickedFeature_) ); @@ -46,37 +44,33 @@ PickFeatureInteraction.handleUpEvent_ = function(event) { return true; }; -PickFeatureInteraction.handleMoveEvent_ = function(event) { - const elem = event.map.getTargetElement(); - const intersectingFeature = this.featuresAtPixel_(event.pixel, event.map); - elem.style.cursor = intersectingFeature ? 'pointer': ''; +PickFeatureInteraction.handleMoveEvent_ = function(e) { + const intersectingFeature = this.featuresAtPixel_(e.pixel, e.map); + e.map.getTargetElement().style.cursor = intersectingFeature ? 'pointer': ''; }; PickFeatureInteraction.prototype.featuresAtPixel_ = function(pixel, map) { let featureFound = null; - const intersectingFeature = map.forEachFeatureAtPixel(pixel, (feature) => { - if (this.features_) { - if (this.features_.indexOf(feature) > -1)return feature - else return null; - } - return feature; - }, { - layerFilter: this.layerFilter_, - hitTolerance: (isMobile && isMobile.any) ? 10 : 0 - }); - if (intersectingFeature) featureFound = intersectingFeature; + const intersectingFeature = map.forEachFeatureAtPixel(pixel, feature => { + if (this.features_) { + if (this.features_.indexOf(feature) > -1) { return feature } + else { return null } + } + return feature; + }, { + layerFilter: this.layerFilter_, + hitTolerance: (isMobile && isMobile.any) ? 10 : 0 + }); + if (intersectingFeature) { featureFound = intersectingFeature } return featureFound; }; -PickFeatureInteraction.prototype.shouldStopEvent = function(){ +PickFeatureInteraction.prototype.shouldStopEvent = function() { return false; }; -PickFeatureInteraction.prototype.setMap = function(map){ - if (!map) { - const elem = this.getMap().getTargetElement(); - elem.style.cursor = ''; - } +PickFeatureInteraction.prototype.setMap = function(map) { + if (!map) { this.getMap().getTargetElement().style.cursor = ''} ol.interaction.Pointer.prototype.setMap.call(this,map); }; diff --git a/src/app/g3w-ol/layers/bases.js b/src/app/g3w-ol/layers/bases.js index 9e495e9bd..ba0fd7f5e 100755 --- a/src/app/g3w-ol/layers/bases.js +++ b/src/app/g3w-ol/layers/bases.js @@ -1,21 +1,29 @@ const RasterLayers = require('g3w-ol/layers/rasters'); + const BaseLayers = {}; BaseLayers.OSM = {}; -BaseLayers.OSM.get = function({title, id, url}={}){ +BaseLayers.OSM.get = function({ title, id, url } = {}) { return new ol.layer.Tile({ - source: new ol.source.OSM({ - url - }), - id: id || 'osm', - title: title || 'OSM', + source: new ol.source.OSM({ url }), + id: id || 'osm', + title: title || 'OSM', basemap: true }); }; BaseLayers.TMS = { - get({visible=false, url=null, source_type="xyz", minZoom, maxZoom, projection, attributions, crossOrigin='anonymous'}={}) { + get({ + visible = false, + url = null, + source_type = "xyz", + minZoom, + maxZoom, + projection, + attributions, + crossOrigin = 'anonymous' } = {} + ) { let layer; switch(source_type) { case 'xyz': @@ -44,7 +52,14 @@ BaseLayers.TMS = { }; BaseLayers.WMS = { - get({url, projection, attributions, layers, singleTile=false, opacity=1}){ + get({ + url, + projection, + attributions, + layers, + singleTile = false, + opacity = 1 + } = {}) { return RasterLayers.WMSLayer({ url, projection, @@ -73,13 +88,13 @@ BaseLayers.WMTS = { } = {}) { if (matrixSet) { const projectionExtent = projection.getExtent(); - const resolutions = new Array(14); - const size = ol.extent.getWidth(projectionExtent) / 256; - const matrixIds = new Array(14); + const resolutions = new Array(14); + const size = ol.extent.getWidth(projectionExtent) / 256; + const matrixIds = new Array(14); for (var z = 0; z < 14; ++z) { // generate resolutions and matrixIds arrays for this WMTS resolutions[z] = size / Math.pow(2, z); - matrixIds[z] = z; + matrixIds[z] = z; } return new ol.layer.Tile({ opacity, @@ -125,7 +140,7 @@ BaseLayers.WMTS = { BaseLayers.BING = {}; -BaseLayers.BING.get = (config={})=>{ +BaseLayers.BING.get = ( config = {} ) => { const imagerySet = config.imagerySet || 'Aerial'; // 'Road', 'AerialWithLabels', 'Aerial' return new ol.layer.Tile({ name: imagerySet, diff --git a/src/app/g3w-ol/layers/rasters.js b/src/app/g3w-ol/layers/rasters.js index 3000b3b10..ab72a32e3 100755 --- a/src/app/g3w-ol/layers/rasters.js +++ b/src/app/g3w-ol/layers/rasters.js @@ -4,7 +4,11 @@ const DPI = getDPI(); const RasterLayers = {}; -const loadImageTileFunction = function({method='GET', type='image', sourceOptions={}}) { +const loadImageTileFunction = function({ + method = 'GET', + type = 'image', + sourceOptions = {} +}) { window.URL = window.URL || window.webkitURL; sourceOptions[`${type}LoadFunction`] = function(imageTile, url) { const xhr = new XMLHttpRequest(); @@ -65,7 +69,7 @@ RasterLayers.TiledMapProxyWMSLayer = function(opts={}) { }); }; -RasterLayers.WMSLayer = function(layerObj, extraParams={}, method='GET') { +RasterLayers.WMSLayer = function(layerObj, extraParams = {}, method = 'GET') { return RasterLayers._WMSLayer({ layerObj, extraParams, @@ -73,50 +77,56 @@ RasterLayers.WMSLayer = function(layerObj, extraParams={}, method='GET') { }); }; -RasterLayers.ImageArgisMapServer = function(options={}) { - return new ol.layer.Image({ - source: new ol.source.ImageArcGISRest({ - ratio: options.ratio, - params: { - FORMAT: options.format - }, - url: options.url +RasterLayers.ImageArgisMapServer = function(options = {}) { + return new ol.layer.Image({ + source: new ol.source.ImageArcGISRest({ + ratio: options.ratio, + params: { FORMAT: options.format }, + url: options.url }) }) }; -RasterLayers.TiledArgisMapServer = function(options={}) { - const {url, visible=true, extent, projection, attributions, crossOrigin} = options; +RasterLayers.TiledArgisMapServer = function(options = {}) { + const { + url, + visible = true, + extent, + projection, + attributions, + crossOrigin + } = options; + const source = new ol.source.TileArcGISRest({ url, projection, attributions, crossOrigin }); - return new ol.layer.Tile({ + + return new ol.layer.Tile({ extent, visible, source }) }; -RasterLayers._WMSLayer = function(options={}) { - +RasterLayers._WMSLayer = function(options = {}) { const { layerObj, - method='GET', + method = 'GET', extraParams, - tiled=false + tiled = false } = options; const { - iframe_internal=false, - layers='', - version='1.3.0', - sld_version='1.1.0', + iframe_internal = false, + layers = '', + version = '1.3.0', + sld_version = '1.1.0', id, name, - opacity=1.0, + opacity = 1.0, visible, extent, maxResolution, @@ -127,8 +137,8 @@ RasterLayers._WMSLayer = function(options={}) { } = layerObj; let params = { - LAYERS: layers, - VERSION: version, + LAYERS: layers, + VERSION: version, TRANSPARENT: true, SLD_VERSION: sld_version, DPI @@ -139,14 +149,12 @@ RasterLayers._WMSLayer = function(options={}) { * * @since 3.7.11 */ - if (undefined !== format) { - params.FORMAT = format - } + if (undefined !== format) { params.FORMAT = format } const sourceOptions = { - url: layerObj.url, - params: Object.assign({}, params, extraParams), - ratio: 1, + url: layerObj.url, + params: Object.assign({}, params, extraParams), + ratio: 1, projection: (layerObj.projection) ? layerObj.projection.getCode() : null }; @@ -173,21 +181,20 @@ RasterLayers._WMSLayer = function(options={}) { }; -RasterLayers.XYZLayer = function(options={}, method='GET') { +RasterLayers.XYZLayer = function( options = {}, method = 'GET') { const iframe_internal = options.iframe_internal || false; const { url, projection, maxZoom, minZoom, - visible=true, + visible = true, crossOrigin, cache_provider, /** @since 3.10.0 **/ } = options; //in case of no url provide, skip - if (!url) { - return; - } + if (!url) { return } + const sourceOptions = { url, maxZoom, @@ -205,7 +212,7 @@ RasterLayers.XYZLayer = function(options={}, method='GET') { } /** @since 3.10.0 add cache_provider **/ if ('degrees' === projection.getUnits() || 'mapproxy' === cache_provider) { - const extent = projection.getExtent(); + const extent = projection.getExtent(); const resolutions = ol.tilegrid.createXYZ({extent, maxZoom}).getResolutions(); // Need to remove the first resolution because in this version of ol createXYZ doesn't accept maxResolution options. // The extent of EPSG:4326 is not squared [-180, -90, 180, 90] as EPSG:3857 so the resolution is calculated @@ -215,11 +222,10 @@ RasterLayers.XYZLayer = function(options={}, method='GET') { sourceOptions.tileGrid = new ol.tilegrid.TileGrid({ extent, resolutions}); } - const source = new ol.source.XYZ(sourceOptions); return new ol.layer.Tile({ visible, projection, - source + source: new ol.source.XYZ(sourceOptions) }); }; diff --git a/src/app/g3w-ol/projection/projection.js b/src/app/g3w-ol/projection/projection.js index 325467193..c81692468 100644 --- a/src/app/g3w-ol/projection/projection.js +++ b/src/app/g3w-ol/projection/projection.js @@ -1,15 +1,14 @@ -const Projection = function(options={}) { - if (!options.crs) return null; +const Projection = function(options = {}) { + if (!options.crs) { return null } // structure of information crs from server set on each layer and base layer - const {epsg, proj4:proj4def, geographic=false, axisinverted=false, extent} = options.crs; - proj4def && proj4.defs(epsg, proj4def); + const { epsg, proj4:proj4def, geographic = false, axisinverted = false, extent } = options.crs; + if (proj4def) { proj4.defs(epsg, proj4def) } this._axisOrientation = axisinverted ? 'neu' : 'enu'; - const degrees = geographic; ol.proj.Projection.call(this, { code: epsg, extent, axisOrientation: this._axisOrientation, - units: degrees ? 'degrees' : 'm' + units: geographic ? 'degrees' : 'm' }); }; @@ -22,7 +21,7 @@ proto.getAxisOrientation = function() { }; proto.isInvertedAxisOrientation = function() { - return this._axisOrientation === 'neu'; + return 'neu' === this._axisOrientation; }; proto.getOlProjection = function() {}; diff --git a/src/app/g3w-ol/projection/projections.js b/src/app/g3w-ol/projection/projections.js index b7fe9be47..31dfd4f52 100644 --- a/src/app/g3w-ol/projection/projections.js +++ b/src/app/g3w-ol/projection/projections.js @@ -13,14 +13,10 @@ const Projections = { return ol.proj.get(epsg); }, - get(crs={}) { + get(crs = {}) { const cachedProjection = this.isRegistered(crs.epsg); - if (cachedProjection) { - return cachedProjection; - } - const projection = new Projection({ - crs - }); + if (cachedProjection) { return cachedProjection } + const projection = new Projection({ crs }); ol.proj.addProjection(projection); ol.proj.proj4.register(proj4); return projection; @@ -37,13 +33,12 @@ const Projections = { return new Promise((resolve, reject) => { let projection = this.isRegistered(epsg); // check if already register - if (projection) { - resolve(projection); - } else { + if (projection) { resolve(projection) } + else { XHR.get({url: `${API_BASE_URLS.CRS}${epsg.split(':')[1]}`}) - .then(({result, data}) => { + .then(({ result, data }) => { if (result) { - data.epsg = normalizeEpsg(data.epsg); + data.epsg = normalizeEpsg(data.epsg); projection = this.get(data); ol.proj.proj4.register(proj4); resolve(projection); diff --git a/src/app/gui/catalog/catalogservice.js b/src/app/gui/catalog/catalogservice.js deleted file mode 100644 index 2a95cefb1..000000000 --- a/src/app/gui/catalog/catalogservice.js +++ /dev/null @@ -1,182 +0,0 @@ -import CatalogLayersStoresRegistry from 'store/catalog-layers'; -import ProjectsRegistry from 'store/projects'; -import ApplicationService from 'services/application'; - -const { base, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); - -function CatalogService() { - this.state = { - prstate: ProjectsRegistry.state, - highlightlayers: false, - external: { - wms: [], // added by wms cside bar component - vector: [] // added to map controls for the moment - }, - layerstrees: [], - layersgroups: [] - }; - - this.setters = { - - /** - * @param {{ layer: unknown, type: 'vector' }} - * - * @fires CatalogService~addExternalLayer - * - * @since 3.8.0 - */ - addExternalLayer({layer, type='vector'} = {}) { - layer.removable = true; - this.state.external[type].push(layer); - }, - - /** - * @param {{ name: string, type: 'vector' }} - * - * @fires CatalogService~removeExternalLayer - * - * @since 3.8.0 - */ - removeExternalLayer({name, type='vector'} = {}) { - this.state.external[type].filter((layer, index) => { - if (layer.name === name) { - this.state.external[type].splice(index, 1); - return true - } - }); - }, - - /** - * @param {{ layer: unknown, type: unknown, selected: unknown }} - * - * @fires CatalogService~setSelectedExternalLayer - * - * @since 3.8.0 - */ - setSelectedExternalLayer({layer, type, selected}) { - this.state.external[type].forEach(externalLayer => { - if (typeof externalLayer.selected != "undefined") - externalLayer.selected = (layer === externalLayer) ? selected : false; - }) - }, - - }; - - base(this); - const layersStores = CatalogLayersStoresRegistry.getLayersStores(); - - layersStores.forEach(layersStore => this.addLayersStoreToLayersTrees(layersStore)); - - CatalogLayersStoresRegistry.onafter('addLayersStore', layersStore => { - this.addLayersStoreToLayersTrees(layersStore) - }); - - CatalogLayersStoresRegistry.onafter('removeLayersStore', layersStore => { - this.state.layerstrees.find((layersTree, idx) => { - if (layersTree.storeid === layersStore.getId()) { - this.state.layerstrees.splice(idx, 1); - return true; - } - }); - }); - CatalogLayersStoresRegistry.onafter('removeLayersStores', () => { - this.state.layerstrees.forEach((layersTree, idx) => { - this.state.layerstrees.splice(idx, 1); - }); - }); -} - -inherit(CatalogService, G3WObject); - -const proto = CatalogService.prototype; - -proto.createLayersGroup = function({title = 'Layers Group', layers =[]} = {}) { - const nodes = []; - layers.forEach(layer => nodes.push(layer)); - return { - title, - nodes - } -}; - -proto.getMajorQgisVersion = function() { - return ProjectsRegistry.getCurrentProject().getQgisVersion({ - type: 'major' - }); -}; - -// method to add a custom layers group -proto.addLayersGroup = function(layersGroup) { - this.state.layersgroups.push(layersGroup); -}; - -proto.addLayersStoreToLayersTrees = function(layersStore) { - this.state.layerstrees.push({ - tree: layersStore.getLayersTree(), - storeid: layersStore.getId() - }); -}; - -proto.changeMapTheme = async function(map_theme) { - // set is changing project view - ApplicationService.changeProjectView(true); - const {currentProject} = this.state.prstate; - const rootNode = this.state.layerstrees[0]; - rootNode.checked = true; - const layerstree = rootNode.tree[0].nodes; - const changeMapThemeProjectObj = await currentProject.setLayersTreePropertiesFromMapTheme({ - map_theme, - layerstree, - rootNode - }); - ApplicationService.changeProjectView(false); - return changeMapThemeProjectObj; -}; - -/** - * @param {{ type: 'vector' }} - * - * @returns {unknown} - * - * @since 3.8.0 - */ -proto.getExternalLayers = function({type='vector'}) { - return this.state.external[type]; -}; - -/** - * @param {{ type: 'vector' }} - * - * @returns {unknown} - * - * @since 3.8.0 - */ -proto.getExternalSelectedLayers = function({type='vector'}) { - return this.getExternalLayers({type}).filter(layer => layer.selected); -}; - -/** - * @param {{ id: string, type: 'vector' }} - * - * @returns {unknown} - * - * @since 3.8.0 - */ -proto.getExternalLayerById = function({id, type='vector'}) { - return this.state.external[type].find(layer => layer.id === id); -}; - -/** - * @param {{ id: string, type: unknown }} - * - * @returns {boolean} - * - * @since 3.8.0 - */ -proto.isExternalLayerSelected = function({id, type}) { - const externalLayer = this.getExternalLayerById({ id, type }); - return !!(externalLayer && externalLayer.selected); -}; - -module.exports = CatalogService; diff --git a/src/app/gui/catalog/vue/catalog.js b/src/app/gui/catalog/vue/catalog.js index 3b4177b01..d27c5ab10 100755 --- a/src/app/gui/catalog/vue/catalog.js +++ b/src/app/gui/catalog/vue/catalog.js @@ -1,54 +1,7 @@ -import * as catalogComponentOptions from 'components/Catalog.vue'; -import * as catalogLayersGroupComponentOptions from 'components/CatalogLayersGroup.vue'; -import * as catalogTristateTreeComponentOptions from 'components/CatalogTristateTree.vue'; -import * as catalogLayersLegendComponentOptions from 'components/CatalogLayersLegend.vue'; -import * as catalogLayersLegendItemsComponentOptions from 'components/CatalogLayersLegendItems.vue'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -import ComponentsRegistry from 'store/components'; -import GUI from 'services/gui'; - - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); -const Service = require('gui/catalog/catalogservice'); - -const InternalComponent = Vue.extend(catalogComponentOptions); - -Vue.component('g3w-catalog', catalogComponentOptions); -Vue.component('layers-group', catalogLayersGroupComponentOptions); -Vue.component('tristate-tree', catalogTristateTreeComponentOptions); -Vue.component('layerslegend', catalogLayersLegendComponentOptions); -Vue.component('layerslegend-items', catalogLayersLegendItemsComponentOptions); - -function CatalogComponent(options={}) { - options.resizable = true; - base(this, options); - const {legend} = options.config; - this.title = "catalog"; - this.mapComponentId = options.mapcomponentid; - const service = options.service || new Service; - this.setService(service); - this.setInternalComponent(new InternalComponent({ - service, - legend - })); - this.internalComponent.state = this.getService().state; - let listenToMapVisibility = map => { - const mapService = map.getService(); - this.state.visible = !mapService.state.hidden; - mapService.onafter('setHidden', hidden => { - this.state.visible = !mapService.state.hidden; - this.state.expanded = true; - }) - }; - if (this.mapComponentId) { - const map = GUI.getComponent(this.mapComponentId); - !map && ComponentsRegistry.on('componentregistered', component => - (component.getId() === this.mapComponentId) && listenToMapVisibility(component)) - || listenToMapVisibility(map); - } -} - -inherit(CatalogComponent, Component); - -module.exports = CatalogComponent; +import vueComp from 'components/g3w-catalog'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/changemapmenu/changemapmenu.js b/src/app/gui/changemapmenu/changemapmenu.js index f17e3ebb8..4ba1b2e19 100644 --- a/src/app/gui/changemapmenu/changemapmenu.js +++ b/src/app/gui/changemapmenu/changemapmenu.js @@ -1,23 +1,7 @@ /** * @file - * @since 3.8.0 + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 */ -import * as vueComponentOptions from 'components/ChangeMapMenu.vue'; - -const { base, inherit, merge } = require('utils'); -const Component = require('gui/component/component'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -function ChangeMapMenuComponent(options={}) { - options.id = 'changemapmenu'; - base(this, options); - this.state.visible = true; - merge(this, options); - this.internalComponent = new InternalComponent(); -} -inherit(ChangeMapMenuComponent, Component); - -module.exports = ChangeMapMenuComponent; - +import vueComp from 'components/g3w-changemapmenu'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/component/component.js b/src/app/gui/component/component.js index c2f6ab21b..d4561527e 100644 --- a/src/app/gui/component/component.js +++ b/src/app/gui/component/component.js @@ -1,409 +1,7 @@ -const { - base, - inherit, - merge, - noop, - capitalize_first_letter, - resolve -} = require('utils'); -const G3WObject = require('core/g3wobject'); - -/** @deprecated */ -const _cloneDeep = require('lodash.clonedeep'); - -/** - * Component class - * - * @param { Object} options - * @param { number } options.id - * @param { string } options.title - * @param { boolean } options.visible - * @param { boolean } options.open - * @param { boolean } options.resizable - * @param { null | unknown } options.info - * @param { boolean } options.loading - * @param { boolean } options.disabled - * @param { boolean } options.closewhenshowviewportcontent - * @param options.events - */ -const Component = function(options = {}) { - - const { - id = Math.random() * 1000, - title = '', - visible = true, - open = false, - resizable = false, - info = null, - loading = false, - disabled = false, - closewhenshowviewportcontent = true, - } = options; - - this._firstLayout = true; - - /** internal VUE component */ - this.internalComponent = null; - - /** @type { Array } */ - this._components = []; - - /** @type { string } */ - this.id = id; - - /** @type { string } */ - this.title = title; - - this.state = { - visible, - open, - resizable, - info, - loading, - disabled, - closewhenshowviewportcontent, - sizes: { - width:0, - height:0 - } - }; - - this.setters = { - - setOpen(bool) { - this.state.open = bool; - this._setOpen(bool); - }, - - setVisible(bool) { - this.state.visible = bool; - this._setVisible(bool); - }, - - setLoading(bool=false) { - this.state.loading = bool; - }, - - setDisabled(bool=false) { - this.state.disabled = bool; - }, - - reload() { - this._reload(); - }, - - }; - - merge(this, options); - - base(this); - - // add events options - this.events = options.events; - - if (this.events) { - this.handleEventsComponent(); - } - -}; - -inherit(Component, G3WObject); - -const proto = Component.prototype; - -/** - * @param { Object } options - * @param { Array } options.components - * @param { Object } options.service - * @param { Function } options.service.init - * @param options.vueComponentObject - * @param options.template - * @param options.propsData - */ -proto.init = function(options = {}) { - this.vueComponent = this.createVueComponent(options.vueComponentObject); - this._components = options.components || []; - - this.setService(options.service || noop); - - if (this._service.init) { - this._service.init(options); - } - - if (options.template) { - this.setInternalComponentTemplate(options.template); - } - - this.setInternalComponent = function() { - this.internalComponent = new (Vue.extend(this.vueComponent))({ - service: this._service, - template: options.template, - propsData: options.propsData - }); - this.internalComponent.state = this.getService().state; - }; - - this.setInternalComponent(); - - return this; -}; - -proto.getId = function() { - return this.id; -}; - -proto.setId = function(id) { - this.id = id; -}; - -proto.getOpen = function() { - return this.state.open; -}; - -proto.closeWhenViewportContentIsOpen = function() { - return this.getOpen() && this.state.closewhenshowviewportcontent; -}; - -proto.getVisible = function() { - return this.state.visible; -}; - -proto.getTitle = function() { - return this.state.title; -}; - -proto.setTitle = function(title) { - this.state.title = title; -}; - -proto.getService = function() { - return this._service; -}; - -proto.setService = function(service) { - this._service = service; -}; - -proto.handleEventsComponent = function() { - if (this.events.open) { - const { when = "after", cb = () => {} } = this.events.open; - this[`on${when}`]('setOpen', bool => cb(bool)); - } -}; - -proto.insertComponentAt = function(index, Component) { - this._components.splice(index, 0, Component); -}; - -proto.removeCompomentAt = function(index) { - this._components.splice(index, 1); -}; - -proto.addComponent = function(Component) { - this._components.push(Component); -}; - -proto.popComponent = function() { - return this._components.pop(); -}; - -proto.removeComponent = function(Component) { - this._components.forEach((c, i) => { - if (c === Component) { - this.splice(i, 1); - return false; - } - }) -}; - -proto.setComponents = function(components) { - this._components = Array.isArray(components) ? components: []; -}; - -proto.exendComponents = function(components) { - _.merge(this._components, components); -}; - -proto.getInternalComponent = function() { - return this.internalComponent; -}; - -proto.setInternalComponent = function(internalComponent, options={}) { - this.internalComponent = !internalComponent && this.internalComponentClass ? new this.internalComponentClass : internalComponent; - (options.events || []).forEach(e => this.internalComponent.$on(e.name, data => e.handler && e.handler(data) || this[`set${capitalize_first_letter(e.name)}`](data))) -}; - -proto.createVueComponent = function (vueObjOptions) { - return _cloneDeep(vueObjOptions); -}; - -proto.addInternalComponentData = function(data) { - _.merge(this.internalComponent, data) -}; - -proto.overwriteServiceMethod = function(methodName, method) { - this._service[methodName] = method; -}; - -proto.overwriteServiceMethods = function(methodsOptions) { - Object.entries(methodsOptions).forEach(([methodName, method]) => this.overwriteServiceMethod(methodName, method)) -}; - -proto.extendService = function(serviceOptions) { - if (this._service) { - merge(this._service, serviceOptions); - } -}; - -proto.extendInternalComponent = function(internalComponentOptions) { - if(!this.vueComponent) { - this.vueComponent = internalComponentOptions; - return; - } - Object - .entries(internalComponentOptions) - .forEach(([key, value]) => { - switch (key) { - case 'methods': this.extendInternalComponentMethods(value); break; - case 'components': this.extendInternalComponentComponents(value); break; - case 'computed': merge(this.vueComponent[key], value); break; - case 'data': merge(this.vueComponent[key], value); break; - } - }); -}; - -proto.extendInternalComponentComponents = function(components) { - if (components) { - merge(this.vueComponent.components, components); - } -}; - -proto.extendComponents = function(components) { - this.extendInternalComponentComponents(components); -}; - -proto.addComponent = function(component) { - if (component) { - this.vueComponent.components[component.key] = component.value; - } -}; - -/** @TODO check if unusued (invalid call to "forEach.forEach") */ -proto.extendInternalComponentMethods = function(methods) { - if (methods) { - Object.entries(methods).forEach.forEach(([key, value]) => (!(value instanceof Function)) && delete methods[key]); - merge(this.vueComponent.methods, methods); - } -}; - -proto.extendInternalComponentComputed = function(computed) { - if (computed) { - Object.entries(computed).forEach(([key, value]) => (!(value instanceof Function)) && delete computed[key]); - merge(this.vueComponent.computed, computed); - } -}; - -proto.setInternalComponentTemplate = function(template) { - if (template) { - this.vueComponent.template = template; - } -}; - -proto.getInternalTemplate = function() { - return this.vueComponent.template; -}; - -proto.destroy = function() {}; - -proto.click = function() {}; - -// hook function to show componet -proto.show = function() {}; - -proto._setOpen = function(bool) {}; - -proto._setVisible = function() {}; - -proto._reload = function() {}; - -/** - * @param { Element | 'string' } parent DOM element - * @param { boolean } append - * - * @returns jquery promise - * - * @fires internalComponent~ready - * @fires mount - */ -proto.mount = function(parent, append) { - const d = $.Deferred(); - - if (!this.internalComponent) { - this.setInternalComponent(); - } - - if (append) { - $(parent).append(this.internalComponent.$mount().$el); - } - - if (!append){ - this.internalComponent.$mount(parent); - } - - this.internalComponent.$nextTick(() => { - $(parent).localize(); - this.emit('ready'); - d.resolve(true); - }); - - // emit mount event - this.emit('mount'); - - return d.promise(); -}; - -/** - * @returns jquery promise - * - * @fires unmount - */ -proto.unmount = function() { - if (!this.internalComponent) { - return resolve(); - } - if (this.state.resizable) { - this.internalComponent.$off('resize-component', this.internalComponent.layout); - } - this.state.open = false; - this.internalComponent.$destroy(true); // destroy vue component - $(this.internalComponent.$el).remove(); // remove dom element - this.internalComponent = null; // set internal componet to null (for GC) - this.emit('unmount'); // emit unmount event - return resolve(); -}; - -/** - * @returns { Element } DOM element - */ -proto.ismount = function() { - return this.internalComponent && this.internalComponent.$el; -}; - /** - * @param { number } width - * @param { number } height - * - * @listens internalComponent~resize-component - * @fires internalComponent~resize-component - * @fires layout + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 */ -proto.layout = function(width, height) { - if (this.state.resizable && this._firstLayout) { - this.internalComponent.$on('resize-component', this.internalComponent.layout); - this._firstLayout = false; - } - this.internalComponent.$nextTick(() => { this.internalComponent.$emit('resize-component', { width, height }); }); - this.emit('layout'); -}; -module.exports = Component; \ No newline at end of file +import vueComp from 'core/g3w-component'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/external/select2/options/autocomplete.js b/src/app/gui/external/select2/options/autocomplete.js deleted file mode 100644 index fe1cb0840..000000000 --- a/src/app/gui/external/select2/options/autocomplete.js +++ /dev/null @@ -1,36 +0,0 @@ -const { t } = require('core/i18n/i18n.service'); - -module.exports = { - matcher: (params, data) => { - const searchItem = params.term ? params.term.toLowerCase(): params.term; - // If there are no search terms, return all of the data - if ($.trim(searchItem) === '') return data; - // Do not display the item if there is no 'text' property - if (typeof data.text === 'undefined') return null; - // `params.term` should be the term that is used for searching - // `data.text` is the text that is displayed for the data object - if (data.text.toLowerCase().indexOf(searchItem) > -1) { - const modifiedData = $.extend({}, data, true); - // You can return modified objects from here - // This includes matching the `children` how you want in nested data sets - return modifiedData; - } - // Return `null` if the term should not be displayed - return null; - }, - language: { - noResults(){ - return t("sdk.search.no_results"); - }, - errorLoading(){ - return t("sdk.search.error_loading") - }, - searching(){ - return t("sdk.search.searching") - }, - inputTooShort(args) { - const remainingChars = args.minimum - args.input.length; - return `${t("sdk.search.autocomplete.inputshort.pre")} ${remainingChars} ${t("sdk.search.autocomplete.inputshort.post")}`; - } - }, -}; \ No newline at end of file diff --git a/src/app/gui/fields/fields.js b/src/app/gui/fields/fields.js index 158f32b32..75033607a 100644 --- a/src/app/gui/fields/fields.js +++ b/src/app/gui/fields/fields.js @@ -1,8 +1,8 @@ -import Text from 'components/FieldText.vue'; -import Link from 'components/FieldLink.vue'; -import Image from 'components/FieldImage.vue' -import Geo from 'components/FieldGeo.vue'; -import Media from 'components/FieldMedia.vue'; +import Text from 'components/FieldText.vue'; +import Link from 'components/FieldLink.vue'; +import Image from 'components/FieldImage.vue' +import Geo from 'components/FieldGeo.vue'; +import Media from 'components/FieldMedia.vue'; import VueField from 'components/FieldVue.vue'; const Fields = { diff --git a/src/app/gui/fields/fieldsservice.js b/src/app/gui/fields/fieldsservice.js index 6c73f1171..0194b75aa 100644 --- a/src/app/gui/fields/fieldsservice.js +++ b/src/app/gui/fields/fieldsservice.js @@ -1,9 +1,9 @@ import CatalogLayersStoresRegistry from 'store/catalog-layers'; -const Fields = require('./fields'); +const Fields = require('./fields'); const { toRawType } = require('utils'); -const URLPattern = /^(https?:\/\/[^\s]+)/g; +const URLPattern = /^(https?:\/\/[^\s]+)/g; const PhotoPattern = /[^\s]+.(png|jpg|jpeg|gif)$/g; const FieldType = { @@ -21,76 +21,83 @@ const FieldType = { module.exports = { /** * Get Type field from field value - * field : Object contain the value of the field + * field: Object contains the value of the field * @param field * @returns {string} */ - getType(field){ + getType(field) { let type = field.type; if (type !== 'vue'){ const fieldValue = field.value; const value = fieldValue && toRawType(fieldValue) === 'Object' && !fieldValue.coordinates && !fieldValue.vue ? fieldValue.value : fieldValue; - if (!value) type = FieldType.SIMPLE; - else if (value && typeof value == 'object') { - if (value.coordinates) type = FieldType.GEO; - else if (value.vue) type = FieldType.VUE; - } else if(value && Array.isArray(value)) { - if (value.length && value[0].photo) type = FieldType.PHOTO; - else type = FieldType.SIMPLE + if (!value) { + type = FieldType.SIMPLE; + } else if (value && typeof value == 'object') { + if (value.coordinates) { + type = FieldType.GEO; + } else if (value.vue) { + type = FieldType.VUE; + } + } else if (value && Array.isArray(value)) { + if (value.length && value[0].photo) { + type = FieldType.PHOTO; + } else { + type = FieldType.SIMPLE + } } else if (value.toString().toLowerCase().match(PhotoPattern)) { type = FieldType.PHOTO; } else if (value.toString().match(URLPattern)) { type = FieldType.LINK; - } else type = FieldType.SIMPLE; + } else { + type = FieldType.SIMPLE; + } } return `${type}_field`; }, - isSimple(field){ - return this.getType(field) === `${FieldType.SIMPLE}_field`; + isSimple(field) { + return `${FieldType.SIMPLE}_field` === this.getType(field); }, - isLink(field){ - return this.getType(field) === `${FieldType.LINK}_field`; + isLink(field) { + return `${FieldType.LINK}_field` === this.getType(field); }, - isImage(field){ - return this.getType(field) === `${FieldType.IMAGE}_field`; + isImage(field) { + return `${FieldType.IMAGE}_field` === this.getType(field); }, - isPhoto(field){ - return this.getType(field) === `${FieldType.PHOTO}_field`; + isPhoto(field) { + return `${FieldType.PHOTO}_field` === this.getType(field); }, - isVue(field){ - return this.getType(field) === `${FieldType.VUE}_field`; + isVue(field) { + return `${FieldType.VUE}_field` === this.getType(field); }, /** * Method to add a new field type to Fields * @param type * @param field */ - add({type, field}){ + add({type, field}) { Fields[type] = field; }, /** - * Remove field from Fields list + * Remove field from a Fields list * @param type */ - remove(type){ + remove(type) { delete Fields[type]; }, /** - * chenge type of field (example to set vue type) + * change type of field (example to set vue type) * @param layerId * @param field */ - changeConfigFieldType({layerId, field={}}){ - const layer = CatalogLayersStoresRegistry.getLayerById(layerId); - layer.changeConfigFieldType(field); + changeConfigFieldType({layerId, field={}}) { + CatalogLayersStoresRegistry.getLayerById(layerId).changeConfigFieldType(field); }, /** * Reset origin type * @param layerId * @param field */ - resetConfigFieldType({layerId, field={}}){ - const layer = CatalogLayersStoresRegistry.getLayerById(layerId); - layer.resetConfigField(field); + resetConfigFieldType({layerId, field={}}) { + CatalogLayersStoresRegistry.getLayerById(layerId).resetConfigField(field); } }; \ No newline at end of file diff --git a/src/app/gui/form/formservice.js b/src/app/gui/form/formservice.js index b287e3c2d..0681d7e4b 100644 --- a/src/app/gui/form/formservice.js +++ b/src/app/gui/form/formservice.js @@ -453,8 +453,11 @@ proto.addComponents = function(components = []) { }; proto.addComponent = function(component) { + if (!component) { + return; + } const {id, title, name, icon, valid, headerComponent, header=true} = component; - if (valid !== undefined) { + if (undefined !== valid) { this.state.componentstovalidate[id] = valid; this.state.valid = this.state.valid && valid; this.eventBus.$emit('add-component-validate', { @@ -477,8 +480,11 @@ proto.replaceComponent = function({id, component}={}) { }; proto.disableComponent = function({id, disabled}) { - if (disabled) this.state.disabledcomponents.push(id); - else this.state.disabledcomponents = this.state.disabledcomponents.filter(disableId => disabledId !== id); + if (disabled) { + this.state.disabledcomponents.push(id); + } else { + this.state.disabledcomponents = this.state.disabledcomponents.filter(disableId => disabledId !== id); + } }; proto.setCurrentComponentById = function(id) { @@ -518,7 +524,7 @@ proto.addedComponentTo = function(formcomponent = 'body') { proto.addToValidate = function(input) { this.state.tovalidate[input.name] = input; - // check if is mounted on form gui otherwise leave form component to run is Valid whe form is mounted on dom + // check if is mounted on form gui otherwise leave form component to run is Valid when form is mounted on dom if (this.state.ready) { this.isValid(input); } @@ -529,7 +535,7 @@ proto.removeToValidate = function(input) { this.isValid(); }; -proto.getState = function () { +proto.getState = function() { return this.state; }; @@ -597,7 +603,7 @@ proto.saveDefaultExpressionFieldsNotDependencies = async function() { // disable listen changeInput this.listenChangeInput = false; - // Array contain field name already resolved with server default_expression request + // Array contains field name already resolved with server default_expression request const requested_expressions = []; // array of defaultExpressionPromises request const pending_expressions = []; @@ -611,7 +617,7 @@ proto.saveDefaultExpressionFieldsNotDependencies = async function() { return ( // check if dependency field is field on update this.default_expression_fields_on_update.find(({name}) => name === field) && - // if has bind current field + // if it has bind current field this.default_expression_fields_dependencies[field].find(fieldName => fieldName === this.default_expression_fields_on_update[i].name) ) }); @@ -620,7 +626,7 @@ proto.saveDefaultExpressionFieldsNotDependencies = async function() { // need to evaluate its value and after evaluate field value expression for (let i = 0; i < dFs.length; i++) { // in case already done a default_expression request evaluation from server - if ("undefined" !== typeof requested_expressions.find(name => name === dFs[i])) { + if (undefined !== requested_expressions.find(name => name === dFs[i])) { continue; } // get value. Need to wait response @@ -643,7 +649,7 @@ proto.saveDefaultExpressionFieldsNotDependencies = async function() { } this.default_expression_fields_on_update.forEach(field => { - if ("undefined" === typeof requested_expressions.find(name => name === field.name)) { + if (undefined === requested_expressions.find(name => name === field.name)) { pending_expressions.push(FormService._getDefaultExpression({ field, feature: this.feature, @@ -810,7 +816,7 @@ FormService._getDefaultExpression = async function({ return value; } catch(err) { - if ("undefined" !== typeof default_value) { + if (undefined !== default_value) { field.value = default_value } return Promise.reject(err); diff --git a/src/app/gui/form/vue/form.js b/src/app/gui/form/vue/form.js index 863ed5257..aac480630 100644 --- a/src/app/gui/form/vue/form.js +++ b/src/app/gui/form/vue/form.js @@ -1,90 +1,7 @@ -import * as vueComponentOptions from 'components/Form.vue'; -import BodyFormComponent from 'components/FormBody.vue'; -import GUI from 'services/gui'; - -const { base, inherit } = require('utils'); -const Component = require('gui/component/component'); -const Service = require('gui/form/formservice'); - -function FormComponent(options = {}) { - const {id='form', name, title, headerComponent} = options; - base(this, options); - options.service = options.service ? new options.service : new Service; - options.vueComponentObject = options.vueComponentObject || vueComponentOptions; - //set element of the form - const components = options.components || [ - { - id, - title, - name, - root: true, - component: BodyFormComponent, - headerComponent - } - ]; - options.perc = options.layer.getFormPercentage() !== null ? options.layer.getFormPercentage() : options.perc; - // initialize component - this.init(options); - this.getService().addComponents(components); - this.getService().setComponent(components[0].component); - /** - * Used to add component to form body - * @param component - */ - this.addBodyFormComponent = function({component, where='after'}={}){ - this.getInternalComponent().body.components[where].push(component); - }; - - this.addBodyFormComponents = function({components=[], where="after"}={}){ - components.forEach(component => this.addBodyFormComponent({ - component, - where - })) - }; - - this.addFormComponents = function(components = []) { - this.getService().addComponents(components); - }; - - this.addFormComponent = function(component) { - component && this.getService().addComponent(component) - }; - // some utilities methods - this.addDependecyComponents = function(components) { - this.getService().addDependecyComponents(components) - }; - this.addComponentBeforeBody = function(Component) { - //this.getService().addedComponentTo('body'); - //this.insertComponentAt(1, Component); - }; - - this.addComponentAfterBody = function(Component) { - //this.getService().addedComponentTo('body'); - //this.insertComponentAt(2, Component) - }; - - this.addComponentBeforeFooter = function() { - //TODO - }; - - this.addComponentAfterFooter = function(Component) { - //TODO - }; - // overwrite father mount method. - this.mount = function(parent, append) { - return base(this, 'mount', parent, append) - .then(() => { - // set modal window to true - GUI.setModal(true); - }); - }; - - this.layout = function() { - this.internalComponent.reloadLayout(); - }; -} - -inherit(FormComponent, Component); - -module.exports = FormComponent; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ +import vueComp from 'components/g3w-form'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/map/mapservice.js b/src/app/gui/map/mapservice.js index 315b313f7..1046b74e5 100644 --- a/src/app/gui/map/mapservice.js +++ b/src/app/gui/map/mapservice.js @@ -104,7 +104,7 @@ class OlMapViewer { } /** - * @FIXME add description + * Destroy OL map object */ destroy() { if (this.map) { @@ -114,7 +114,7 @@ class OlMapViewer { } /** - * @FIXME add description + * Get Ol Map view Object */ getView() { return this.map.getView(); @@ -130,21 +130,24 @@ class OlMapViewer { updateView(){ } /** - * @FIXME add description + * Return mao OL object */ getMap() { return this.map; } /** - * @FIXME add description + * Set Map Ol target (DOM element) + * @param { String } id */ setTarget(id) { this.map.setTarget(id); } /** - * @FIXME add description + * + * @param { Array } coordinate + * @param { Number } zoom */ zoomTo(coordinate, zoom) { const view = this.map.getView(); @@ -175,7 +178,9 @@ class OlMapViewer { } /** - * @FIXME add description + * Based on coordinates, set Map center to coordinate at resolution is passed as option + * @param { Array } coordinates + * @param { Object } options */ goToRes(coordinates, options = {}) { return new Promise((resolve) => { @@ -222,35 +227,36 @@ class OlMapViewer { } /** - * @FIXME add description + * Get current map zoom level */ getZoom() { return this.map.getView().getZoom(); } /** - * @FIXME add description + * Get current map resolution */ getResolution() { return this.map.getView().getResolution(); } /** - * @FIXME add description + * Get current map center */ getCenter() { return this.map.getView().getCenter(); } /** - * @FIXME add description + * Get current map Bounding Box */ getBBOX() { return this.map.getView().calculateExtent(this.map.getSize()); }; /** - * @FIXME add description + * Get map layer by name + * @param { String } layerName */ getLayerByName(layerName) { return this.map.getLayers().find(layer => layerName === layer.get('name')); @@ -293,10 +299,7 @@ class OlMapViewer { return this .map .getLayers() - .filter((layer) => { - const props = layer.getProperties(); - return (true !== props.basemap); - }); + .filter(layer => !layer.getProperties().basemap); } /** @@ -307,10 +310,10 @@ class OlMapViewer { }; /** - * @TODO double check (unusued and broken code ?) + * @TODO double check (unused and broken code ?) */ changeBaseLayer(layerName) { - this.map.getLayers().insertAt(0, this.getLayerByName(layername)); + this.map.getLayers().insertAt(0, this.getLayerByName(layerName)); } } @@ -364,9 +367,9 @@ function MapService(options={}) { }) this.viewer = null; - this.target = options.target || null; + this.target = options.target || 'map'; this.layersCount = 0; // useful to set Zindex to layer order on map - this.maps_container = options.maps_container || null; + this.maps_container = options.maps_container || 'g3w-maps'; this._layersStoresEventKeys = {}; this._keyEvents = { ol: [], @@ -474,14 +477,15 @@ function MapService(options={}) { } this._decrementLoaders(); }; - if (options.project) this.project = options.project; - else { + if (options.project) { + this.project = options.project; + } else { this.project = ProjectsRegistry.getCurrentProject(); - //on after setting current project + //on after setting a current project const keysetCurrentProject = ProjectsRegistry.onafter('setCurrentProject', project => { this.removeLayers(); this._removeListeners(); - // check if reload same project + // check if reload a same project const isSameProject = this.project.getId() === project.getId(); this.project = project; const changeProjectCallBack = () => { @@ -491,7 +495,9 @@ function MapService(options={}) { this.setUpMapOlEvents(); this.setupCustomMapParamsToLegendUrl(); }; - ApplicationService.isIframe() && changeProjectCallBack(); + if (ApplicationService.isIframe()) { + changeProjectCallBack(); + } isSameProject ? changeProjectCallBack() : this.getMap().once('change:size', changeProjectCallBack); }); this._keyEvents.g3wobject.push({ @@ -570,7 +576,9 @@ function MapService(options={}) { }); const extraParamsSet = (extraParams, update) => { - update && this.getMapLayers().forEach(mapLayer => mapLayer.update(this.state, extraParams)); + if (update) { + this.getMapLayers().forEach(mapLayer => mapLayer.update(this.state, extraParams)); + } }; this.on('extraParamsSet', extraParamsSet); @@ -607,10 +615,15 @@ proto.setUpMapOlEvents = function() { if (dynamicLegend) { const keyolmoveeend = this.viewer.map.on("moveend", evt => this.setupCustomMapParamsToLegendUrl()); this._keyEvents.ol.push(keyolmoveeend); - } else this.setupCustomMapParamsToLegendUrl(); //set always to show legend at start + } else { + //set always to show legend at the start + this.setupCustomMapParamsToLegendUrl(); + } }; -//clear methods to remove all listeners events +/** + * Clear methods to remove all listeners events + */ proto.clear = function() { Object .keys(this._keyEvents) @@ -645,8 +658,7 @@ proto.hideMapSpinner = function() { proto.getScaleFromExtent = function(extent) { const resolution = this.getMap().getView().getResolutionForExtent(extent, this.getMap().getSize()); - const scale = getScaleFromResolution(resolution, this.getMapUnits()); - return scale; + return getScaleFromResolution(resolution, this.getMapUnits()); }; proto._addHideMap = function({ratio, layers=[], mainview=false} = {}) { @@ -684,7 +696,9 @@ proto.removeHideMap = function(id) { break; } } - index !== undefined && this.state.hidemaps.splice(index,1); + if (index !== undefined) { + this.state.hidemaps.splice(index,1); + } }; proto._showHideMapElement = function({map, show=false} = {}) { @@ -707,7 +721,9 @@ proto.getApplicationAttribution = function() { const {header_terms_of_use_link, header_terms_of_use_text} = this.config.group; if (header_terms_of_use_text) { return header_terms_of_use_link ? `${header_terms_of_use_text}` : `${header_terms_of_use_text}`; - } else return false + } else { + return false + } }; proto.slaveOf = function(mapService, sameLayers) { @@ -732,8 +748,7 @@ proto.getMap = function() { }; proto.getMapCanvas = function(map) { - const viewport = map ? map.getViewport() : $(`#${this.maps_container} .g3w-map`).last().children('.ol-viewport')[0]; - return $(viewport).children('canvas')[0]; + return $(map ? map.getViewport() : $(`#${this.maps_container} .g3w-map`).last().children('.ol-viewport')[0]).children('canvas')[0]; }; proto.getProjection = function() { @@ -745,7 +760,7 @@ proto.isMapHidden = function() { }; proto.isAxisOrientationInverted = function() { - return this.getProjection().getAxisOrientation() === 'neu' ? true : false; + return 'neu' === this.getProjection().getAxisOrientation(); }; proto.getCrs = function() { @@ -769,8 +784,7 @@ proto.getEpsg = function() { }; proto.getGetFeatureInfoUrlForLayer = function(layer, coordinates, resolution, epsg, params) { - const mapLayer = this.getMapLayerForLayer(layer); - return mapLayer.getGetFeatureInfoUrl(coordinates,resolution,epsg,params); + return this.getMapLayerForLayer(layer).getGetFeatureInfoUrl(coordinates,resolution,epsg,params); }; /** @@ -793,7 +807,7 @@ proto.getLayerById = function(id) { return this.getMap().getLayers().getArray().find(layer => layer.get('id') === id); }; -// method do get all feature from vector layer based on coordinates +// method does get all features from vector layer based on coordinates proto.getVectorLayerFeaturesFromCoordinates = function(layerId, coordinates) { let intersectGeom; let features = []; @@ -836,33 +850,28 @@ proto.getVectorLayerFeaturesFromCoordinates = function(layerId, coordinates) { }; proto.getQueryLayerByCoordinates = function({layer, coordinates} = {}) { - const mapProjection = this.getProjection(); - const resolution = this.getResolution(); return new Promise((resolve, reject) => { layer.query({ coordinates, - mapProjection, - resolution - }).then((response) => resolve(response)) - .fail(err => reject(err)) + mapProjection: this.getProjection(), + resolution: this.getResolution(), + }) + .then((response) => resolve(response)) + .fail(err => reject(err)) }) }; proto.getQueryLayerPromiseByCoordinates = function({layer, coordinates} = {}) { return new Promise((resolve, reject) => { - const mapProjection = this.getProjection(); - const resolution = this.getResolution(); layer.query({ coordinates, - mapProjection, - resolution - }).then((response) => { - resolve(response) - }).fail((error)=> { - reject(error); + mapProjection: this.getProjection(), + resolution: this.getResolution() }) + .then((response) => resolve(response)) + .fail((error) => reject(error)) }) -}; +} //setup controls /* @@ -871,10 +880,8 @@ proto.getQueryLayerPromiseByCoordinates = function({layer, coordinates} = {}) { lh: h: horizontal: v vertical (default) } */ - proto.activeMapControl = function(controlName) { - const mapControl = this._mapControls.find(control => control.type === controlName); - const control = mapControl.control; + const control = this._mapControls.find(control => controlName === control.type).control; !control.isToggled() ? control.toggle() : null; }; @@ -903,7 +910,9 @@ proto.changeScaleLineUnit = function(unit) { const scalelinecontrol = this.getMapControlByType({ type: 'scaleline' }); - scalelinecontrol && scalelinecontrol.getOlControl().setUnits(unit); + if (scalelinecontrol) { + scalelinecontrol.getOlControl().setUnits(unit); + } }; proto.showAddLayerModal = function() { @@ -915,12 +924,10 @@ proto._checkMapControls = function() { }; proto._setupControls = function() { - const baseLayers = getMapLayersByFilter({ BASELAYER: true }); - this.getMapLayers().forEach(mapLayer => mapLayer.getSource().setAttributions(this.getApplicationAttribution())); - // check if base layer is set. If true add attribution control - if (this.getApplicationAttribution() || baseLayers.length) { + // check if a base layer is set. If true, add attribution control + if (this.getApplicationAttribution() || getMapLayersByFilter({ BASELAYER: true }).length) { const attributionControl = new ol.control.Attribution({ collapsible: false, target: 'map_footer_left' @@ -1175,8 +1182,13 @@ proto._setupControls = function() { /** * Set ZIndex layer from fa stack */ -proto.setZIndexLayer = function({layer, zindex=this.getMap().getLayers().getLength()}={}) { - layer && layer.setZIndex(zindex); +proto.setZIndexLayer = function({ + layer, + zindex = this.getMap().getLayers().getLength() +}={}) { + if (layer) { + layer.setZIndex(zindex); + } }; /** @@ -1225,12 +1237,11 @@ proto.zoomToFid = async function(zoom_to_fid = '', separator = '|') { /** * Handle ztf url parameter - * + * * @param zoom_to_feature */ proto.handleZoomToFeaturesUrlParameter = async function({ - zoom_to_features = '', - search_endpoint = 'api', + zoom_to_features = '' } = {}) { try { const [id, filter] = zoom_to_features.split(':'); @@ -1251,8 +1262,7 @@ proto.handleZoomToFeaturesUrlParameter = async function({ const r = pLayer && await DataRouterService.getData('search:features', { inputs: { layer, - filter: createFilterFromString({ layer, search_endpoint, filter }), - search_endpoint + filter: createFilterFromString({ layer, filter }), }, outputs: { show: { @@ -1297,14 +1307,12 @@ proto.addMapExtentUrlParameterToUrl = function(url, epsg) { proto.getMapExtentUrl = function() { const url = new URL(location.href); - const map_extent = this.getMapExtent().toString(); - url.searchParams.set('map_extent', map_extent); + url.searchParams.set('map_extent', this.getMapExtent().toString()); return url.toString() }; proto.createCopyMapExtentUrl = function() { - const url = this.getMapExtentUrl(); - copyUrl(url); + copyUrl(this.getMapExtentUrl()); }; proto._setMapControlsGrid = function(length) { @@ -1350,9 +1358,8 @@ proto._setMapControlsInsideContainerLenght = function() { this.state.mapControl.length = 1; // count the mapcontrol inside g3w-map-control container this._mapControls.forEach(control => { - const map = this.getMap(); this.state.mapControl.length+=control.mapcontrol ? control.id === 'zoom' ? 2 : 1: 0; - control.control.changelayout ? control.control.changelayout(map) : null; + control.control.changelayout ? control.control.changelayout(this.getMap()) : null; }); // add 1 id odd number this.state.mapControl.length += this.state.mapControl.length% 2; @@ -1361,16 +1368,16 @@ proto._setMapControlsInsideContainerLenght = function() { }; /** - * Get filtrable layer. Get parameter to custom filter Object + * Get filterable layer. Get parameter to custom filter Object */ -proto.filterableLayersAvailable = function(options={}) { +proto.filterableLayersAvailable = function(options = {}) { return getMapLayersByFilter({ FILTERABLE: true, SELECTED_OR_ALL: true, }, options).filter(layer => 'wfs' === layer.getProvider('filter').getName()); }; -proto.setMapControlsAlignement = function(alignement='rv') { +proto.setMapControlsAlignement = function(alignement = 'rv') { this.state.mapcontrolsalignement = alignement; }; @@ -1404,7 +1411,7 @@ proto.setMapControlsContainer = function(mapControlDom) { proto._updateMapControlsLayout = function({width, height}={}) { // case mobile open keyboard - (width == 0 || height == 0) ? this.state.mapcontrolDOM.css('z-index', 0) : this.state.mapcontrolDOM.css('z-index', 1); + (0 == width || 0 == height) ? this.state.mapcontrolDOM.css('z-index', 0) : this.state.mapcontrolDOM.css('z-index', 1); // update only when all control are ready if (this.state.mapcontrolready && this.state.mapControl.update) { const changedAndMoreSpace = { @@ -1412,20 +1419,17 @@ proto._updateMapControlsLayout = function({width, height}={}) { space: false }; // count the mapcontrol insied g3w-map-control container - this._mapControls.forEach(control => { - const map = this.getMap(); - control.control.changelayout ? control.control.changelayout(map) : null; - }); + this._mapControls.forEach(control => control.control.changelayout ? control.control.changelayout(this.getMap()) : null); // check if is vertical if (this.isMapControlsVerticalAlignement()) { const handleVerticalMapControlDOMElements = () => { const mapControslHeight = this.state.mapControl.grid[this.state.mapControl.currentIndex].columns * this.state.mapcontrolSizes.minWidth; // get bottom controls - const bottomMapControls = $(`.ol-control-b${this.getMapControlsAlignement()[0]}`); - const bottomMapControlTop = bottomMapControls.length ? $(bottomMapControls[bottomMapControls.length - 1]).position().top: height; + const bottomMapControls = document.getElementsByClassName(`.ol-control-b${this.getMapControlsAlignement()[0]}`); + const bottomMapControlTop = bottomMapControls.length ? $(bottomMapControls[bottomMapControls.length - 1]).getBoundingClientRect().top : height; const freeSpace = bottomMapControlTop > 0 ? bottomMapControlTop - mapControslHeight : height - mapControslHeight; if (freeSpace < 10) { - this.state.mapControl.currentIndex = this.state.mapControl.currentIndex === this.state.mapControl.grid.length - 1 ? this.state.mapControl.currentIndex : this.state.mapControl.currentIndex +1; + this.state.mapControl.currentIndex = this.state.mapControl.currentIndex === this.state.mapControl.grid.length - 1 ? this.state.mapControl.currentIndex : this.state.mapControl.currentIndex + 1; changedAndMoreSpace.changed = true; } else { // check if there enough space to expand map controls @@ -1445,11 +1449,17 @@ proto._updateMapControlsLayout = function({width, height}={}) { this.state.mapcontrolDOM.css('height', `${mapControslHeight}px`); this.state.mapcontrolDOM.css('width', `${mapControlsWidth}px`); changedAndMoreSpace.changed = false; - changedAndMoreSpace.space && setTimeout(()=> handleVerticalMapControlDOMElements()); + if (changedAndMoreSpace.space) { + setTimeout(handleVerticalMapControlDOMElements); + } } }; handleVerticalMapControlDOMElements(); - } else isMobile.any && this.setMapControlsAlignement('rv'); + } else { + if (isMobile.any) { + this.setMapControlsAlignement('rv'); + } + } } }; @@ -1460,13 +1470,16 @@ proto._updateMapControlsLayout = function({width, height}={}) { * @private */ proto._setMapControlVisible = function({control, visible=true}) { - control && control.setVisible(visible); + if (control) { + control.setVisible(visible); + } }; proto._addControlToMapControls = function(control, visible=true) { - const controlElement = control.element; - if (!visible) control.element.style.display = "none"; - $('.g3w-map-controls').append(controlElement); + if (!visible) { + control.element.style.display = "none"; + } + $('.g3w-map-controls').append(control.element); }; /** @@ -1562,15 +1575,21 @@ proto.toggleControls = function(toggle, types) { this._removeControls(); this._mapControls.forEach(controlObj => { if (types) { - if (types.indexOf(controlObj.type) > -1) controlObj.visible = toggle; - } else controlObj.visible = toggle; + if (types.indexOf(controlObj.type) > -1) { + controlObj.visible = toggle; + } + } else { + controlObj.visible = toggle; + } }); this._layoutControls(); }; proto._layoutControls = function() { this._mapControls.forEach(controlObj => { - if (controlObj.visible) this.viewer.map.addControl(controlObj.control); + if (controlObj.visible) { + this.viewer.map.addControl(controlObj.control); + } }) }; @@ -1615,7 +1634,9 @@ proto._unToggleControls = function({close=true} = {}) { this._mapControls.forEach(controlObj => { if (controlObj.control.isToggled && controlObj.control.isToggled()) { controlObj.control.toggle(false); - close && GUI.closeContent(); + if (close) { + GUI.closeContent(); + } } }); }; @@ -1649,17 +1670,17 @@ proto._setupCustomMapParamsToLegendUrl = function(bool=true) { if (bool) { const map = this.getMap(); const size = map && map.getSize().filter(value => value > 0) || null; - let bbox = size && size.length === 2 ? map.getView().calculateExtent(size) : this.project.state.initextent; - // in case of axis orientation inverted i need to inverted the axis - bbox = map.getView().getProjection().getAxisOrientation() === "neu" ? [bbox[1], bbox[0], bbox[3], bbox[2]] : bbox; - const crs = this.getEpsg(); - //setup initial legend parameter - this.getMapLayers().forEach(mapLayer => { - mapLayer.setupCustomMapParamsToLegendUrl && mapLayer.setupCustomMapParamsToLegendUrl({ - crs, - bbox - }) - }); + const bbox = size && size.length === 2 ? map.getView().calculateExtent(size) : this.project.state.initextent; + this.getMapLayers() + .forEach(mapLayer => { + if (mapLayer.setupCustomMapParamsToLegendUrl) { + mapLayer.setupCustomMapParamsToLegendUrl({ + crs: this.getEpsg(), + // in the case of axis orientation inverted if it needs to invert the axis + bbox: map.getView().getProjection().getAxisOrientation() === "neu" ? [bbox[1], bbox[0], bbox[3], bbox[2]] : bbox, + }) + } + }) this.emit('change-map-legend-params') } @@ -1671,9 +1692,7 @@ proto.addMapLayer = function(mapLayer) { }; proto.getMapLayerByLayerId = function(layerId) { - return this.getMapLayers().find(mapLayer => { - return mapLayer.getLayerConfigs().find(layer => layer.getId() === layerId); - }) + return this.getMapLayers().find(mapLayer => mapLayer.getLayerConfigs().find(layer => layerId === layer.getId())) }; proto.getMapLayers = function() { @@ -1685,10 +1704,7 @@ proto.getBaseLayers = function() { }; proto.getMapLayerForLayer = function(layer) { - const multilayerId = `layer_${layer.getMultiLayerId()}`; - const mapLayers = this.getMapLayers(); - const mapLayer = mapLayers.find(mapLayer => mapLayer.getId() === multilayerId); - return mapLayer; + return this.getMapLayers().find(mapLayer => `layer_${layer.getMultiLayerId()}` === mapLayer.getId()); }; proto.getProjectLayer = function(layerId) { @@ -1696,10 +1712,10 @@ proto.getProjectLayer = function(layerId) { }; proto._setSettings = function() { - const {ZOOM} = MAP_SETTINGS; + const { ZOOM } = MAP_SETTINGS; const maxScale = this.getScaleFromExtent(this.project.state.initextent); // settings maxScale - ZOOM.maxScale = ZOOM.maxScale > maxScale ? maxScale : ZOOM.maxScale; + ZOOM.maxScale = ZOOM.maxScale > maxScale ? maxScale : ZOOM.maxScale; }; proto._resetView = function() { @@ -1845,7 +1861,9 @@ proto.getMapUnits = function() { }; proto._removeListeners = function() { - this._setBaseLayerListenerKey && this.project.un('setBaseLayer', this._setBaseLayerListenerKey); + if (this._setBaseLayerListenerKey) { + this.project.un('setBaseLayer', this._setBaseLayerListenerKey); + } }; // remove all events of layersStore @@ -1871,7 +1889,7 @@ proto._setUpEventsKeysToLayersStore = function(store) { }; proto._setupListeners = function() { - this._setBaseLayerListenerKey = this.project.onafter('setBaseLayer',() => { + this._setBaseLayerListenerKey = this.project.onafter('setBaseLayer', () => { this.updateMapLayers(); }); }; @@ -2027,7 +2045,9 @@ proto.setLayerZIndex = function({layer, zindex=this.layersCount+=1}) { */ proto.addLayerToMap = function(layer) { const olLayer = layer.getOLLayer(); - olLayer && this.getMap().addLayer(olLayer); + if (olLayer) { + this.getMap().addLayer(olLayer); + } }; /** @@ -2041,9 +2061,8 @@ proto._setMapProjectionToLayers = function(layers) { proto.createMapLayer = function(layer) { layer.setMapProjection(this.getProjection()); - const multilayerId = `layer_${layer.getMultiLayerId()}`; const mapLayer = layer.getMapLayer({ - id: multilayerId, + id: `layer_${layer.getMultiLayerId()}`, projection: this.getProjection() }, this.layersExtraParams); mapLayer.addLayer(layer); @@ -2077,8 +2096,8 @@ proto.getOverviewMapLayers = function(project) { * @param mapLayer * @param options */ -proto.updateMapLayer = function(mapLayer, options={force:false}, {showSpinner=true} = {}) { - // if force adds g3w_time parameter to force request of map layer from server +proto.updateMapLayer = function(mapLayer, options = { force: false }, { showSpinner = true } = {}) { + // if force to add g3w_time parameter to force request of map layer from server if (options.force) { options.g3w_time = Date.now(); } @@ -2093,24 +2112,24 @@ proto.updateMapLayer = function(mapLayer, options={force:false}, {showSpinner=tr // run update function on each mapLayer proto.updateMapLayers = function(options={}) { this.getMapLayers().forEach(mapLayer => this.updateMapLayer(mapLayer, options)); - const baseLayers = this.getBaseLayers(); - //updatebase layer - Object.values(baseLayers).forEach(baseLayer => baseLayer.update(this.state, this.layersExtraParams)); + //update base layer + Object.values(this.getBaseLayers()).forEach(baseLayer => baseLayer.update(this.state, this.layersExtraParams)); }; // register map Layer listeners of creation proto.registerMapLayerListeners = function(mapLayer, projectLayer=true) { this.registerMapLayerLoadingEvents(mapLayer); //listen change filter token - if (projectLayer && mapLayer.layers && Array.isArray(mapLayer.layers)) + if (projectLayer && mapLayer.layers && Array.isArray(mapLayer.layers)) { mapLayer.layers.forEach(layer => { layer.onbefore('change', () => this.updateMapLayer(mapLayer, {force: true})); layer.on('filtertokenchange', () => this.updateMapLayer(mapLayer, {force: true})) }); + } /// }; -/** Methods to register and unregister load map +/** Methods to register and unregister map loadmap * * */ proto.registerMapLayerLoadingEvents = function(mapLayer) { @@ -2133,11 +2152,12 @@ proto.unregisterMapLayerLoadingEvents = function(mapLayer) { proto.unregisterMapLayerListeners = function(mapLayer, projectLayer=false) { this.unregisterMapLayerLoadingEvents(mapLayer); // try to remove layer filter token - if (projectLayer && mapLayer.layers && Array.isArray(mapLayer.layers)) + if (projectLayer && mapLayer.layers && Array.isArray(mapLayer.layers)) { mapLayer.layers.forEach(layer => { layer.un('change'); layer.removeEvent('filtertokenchange') }); + } }; proto.setTarget = function(elId) { @@ -2155,7 +2175,7 @@ proto.getCurrentToggledMapControl = function() { * @param options is an object contain: { * active: If set new interaction active or not * active: If set new interaction active or not - * close: if close eventually GUI Content (es. result right content ) + * close: if eventually close GUI Content (es. result right content) * } * return object having current toggled control if there is a toggled mapcontrol */ @@ -2164,7 +2184,9 @@ proto.addInteraction = function(interaction, options={active:true, close:true}) const control = this.getCurrentToggledMapControl(); const toggled = control && control.isToggled && control.isToggled() || false; const untoggleMapControls = control && control.isClickMap ? control.isClickMap() : true; - untoggleMapControls && active && this._unToggleControls(options); + if (untoggleMapControls && active) { + this._unToggleControls(options); + } this.getMap().addInteraction(interaction); interaction.setActive(active); this._externalInteractions.push(interaction); @@ -2175,7 +2197,9 @@ proto.addInteraction = function(interaction, options={active:true, close:true}) }; proto.removeInteraction = function(interaction) { - interaction && interaction.setActive(false); + if (interaction) { + interaction.setActive(false); + } this.viewer.map.removeInteraction(interaction); this._externalInteractions = this._externalInteractions.filter(_interaction => interaction !== _interaction); }; @@ -2229,22 +2253,30 @@ proto.getGeometryAndExtentFromFeatures = function(features=[]) { extent = !extent ? featureExtent : ol.extent.extend(extent, featureExtent); geometryType = geometryType ? geometryType : geometry.getType(); coordinates = geometry.getCoordinates(); - if (geometryType.includes('Multi')) geometryCoordinates = [...geometryCoordinates, ...coordinates]; - else geometryCoordinates.push(coordinates); + if (geometryType.includes('Multi')) { + geometryCoordinates = [...geometryCoordinates, ...coordinates]; + } else { + geometryCoordinates.push(coordinates); + } } else { const featureExtent = feature.bbox; extent = !extent ? featureExtent : ol.extent.extend(extent, featureExtent); geometryType = geometry.type; coordinates = geometry.coordinates; } - if (geometryType.includes('Multi')) geometryCoordinates = [...geometryCoordinates, ...coordinates]; - else geometryCoordinates.push(coordinates); + if (geometryType.includes('Multi')) { + geometryCoordinates = [...geometryCoordinates, ...coordinates]; + } else { + geometryCoordinates.push(coordinates); + } } } try { const olClassGeomType = geometryType.includes('Multi') ? geometryType : `Multi${geometryType}`; geometry = new ol.geom[olClassGeomType](geometryCoordinates); - if (extent === undefined) extent = geometry.getExtent(); + if (extent === undefined) { + extent = geometry.getExtent(); + } } catch(err) {} return { extent, @@ -2253,7 +2285,7 @@ proto.getGeometryAndExtentFromFeatures = function(features=[]) { }; proto.highlightFeatures = function(features, options={}) { - const {geometry} = this.getGeometryAndExtentFromFeatures(features); + const { geometry } = this.getGeometryAndExtentFromFeatures(features); //force zoom false options.zoom = false; this.highlightGeometry(geometry, options); @@ -2284,7 +2316,7 @@ proto.zoomToFeatures = function(features, options = { highlight: false }) { * @param { Object } options * @param { boolean } options.force * @param { ol.geometry } options.highLightGeometry - * + * * @returns { Promise } */ proto.zoomToExtent = async function(extent, options = {}) { @@ -2311,11 +2343,8 @@ proto.zoomToProjectInitExtent = function() { /** * End zoom methods */ - proto.compareExtentWithProjectMaxExtent = function(extent) { - const projectExtent = this.project.state.extent; - const inside = ol.extent.containsExtent(projectExtent, extent); - return inside ? extent : projectExtent; + return ol.extent.containsExtent(this.project.state.extent, extent) ? extent : this.project.state.extent; }; /** @@ -2333,7 +2362,7 @@ proto.getResolutionForZoomToExtent = function(extent, options={force:false}) { const extentResolution = map.getView().getResolutionForExtent(extent, map.getSize()); // resolution of request extent - // retrive resolution from given `extent` + // retrieve resolution from given `extent` if (true === options.force) { return extentResolution; } @@ -2352,9 +2381,9 @@ proto.goToBBox = function(bbox, epsg=this.getEpsg()) { this.viewer.fit(this.compareExtentWithProjectMaxExtent(bbox)); }; -proto.goToWGS84 = function(coordinates,zoom) { +proto.goToWGS84 = function(coordinates, zoom) { coordinates = ol.proj.transform(coordinates,'EPSG:4326',this.project.state.crs.epsg); - this.goTo(coordinates,zoom); + this.goTo(coordinates, zoom); }; proto.extentToWGS84 = function(extent) { @@ -2363,7 +2392,7 @@ proto.extentToWGS84 = function(extent) { proto.getResolutionForMeters = function(meters) { const viewport = this.viewer.map.getViewport(); - return meters / Math.max(viewport.clientWidth,viewport.clientHeight); + return meters / Math.max(viewport.clientWidth, viewport.clientHeight); }; let animatingHighlight = false; @@ -2405,20 +2434,20 @@ proto.clearSelectionFeatures = function() { /** * @since 3.9.0 */ -proto.setSelectionLayerVisible = function(visible=true) { +proto.setSelectionLayerVisible = function(visible = true) { this.defaultsLayers.selectionLayer.setVisible(visible); }; /** - * - * @param { ol.geom.Geometry | * } geometryObj + * + * @param { ol.geom.Geometry | * } geometryObj * @param { Object } options * @param { boolean } options.zoom * @param { boolean } options.highlight * @param options.style * @param options.color - * - * @returns { Promise } + * + * @returns { Promise } */ proto.highlightGeometry = function(geometryObj, options = {}) { const duration = options.duration || MAP_SETTINGS.ANIMATION.duration; @@ -2490,8 +2519,13 @@ proto.refreshMap = function(options={force: true}) { this.updateMapLayers(options); }; -// called when layout (window) resize -proto.layout = function({width, height}) { +// called when layout (window) resizes +proto.layout = function({ width, height }) { + const el = document.getElementById(this.target); + if (el) { + el.style.height = height + 'px'; + el.style.width = width + 'px'; + } const is_hidden = (width <= 0 || height <= 0); if (!this.viewer) { this.setupViewer(width,height); @@ -2507,22 +2541,24 @@ proto.layout = function({width, height}) { } } this.setHidden(is_hidden); - this._mapControls.length && this._updateMapControlsLayout({width, height}); + if (this._mapControls.length) { + this._updateMapControlsLayout({width, height}); + } }; //remove BaseLayers proto._removeBaseLayers = function() { - Object.keys(this.mapBaseLayers).forEach(baseLayerId=>{ - this.viewer.map.removeLayer(this.mapBaseLayers[baseLayerId].getOLLayer()) - }) + Object.keys(this.mapBaseLayers) + .forEach(baseLayerId => this.viewer.map.removeLayer(this.mapBaseLayers[baseLayerId].getOLLayer())) }; // function to remove maplayers proto._removeMapLayers = function() { - this.getMapLayers().forEach(mapLayer => { - this.unregisterMapLayerListeners(mapLayer); - this.viewer.map.removeLayer(mapLayer.getOLLayer()); - }); + this.getMapLayers() + .forEach(mapLayer => { + this.unregisterMapLayerListeners(mapLayer); + this.viewer.map.removeLayer(mapLayer.getOLLayer()); + }); this._mapLayers = []; }; @@ -2531,16 +2567,12 @@ proto.getMapBBOX = function() { }; proto._updateMapView = function() { - const bbox = this.viewer.getBBOX(); - const resolution = this.viewer.getResolution(); - const center = this.viewer.getCenter(); - const size = this.getMap().getSize(); - this.updateMapView(bbox, resolution, center, size); + //bbox, resolution, center, size + this.updateMapView(this.viewer.getBBOX(), this.viewer.getResolution(), this.viewer.getCenter(), this.getMap().getSize()); }; proto.getMapSize = function() { - const map = this.viewer.map; - return map.getSize(); + return this.viewer.map.getSize(); }; proto.setInnerGreyCoverScale = function(scale) { @@ -2585,13 +2617,21 @@ proto.setInnerGreyCoverBBox = function(options={}) { this._drawShadow.inner[2] = x_max; this._drawShadow.inner[3] = y_max; } - if (_.isNil(scale)) this._drawShadow.scale = this._drawShadow.scale || 1; - else this._drawShadow.scale = scale; + if (_.isNil(scale)) { + this._drawShadow.scale = this._drawShadow.scale || 1; + } else { + this._drawShadow.scale = scale; + } - if (_.isNil(rotation)) this._drawShadow.rotation = this._drawShadow.rotation || 0; - else this._drawShadow.rotation = rotation; + if (_.isNil(rotation)) { + this._drawShadow.rotation = this._drawShadow.rotation || 0; + } else { + this._drawShadow.rotation = rotation; + } - this._drawShadow.outer && map.render(); + if (this._drawShadow.outer) { + map.render(); + } }; // grey map precompose mapcompose @@ -2603,13 +2643,13 @@ proto.startDrawGreyCover = function(message) { const postcompose = evt => { const ctx = evt.context; const size = this.getMap().getSize(); - // Inner polygon,must be counter-clockwise + // Inner polygon must be counter-clockwise const height = size[1] * ol.has.DEVICE_PIXEL_RATIO; const width = size[0] * ol.has.DEVICE_PIXEL_RATIO; this._drawShadow.outer = [0,0,width, height]; ctx.restore(); ctx.beginPath(); - // Outside polygon, must be clockwise + // Outside polygon must be clockwise ctx.moveTo(0, 0); ctx.lineTo(width, 0); ctx.lineTo(width, height); @@ -2625,7 +2665,7 @@ proto.startDrawGreyCover = function(message) { y_max = this._drawShadow.inner[1]; rotation = this._drawShadow.rotation; scale = this._drawShadow.scale; - // Inner polygon,must be counter-clockwise antiorario + // Inner polygon must be counter-clockwise antiorario ctx.translate((x_max+x_min)/2, (y_max+y_min)/2); ctx.rotate(rotation*Math.PI / 180); ctx.moveTo(-((x_max-x_min)/2),((y_max-y_min)/2)); @@ -2654,13 +2694,14 @@ proto.startDrawGreyCover = function(message) { }; proto.stopDrawGreyCover = function() { - const map = this.getMap(); if (this._greyListenerKey) { ol.Observable.unByKey(this._greyListenerKey); this._greyListenerKey = null; - this._drawShadow.inner.length && this._resetDrawShadowInner(); + if (this._drawShadow.inner.length) { + this._resetDrawShadowInner(); + } } - map.render(); + this.getMap().render(); }; proto.removeExternalLayers = function() { @@ -2678,8 +2719,10 @@ proto.changeLayerVisibility = function({id, external=false, visible}) { proto.changeLayerOpacity = function({id, opacity=1}={}) { const layer = this.getLayerById(id); - layer && layer.setOpacity(opacity); - this.emit('change-layer-opacity', {id, opacity}); + if (layer) { + layer.setOpacity(opacity); + this.emit('change-layer-opacity', {id, opacity}); + } }; proto.changeLayerMapPosition = function({id, position=MAP_SETTINGS.LAYER_POSITIONS.default}) { @@ -2706,11 +2749,13 @@ proto.removeExternalLayer = function(name) { this.viewer.map.removeLayer(layer); const type = layer._type || 'vector'; GUI.getService('catalog').removeExternalLayer({ name, type }); - if (type == 'wms') { + if ('wms' == type) { this._externalMapLayers = this._externalMapLayers .filter(ext => { const found = ext.getId() === layer.id; - if (found) this.unregisterMapLayerListeners(ext, layer.projectLayer); + if (found) { + this.unregisterMapLayerListeners(ext, layer.projectLayer); + } return !found; }); } @@ -2722,11 +2767,15 @@ proto.removeExternalLayer = function(name) { /** * Add external WMS layer to map * - * @param url - * @param layers - * @param name - * @param projection - * @param position + * @param { Object } wms + * @param { string } wms.url + * @param { string } wms.name + * @param wms.epsg + * @param wms.position + * @param wms.opacity + * @param wms.visible + * @param wms.layers + * * @returns {Promise} */ proto.addExternalWMSLayer = function({ @@ -2815,7 +2864,7 @@ proto.addExternalLayer = async function(externalLayer, options={}) { vectorLayer = externalLayer; vectorLayer.filter = { // used by `selection` for query result purpose ? - active: false // UNUSUED - it means not yet implemented? + active: false // UNUSED - it means not yet implemented? }; vectorLayer.selection = { active: false, @@ -2991,11 +3040,10 @@ proto.setExternalLayerStyle = function(color, field) { stroke: new ol.style.Stroke({ color, width: 3 }) }) }; - const styleFunction = function(feature, resolution) { + return function(feature, resolution) { const func = feature.getStyleFunction(); return func ? func.call(feature, resolution) : defaultStyle[feature.getGeometry().getType()]; }; - return styleFunction; }; /** @@ -3029,12 +3077,15 @@ proto._handlePrint = async function(controlType) { message: 'SecurityError' === err.name ? 'mapcontrols.screenshot.securityError' : 'mapcontrols.screenshot.error', autoclose: false }); + console.warn(err); } // End download ApplicationService.setDownload(false, download_id); return true; }; +proto.getCookie = (name) => Vue.cookie.get(name); + /** * Wrapper for native Open Layers controls */ @@ -3102,7 +3153,6 @@ function OLControl(type) { }); } - ol.inherits(_ctor, ol.control.Control); return _ctor; } diff --git a/src/app/gui/map/vue/map.js b/src/app/gui/map/vue/map.js index 51219164e..25afd4001 100755 --- a/src/app/gui/map/vue/map.js +++ b/src/app/gui/map/vue/map.js @@ -1,45 +1,7 @@ -import * as vueComponentOptions from 'components/Map.vue'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { base, merge, inherit } = require('utils'); -const Component = require('gui/component/component'); -const { MapService } = require('gui/map/mapservice'); - -// interanl registration -const InternalComponent = Vue.extend(vueComponentOptions); - -Vue.component('g3w-map', vueComponentOptions); - -function MapComponent(options = {}) { - base(this, options); - this.id = "map-component"; - this.title = "Map Component"; - const target = options.target || "map"; - const maps_container = options.maps_container || "g3w-maps"; - options.target = target; - options.maps_container = maps_container; - const service = new MapService(options); - this.setService(service); - merge(this, options); - this.internalComponent = new InternalComponent({ - service, - target, - maps_container - }); - /** - * add Vue get cookie method - * - */ - service.getCookie = this.internalComponent.$cookie.get; -} - -inherit(MapComponent, Component); - -const proto = MapComponent.prototype; - -proto.layout = function(width, height) { - $(`#${this.target}`).height(height); - $(`#${this.target}`).width(width); - this._service.layout({width, height}); -}; - -module.exports = MapComponent; \ No newline at end of file +import vueComp from 'components/g3w-map'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/metadata/metadataservice.js b/src/app/gui/metadata/metadataservice.js deleted file mode 100644 index ecfbe7941..000000000 --- a/src/app/gui/metadata/metadataservice.js +++ /dev/null @@ -1,99 +0,0 @@ -import ProjectsRegistry from 'store/projects'; -import GUI from 'services/gui'; - -const { inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); -const ProjectMetadataComponent = require('gui/metadata/vue/components/project/project'); - -const METADATAGROUPS = { - general: [ - 'title', - 'name', - 'description', - 'abstract', - 'keywords', - 'fees', - 'accessconstraints', - 'contactinformation', - 'wms_url' - ], - spatial: [ - 'crs', - 'extent' - ], - layers: [ - 'layers' - ] -}; - -function MetadataService() { - this.content = null; - this.show = false; - this.state = { - name: '', - groups: {} - }; - this._buildProjectGroupMetadata(); -} - -inherit(MetadataService, G3WObject); - -const proto = MetadataService.prototype; - -proto._buildProjectGroupMetadata = function() { - const project = ProjectsRegistry.getCurrentProject().getState(); - this.state.name = project.title; - const groups = {}; - Object.entries(METADATAGROUPS).forEach(([groupName, value]) => { - groups[groupName] = {}; - value.forEach(field => { - const fieldValue = project.metadata && project.metadata[field] ? project.metadata[field] : project[field]; - if (!!fieldValue) { - groups[groupName][field] = { - label: ['sdk','metadata','groups', groupName, 'fields', field].join('.'), - value: fieldValue - } - } - }) - }); - this.state.groups = groups; -}; - -proto.getProjectMetadata = function() { - return this.state; -}; - -proto.getLayersMetadata = function() { - return this.state.groups.layers; -}; - -proto.getLayerMetadata = function(id) { - const layerMetadata = this.state.groups.layers.filter(layer => layer.id === id); - return layerMetadata[0]; -}; - -proto.showMetadata = function(bool) { - this.show = bool; - if (this.show) { - this.content = new ProjectMetadataComponent({ - state: this.getProjectMetadata(), - service: this - }); - GUI.setContent({ - content: this.content, - title: "sdk.metadata.title", - perc: 100 - }); - this.show = true; - } else GUI.closeContent() - -}; - -proto.reload = function() { - this.emit('reload'); - this._buildProjectGroupMetadata(); -}; - - - -module.exports = MetadataService; diff --git a/src/app/gui/metadata/vue/components/layer/layer.js b/src/app/gui/metadata/vue/components/layer/layer.js deleted file mode 100644 index b5f8d2011..000000000 --- a/src/app/gui/metadata/vue/components/layer/layer.js +++ /dev/null @@ -1,18 +0,0 @@ -import Layer from 'components/MetadataLayer.vue'; - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); - -function LayerComponent({state = {}, service} = {}) { - base(this); - const vueComponent = Vue.extend(Layer); - this.setService(service); - this.internalComponent = new vueComponent({ - state - }); - this.layout = function() {}; -} - -inherit(LayerComponent, Component); - -module.exports = LayerComponent; diff --git a/src/app/gui/metadata/vue/components/project/project.js b/src/app/gui/metadata/vue/components/project/project.js deleted file mode 100644 index 9c46ddc3b..000000000 --- a/src/app/gui/metadata/vue/components/project/project.js +++ /dev/null @@ -1,18 +0,0 @@ -import ProjectCatalog from 'components/MetadataProject.vue' - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); - -function ProjectMetadataComponent({state = {}, service} = {}) { - base(this); - const vueComponent = Vue.extend(ProjectCatalog); - this.setService(service); - this.internalComponent = new vueComponent({ - state - }); - this.layout = function() {}; -} - -inherit(ProjectMetadataComponent, Component); - -module.exports = ProjectMetadataComponent; diff --git a/src/app/gui/metadata/vue/metadata.js b/src/app/gui/metadata/vue/metadata.js index 882e74b37..48a434c32 100644 --- a/src/app/gui/metadata/vue/metadata.js +++ b/src/app/gui/metadata/vue/metadata.js @@ -1,38 +1,7 @@ -import * as vueComponentOptions from 'components/Metadata.vue'; - -import GUI from 'services/gui'; - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); -const MetadataService = require('gui/metadata/metadataservice'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -const MetadataComponent = function(options = {}) { - base(this, options); - this.title = "sdk.metadata.title"; - const service = options.service || new MetadataService(options); - this.setService(service); - this._service.on('reload', () => { - this.setOpen(false); - }); - this.setInternalComponent = function () { - this.internalComponent = new InternalComponent({ - service: service - }); - this.internalComponent.state = service.state; - return this.internalComponent; - }; - this._setOpen = function(bool) { - this._service.showMetadata(bool); - }; - GUI.on('closecontent', ()=>{ - this.state.open = false; - }) -}; - -inherit(MetadataComponent, Component); - -module.exports = MetadataComponent; - +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ +import vueComp from 'components/g3w-metadata'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/panel.js b/src/app/gui/panel.js index e9bf731ab..1df57eae0 100644 --- a/src/app/gui/panel.js +++ b/src/app/gui/panel.js @@ -1,74 +1,7 @@ -import GUI from 'services/gui'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { inherit, resolve: resolvedValue } = require('utils'); -const G3WObject = require('core/g3wobject'); - -const Panel = function(options={}) { - this.id = options.id || null; - this.title = options.title || ''; - this.internalPanel = options.panel || null; - this.service = options.service; -}; - -inherit(Panel, G3WObject); - -const proto = Panel.prototype; - -proto.getId = function(){ - return this.id; -}; - -proto.getTitle = function(){ - return this.title; -}; - -proto.getService = function(){ - return this.service; -}; - -proto.setService = function(service) { - this.service = service; -}; - -proto.getInternalPanel = function() { - return this.internalPanel; -}; - -proto.setInternalPanel = function(internalPanel) { - this.internalPanel = internalPanel; -}; - -proto.show = function() { - GUI.showPanel(this); -}; - -proto.close = function(){ - GUI.closePanel(); -}; - -proto.mount = function(parent) { - const panel = this.internalPanel; - const iCinstance = panel.$mount(); - $(parent).append(iCinstance.$el); - iCinstance.$nextTick(() => { - $(parent).localize(); - panel.onShow && panel.onShow(); - }); - return resolvedValue(true); -}; - -proto.unmount = function() { - const panel = this.internalPanel; - const d = $.Deferred(); - panel.$destroy(true); - $(panel.$el).remove(); - panel.onClose && panel.onClose(); - this.internalComponent = null; - d.resolve(); - return d.promise(); -}; - -proto.onResize = function(parentWidth,parentHeight){}; - - -module.exports = Panel; +import vueComp from 'core/g3w-panel'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/print/printservice.js b/src/app/gui/print/printservice.js deleted file mode 100644 index d76d30a02..000000000 --- a/src/app/gui/print/printservice.js +++ /dev/null @@ -1,678 +0,0 @@ -import ProjectsRegistry from 'store/projects'; -import ApplicationService from 'services/application'; -import ApplicationState from 'store/application-state'; -import { - PRINT_SCALES as scale, - PRINT_RESOLUTIONS as dpis, - PRINT_FORMATS as formats -} from 'app/constant'; -import GUI from 'services/gui'; -import { getScaleFromResolution } from 'utils/getScaleFromResolution'; -import { getResolutionFromScale } from 'utils/getResolutionFromScale'; -import { getMetersFromDegrees } from 'utils/getMetersFromDegrees'; - - -const { - base, - inherit, - downloadFile, - convertObjectToUrlParams, -} = require('utils'); -const { t } = require('core/i18n/i18n.service'); -const G3WObject = require('core/g3wobject'); -const PrintPage = require('gui/print/vue/printpage'); - -/* - http://localhost/fcgi-bin/qgis_mapserver/qgis_mapserv.fcgi - ?MAP=/home/marco/geodaten/projekte/composertest.qgs - &SERVICE=WMS&VERSION=1.3.0 - &REQUEST=GetPrint - &TEMPLATE=Composer 1 - &map0:extent=693457.466131,227122.338236,700476.845177,230609.807051 - &BBOX=693457.466131,227122.338236,700476.845177,230609.807051 - &CRS=EPSG:21781 - &WIDTH=1467 - &HEIGHT=729 - &LAYERS=layer0,layer1 - &STYLES=, - &FORMAT=pdf - &DPI=300 - &TRANSPARENT=true - - In detail, the following parameters can be used to set properties for composer maps: - - :EXTENT= //mandatory - :ROTATION= //optional, defaults to 0 - :SCALE= //optional. Forces scale denominator as server and client may have different scale calculations - :LAYERS= //optional. Defaults to all layer in the WMS request - :STYLES= //optional - :GRID_INTERVAL_X= //set the grid interval in x-direction for composer grids - :GRID_INTERVAL_Y= //set the grid interval in x-direction for composer grids - */ - -/** - * @deprecated since 3.9.1 will be removed in 4.x - * - * ORIGINAL SOURCE: src\app\core\print\printservice.js@3.9.0 - */ -const PRINT_UTILS = { - /** - * @param { Object } opts - * @param opts.rotation, - * @param opts.dpi - * @param opts.format - * @param opts.template - * @param { Array } opts.maps - * @param { Array } opts.labels - * @param opts.is_maps_preset_theme - * @param { 'GET' | 'POST' } method - */ - print(opts = {}, method = 'GET') { - const store = ProjectsRegistry.getCurrentProject().getLayersStore(); - const layers = store - .getLayers({ PRINTABLE: { scale: opts.scale }, SERVERTYPE: 'QGIS' }) - .reverse(); // reverse order is important - - // skip when .. - if (!layers.length) { - return Promise.resolve({layers: false}) - } - - const LAYERS = layers.map(l => l.getPrintLayerName()).join(); - - return PRINT_UTILS[method]({ - url: store.getWmsUrl(), - mime_type: ({ pdf: 'application/pdf', jpg: 'image/jpeg' })[opts.format], - params: { - SERVICE: 'WMS', - VERSION: '1.3.0', - REQUEST: 'GetPrint', - TEMPLATE: opts.template, - DPI: opts.dpi, - STYLES: layers.map(l => l.getStyle()).join(','), - LAYERS: opts.is_maps_preset_theme ? undefined : LAYERS, - FORMAT: opts.format, - CRS: store.getProjection().getCode(), - filtertoken: ApplicationState.tokens.filtertoken, - ...(opts.maps || []).reduce((params, map) => { - params[map.name + ':SCALE'] = map.scale; - params[map.name + ':EXTENT'] = map.extent; - params[map.name + ':ROTATION'] = opts.rotation; - params[map.name + ':LAYERS'] = opts.is_maps_preset_theme && undefined === map.preset_theme ? LAYERS : undefined; - return params; - }, {}), - ...(opts.labels || []).reduce((params, label) => { - params[label.id] = label.text; - return params; - }, {}) - }, - }); - }, - /** - * @param { Object } opts - * @param opts.field - * @param opts.values - * @param opts.template - * @param opts.download - * @param { 'GET' | 'POST' } method - */ - printAtlas(opts = {}, method = 'GET') { - const store = ProjectsRegistry.getCurrentProject().getLayersStore(); - const multi = opts.values.length > 1; - return PRINT_UTILS[method]({ - url: store.getWmsUrl(), - mime_type: 'application/pdf', - params: { - SERVICE: 'WMS', - VERSION: '1.3.0', - REQUEST: 'GetPrintAtlas', - EXP_FILTER: opts.field + (multi ? ' IN (' : '=') + (opts.values.map(v => `'${v}'`).join()) + (multi ? ')' : ''), - TEMPLATE: opts.template, - filtertoken: ApplicationState.tokens.filtertoken, - DOWNLOAD: opts.download ? 1 : undefined, - }, - }) - }, - - /** - * @param { Object } opts - * @param opts.url - * @param opts.params - * @param opts.mime_type - * @return {Promise<{mime_type, layers: boolean, url: string}>} - * @constructor - */ - async POST({ url, params, mime_type }) { - const response = await fetch(url, { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, - body: convertObjectToUrlParams(params), - }); - if (!response.ok) { - //@TODO Need to translate - throw new Error(500 === response.status ? 'Internal Server Error' : 'Request Failed'); - } - return { - mime_type, - layers: true, - url: URL.createObjectURL(await response.blob()), - }; - }, - /** - * @param { Object } opts - * @param opts.url - * @param opts.params - * @param opts.mime_type - * @return {Promise} - * @constructor - */ - GET({url, params, mime_type}) { - return new Promise((resolve, reject) => { - resolve({ - url: `${url}?${convertObjectToUrlParams(params)}`, - layers: true, - mime_type - }); - }) - }, - - /** - * Get wms url for current project - * @returns {*} - */ - getUrl() { - return ProjectsRegistry.getCurrentProject().getLayersStore().getWmsUrl(); - }, - -}; - -function PrintComponentService() { - base(this); - - /** @deprecated since 3.9.1 will be removed in 4.x */ - this.printService = PRINT_UTILS; - - this._initialized = false; - this.state = { - loading: false - }; - this._moveMapKeyEvent = null; - this._page = null; - this._mapService = null; - this._map = null; - this._mapUnits; - this._scalesResolutions = {}; - - this.init = function() { - this._project = ProjectsRegistry.getCurrentProject(); - this.state.print = this._project.getPrint() || []; - this.state.visible = this.state.print.length > 0; - this.state.isShow = false; - this.state.url = null; - this.state.output = { - url: null, - method: this._project.getOwsMethod(), - layers: true, - format: null, - loading: false, - type: null - }; - this.state.printextent = { - minx: [0, 0], - miny: [0, 0], - maxx: [0, 0], - maxy: [0, 0] - }; - if (this.state.visible) { - this.setInitState(); - } - }; -} - -inherit(PrintComponentService, G3WObject); - -const proto = PrintComponentService.prototype; - -/** - * - */ -proto.setInitState = function() { - this.state.template = this.state.print[0].name; - this.state.atlas = this.state.print[0].atlas; - this.state.atlasValues = []; - this.state.rotation = 0; - this.state.inner = [0, 0, 0, 0]; - this.state.center = null; - this.state.size = null; - this.state.scale = scale; - this.state.scala = null; - this.state.dpis = dpis; - this.state.dpi = dpis[0]; - this.state.formats = formats; - this.state.output.format = formats[0].value; - this.state.maps = this.state.print[0].maps; - // label section - this.state.labels = this.state.print[0].labels; -}; - -/** - * - */ -proto.changeTemplate = function() { - if (!this.state.template) { - return; - } - const has_previous = this.state.atlas || 0 === this.state.maps.length; - const print = this.state.print.find(p => p.name === this.state.template) - - this.state.maps = print.maps; - this.state.atlas = print.atlas; - this.state.labels = print.labels; - this.state.atlasValues = []; - - if (this.state.atlas) { - this._clearPrint(); - } else if (has_previous) { - this.showPrintArea(true); - } else { - this._setPrintArea(); - } -}; - -/** - * On change scala set print area - */ -proto.changeScale = function() { - if (this.state.scala) { - this._setPrintArea(); - } -}; - -/** - * On change rotation, rotate print area - */ -proto.changeRotation = function() { - this._mapService - .setInnerGreyCoverBBox({ - rotation: this.state.rotation - }); -}; - -/** - * - * @returns {string} - * @private - */ -proto._getPrintExtent = function() { - const [minx, miny, maxx, maxy] = [ - ... this.state.printextent.lowerleft, - ...this.state.printextent.upperright - ]; - return ( - this._mapService.isAxisOrientationInverted() ? - [miny, minx, maxy, maxx ] : - [minx, miny, maxx, maxy] - ).join(); -}; - -/** - * - * @param extent - * @returns {string} - */ -proto.getOverviewExtent = function(extent={}) { - const {xmin, xmax, ymin, ymax} = extent; - return ( - this._mapService.isAxisOrientationInverted() ? - [ymin, xmin, ymax, xmax ] : - [xmin, ymin, xmax, ymax] - ).join(); -}; - -/** - * - * @returns {{template, maps: {extent: *, name: *, preset_theme: *, scale: *|null}[], rotation, format, scale: (null|*), is_maps_preset_theme: boolean, dpi: (number|*), labels}} - * @private - */ -proto._getOptionsPrint = function() { - let is_maps_preset_theme = false; - const maps = this.state.maps.map(map => { - is_maps_preset_theme = is_maps_preset_theme || undefined !== map.preset_theme; - return { - name: map.name, - preset_theme: map.preset_theme, - scale: map.overview ? map.scale : this.state.scala, - extent: map.overview ? this.getOverviewExtent(map.extent) : this._getPrintExtent() - } - }); - - return { - rotation: this.state.rotation, - dpi: this.state.dpi, - template: this.state.template, - maps, - scale: this.state.scala, - format: this.state.output.format, - labels: this.state.labels, - is_maps_preset_theme - }; -}; - -/** - * - */ -proto.setPrintAreaAfterCloseContent = function() { - this._map.once('postrender', this._setPrintArea.bind(this)); - this.stopLoading(); -}; - -/** - * - * @returns {Promise} - */ -proto.print = function() { - return new Promise((resolve, reject) => { - //disable sidebar - GUI.disableSideBar(true); - //atlas print - if (this.state.atlas) { - const caller_download_id = ApplicationService.setDownload(true); - this.state.loading = true; - this.printService - .printAtlas({ - template: this.state.template, - field: this.state.atlas.field_name || '$id', - values: this.state.atlasValues, - download: true - }) - .then(({url}) => { - downloadFile({ - url, - filename: this.state.template, - mime_type: 'application/pdf' - }) - .then(resolve) - .catch(error => { - this.showError(error); - reject(); - }) - .finally(() => { - this.state.loading = false; - ApplicationService.setDownload(false, caller_download_id); - GUI.disableSideBar(false); - }); - }) - } else { - this.state.output.url = null; - this.state.output.layers = true; - this._page = new PrintPage({ - service: this - }); - - GUI.setContent({ - content: this._page, - title: 'print', - perc: 100 - }); - - this.printService - .print(this._getOptionsPrint(), this.state.output.method) - .then((data) => { - this.state.output.url = data.url; - this.state.output.layers = data.layers; - this.state.output.mime_type = data.mime_type; - resolve(); - }) - .catch(err => { - this.showError(); - reject(err); - }) - .finally(() => { - // in case of no layers - if (!this.state.output.layers) { - GUI.disableSideBar(false); - } - }); - } - }) - -}; - -/** - * Set loading - */ -proto.startLoading = function() { - this.state.output.loading = true; -}; - -/** - *Stop Loading - */ -proto.stopLoading = function() { - this.state.output.loading = false; -}; - -/** - * - * @param error - */ -proto.showError = function(error) { - GUI.notify.error(error || t("info.server_error")); - GUI.closeContent(); -}; - -/** - * - * @private - */ -proto._calculateInternalPrintExtent = function() { - const resolution = this._map.getView().getResolution(); - const scala = parseFloat(this.state.scala); - const {h: height, w: width} = this.state.maps.find(map=> !map.overview); - const resolutionInMeters = this._mapService.getMapUnits() === 'm' ? resolution : getMetersFromDegrees(resolution); - const w = (((width / 1000.0) * scala) / resolutionInMeters); - const h = (((height / 1000.0) * scala) / resolutionInMeters); - // get current map center ( in pixel) - const center = [ - (this.state.size[0]) / 2, // X - (this.state.size[1]) / 2 // Y - ]; - // Calculate the inner bbox in pixel - const xmin = center[0] - (w / 2); - const ymin = center[1] - (h / 2); - const xmax = center[0] + (w / 2); - const ymax = center[1] + (h / 2); - - this.state.printextent.lowerleft = this._map.getCoordinateFromPixel([xmin, ymax]) - ? this._map.getCoordinateFromPixel([xmin, ymax]) - : this.state.printextent.lowerleft; - - this.state.printextent.upperright = this._map.getCoordinateFromPixel([xmax, ymin]) - ? this._map.getCoordinateFromPixel([xmax, ymin]) - : this.state.printextent.upperright; - - this.state.inner = [xmin, ymax, xmax, ymin]; -}; - -/** - * - * @private - */ -proto._setPrintArea = function() { - //No maps set. Only attributes label - if (0 === this.state.maps.length) { - this._clearPrint(); - return; - } - this.state.size = this._map.getSize(); - const resolution = this._map.getView().getResolution(); - this.state.currentScala = getScaleFromResolution(resolution, this._mapUnits); - this.state.center = this._map.getView().getCenter(); - - this._calculateInternalPrintExtent(); - this._mapService.setInnerGreyCoverBBox({ - type: 'pixel', - inner: this.state.inner, - rotation: this.state.rotation - }); -}; - -/** - * - * @param reset - * @private - */ -proto._clearPrint = function(reset=false) { - ol.Observable.unByKey(this._moveMapKeyEvent); - this._moveMapKeyEvent = null; - this._mapService.stopDrawGreyCover(); -}; - -/** - * - * @param maxResolution - * @private - */ -proto._setAllScalesBasedOnMaxResolution = function(maxResolution) { - let resolution = maxResolution; - const mapScala = getScaleFromResolution(resolution, this._mapUnits); - const orderScales = _.orderBy(this.state.scale, ['value'], ['desc']); - let scale = []; - let addedFirstHighestScale = false; - const handleScala = (scala) => { - scale.push(scala); - resolution = getResolutionFromScale(scala.value, this._mapUnits); - this._scalesResolutions[scala.value] = resolution; - resolution = resolution / 2; - }; - orderScales - .forEach((scala, index) => { - if (mapScala > scala.value) { - if (!addedFirstHighestScale) { - const higherScale = orderScales[index-1]; - handleScala(higherScale); - addedFirstHighestScale = true; - } - handleScala(scala); - } - }); - - this.state.scale = scale; -}; - -/** - * - * @private - */ -proto._setInitialScalaSelect = function() { - this.state.scala = this.state.scale[0].value; - $('#scala').val(this.state.scala); -}; - -/** - * - * @param resolution - * @private - */ -proto._setCurrentScala = function(resolution) { - Object - .entries(this._scalesResolutions) - .find(([scala, res]) => { - if (resolution <= res) { - this.state.scala = scala; - return true - } - }); -}; - -/** - * - * @private - */ -proto._setMoveendMapEvent = function() { - this._moveMapKeyEvent = this._map.on('moveend', this._setPrintArea.bind(this)); -}; - -/** - * - * @private - */ -proto._showPrintArea = function() { - if (this.state.atlas === undefined) { - this._setPrintArea(); - this._mapService.startDrawGreyCover(); - } -}; - -/** - * - * @private - */ -proto._initPrintConfig = function() { - if (!this._initialized) { - const maxResolution = this._map.getView().getMaxResolution(); - this._setAllScalesBasedOnMaxResolution(maxResolution); - this._initialized = true; - } - const resolution = this._map.getView().getResolution(); - this._setCurrentScala(resolution); -}; - -/** - * - * @param bool - */ -proto.showPrintArea = function(bool) { - // close content if open - this.state.isShow = bool; - GUI - .closeContent() - .then(mapComponent => { - setTimeout(() => { - this._mapService = mapComponent.getService(); - this._mapUnits = this._mapService.getMapUnits(); - this._mapService.getMap().once('postrender', evt => { - this._map = evt.map; - if (bool) { - this._setMoveendMapEvent(); - this._initPrintConfig(); - this._showPrintArea(); - } else { - this._clearPrint(); - } - }); - this._mapService.getMap().renderSync(); - }) - }) -}; - -/** - * - */ -proto.reload = function() { - this._project = ProjectsRegistry.getCurrentProject(); - this._mapService = GUI.getService('map'); - this._map = this._mapService.viewer.map; - this.state.print = this._project.state.print || []; - this.state.visible = this.state.print.length > 0; - - if (this.state.visible) { - this.state.template = this.state.print[0].name; - if (!this._initialized) { - this.init(); - } - this._initPrintConfig(); - this._mapService.on('changeviewaftercurrentproject', () => { - const maxResolution = this._map.getView().getMaxResolution(); - this.state.scale = scale; - this._setAllScalesBasedOnMaxResolution(maxResolution); - }); - } else { - this._clearPrint(); - } -}; - -module.exports = { - PrintComponentService, - PRINT_UTILS, -}; \ No newline at end of file diff --git a/src/app/gui/print/vue/print.js b/src/app/gui/print/vue/print.js index 4983f0f2d..8bff1039a 100644 --- a/src/app/gui/print/vue/print.js +++ b/src/app/gui/print/vue/print.js @@ -1,41 +1,7 @@ -import * as vueComponentOptions from 'components/Print.vue'; - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); -const { PrintComponentService } = require('gui/print/printservice'); - -function PrintComponent(options={}) { - base(this, options); - this.title = "print"; - this.vueComponent = vueComponentOptions; - this.internalComponent = null; - const service = options.service || new PrintComponentService; - this.setService(service); - // init service - this._service.init(); - this.setInternalComponent = function() { - const InternalComponent = Vue.extend(this.vueComponent); - this.internalComponent = new InternalComponent({ - service - }); - this.state.visible = service.state.visible; - this.internalComponent.state = service.state; - return this.internalComponent; - }; - - this._reload = function() { - const service = this.getService(); - service.reload(); - this.state.visible = service.state.visible; - }; - - this._setOpen = function(bool) { - this._service.showPrintArea(bool); - }; -} - -inherit(PrintComponent, Component); - -module.exports = PrintComponent; - +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ +import vueComp from 'components/g3w-print'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/print/vue/printpage.js b/src/app/gui/print/vue/printpage.js deleted file mode 100644 index 23b525d06..000000000 --- a/src/app/gui/print/vue/printpage.js +++ /dev/null @@ -1,28 +0,0 @@ -import * as vueComponentOptions from 'components/PrintPage.vue'; - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -const PrintPage = function(options={}) { - base(this); - const service = options.service; - this.setService(service); - const internalComponent = new InternalComponent({ - service - }); - this.setInternalComponent(internalComponent); - this.internalComponent.state = service.state.output; - - this.unmount = function() { - this.getService().setPrintAreaAfterCloseContent(); - return base(this, 'unmount') - } -}; - -inherit(PrintPage, Component); - -module.exports = PrintPage; - - diff --git a/src/app/gui/projectsmenu/menu.js b/src/app/gui/projectsmenu/menu.js deleted file mode 100644 index 1190f7537..000000000 --- a/src/app/gui/projectsmenu/menu.js +++ /dev/null @@ -1,28 +0,0 @@ -import * as vueComponentOptions from 'components/ProjectsMenu.vue'; - -const { base, inherit, merge } = require('utils'); -const Component = require('gui/component/component'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -function MenuComponent(options={}){ - base(this,options); - this.title = options.title || "menu"; - this.state.visible = true; - this.state.menuitems = options.menuitems; - const host = options.host; - merge(this, options); - this.internalComponent = new InternalComponent({ - service: this, - host - }); - this.internalComponent.state = this.state; -} -inherit(MenuComponent, Component); - -const proto = MenuComponent.prototype; - -proto.trigger = function(item) {}; - -module.exports = MenuComponent; - diff --git a/src/app/gui/projectsmenu/projectsmenu.js b/src/app/gui/projectsmenu/projectsmenu.js index c96d8fb3a..f55d8715c 100644 --- a/src/app/gui/projectsmenu/projectsmenu.js +++ b/src/app/gui/projectsmenu/projectsmenu.js @@ -1,32 +1,7 @@ -import ProjectsRegistry from 'store/projects'; -import ApplicationService from 'services/application'; - -const { base, inherit } = require('utils'); -const MenuComponent = require('gui/projectsmenu/menu'); - -function ProjectsMenuComponent(options={}) { - options.id = 'projectsmenu'; - base(this, options); - this.state.menuitems = []; - const host = options.host; - const projects = options.projects || ProjectsRegistry.getListableProjects(); - this.state.menuitems = projects.map(project => ({ - title: project.title, - description: project.description, - thumbnail: project.thumbnail, - gid: project.gid, - cbk: options.cbk || function(options={}) { - const {gid} = options; - return ApplicationService.changeProject({ - gid, - host - }) - } - })); -} - -inherit(ProjectsMenuComponent, MenuComponent); - -module.exports = ProjectsMenuComponent; - +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ +import vueComp from 'components/g3w-projectsmenu'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/querybuilder/querybuilderuifactory.js b/src/app/gui/querybuilder/querybuilderuifactory.js index 08ed75380..b225f3fd5 100644 --- a/src/app/gui/querybuilder/querybuilderuifactory.js +++ b/src/app/gui/querybuilder/querybuilderuifactory.js @@ -1,31 +1,7 @@ -const QueryBuilder = require('gui/querybuilder/vue/querybuilder'); -const QueryBuilderPanel = require('gui/querybuilder/vue/panel/querybuilderpanel'); - -const QuerybuilderUIfactory = { - type: null, - show({type='sidebar', options}={}){ - let QueryBuilderInstance; - this.type = this.type === null ? type : this.type; - if (this.type==='modal') { - QueryBuilderInstance = new QueryBuilder({ - options - }); - const queryBuilderDom = QueryBuilderInstance.$mount().$el; - GUI.showModalDialog({ - title: 'Query Builder', - message: queryBuilderDom, - className: "modal-background-dark " - }) - } else { - const panel = new QueryBuilderPanel({ - options - }); - QueryBuilderInstance = panel.getInternalPanel(); - panel.show(); - } - return QueryBuilderInstance; - } -}; - -module.exports = QuerybuilderUIfactory; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ +import vueComp from 'components/g3w-querybuilder'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/querybuilder/vue/panel/querybuilderpanel.js b/src/app/gui/querybuilder/vue/panel/querybuilderpanel.js deleted file mode 100644 index b164c8eb7..000000000 --- a/src/app/gui/querybuilder/vue/panel/querybuilderpanel.js +++ /dev/null @@ -1,14 +0,0 @@ -const { inherit, base } = require('utils'); -const Panel = require('gui/panel'); -const QueryBuilder = require('gui/querybuilder/vue/querybuilder'); - -function QueryBuilderPanel(options={}) { - options.title = 'Query Builder'; - base(this, options); - const internalPanel = new QueryBuilder(options); - this.setInternalPanel(internalPanel); -} - -inherit(QueryBuilderPanel, Panel); - -module.exports = QueryBuilderPanel; diff --git a/src/app/gui/querybuilder/vue/querybuilder.js b/src/app/gui/querybuilder/vue/querybuilder.js deleted file mode 100644 index d7d1e0cb4..000000000 --- a/src/app/gui/querybuilder/vue/querybuilder.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as vueComponentOptions from 'components/QueryBuilder.vue'; - -const QueryBuilder = Vue.extend(vueComponentOptions); - -module.exports = QueryBuilder; diff --git a/src/app/gui/queryresults/queryresultsservice.js b/src/app/gui/queryresults/queryresultsservice.js index 27b0fd626..5990c1f45 100644 --- a/src/app/gui/queryresults/queryresultsservice.js +++ b/src/app/gui/queryresults/queryresultsservice.js @@ -18,6 +18,7 @@ import { createFeatureFromBBOX } from 'utils/createFeatureFromBBO import { createFeatureFromCoordinates } from 'utils/createFeatureFromCoordinates'; import { intersects } from 'utils/intersects'; import { within } from 'utils/within'; +import { printAtlas } from 'utils/printAtlas'; const { noop, @@ -30,14 +31,11 @@ const { t } = require('core/i18n/i18n.service'); const Layer = require('core/layers/layer'); const G3WObject = require('core/g3wobject'); const VectorLayer = require('core/layers/vectorlayer'); -const { PRINT_UTILS } = require('gui/print/printservice'); const RelationsPage = require('gui/relations/vue/relationspage'); const PickCoordinatesInteraction = require('g3w-ol/interactions/pickcoordinatesinteraction'); const deprecate = require('util-deprecate'); -const { printAtlas } = PRINT_UTILS; - /** * Get and set vue reactivity to QueryResultsService * @@ -57,9 +55,6 @@ class QueryResultsService extends G3WObject { this._changeLayerResult = this.setters.changeLayerResult; this._addComponent = this.setters.addComponent; - /** @deprecated since 3.9.1 will be removed in 4.x */ - this.printService = PRINT_UTILS; - /** * @FIXME add description */ @@ -2290,7 +2285,7 @@ QueryResultsService.prototype.setters = { // whether add external layers to response if (true === queryResponse.query.external.add && false === options.add) { - const catalogService = GUI.getService('catalog'); + const catalog = GUI.getService('catalog'); /** @type { boolean | undefined } */ const FILTER_SELECTED = queryResponse.query.external.filter.SELECTED; @@ -2299,7 +2294,7 @@ QueryResultsService.prototype.setters = { this._vectorLayers .forEach(layer => { const id = layer.get('id'); - const is_selected = catalogService.isExternalLayerSelected({ id, type: 'vector' }); + const is_selected = !!(catalog.state.external.vector.find(l => l.id === id) || {}).selected; const is_visible = layer.getVisible(); // TODO: extract this into `layer.isSomething()` ? if (is_visible && ((is_selected === FILTER_SELECTED) || (undefined === FILTER_SELECTED))) { diff --git a/src/app/gui/queryresults/vue/queryresults.js b/src/app/gui/queryresults/vue/queryresults.js index a246181d7..379f81920 100644 --- a/src/app/gui/queryresults/vue/queryresults.js +++ b/src/app/gui/queryresults/vue/queryresults.js @@ -1,39 +1,7 @@ -import * as vueComponentOptions from 'components/QueryResults.vue'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { base, inherit } = require('utils'); -const Component = require('gui/component/component'); -const QueryResultsService = require('gui/queryresults/queryresultsservice'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -function QueryResultsComponent(options={}) { - base(this, options); - this.id = "queryresults"; - this.title = "Query Results"; - this._service = new QueryResultsService(); - this.setInternalComponent = function() { - this.internalComponent = new InternalComponent({ - queryResultsService: this._service - }); - this.internalComponent.querytitle = this._service.state.querytitle; - }; - - this.getElement = function() { - if (this.internalComponent) return this.internalComponent.$el; - }; - - this._service.onafter('setLayersData', async () => { - !this.internalComponent && this.setInternalComponent(); - await this.internalComponent.$nextTick(); - }); - - this.layout = function(width,height) {}; - this.unmount = function() { - this.getService().closeComponent(); - return base(this, 'unmount') - } -} - -inherit(QueryResultsComponent, Component); - -module.exports = QueryResultsComponent; +import vueComp from 'components/g3w-queryresults'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/relations/relationsservice.js b/src/app/gui/relations/relationsservice.js deleted file mode 100644 index d62586e0c..000000000 --- a/src/app/gui/relations/relationsservice.js +++ /dev/null @@ -1,77 +0,0 @@ -import { G3W_FID } from 'app/constant'; -import RelationsService from 'services/relations'; -import ApplicationService from 'services/application'; -import GUI from 'services/gui'; - -const { inherit, base } = require('utils'); -const G3WObject = require('core/g3wobject'); - -function RelationsComponentService(options={}) { - this.state = {}; - this._options = {}; - base(this); -} - -inherit(RelationsComponentService, G3WObject); - -const proto = RelationsComponentService.prototype; - -proto.getRelations = function(options={}) { - this._options = options; - return RelationsService.getRelations(options); -}; - -proto.getRelationsNM = async function({nmRelation, features}){ - return await RelationsService.getRelationsNM({ - nmRelation, - features - }) -}; - -proto.saveRelations = async function(type){ - this._options.type = type; - const caller_download_id = ApplicationService.setDownload(true); - try { - await RelationsService.save(this._options) - } catch(err){ - GUI.showUserMessage({ - type: 'alert', - message: err || "info.server_error", - closable: true - }) - } - ApplicationService.setDownload(false, caller_download_id); -}; - -proto.buildRelationTable = function(relations=[], id) { - const layer = ApplicationService.getCurrentProject().getLayerById(id); - const headers = layer.getTableHeaders(); - let columns = null; - let rows = []; - let rows_fid = []; - let fields; - if (relations.length) { - const attributes = Object.keys(relations[0].attributes); - columns = headers.filter(header => attributes.indexOf(header.name) !==-1); - rows = relations.map(relation => { - rows_fid.push(relation.attributes[G3W_FID]); - return columns.map(column => { - return relation.attributes[column.name] - }) - }); - fields = columns; - columns = columns.map(column => column.label); - } - return { - columns, - rows, - rows_fid, - features: relations, - fields, - formStructure : layer.getLayerEditingFormStructure(), - rowFormStructure: null, - layerId: layer.getId() - } -}; - -module.exports = RelationsComponentService; diff --git a/src/app/gui/relations/vue/relationspage.js b/src/app/gui/relations/vue/relationspage.js index 30dc94a73..3aa54cb4e 100644 --- a/src/app/gui/relations/vue/relationspage.js +++ b/src/app/gui/relations/vue/relationspage.js @@ -1,37 +1,7 @@ -import * as vueComponentOptions from 'components/RelationsPage.vue'; - -const { base, inherit } = require('utils'); -const Component = require('gui/component/component'); -const Service = require('gui/relations/relationsservice'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -const RelationsPage = function(options={}) { - base(this, options); - const service = options.service || new Service(); - const {layer, relation=null, relations=[], feature=null, table=null, chartRelationIds=[], nmRelation, currentview="relations"} = options; - this.setService(service); - const internalComponent = new InternalComponent({ - previousview: currentview, - service, - relations, - relation, - nmRelation, - chartRelationIds, - feature, - currentview, - layer, - table - }); - this.setInternalComponent(internalComponent); - internalComponent.state = service.state; - this.layout = function() { - internalComponent.reloadLayout(); - }; -}; - -inherit(RelationsPage, Component); - -module.exports = RelationsPage; - +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ +import vueComp from 'components/g3w-relationspage'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/search/service.js b/src/app/gui/search/service.js deleted file mode 100644 index eff5c459b..000000000 --- a/src/app/gui/search/service.js +++ /dev/null @@ -1,80 +0,0 @@ -import QueryBuilderService from 'services/querybuilder'; -import ProjectsRegistry from 'store/projects'; - -const { base, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); -const SearchPanel = require('gui/search/vue/panel/searchpanel'); - -function Service() { - base(this); - const currentProjectState = ProjectsRegistry.getCurrentProject().state; - this.title = currentProjectState.search_title || "search"; - this.init = function(searchesObject) { - this.state.searches = searchesObject || currentProjectState.search; - }; - this.state = { - searches: [], - searchtools: [], - querybuildersearches: QueryBuilderService.getCurrentProjectItems() - }; -} - -inherit(Service, G3WObject); - -const proto = Service.prototype; - -proto.removeItem = function({type, index}={}){ - switch(type) { - case 'querybuilder': - this.state.querybuildersearches.splice(index, 1); - break; - } -}; - -proto.getTitle = function() { - return this.title; -}; - -proto.showPanel = function(config={}) { - const panel = new SearchPanel(config); - panel.show(); - return panel; -}; - -proto.cleanSearchPanels = function() { - this.state.panels = {}; -}; - -proto.stop = function(){ - const d = $.Deferred(); - d.resolve(); - return d.promise(); -}; - -proto.addTool = function(searchTool) { - this.state.searchtools.push(searchTool); -}; - -proto.addTools = function(searchTools) { - for (const searchTool of searchTools) { - this.addTool(searchTool); - } -}; - -proto.addQueryBuilderSearch = function(querybuildersearch){ - this.state.querybuildersearches.push(querybuildersearch); -}; - -proto.removeTool = function(searchTool) {}; - -proto.removeTools = function() { - this.state.searchtools.splice(0) -}; - -proto.reload = function() { - this.state.searches = ProjectsRegistry.getCurrentProject().state.search; - this.state.querybuildersearches = QueryBuilderService.getCurrentProjectItems(); -}; - - -module.exports = Service; diff --git a/src/app/gui/search/vue/panel/searchpanel.js b/src/app/gui/search/vue/panel/searchpanel.js index 976b1a13a..196e67cf9 100644 --- a/src/app/gui/search/vue/panel/searchpanel.js +++ b/src/app/gui/search/vue/panel/searchpanel.js @@ -1,28 +1,7 @@ -import * as vueComponentOptions from 'components/SearchPanel.vue'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { base, inherit, uniqueId } = require('utils'); -const Panel = require('gui/panel'); -const Service = require('gui/search/vue/panel/searchservice'); - -const SearchPanelComponent = Vue.extend(vueComponentOptions); - -function SearchPanel(options = {}) { - const service = options.service || new Service(options); - this.setService(service); - this.id = uniqueId(); - this.title = 'search'; - const SearchPanel = options.component || SearchPanelComponent; - const internalPanel = new SearchPanel({ - service - }); - this.setInternalPanel(internalPanel); - this.unmount = function() { - return base(this, 'unmount').then(() => { - service.clear() - }) - } -} - -inherit(SearchPanel, Panel); - -module.exports = SearchPanel; +import { SearchPanel } from 'components/g3w-search'; +module.exports = SearchPanel; \ No newline at end of file diff --git a/src/app/gui/search/vue/panel/searchservice.js b/src/app/gui/search/vue/panel/searchservice.js deleted file mode 100644 index 28285f031..000000000 --- a/src/app/gui/search/vue/panel/searchservice.js +++ /dev/null @@ -1,993 +0,0 @@ -import { SEARCH_ALLVALUE as ALLVALUE } from 'app/constant'; -import CatalogLayersStoresRegistry from 'store/catalog-layers'; -import DataRouterService from 'services/data'; -import ProjectsRegistry from 'store/projects'; -import GUI from 'services/gui'; - -const { - base, - inherit, - toRawType, - getUniqueDomId, - createFilterFormInputs, - createSingleFieldParameter, - isEmptyObject, - sortAlphabeticallyArray, - sortNumericArray -} = require('utils'); - -const G3WObject = require('core/g3wobject'); - -const NONVALIDVALUES = [null, undefined, ALLVALUE]; - -function SearchService(config = {}) { - - this.debounces = { - run: { - fnc: (...args) => { - const [width, heigth] = this.mapService.getMap().getSize(); - if (!GUI.isMobile() || !(width === 0 || heigth === 0)) { - this._run(...args); - return; - } - GUI.hideSidebar(); - setTimeout(() => { this._run(...args); }, 600); - } - } - }; - - base(this); - - /** - * reactivity data - */ - this.state = { - title: null, - forminputs: [], - loading: {}, - searching: false, - }; - - /** - * @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; - - /** - * @type { 'search' | 'search_1n' } - */ - this.type = this.config.type || 'search'; - - /** - * @FIXME add description - */ - this.return = options.return || 'data'; - - /** - * @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(id => CatalogLayersStoresRegistry.getLayerById(id)); - - /** - * Create the form search structure - */ - this.createInputsFormFromFilter({ filter: (options.filter || []) }); - -} - -inherit(SearchService, G3WObject); - -const proto = SearchService.prototype; - -/** - * @TODO slim down and refactor - * - * Create right search structure for search form - * - * @param { Object } opts - * @param { Array } opts.filter input - * - * @returns { Promise } form input - */ -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 it has a dependence - const dependance_strict = undefined !== input.options.dependance_strict ? input.options.dependance_strict : false; - const dependance = undefined !== input.options.dependance ? input.options.dependance : false; - const isInputSelectType = ['selectfield', 'autocompletefield'].includes(input.type); - input.options.values = undefined !== input.options.values ? input.options.values : []; - const { values } = input.options; - - let promise; - - //In case of select input - if ('selectfield' === input.type) { - // ensure setting values options to empty array when undefined - input.loading = true; - - promise = new Promise((resolve, reject) => { - - // in case of dependence load right now - if (dependance && dependance_strict) { - input.loading = false; - return resolve(); - } - - // not strictly dependence - if (!dependance_strict) { - this - .getValuesFromField(input) - .then(_values => { values.splice(0, values.length, ...this.valuesToKeysValues(_values)); }) - .catch((err) => { console.warn(err); values.length = 0 }) - .finally(() => { input.loading = false; resolve(); }) - } - }); - - promise.then(() => { - values[values.length && ALLVALUE !== values[0].value ? 'unshift' : 'push']({ value:ALLVALUE }); - input.value = ALLVALUE; - }); - - } - - // there is a dependence - if (isInputSelectType && dependance) { - 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 (isInputSelectType && dependance && values.length > 0) { - input.widget = 'valuemap'; - input.options._values = [...values]; - } - - //Set input widget - if (isInputSelectType && dependance && !values.length && input.options.layer_id) { - input.widget = 'valuerelation'; - } - - // add form inputs to list of search input - this.state.forminputs.push(input); - } -}; - -/** - * Get return type - */ -proto.getReturnType = function() { - return this.return; -}; - -/** - * Set return type - */ -proto.setReturnType = function(returnType='data') { - this.return = returnType; - this.show = ('data' === returnType); -}; - -/** - * @param field - * - * @returns {*} - */ -proto.getAutoFieldDependeciesParamField = function(field) { - const fieldDependency = this.getCurrentFieldDependance(field); - if (fieldDependency) { - const [field, value] = Object.entries(fieldDependency)[0]; - return this.createFieldsDependenciesAutocompleteParameter({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 })); - } - if (!dependendency) { - return fields.length && fields.join() || undefined; - } - const [dfield, dvalue] = Object.entries(dependendency)[0]; - // In case of some input dependeny are not filled - if (undefined !== dvalue) { - // need to set to lower case for api purpose - const { op, logicop } = this.getFilterInputFromField(dfield); - fields.unshift(`${dfield}|${op.toLowerCase()}|${encodeURI(dvalue)}|` + (fields.length ? logicop.toLowerCase() : '')); - } - return this.createFieldsDependenciesAutocompleteParameter({ fields, dfield }); -}; - -/** - * Request to server value for a specific select field - * - * @param field form input - * - * @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 }); - return this.getValueRelationValues( - field, - // filter - createFilterFormInputs({ - layer: CatalogLayersStoresRegistry.getLayerById(field.options.layer_id), - search_endpoint: this.getSearchEndPoint(), - inputs: [{value: uniqueValues, attribute: field.options.value, logicop: "OR", operator: "eq" }] - }) - ); - } - - // 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 }) -}; - -/** - * @param field - * @param filter - * - * @returns { Promise<[]> } - */ -proto.getValueRelationValues = async function(field, filter) { - try { - const { data = [] } = await DataRouterService.getData('search:features', { - inputs:{ - layer: CatalogLayersStoresRegistry.getLayerById(field.options.layer_id), - search_endpoint: this.getSearchEndPoint(), - filter, - ordering: field.options.key - }, - outputs: false - }); - const values = []; - (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 []; - } -}; - -/** - * Return mapped values - * - * @param field - * - * @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<*> } - * - * @since 3.8.0 - */ -proto.getLayersFilterData = async function(layers, 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, - fformatter, - }))); - - const data = Array.from( - promisesData - .filter(({status}) => 'fulfilled' === status) - .reduce((accumulator, { value = [] }) => new Set([...accumulator, ...value]), []) - ) - //check if is not empty array - switch (data.length && typeof data[0]) { - case 'string': return sortAlphabeticallyArray(data); - case 'number': return sortNumericArray(data); - default: return data; - } -}; - -/** - * Get unique values from field - * - * @param { Object } options - * @param options.field - * @param options.value - * @param options.unique - * - * @returns { Promise<[]> } - */ -proto.getUniqueValuesFromField = async function({field, value, output}) { - let data = []; - try { - data = await this.getLayersFilterData( - (1 === this.searchLayers.length ? [this.searchLayer] : this.searchLayers), { - field: this.getAutoFieldDependeciesParamField(field), - suggest: value !== undefined ? `${field}|${value}` : undefined, - unique: field, - ordering: field - }); - - if ('autocomplete' === output) { - data = data.map(value => ({ id:value, text:value })); - } - } catch(e) { console.warn(e); } - - return data; -}; - -/** - * Perform search - * - * @param { Object } opts - * @param opts.filter - * @param opts.search_endpoint - * @param opts.queryUrl - * @param opts.feature_count - * @param opts.show - * - * @returns { Promise } - */ -proto.doSearch = async function({ - filter, - search_endpoint = this.getSearchEndPoint(), - queryUrl = this.url, - feature_count = 10000, - show = this.show, -} = {}) { - - //get or create request filter - filter = filter || this.createFilter(); - - //set searching to true - this.state.searching = true; - - let data; - - try { - data = await DataRouterService.getData('search:features', { - inputs:{ - layer: this.searchLayers, - search_endpoint, - filter, - queryUrl, - formatter: 1, - feature_count, - raw: ('search' === this.return) // in order to get raw response - }, - outputs: show && { title: this.state.title } - }); - // not show (request internal. No output data are show) - if (!show) { - const parsed = ('search_1n' === this.type) - ? await parse_search_1n(data, { - search_endpoint, - feature_count, - relation_id: this.config.options.search_1n_relationid, - output_title: this.state.title - }) - : parse_search_by_returnType(data, this.return); - data = parsed ? parsed : data; - } else if (this.project.state.autozoom_query && data && 1 === data.data.length) { - this.mapService.zoomToFeatures(data.data[0].features); // auto zoom_query - } - } catch(e) { - console.warn(e); - } - - //set searchin false - this.state.searching = false; - - return data; -}; - -/** - * Filter input by NONVALIDVALUES - * - * @returns { Array } - */ -proto.filterValidFormInputs = function() { - return this.state - .forminputs - .filter(input => -1 === NONVALIDVALUES.indexOf(input.value) && '' !== input.value.toString().trim()); -}; - -/** - * @returns { string | * } - */ -proto.getSearchEndPoint = function() { - return this.search_endpoint || this.searchLayer.getSearchEndPoint() -}; - -/** - * 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(); -}; - -/** - * 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; -}; - -/** - * @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]); - } - 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; -}; - -proto._getCascadeDependanciesFilter = function(field, dependencies = []) { - const dependance = this.getFilterInputFromField(field).input.options.dependance; - if (dependance) { - dependencies.unshift(dependance); - this._getCascadeDependanciesFilter(dependance, dependencies) - } - return dependencies; -}; - -/** - * Check if a field has a dependance - * - * @param field - * - * @returns { Object } - */ -proto.getCurrentFieldDependance = function(field) { - const dependance = this.inputdependance[field]; - return dependance ? ({ - [dependance]: - (this.cachedependencies[dependance] && ALLVALUE !== this.cachedependencies[dependance]._currentValue) - ? this.cachedependencies[dependance]._currentValue // dependance as value - : undefined // undefined = so it no add on list o field dependance - }) : dependance; -}; - -/** - * 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; -}; - -/** - * @TODO slim down and refactor - * - * Fill all dependencies inputs based on value - */ -proto.fillDependencyInputs = function({field, subscribers=[], value=ALLVALUE}={}) { - const isRoot = this.inputdependance[field] === undefined; - //check id inpute father is valid to search on subscribers - const invalidValue = value===ALLVALUE || value === null || value === undefined || value.toString().trim() === ''; - return new Promise((resolve, reject) => { - //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 { - //set starting all 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 - } - subscribe.value = subscribe.type !== 'selectfield' ? ALLVALUE : null; - }); - // 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'); - if (value && value !== ALLVALUE) { - let isCached; - let rootValues; - if (isRoot) { - const cachedValue = this.cachedependencies[field] && this.cachedependencies[field][value]; - isCached = cachedValue !== undefined; - rootValues = isCached && cachedValue; - } else { - const dependenceCurrentValue = this.getDependanceCurrentValue(field); - const cachedValue = this.cachedependencies[field] - && this.cachedependencies[field][dependenceCurrentValue] - && this.cachedependencies[field][dependenceCurrentValue][value]; - isCached = cachedValue !== undefined; - rootValues = isCached && cachedValue; - } - if (isCached) { - for (let i = 0; i < subscribers.length; i++) { - const subscribe = subscribers[i]; - const values = rootValues[subscribe.attribute]; - if (values && values.length) { - for (let i = 0; i < values.length; i++) { - subscribe.options.values.push(values[i]); - } - } - // set disabled false to dependence field - subscribe.options.disabled = false; - resolve() - } - } else { - this.state.loading[field] = true; - 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] || {} - } - // exclude autocomplete subscribers - if (notAutocompleteSubscribers.length > 0) { - const fieldParams = this.createFieldsDependenciesAutocompleteParameter({ - field, - value - }); - //need to set undefined because if - // it has a subscribe input with valuerelations widget needs to extract the value of the field to get - // filter data from relation layer - this.searchLayer.getFilterData({ - field: fieldParams, - formatter: 0 //v3.0 need to force to use raw value with formatter 0 parameter - }) - .then(async data => { - const parentData = data.data[0].features || []; - for (let i = 0; i < notAutocompleteSubscribers.length; i++) { - const subscribe = notAutocompleteSubscribers[i]; - const { attribute, widget } = subscribe; - const uniqueValues = new Set(); - // case value map - if (widget === 'valuemap') { - let values = [...subscribe.options._values]; - parentData.forEach(feature => { - const value = feature.get(attribute); - if (value) { - // need to covert to string - // because input values are string - uniqueValues.add(`${value}`); - } - }); - const data = [...uniqueValues]; - values = values.filter(({key}) => data.indexOf(key) !== -1); - values.forEach(value => subscribe.options.values.push(value)); - } else if (widget === 'valuerelation') { - 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.value, //v3.8.x has 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)} - } - } else { - parentData.forEach(feature => { - const value = feature.get(attribute); - value && uniqueValues.add(value); - }); - this.valuesToKeysValues([...uniqueValues].sort()).forEach(value => subscribe.options.values.push(value)); - } - if (isRoot) { - this.cachedependencies[field][value][subscribe.attribute] = subscribe.options.values.slice(1); - } else { - const dependenceValue = this.getDependanceCurrentValue(field); - this.cachedependencies[field][dependenceValue][value][subscribe.attribute] = subscribe.options.values.slice(1); - } - subscribe.options.disabled = false; - } - }) - .catch(error => reject(error)) - .finally(() => { - this.state.loading[field] = false; - resolve(); - }) - } else { - //set disable - subscribers.forEach(subscribe => { - 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); - 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 - */ -proto.valuesToKeysValues = function(values) { - return values.length ? - ('Object' !== toRawType(values[0]) ? values.map(value => ({ key: value, value })) : values) : - values; -}; - -/** - * @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()), - layers: [], - infoFormat: this.searchLayer.getInfoFormat(ogcService), - crs: this.searchLayer.getCrs(), - serverType: this.searchLayer.getServerType() - }; -}; - -/** - * @param layer - */ -proto.setSearchLayer = function(layer) { - this.searchLayer = layer; -}; - -/** - * @returns { null | * } - */ -proto.getSearchLayer = function() { - return this.searchLayer; -}; - -/** - * - */ -proto.clear = function() { - this.state = null; -}; - -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; - } - } - boolean[operator].push({ - [input.op] : { - [input.attribute]: null - }}); - }); - return boolean; -} - -/** - * Search father layer id based on result of child layer - */ -async function parse_search_1n(data, options) { - const { search_endpoint, feature_count, relation_id, output_title } = options; - - const { features = [] } = data.data[0] || {}; - - const project = ProjectsRegistry.getCurrentProject(); - - // check if it has features on result - if (!features.length) { - //show empty result output - DataRouterService.showEmptyOutputs(); - return []; - } - - //get relation - const relation = project.getRelationById(relation_id); - - //if exist relation - if (relation) { - - const inputs = []; //store inputs - - //extract properties from relation object - const { - referencedLayer, //father layer id - fieldRef: {referencingField, referencedField}} = relation; // child and father relation fields - - //Number of relation fields - const rFLength = referencingField.length; - - //Just one field - if (1 === rFLength) { - const uniqueValues = new Set(); - //loop trough feature child layer - features.forEach(feature => { - const value = feature.get(referencingField[0]); - if (!uniqueValues.has(value)) { - uniqueValues.add(value); - } - }) - inputs.push({ attribute: referencedField[0], logicop: "OR", operator: "eq", value: Array.from(uniqueValues) }) - } else { - const uniqueValues = []; - features.forEach(feature => { - const values = referencingField.map(rF => feature.get(rF)); - if (!uniqueValues.find((v) => { - return v.reduce((accumulator, value, index) => { - return accumulator && values[index] === value; - }, true); - })) { - uniqueValues.push(values); - inputs.push({ attribute: referencedField, logicop: "OR", operator: "eq", value: values }) - } - }) - } - - const layer = project.getLayerById(referencedLayer); - - - data = await DataRouterService.getData('search:features', { - inputs: { - layer, - search_endpoint, - filter: createFilterFormInputs({ layer, search_endpoint, inputs }), - formatter: 1, - feature_count - }, - outputs: { - title: output_title - } - }); - - } - return data; -} - -function parse_search_by_returnType(data, returnType) { - if ('search' === returnType) { - GUI.closeContent(); - // in case of api get first response on array - data = data.data[0].data; - if (isEmptyObject(data)) { - DataRouterService.showCustomOutputDataPromise(Promise.resolve({})); - } else { - const SearchPanel = require('gui/search/vue/panel/searchpanel'); - (new SearchPanel(data)).show(); - } - } - return data; -} - -module.exports = SearchService; diff --git a/src/app/gui/search/vue/search.js b/src/app/gui/search/vue/search.js index f00e3ab06..b1633f624 100755 --- a/src/app/gui/search/vue/search.js +++ b/src/app/gui/search/vue/search.js @@ -1,31 +1,7 @@ -import * as vueComponentOptions from 'components/Search.vue'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); -const Service = require('gui/search/service'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -function SearchComponent(options={}){ - base(this, options); - this.id = "search"; - this._service = options.service || new Service(); - this._service.init(); - this.title = this._service.getTitle(); - this.internalComponent = new InternalComponent({ - service: this._service - }); - this.internalComponent.state = this._service.state; - this.state.visible = true; - this._reload = function() { - this._service.reload(); - }; - this.unmount = function() { - this._searches_searchtools.$destroy(); - return base(this, 'unmount'); - } -} - -inherit(SearchComponent, Component); - -module.exports = SearchComponent; +import { SearchComponent } from 'components/g3w-search'; +module.exports = SearchComponent; \ No newline at end of file diff --git a/src/app/gui/spatialbookmarks/vue/spatialbookmarks.js b/src/app/gui/spatialbookmarks/vue/spatialbookmarks.js index dcf59dc99..43e7dd1ae 100644 --- a/src/app/gui/spatialbookmarks/vue/spatialbookmarks.js +++ b/src/app/gui/spatialbookmarks/vue/spatialbookmarks.js @@ -1,33 +1,7 @@ /** * @file - * @since v3.8 + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 */ - -import * as vueComponentOptions from 'components/SpatialBookMarks.vue'; - -import GUI from 'services/gui'; - -const { inherit, base } = require('utils'); -const Component = require('gui/component/component'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -const SpatialBookMarksComponent = function(options = {}) { - base(this, options); - this.title = "sdk.spatialbookmarks.title"; - this.setInternalComponent = function () { - this.internalComponent = new InternalComponent(); - return this.internalComponent; - }; - - GUI.on('closecontent', () => { - this.state.open = false; - }); - -}; - -inherit(SpatialBookMarksComponent, Component); - -module.exports = SpatialBookMarksComponent; - +import vueComp from 'components/g3w-spatialbookmarks'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/streetview/vue/streetview.js b/src/app/gui/streetview/vue/streetview.js deleted file mode 100644 index 3595c0cfe..000000000 --- a/src/app/gui/streetview/vue/streetview.js +++ /dev/null @@ -1,25 +0,0 @@ -import * as vueComponentOptions from 'components/StreetView.vue'; - -const { base, inherit } = require('utils'); -const Component = require('gui/component/component'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -const StreetViewComponent = function(options={}) { - base(this); - const {keyError} = options; - const internalComponent = new InternalComponent({ - keyError - }); - this.setInternalComponent(internalComponent); - this.unmount = function() { - return base(this, 'unmount'); - } -}; - -inherit(StreetViewComponent, Component); - - -module.exports = StreetViewComponent; - - diff --git a/src/app/gui/table/tableservice.js b/src/app/gui/table/tableservice.js deleted file mode 100644 index 5f0be0836..000000000 --- a/src/app/gui/table/tableservice.js +++ /dev/null @@ -1,786 +0,0 @@ -import CatalogLayersStoresRegistry from 'store/catalog-layers'; -import DataRouterService from 'services/data'; -import GUI from 'services/gui'; -import { coordinatesToGeometry } from 'utils/coordinatesToGeometry'; - -const { inherit, noop } = require('utils'); -const G3WObject = require('core/g3wobject'); -const { t } = require('core/i18n/i18n.service'); -const { SELECTION_STATE } = require('core/layers/layer'); - -const PAGELENGTHS = [10, 25, 50]; - -/** - * Create a unique feature key - */ -function _createFeatureKey(values) { - return values.join('__'); -} - -/** - * TableService Class - * - * @param options.layer - * @param options.formatter - * - * @constructor - */ -const TableService = function(options = {}) { - - /** - * Number of pages - */ - this.currentPage = 0; - - /** - * @FIXME add description - */ - this.layer = options.layer; - - /** - * @FIXME add description - */ - this.formatter = options.formatter; - - /** - * @FIXME add description - */ - this.allfeaturesnumber = undefined; - - /** - * @FIXME add description - */ - this.nopaginationsfilter = []; - - /** - * @FIXME add description - */ - this.selectedfeaturesfid = this.layer.getSelectionFids(); - - /** - * Whether layer has geometry - */ - this.geolayer = this.layer.isGeoLayer(); - - /** - * @FIXME add description - */ - this.relationsGeometry = this._relationsGeometry(); - - /** - * @FIXME add description - */ - this.projection = this.geolayer ? this.layer.getProjection() : null; - - /** - * @FIXME add description - */ - this.mapService = GUI.getService('map'); - - /** - * @FIXME add description - */ - this.getAll = false; - - /** - * @FIXME add description - */ - this.paginationfilter = false; - - /** - * @FIXME add description - */ - this.mapBBoxEventHandlerKey = { - key: null, - cb: null - }; - - - // bind context on event listeners - this.clearAllSelection = this.clearAllSelection.bind(this); - this.filterChangeHandler = this.filterChangeHandler.bind(this); - this.onGUIContent = this.onGUIContent.bind(this); - - /** - * @FIXME add description - */ - this.state = { - pageLengths: PAGELENGTHS, - pageLength: this.layer.getAttributeTablePageLength() || PAGELENGTHS[0], - features: [], - title: this.layer.getTitle(), - headers: this.getHeaders(), - geometry: true, - loading: false, - allfeatures: 0, - pagination: !this.getAll, - selectAll: false, - nofilteredrow: false, - tools: { - geolayer: { - show: this.geolayer, - active: false, - in_bbox: undefined, - }, - show: false, - filter: this.layer.state.filter - } - }; - - /** - * Pagination filter features - */ - this._async = { - state: false, - fnc: noop - }; - - GUI.onbefore('setContent', this.onGUIContent); - this.layer.on('unselectionall', this.clearAllSelection); - this.layer.on('filtertokenchange', this.filterChangeHandler); -}; - -inherit(TableService, G3WObject); - -const proto = TableService.prototype; - -/** - * @since 3.9.0 - */ -proto._relationsGeometry = function() { - - // layer has geometry - if (this.geolayer) { - return []; - } - - const relations = []; - - this.layer - .getRelations() - .getArray() - .forEach(relation => { - const layer = CatalogLayersStoresRegistry.getLayerById(relation.getFather()); // get project layer - if ( - this.layer.getId() !== relation.getFather() && // current layer is not child layer of relation - layer.isGeoLayer() // relation layer has geometry - ) { - relations.push({ - layer, - father_fields: relation.getFatherField(), // NB: since g3w-admin@v3.7.0 this is an Array value. - fields: relation.getChildField(), // NB: since g3w-admin@v3.7.0 this is an Array value. - features: {}, - }) - } - }); - - return relations; -}; - -/** - * @since 3.9.0 - */ -proto.clearAllSelection = function() { - this.state.features.forEach(feature => feature.selected = false); - this.state.tools.show = false; - this.state.selectAll = false; -}; - -/** - * @since 3.9.0 - * - * @param { Object } opts - * @param { string } opts.type - * - * @fires redraw when `opts.type` in_bbox filter (or not select all) - */ -proto.filterChangeHandler = async function ({ type } = {}) { - this.allfeaturesnumber = undefined; - if (type === 'in_bbox' || !this.selectedfeaturesfid.has(SELECTION_STATE.ALL)) { - this.emit('redraw', this.state.pagination ? [] : await this.reloadData()); - } -}; - -/** - * @since 3.9.0 - */ -proto.onGUIContent = function(options) { - this._async.state = (100 === options.perc); -}; - -proto.toggleFilterToken = async function() { - await this.layer.toggleFilterToken(); -}; - -/** - * first value = `null` for DataTable purpose (used to add a custom input selector) - */ -proto.getHeaders = function() { - return [null, ...this.layer.getTableHeaders()]; -}; - -/** - * DataTable pagination - */ -proto.setDataForDataTable = function() { - const data = []; - this.state.features.forEach(feature => { - const attributes = feature.attributes ? feature.attributes : feature.properties; - const values = [null]; - this.state.headers.forEach(header => { - if (header) { - header.value = attributes[header.name]; - values.push(header.value); - // header.label = undefined; // removes label. - } - }); - data.push(values) - }); - return data; -}; - -proto.addRemoveSelectedFeature = function(feature) { - feature.selected = !feature.selected; - - const selected = this.selectedfeaturesfid; - const filter = this.nopaginationsfilter; - const count = this.allfeaturesnumber; - - const select_all = this.state.selectAll; - const has_pagination = this.state.pagination; - const features = this.state.features; - const is_active = this.state.tools && this.state.tools.filter && this.state.tools.filter.active - - const is_exclude = !select_all && selected.has(SELECTION_STATE.EXCLUDE); - const is_default = !select_all && !is_exclude; - - /** @FIXME add description */ - if (select_all) { - this.state.selectAll = false; - } - - /** @FIXME add description */ - if (select_all) { - this.layer.excludeSelectionFid(feature.id, has_pagination); - } - - /** @FIXME add description */ - if (is_exclude || is_default) { - this.layer[feature.selected ? 'includeSelectionFid' : 'excludeSelectionFid'](feature.id); - } - - /** @FIXME add description */ - if (!is_active && ( (is_exclude && 1 === selected.size) || (is_default && selected.size === count)) ) { - this.layer.setSelectionFidsAll(); - } - - /** @FIXME add description */ - if (is_exclude && 1 !== selected.size && selected.size === features.length + 1) { - this.layer.clearSelectionFids(); - } - - /** @FIXME add description */ - this.state.tools.show = selected.size > 0; - - /** @FIXME add description */ - if ( - (is_exclude && 1 === selected.size) || - (is_default && selected.size === count) || - (!has_pagination && filter.length && filter.length === features.filter(f => f.selected).length) - ) { - this.state.selectAll = true; - } - -}; - -proto.createFeatureForSelection = function(feature) { - return { - attributes: feature.attributes ? feature.attributes : feature.properties, - geometry: this._returnGeometry(feature), - } -}; - -proto.getAllFeatures = function(params) { - GUI.setLoadingContent(true); - return new Promise((resolve, reject) => { - this.layer - .getDataTable(params || {}) - .then(data => { - const is_valid = this.geolayer && data.features; - - if (is_valid && !params) { - const loaded_features = this.state.features.map(f => f.id); - data.features.forEach(f => { - if (-1 === loaded_features.indexOf(f.id) && f.geometry) { - this.layer.addOlSelectionFeature({ - id: f.id, - feature: this.createFeatureForSelection(f), - }); - } - }); - this.getAll = true; - } - - if (is_valid) { - resolve(data.features); - } - }) - .fail(() => reject()) - .always(() => GUI.setLoadingContent(false)); - }); -}; - -proto.switchSelection = async function() { - const has_pagination = this.state.pagination; - const filter = this.nopaginationsfilter; - const filtered = !has_pagination && filter.length ? [] : undefined; - let selected = false; - - // pagination - if (has_pagination) { - this.state.features.forEach(f => { - f.selected = !f.selected; - selected = f.selected; - }); - } - - if (has_pagination && !this.getAll) { - await this.getAllFeatures(); - } - - this.state.selectAll = (has_pagination && this.paginationfilter) ? selected : this.state.selectAll; - - // filtered - if (!has_pagination && filter.length) { - this.state.features.forEach((f, i) => { - if (-1 !== filter.indexOf(i)) { - filtered.push(f); - } - f.selected = !f.selected; - this.layer[f.selected ? 'includeSelectionFid' : 'excludeSelectionFid' ](f.id); - selected = selected || f.selected; - }); - this.state.tools.show = selected; - } - - // no filter - if (!has_pagination && !filter.length) { - this.state.features.forEach(f => { f.selected = !f.selected; }); - } - - if (has_pagination || !filter.length) { - this.layer.invertSelectionFids(); - } - - if (!has_pagination) { - this.checkSelectAll(filtered); - } - - if (has_pagination || !filter.length) { - this.state.tools.show = this.selectedfeaturesfid.size > 0; - } - -}; - -proto.clearLayerSelection = function() { - this.layer.clearSelectionFids(); -}; - -/** - * Called when a selected feature is checked - * - * @returns {Promise} - */ -proto.selectAllFeatures = async function() { - - // set inverse of selectAll - this.state.selectAll = !this.state.selectAll; - - const has_pagination = this.state.pagination; - const filter = this.nopaginationsfilter; - let selected = false; - - // filtered - if (!has_pagination && filter.length) { - this.state.features.forEach((f, i) =>{ - if (-1 !== filter.indexOf(i)) { - f.selected = this.state.selectAll; - this.layer[f.selected ? 'includeSelectionFid': 'excludeSelectionFid'](f.id); - selected = selected || f.selected; - } - }); - this.state.tools.show = selected; - } - - // no filter - if (!has_pagination && !filter.length) { - this.state.tools.show = this.state.selectAll; - this.layer[this.state.selectAll ? 'setSelectionFidsAll': 'clearSelectionFids'](); - this.state.features.forEach(f => f.selected = this.state.selectAll); - } - - // filtered pagination - if (has_pagination && this.paginationfilter && this.state.featurescount >= this.state.allfeatures) { - this.state.features.forEach(f => { - f.selected = this.state.selectAll; - this.layer[f.selected ? 'includeSelectionFid': 'excludeSelectionFid'](f.id); - }); - } - - if (has_pagination && this.paginationfilter && this.state.featurescount < this.state.allfeatures) { - const features = await this.getAllFeatures({ - search: this.paginationParams.search, - ordering: this.paginationParams.ordering, - formatter: this.paginationParams.formatter, - in_bbox: this.paginationParams.in_bbox, - }); - features.forEach(f => { - if (!this.getAll && this.geolayer && f.geometry) { - this.layer.addOlSelectionFeature({ - id: f.id, - feature: this.createFeatureForSelection(f) - }); - } - this.layer[this.state.selectAll ? 'includeSelectionFid' : 'excludeSelectionFid'](f.id); - }) - } - - if (has_pagination) { - this.state.features.forEach(f => f.selected = this.state.selectAll); - } - - if (has_pagination && !this.paginationfilter && !this.getAll) { - await this.getAllFeatures(); - } - - if (has_pagination && !this.paginationfilter) { - this.layer[this.state.selectAll ? 'setSelectionFidsAll': 'clearSelectionFids'](); - } - - if (has_pagination) { - this.state.tools.show = this.state.selectAll || this.selectedfeaturesfid.size > 0; - } - -}; - -/** - * Set filtered features - * - * @param index features index - */ -proto.setFilteredFeature = function(index) { - const filter = this.nopaginationsfilter = index; - if (0 === index.length || index.length === this.allfeaturesnumber) { - this.checkSelectAll(); - } else { - this.checkSelectAll(filter.map(i => this.state.features[i])); - } -}; - -proto.setAttributeTablePageLength = function(length) { - this.layer.setAttributeTablePageLength(length); -}; - -/** - * Get DataTable layer - * - * @param data.start - * @param data.order - * @param data.length - * @param data.columns - * @param data.search - * @param data.firstCall - * - * @returns {Promise<{{ data: [], recordsTotal: number, recordsFiltered: number }}>} - */ -proto.getData = function({ - start = 0, - order = [], - length = this.state.pageLength, - columns = [], - search = { value: null }, - firstCall = false -} = {}) { - - // reset features before load - GUI.setLoadingContent(true); - - this.setAttributeTablePageLength(length); - - return new Promise((resolve, reject) => { - - // skip when .. - if (!this.state.headers.length) { - resolve({ - data: [], - recordsTotal: 0, - recordsFiltered: 0 - }); - return; - } - - let searchText = search.value && search.value.length > 0 ? search.value : null; - - this.state.features.splice(0); - - if (!order.length) { - order.push({ - column: 1, - dir: 'asc', - }); - } - - const ordering = ('asc' === order[0].dir ? '' : '-') + this.state.headers[order[0].column].name; - - this.currentPage = (start === 0 || (this.state.pagination && this.state.tools.filter.active)) ? 1 : (start/length) + 1; - - const in_bbox = this.state.tools.geolayer.in_bbox; - - const field = this.state.pagination - ? columns.filter(c => c.search && c.search.value).map(c => `${c.name}|ilike|${c.search.value}|and`).join(',') - : undefined; - - this.paginationParams = { - field: field || undefined, - page: this.currentPage, - page_size: length, - search: searchText, - in_bbox, - formatter: this.formatter, - ordering - }; - - this.layer - .getDataTable( - this.state.pagination - ? this.paginationParams - : ({ ordering, in_bbox, formatter: this.formatter }) - ) - .then(data => { - const { features = [] } = data; - - this.state.allfeatures = data.count || this.state.features.length; - this.state.featurescount = features.length; - this.allfeaturesnumber = (undefined === this.allfeaturesnumber ? data.count : this.allfeaturesnumber); - this.paginationfilter = (data.count !== this.allfeaturesnumber); - this.state.pagination = firstCall - ? this.state.tools.filter.active || features.length < this.allfeaturesnumber - : this.state.pagination; - - this.addFeatures(features); - - resolve({ - data: this.setDataForDataTable(), - recordsFiltered: data.count, - recordsTotal: data.count - }); - }) - .fail(err => { GUI.notify.error(t("info.server_error")); reject(err); }) - .always(() => { GUI.setLoadingContent(false); }) - }); -}; - -proto.setInBBoxParam = function() { - const { geolayer } = this.state.tools; - geolayer.in_bbox = geolayer.active ? this.mapService.getMapBBOX().join(',') : undefined; -}; - -proto.resetMapBBoxEventHandlerKey = function() { - const listener = this.mapBBoxEventHandlerKey; - ol.Observable.unByKey(listener.key); - listener.key = null; - listener.cb = null; -}; - -proto.getDataFromBBOX = async function() { - const { geolayer } = this.state.tools; - - geolayer.active = !geolayer.active; - - const is_active = geolayer.active; - const listener = this.mapBBoxEventHandlerKey; - - if (is_active && this.state.pagination) { - listener.cb = () => { - this.setInBBoxParam(); - this.emit('ajax-reload'); - }; - } - - if (is_active && !this.state.pagination) { - listener.cb = async () => { - this.setInBBoxParam(); - this.filterChangeHandler({ type: 'in_bbox' }); - }; - } - - if (is_active) { - listener.key = this.mapService.getMap().on('moveend', listener.cb); - } - - if (listener.cb) { - listener.cb(); - } - - if (!is_active) { - this.resetMapBBoxEventHandlerKey(); - } -}; - -proto.addFeature = function(feature) { - const tableFeature = { - id: feature.id, - selected: this.layer.hasSelectionFid(feature.id), - attributes: feature.attributes || feature.properties, - geometry: this.geolayer && feature.geometry || undefined - }; - - const has_geom = this.geolayer && feature.geometry; - const selection = has_geom && this.layer.getOlSelectionFeature(feature.id); - - if (has_geom && !selection) { - this.layer.addOlSelectionFeature({ - id: feature.id, - feature: this.createFeatureForSelection(feature) - }); - } - - this.state.features.push(tableFeature); -}; - -proto.checkSelectAll = function(features = this.state.features) { - this.state.selectAll = ( - this.selectedfeaturesfid.has(SELECTION_STATE.ALL) || - (features.length && features.reduce((selectAll, f) => selectAll && f.selected, true)) - ); -}; - -proto.addFeatures = function(features=[]) { - features.forEach(f => this.addFeature(f)); - this.state.tools.show = this.layer.getFilterActive() || this.selectedfeaturesfid.size > 0; - this.checkSelectAll(); -}; - -proto.reloadData = async function(pagination=false) { - this.state.features.splice(0); - this.state.pagination = pagination; - const { data = [] } = await this.getData(); - return data; -}; - -proto._setLayout = function() { - //TODO -}; - -proto._returnGeometry = function(feature) { - if (feature.attributes) return feature.geometry; - if (feature.geometry) return coordinatesToGeometry(feature.geometry.type, feature.geometry.coordinates); -}; - -proto.zoomAndHighLightFeature = function(feature, zoom = true) { - // async highlight - if (feature.geometry && this._async.state) { - this._async.fnc = this.mapService.highlightGeometry.bind(mapService, feature.geometry, { zoom }); - } - // sync highlight - if (feature.geometry && !this._async.state) { - this.mapService.highlightGeometry(feature.geometry , { zoom }); - } -}; - -/** - * Zoom to eventually features relation - */ -proto.zoomAndHighLightGeometryRelationFeatures = async function(feature, zoom = true) { - - // skip when there are no relation features geometry - if (!this.relationsGeometry.length > 0) { - return; - } - - const features = []; - const promises = []; - const field_values = []; // check if add or not - - this.relationsGeometry - .forEach(({ - layer, - father_fields, - fields, - features - }) => { - const values = fields.map(f => feature.attributes[f]); - - field_values.push(values); - - let promise; - - if (zoom && undefined === features[k]) { - promise = DataRouterService - .getData('search:features', { - inputs: { - layer, - formatter: 1, - search_endpoint: 'api', - filter: ( - father_fields - .reduce((filter, field, index) => { - filter = `${filter}${index > 0 ? '|AND,' : ''}${field}|eq|${encodeURIComponent(values[index])}` - return filter; - }, '') - ), - }, - outputs: false, // just a request not show on result - }); - } - - promises.push(promise); - }); - - (await Promise.allSettled(promises)) - .forEach(({ - status, - value - }, index) => { - if ('fulfilled' === status) { - - const relation = this.relationsGeometry[index]; - const k = _createFeatureKey(field_values[index]); - const data = value && value.data[0]; - - if (undefined === relation.features[k]) { - relation.features[k] = data && data.features || []; - } - - relation.features[k].forEach(f => features.push(f)); - - } - }); - - if (zoom) { - this.mapService.zoomToFeatures(features, { highlight: true }); - } else { - this.mapService.highlightFeatures(features); - } - -}; - -proto.clear = function() { - this.layer.off('unselectionall', this.clearAllSelection); - this.layer.off('filtertokenchange', this.filterChangeHandler); - - this.resetMapBBoxEventHandlerKey(); - - this.allfeaturesnumber = null; - this.mapService = null; - - if (this._async.state) { - setTimeout(() => { - this._async.fnc(); - this._async.state = false; - this._async.fnc = noop; - }); - } -}; - -module.exports = TableService; diff --git a/src/app/gui/table/vue/table.js b/src/app/gui/table/vue/table.js deleted file mode 100644 index a361b1802..000000000 --- a/src/app/gui/table/vue/table.js +++ /dev/null @@ -1,73 +0,0 @@ -import Table from 'components/Table.vue'; -import GUI from 'services/gui'; - -const { t } = require('core/i18n/i18n.service'); -const { base, inherit } = require('utils'); -const Component = require('gui/component/component'); -const TableService = require('gui/table/tableservice'); - -const InternalComponent = Vue.extend(Table); - -const TableComponent = function(options = {}) { - base(this); - this.id = "openattributetable"; - const {layer, formatter} = options; - const service = options.service || new TableService({ - layer, - formatter - }); - - this.setService(service); - const internalComponent = new InternalComponent({ - service - }); - - this.setInternalComponent(internalComponent); - internalComponent.state = service.state; - - service.on('redraw', ()=>{ - this.layout(); - }); - - this.unmount = function() { - return base(this, 'unmount') - }; - - this.layout = function() { - internalComponent.reloadLayout(); - }; -}; - -inherit(TableComponent, Component); - -const proto = TableComponent.prototype; - -// overwrite show method -proto.show = function(options = {}) { - const service = this.getService(); - // close all sidebar open component - GUI.closeOpenSideBarComponent(); - service.getData({firstCall: true}) - .then(() => { - GUI.showContent({ - content: this, - perc: 50, - split: GUI.isMobile() ? 'h': 'v', - push: false, - title: options.title - }); - }) - .catch(err => GUI.notify.error(t("info.server_error"))) - .finally(() => this.emit('show')); -}; - -proto.unmount = function() { - return base(this, 'unmount').then(() => { - this._service.clear(); - }) -}; - - -module.exports = TableComponent; - - diff --git a/src/app/gui/tools/service.js b/src/app/gui/tools/service.js deleted file mode 100644 index 0c2b51643..000000000 --- a/src/app/gui/tools/service.js +++ /dev/null @@ -1,119 +0,0 @@ -import ProjectsRegistry from 'store/projects'; - -const { base, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); - -function Service(options={}){ - this.config = null; - this.state = { - ...options, - toolsGroups: [], - visible: false, - loading: false - }; - this.setters = { - addTool(tool, groupName) { - tool.state = tool.state ? tool.state : { - type: null, - message: null - }; - return this._addTool(tool, groupName); - }, - addTools(tools, groupName) { - return this._addTools(tools, groupName); - }, - addToolGroup(order, name) { - return this._addToolGroup(order, name); - }, - removeToolGroup(name){ - return this._removeToolGroup(name); - }, - removeTools() { - return this._removeTools(); - } - }; - - base(this); - - const project = ProjectsRegistry.getCurrentProject(); - const {tools={}} = project.getState(); - for (let toolName in tools) { - const groupName = toolName.toUpperCase(); - this.addToolGroup(0, groupName); - const _tools = tools[toolName].map(tool => ({ - name: tool.name, - action: ToolsService.ACTIONS[toolName].bind(null, tool) - })); - this.addTools(_tools, {position: 0, title: groupName}) - } -} - -inherit(Service, G3WObject); - -const proto = Service.prototype; - -proto.reload = function() { - this.removeTools(); -}; - -proto._addTool = function(tool, {position : order, title: name}) { - let group = this._addToolGroup(order, name); - if (tool.action === undefined && tool.type) - tool.action = Service.ACTIONS[tool.type] ? Service.ACTIONS[tool.type].bind(null, tool.options) : ()=>{}; - group.tools.push(tool); -}; - -proto._addTools = function(tools, groupName) { - tools.forEach(tool => this.addTool(tool, groupName)); -}; - -proto.setLoading = function(bool=false) { - this.state.loading = bool; -}; - -proto._removeTool = function(toolIdx) { - this.state.toolsGroups = this.state.toolsGroups.splice(toolIdx, 1); -}; - -proto._removeTools = function() { - this.state.toolsGroups.splice(0); -}; - -proto.updateToolsGroup = function(order, groupConfig) { - Vue.set(this.state.toolsGroups, order, groupConfig); -}; - -proto.getState = function() { - return this.state; -}; - -proto._removeToolGroup = function(name) { - this.state.toolsGroups = this.state.toolsGroups.filter(group => group.name !== name); -}; - -proto._addToolGroup = function(order, name) { - let group = this.state.toolsGroups.find(_group => _group.name === name); - if (!group) { - group = { - name, - tools: [] - }; - this.state.toolsGroups.splice(order, 0, group); - } - return group; -}; - -proto.setToolState = function({id, state={type:null, message: null}}={}){ - this.state.toolsGroups.find(toolGroup => { - const tool = toolGroup.tools.find(tool => tool.name === id); - if (tool) { - tool.state.type = state.type; - tool.state.message = state.message; - return true; - } - }) -}; - -Service.ACTIONS = {}; - -module.exports = Service; diff --git a/src/app/gui/tools/vue/tools.js b/src/app/gui/tools/vue/tools.js index a3292173c..affc2253c 100644 --- a/src/app/gui/tools/vue/tools.js +++ b/src/app/gui/tools/vue/tools.js @@ -1,32 +1,7 @@ -import * as vueComponentOptions from 'components/Tools.vue'; -import GUI from 'services/gui'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { base, inherit } = require('utils'); -const Component = require('gui/component/component'); -const ToolsService = require('gui/tools/service'); - -const InternalComponent = Vue.extend(vueComponentOptions); - -function ToolsComponent(options={}) { - base(this, options); - this._service = new ToolsService(options); - this.title = "tools"; - - const internalComponent = new InternalComponent({ - toolsService: this._service - }); - - internalComponent.state = this._service.state; - this.setInternalComponent(internalComponent, { - events: [{name: 'visible'}] - }); - - this._setOpen = function(bool=false) { - this.internalComponent.state.open = bool; - bool && GUI.closeContent(); - } -} - -inherit(ToolsComponent, Component); - -module.exports = ToolsComponent; +import vueComp from 'components/g3w-tools'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/utils/barstack.js b/src/app/gui/utils/barstack.js deleted file mode 100644 index 6f557421d..000000000 --- a/src/app/gui/utils/barstack.js +++ /dev/null @@ -1,167 +0,0 @@ -const { resolve, inherit } = require('utils'); -const G3WObject = require('core/g3wobject'); -const Component = require('gui/component/component'); -const Panel = require('gui/panel'); - -//Barstack Class -// It used to mount panels stack -// on top of each parent -function BarStack() { - this._parent = null; - // barstack state. It store the panels array - this.state = { - contentsdata: [] - } -} - -inherit(BarStack, G3WObject); - -const proto = BarStack.prototype; - -// push componenet on top of parent -proto.push = function(content, options={}) { - // parent identify the DOM element where insert (append o meno) the component/panel - this._parent = options.parent; - // call barstack mount method - return this._mount(content, options); -}; - -// remove last component from stack -proto.pop = function() { - const d = $.Deferred(); - if (this.state.contentsdata.length) { - const content = this.state.contentsdata.slice(-1)[0].content; - this._unmount(content).then(() => { - const content = this.state.contentsdata.pop(); - d.resolve(content) - }) - } else d.resolve(); - return d.promise(); -}; - -// clear all stack -proto.clear = function() { - const d = $.Deferred(); - if (this.state.contentsdata.length) { - let unmountRequests = []; - this.state.contentsdata.forEach((data) => { - unmountRequests.push(this._unmount(data.content)); - }); - $.when(unmountRequests).then(() => { - this.state.contentsdata.splice(0, this.state.contentsdata.length); - d.resolve(); - }); - } - else d.resolve(); - return d.promise(); -}; - -proto.getContentData = function() { - return this.state.contentsdata -}; - -proto.getCurrentContentData = function() { - return this.state.contentsdata[this.state.contentsdata.length - 1]; -}; - -proto.getPreviousContentData = function() { - return this.state.contentsdata[this.state.contentsdata.length - 2]; -}; - -// mount component -proto._mount = function(content, options) { - // check the type of content: - // JQuery type - if (content instanceof jQuery) return this._setJqueryContent(content); - //String - else if (_.isString(content)) { - let jqueryEl = $(content); - if (!jqueryEl.length) jqueryEl = $('
'+content+'
'); - return this._setJqueryContent(jqueryEl); - } - // Vue - else if (content.mount && typeof content.mount == 'function') { - this._checkDuplicateVueContent(content); // if already exist it removed before based on id - return this._setVueContent(content,options) - } - // DOM - else return this._setDOMContent(content); -}; - -// JQuery append jQuery component -proto._setJqueryContent = function(content, options) { - $(this._parent).append(content); - this.state.contentsdata.push({ - content, - options - }); - return resolve(); -}; - -//Append DOM element -proto._setDOMContent = function(content, options) { - this._parent.appendChild(content); - this.state.contentsdata.push({ - content, - options - }); - return resolve(); -}; - -// Mount component to parent -proto._setVueContent = function(content, options={}) { - const d = $.Deferred(); - const append = options.append || false; - content.mount(this._parent, append) - .then(() => { - $(this._parent).localize(); - // Insert the content into the array with the following attributes: - // content: component object - // options: es. title, perc etc ... - this.state.contentsdata.push({ - content, - options - }); - d.resolve(content); - }); - return d.promise(); -}; - -// Check duplicate Vue Content -proto._checkDuplicateVueContent = function(content) { - let idxToRemove = null; - const id = content.getId(); - this.state.contentsdata.forEach((data, idx) => { - if (data.content.getId && (data.content.getId() == id)) idxToRemove = idx; - }); - if (!_.isNull(idxToRemove)) { - const data = this.state.contentsdata[idxToRemove]; - data.content.unmount() - .then(() => this.state.contentsdata.splice(idxToRemove,1)); - } -}; - -// unmount component -proto._unmount = function(content) { - const d = $.Deferred(); - if (content instanceof Component || content instanceof Panel) { - content.unmount() - .then(() => d.resolve()); - } - else { - $(this._parent).empty(); - d.resolve(); - } - return d.promise(); -}; - -proto.forEach = function(cbk) { - this.state.contentsdata.forEach(data => cbk(data.content)); -}; - -// Get lenght / numbero of element stored in stack -proto.getLength = function() { - return this.state.contentsdata.length; -}; - -module.exports = BarStack; diff --git a/src/app/gui/utils/utils.js b/src/app/gui/utils/utils.js deleted file mode 100644 index 33cb7fdfa..000000000 --- a/src/app/gui/utils/utils.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - barstack: require('./barstack') -}; \ No newline at end of file diff --git a/src/app/gui/viewport/contentsviewer.js b/src/app/gui/viewport/contentsviewer.js index 666a96c60..8c75b71bc 100644 --- a/src/app/gui/viewport/contentsviewer.js +++ b/src/app/gui/viewport/contentsviewer.js @@ -1,158 +1,7 @@ -import * as vueComponentOptions from 'components/ViewportContentsViewer.vue'; +/** + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 + */ -const { base, inherit } = require('utils'); -const { barstack: Stack } = require('gui/utils/utils'); -const Component = require('gui/component/component'); - -// Internal Component (VUE) of the content of the viewport -const InternalComponent = Vue.extend(vueComponentOptions); - -function ContentsViewerComponent(options={}) { - base(this, options); - this.stack = new Stack(); - this.setService(this); - this.title = "contents"; - this.contentsdata = this.stack.state.contentsdata; - this.state.visible = true; - const internalComponent = new InternalComponent({ - service: this - }); - this.setInternalComponent(internalComponent); - this.internalComponent.state = this.state; -} - -inherit(ContentsViewerComponent, Component); - -const proto = ContentsViewerComponent.prototype; - -proto.setContent = function(options={}) { - const {push=false, content, crumb} = options; - const d = $.Deferred(); - // clean the stack every time, sure to have just one component. - // Use barstack because it handle the logic og mounting component on DOM - if (push) { - this.addContent(content,options) - .then(() => d.resolve(options)); - } else { - // clear stack - this.clearContents() - .then(() => { - this.addContent(content, options) - .then(() => d.resolve(options)); - }) - } - - this.setOpen(true); - return d.promise(); -}; - -proto.addContent = function(content, options={}) { - const d = $.Deferred(); - // parent element is the internal element - options.parent = this.internalComponent.$el; - options.append = true; - const promise = this.stack.push(content, options); - promise.then(() => { - // get stack content - this.contentsdata = this.stack.state.contentsdata; - // update the visibility of the others components - this.updateContentVisibility(); - d.resolve(); - }); - return d.promise(); -}; - -// remove content from stack -proto.removeContent = function() { - this.setOpen(false); - return this.clearContents(); -}; - -// used by viewport.js -proto.popContent = function() { - return this.stack.pop() - .then(() => { - // update the content of contentsdata only after stack is updated - this.contentsdata = this.stack.state.contentsdata; - this.updateContentVisibility(); - }); -}; - -// get component through class -proto.getComponentByClass = function(componentClass) { - let component; - const contentdata = this.stack.getContentData(); - contentdata.forEach(content => { - if (content.content instanceof componentClass) { - component = content.content; - return false - } - }); - return component -}; - -// get component by component id -proto.getComponentById = function(id) { - let component; - const contentdata = this.stack.getContentData(); - contentdata.forEach(content => { - if (content.content.id == id) { - component = content.content; - return false - } - }); - return component -}; - -proto.getContentData = function() { - return this.stack.getContentData(); -}; - -// get current contentdata -proto.getCurrentContentData = function(){ - return this.stack.getCurrentContentData(); -}; - -// get previuos contentdata -proto.getPreviousContentData = function() { - return this.stack.getPreviousContentData(); -}; - -// update visibility of the components of content -proto.updateContentVisibility = function() { - // hide each elements but not the last one - const contentsEls = $(this.internalComponent.$el).children(); - contentsEls.hide(); - contentsEls.last().show(); -}; - -// stack clear because if we want the contentComponente stack -// it has to be empty stack -proto.clearContents = function() { - return this.stack.clear().then(() => this.contentsdata = this.stack.state.contentsdata); -}; - -// Set layout of the content each time -// Parameters are: height and with of the parent content -proto.layout = function(parentWidth, parentHeight) { - const el = $(this.internalComponent.$el); - //run the callback only after that vue state is updated - Vue.nextTick(() => { - const contentsdata = this.stack.state.contentsdata; - // el.parent() is div g3w-view-content - const height = el.parent().height() - - el.siblings('.close-panel-block').outerHeight(true) - - el.siblings('.content_breadcrumb').outerHeight(true) - 10; // margin 10 from bottom - el.height(height); - el.children().first().height(height); - contentsdata.forEach(data => { - //check each componentstored in stack - if (typeof data.content.layout == 'function') { - //call function layout of each component that are stored into the stack - data.content.layout(parentWidth + 0.5, height); - } - }) - }) -}; - -module.exports = ContentsViewerComponent; +import vueComp from 'components/g3w-contentsviewer'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/app/gui/wms/vue/wms.js b/src/app/gui/wms/vue/wms.js index 71835c77c..23aae09f4 100644 --- a/src/app/gui/wms/vue/wms.js +++ b/src/app/gui/wms/vue/wms.js @@ -1,442 +1,7 @@ -import * as vueComponentOptions from 'components/WMS.vue'; -import * as vuePanelComponentOptions from 'components/WMSLayersPanel.vue'; -import { LOCALSTORAGE_EXTERNALWMS_ITEM } from 'app/constant'; -import DataRouterService from 'services/data'; -import ProjectsRegistry from 'store/projects'; -import ApplicationService from 'services/application'; -import GUI from 'services/gui'; -import { base, inherit, uniqueId } from 'utils'; - -const Panel = require('gui/panel'); -const Component = require('gui/component/component'); -const InternalComponent = Vue.extend(vueComponentOptions); -const WMSLayersPanelComponent = Vue.extend(vuePanelComponentOptions); - /** - * ORIGINAL SOURCE: src/app/gui/wms/vue/panel/wmslayerspanel.js@3.8.15 + * @file + * @deprecated do not remove prior to https://github.com/g3w-suite/g3w-client/pull/451 */ -function WmsLayersPanel(options = {}) { - const { service, config } = options; - this.setService(service); - this.id = uniqueId(); - this.title = 'sidebar.wms.panel.title'; - const internal = new WMSLayersPanelComponent({ service, config }); - this.setInternalPanel(internal); - this.unmount = function() { return base(this, 'unmount').then(() => service.clear()); }; -} - -inherit(WmsLayersPanel, Panel); - -/** - * ORIGINAL SOURCE: src/app/gui/wms/service.js@3.8.15 - */ -class Service { - - constructor(options = {}) { - - const { - wmsurls = [] - } = options; - - /** - * Current project id used to store data or get data to current project - */ - this.projectId = ProjectsRegistry.getCurrentProject().getId(); // - - /** - * @FIXME add description - */ - this.panel; - - /** - * @FIXME add description - */ - this.state = { - adminwmsurls: wmsurls, - localwmsurls: [] // array of object {id, url} - }; - - GUI.isReady() - .then(() => { - GUI.getService('map') - .isReady() - .then(async () => { this.state.localwmsurls = await this.loadClientWmsUrls(); }); - }); - - ProjectsRegistry.onafter('setCurrentProject', async (project) => { - this.projectId = project.getId(); - this.state.adminwmsurls = project.wmsurls || []; - }); - - } - - /** - * Getting Wms Urls from local browser storage - */ - async loadClientWmsUrls() { - let data = this.getLocalWMSData(); - - if (undefined === data) { - data = { - urls: [], // unique url for wms - wms: {}, // bject contain url as key and array of layers bind to url - }; - this.updateLocalWMSData(data); - } - - await GUI.isReady(); - - setTimeout(() => { - const map = GUI.getService('map'); - - map.on('remove-external-layer', name => this.deleteWms(name)); - - map.on('change-layer-position-map', ({ id: name, position } = {}) => this.changeLayerData(name, { key: 'position', value: position })); - map.on('change-layer-opacity', ({ id: name, opacity } = {}) => this.changeLayerData(name, { key: 'opacity', value: opacity })); - map.on('change-layer-visibility', ({ id: name, visible } = {}) => this.changeLayerData(name, { key: 'visible', value: visible })); - - // load eventually data - Object.keys(data.wms).forEach(url => { data.wms[url].forEach(config => { this.loadWMSLayerToMap({ url, ...config }) }); }); - }); - - return data.urls; - } - - /** - * Change config of storage layer options as position, opacity - * - * @param { Object } opts - * @param { string } opts.name - * @param opts.config - */ - changeLayerData(name, attribute = {}) { - const data = this.getLocalWMSData(); - Object - .keys(data.wms) - .find((wmsurl) => { - const index = data.wms[wmsurl].findIndex(config => config.name == name); - if (-1 !== index) { - data.wms[wmsurl][index][attribute.key] = attribute.value; - return true; - } - }); - - this.updateLocalWMSData(data); - } - - /** - * Create a common status object - * - * @param { Object } request - * @param request.error - * @param request.added - * - * @returns {{ error, status: string }} - */ - getRequestStatusObject({ - error = false, - added = false, - } = {}) { - return { error, added }; - } - - /** - * Add new WMS url - * - * @param { Object } wms - * @param { string } wms.id - * @param { string } wms.url - * - * @returns {*} - */ - async addNewUrl({ - id, - url, - } = {}) { - const found = this.state.localwmsurls.find(({ id: localid, url: localurl }) => localurl == url || localid == id); - const status = this.getRequestStatusObject({ added: !!found }); - - // skip when url already added - if (found) { - return status; - } - - try { - const response = await this.getWMSLayers(url); - // skip on invalid response - if (!response.result) { - throw 'invalid response'; - } - const data = this.getLocalWMSData(); - this.state.localwmsurls.push({ id, url }); - data.urls = this.state.localwmsurls; - this.updateLocalWMSData(data); - response.wmsurl = url; - this.showWmsLayersPanel(response); - } catch(err) { - console.warn(err); - status.error = true; - } - - return status; - } - - /** - * Delete WMS by name - * - * @param name - */ - deleteWms(name) { - const data = this.getLocalWMSData(); - Object - .keys(data.wms) - .find(wmsurl => { - const index = data.wms[wmsurl].findIndex(config => config.name == name); - - // skip when .. - if (-1 === index) { - return; - } - - /** @TODO add description */ - data.wms[wmsurl].splice(index, 1); - - /** @TODO add description */ - if (0 == data.wms[wmsurl].length) { - delete data.wms[wmsurl]; - } - - return true; - }); - this.updateLocalWMSData(data); - } - - /** - * @param { Object } opts - * @param opts.name - * @param opts.layers - * - * @returns { boolean } WMS is already added (by `name` or `layer` with a specific url) - */ - checkIfWMSAlreadyAdded({ - url, - layers=[], - } = {}) { - const data = this.getLocalWMSData(); - - // wms url is not already added - if (!data.wms[url]) { - return false; - } - - // check if wms layer is already added (by name) - return data.wms[url].some( - ({ layers: addedLayers }) => addedLayers.length === layers.length - ? layers.every((name) => addedLayers.includes(name)) - : undefined - ); - } - - /** - * Delete url from local storage - * @param id - */ - deleteWmsUrl(id) { - this.state.localwmsurls = this.state.localwmsurls .filter(({ id: localid }) => id !== localid); - const data = this.getLocalWMSData(); - data.urls = this.state.localwmsurls; - this.updateLocalWMSData(data); - } - - /** - * Load data from server and show wms layer panel - * - * @param url - * - * @returns { Promise<{ added: boolean, error: boolean }> } - */ - async loadWMSDataAndShowWmsLayersPanel(url) { - const status = this.getRequestStatusObject(); - try { - const response = await this.getWMSLayers(url); - status.error = !response.result; - if (response.result) { - response.wmsurl = url; - this.showWmsLayersPanel(response); - } - } catch(err) { - console.warn(err); - status.error = true; - } - return status; - } - - /** - * show add wms layers to wms panel - * @param config - * @returns {WmsLayersPanel} - */ - showWmsLayersPanel(config={}) { - this.panel = new WmsLayersPanel({ service: this, config }); - this.panel.show(); - return this.panel; - } - - /** - * Get data of wms url from server - * - * @param { string } url - * - * @returns { Promise<{ - * result: boolean, - * info_formats: [], - * layers: [], - * map_formats: [], - * methods: [], - * abstract: null, - * title: null, - * }> } - */ - async getWMSLayers(url) { - // base schema of response - let response = { - result: false, - layers: [], - info_formats: [], // @deprecated since 3.9.0 (inside methods) - abstract: null, - methods: [], // @since 3.9.0 - map_formats: [], // @deprecated since 3.9.0 (inside methods) - title: null - }; - try { - response = await DataRouterService.getData('ows:wmsCapabilities', { inputs: { url }, outputs: false }); - } catch(err) { - console.warn(err); - } - return response; - } - - /** - * Load wms to map - * - * @param { Object } wms - * @param { string } wms.url - * @param { string } wms.name - * @param wms.epsg - * @param wms.position - * @param wms.opacity - * @param wms.visible - * @param wms.layers - * - * @returns {*} - */ - loadWMSLayerToMap({ - url, - name, - epsg, - position, - opacity, - visible = true, - layers = [], - } = {}) { - return GUI.getService('map').addExternalWMSLayer({ url, name, layers, epsg, position, visible, opacity }); - } - - /** - * Check if a layer is already added to map - * - * @param { Object } wms - * @param { string } wms.url - * @param { string } wms.name - * @param wms.epsg - * @param wms.position - * @param wms.methods - * @param wms.layers - * - * @returns { Promise } - */ - async addWMSlayer({ - url, - epsg, - position, - name = `wms_${uniqueId()}`, - layers = [], - opacity = 1, - visible = true, - } = {}) { - const data = this.getLocalWMSData(); - const config = { - url, - name, - layers, - epsg, - position, - visible, - opacity - }; - - if (undefined === data.wms[url]) { - data.wms[url] = [config]; - } else { - data.wms[url].push(config); - } - - this.updateLocalWMSData(data); - - try { - await this.loadWMSLayerToMap(config); - } catch(err) { - console.warn(err); - GUI.getService('map').removeExternalLayer(name); - this.deleteWms(name); - setTimeout(() => { GUI.showUserMessage({ type: 'warning', message: 'sidebar.wms.layer_add_error' }) }); - } - - this.panel.close(); - } - - /** - * Get local storage wms data based on current projectId - * - * @returns {*} - */ - getLocalWMSData() { - const item = ApplicationService.getLocalItem(LOCALSTORAGE_EXTERNALWMS_ITEM); - return item && item[this.projectId]; - } - - /** - * Update local storage data based on changes - * - * @param data - */ - updateLocalWMSData(data) { - const alldata = ApplicationService.getLocalItem(LOCALSTORAGE_EXTERNALWMS_ITEM) || {}; - alldata[this.projectId] = data; - ApplicationService.setLocalItem({ id: LOCALSTORAGE_EXTERNALWMS_ITEM, data: alldata }); - } - - clear() { - this.panel = null; - } - -} - -function WmsComponent(options={}) { - base(this, options); - this._service = new Service(options); - this.title = "WMS"; - const internal = new InternalComponent({ service: this._service }); - internal.state = this._service.state; - this.setInternalComponent(internal); - this._setOpen = function(bool = false) { - this.internalComponent.state.open = bool; - if (bool) { - GUI.closeContent(); - } - }; -} - -inherit(WmsComponent, Component); -module.exports = WmsComponent; +import vueComp from 'components/g3w-wms'; +module.exports = vueComp; \ No newline at end of file diff --git a/src/components/App.vue b/src/components/App.vue index c2fa36fd0..c503c7327 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -30,27 +30,49 @@ data-toggle="collapse" data-target="#main-navbar" > - + + - - + + + -
+
- + -
+
{{ main_title }}
-
{{project_title}}
+
{{ project_title }}
@@ -78,7 +100,10 @@ @@ -92,9 +117,21 @@ /> - @@ -108,8 +145,15 @@ /> - @@ -144,8 +201,16 @@ @@ -182,7 +247,10 @@ @@ -205,63 +273,144 @@ -
- +
+
- +
- + -