diff --git a/components/FormRelation.vue b/components/FormRelation.vue index 582afb10..c4beaf0f 100644 --- a/components/FormRelation.vue +++ b/components/FormRelation.vue @@ -396,7 +396,7 @@ const is_vector = (external || layer.isGeoLayer()) this.runAddRelationWorkflow({ workflow: is_vector - ? new this._add_link_workflow.selectandcopy({ + ? this._add_link_workflow.selectandcopy({ copyLayer: layer, isVector: true, help: 'editing.steps.help.copy', @@ -421,7 +421,7 @@ */ addVectorRelation() { this.runAddRelationWorkflow({ - workflow: new this._add_link_workflow.add(), + workflow: this._add_link_workflow.add(), isVector: Layer.LayerTypes.VECTOR === this._layerType, }); this.show_vector_tools = false; @@ -473,7 +473,7 @@ this.resize(); } else { this.runAddRelationWorkflow({ - workflow: new this._add_link_workflow.add(), + workflow: this._add_link_workflow.add(), isVector: Layer.LayerTypes.VECTOR === this._layerType, }); } @@ -572,14 +572,14 @@ * * @since g3w-client-plugin-editing@v3.7.4 */ - onCommit({ new_relations = {} }) { + onCommit({ relations = {} }) { const relationLayer = getEditingLayerById(this.relation.child); // there is a new relation saved on server - if (new_relations[relationLayer.getId()] && Array.isArray(new_relations[relationLayer.getId()].new)) { + if (relations[relationLayer.getId()] && Array.isArray(relations[relationLayer.getId()].new)) { this._new_relations_ids = [ ...(this._new_relations_ids || []), - ...new_relations[relationLayer.getId()].new.map(({ clientid, id }) => ({ clientid, id })) + ...relations[relationLayer.getId()].new.map(({ clientid, id }) => ({ clientid, id })) ] } }, @@ -906,11 +906,10 @@ await promise; } catch (e) { console.trace('START TOOL FAILED', e); - return Promise.reject(e); } finally { relationtool.state.active = false; } - } catch (e) { + } catch(e) { console.warn(e); } }, @@ -1029,7 +1028,7 @@ this.disabled = true; const is_vector = Layer.LayerTypes.VECTOR === this._layerType; - const workflow = new this._add_link_workflow.link( is_vector ? { + const workflow = this._add_link_workflow.link( is_vector ? { selectStyle: SELECTED_STYLES[this.getLayer().getGeometryType()] } : {}); const options = this._createWorkflowOptions(); diff --git a/components/Toolbox.vue b/components/Toolbox.vue index 5e1fd24b..2f1441e9 100644 --- a/components/Toolbox.vue +++ b/components/Toolbox.vue @@ -98,7 +98,7 @@ diff --git a/components/UserMessage.vue b/components/UserMessage.vue index 65c8e88f..ef14f92c 100644 --- a/components/UserMessage.vue +++ b/components/UserMessage.vue @@ -24,6 +24,7 @@ diff --git a/deprecated.js b/deprecated.js index 8d47e8f9..21bc13c0 100644 --- a/deprecated.js +++ b/deprecated.js @@ -1,93 +1,97 @@ import { promisify } from '../../utils/promisify'; +class Queque { + constructor() { this.tasks = []; } + addTask(task) { this.tasks.push(task); } + run(reverse = false) { while (this.tasks.length) { const task = reverse ? this.tasks.pop() : this.tasks.shift(); task(); } } + flush() { return this.tasks.splice(0); } + getLength() { return this.tasks.length; } + clear() { this.run(); this.tasks = []; } +} + + /** * Class Flow of workflow step by step * * ORIGINAL SOURCE: g3w-client/src/core/workflow/flow.js@v3.9.1 * ORIGINAL SOURCE: g3w-client/src/core/workflow/queque.js@v3.9.1 */ -export function Flow() { - console.warn('[G3W-CLIENT] g3wsdk.core.workflow.Flow is deprecated'); - - class Queque { - constructor() { this.tasks = []; } - addTask(task) { this.tasks.push(task); } - run(reverse = false) { while (this.tasks.length) { const task = reverse ? this.tasks.pop() : this.tasks.shift(); task(); } } - flush() { return this.tasks.splice(0); } - getLength() { return this.tasks.length; } - clear() { this.run(); this.tasks = []; } +export class Flow extends g3wsdk.core.G3WObject { + constructor() { + super(); + console.warn('[G3W-CLIENT] g3wsdk.core.workflow.Flow is deprecated'); + this.steps = []; + this.counter = 0; + this.context = null; + this.queques = { + end: new Queque(), + micro: new Queque() + }; + this.inputs; + this.d; + this._workflow; } - let steps = []; - let inputs; - let counter = 0; - let context = null; - let d; - let _workflow; - this.queques = { - end: new Queque(), - micro: new Queque() - }; //start workflow - this.start = function(workflow) { - d = $.Deferred(); - if (counter > 0) { + start(workflow) { + this.d = $.Deferred(); + if (this.counter > 0) { console.log("reset workflow before restarting"); } - _workflow = workflow; - inputs = workflow.getInputs(); - context = workflow.getContext(); - steps = workflow.getSteps(); + this._workflow = workflow; + this.inputs = workflow.getInputs(); + this.context = workflow.getContext(); + this.steps = workflow.getSteps(); // check if there are steps - if (steps && steps.length) { + if (this.steps && this.steps.length) { //run step (first) - this.runStep(steps[0], inputs, context); + this.runStep(this.steps[0], this.inputs, this.context); } // return a promise that will be reolved if all step go right - return d.promise(); + return this.d.promise(); }; //run step - this.runStep = function(step, inputs) { + runStep(step, inputs) { //run step that run task - _workflow.setMessages({ + this._workflow.setMessages({ help: step.state.help }); const runMicroTasks = this.queques.micro.getLength(); - step.run(inputs, context, this.queques) + step.run(inputs, this.context, this.queques) .then(outputs => { runMicroTasks && this.queques.micro.run(); this.onDone(outputs); }) - .fail(error => this.onError(error)); + .fail(e => this.onError(e)); }; //check if all step are resolved - this.onDone = function(outputs) { - counter++; - if (counter === steps.length) { - counter = 0; - d.resolve(outputs); + onDone(outputs) { + this.counter++; + if (this.counter === this.steps.length) { + this.counter = 0; + this.d.resolve(outputs); return; } - this.runStep(steps[counter], outputs); + this.runStep(this.steps[this.counter], outputs); }; // in case of error - this.onError = function(err) { - counter = 0; + onError(e) { + this.counter = 0; this.clearQueques(); - d.reject(err); + this.d.reject(e); }; // stop flow - this.stop = function() { + stop() { const d = $.Deferred(); - steps[counter].isRunning() ? steps[counter].stop() : null; + this.steps[counter].isRunning() ? this.steps[this.counter].stop() : null; this.clearQueques(); - if (counter > 0) { + if (this.counter > 0) { // set counter to 0 - counter = 0; + this.counter = 0; // reject flow d.reject(); } else { @@ -97,15 +101,13 @@ export function Flow() { return d.promise(); }; - this.clearQueques = function(){ + clearQueques(){ this.queques.micro.clear(); this.queques.end.clear(); } - g3wsdk.core.utils.base(this) } -g3wsdk.core.utils.inherit(Flow, g3wsdk.core.G3WObject); /** * ORIGINAL SOURCE: g3w-client/src/services/editing.js@v3.9.1 @@ -812,15 +814,15 @@ export class Session extends g3wsdk.core.G3WObject { return; } - const { new_relations = {} } = response.response; // check if new relations are saved on server + const { relations = {} } = response.response; // check if new relations are saved on server // sync server data with local data - for (const id in new_relations) { + for (const id in relations) { Session.Registry .getSession(id) // get session of relation by id .getEditor() .applyCommitResponse({ // apply commit response to current editing relation layer - response: new_relations[id], + response: relations[id], result: true }); } diff --git a/g3wsdk/editing/editor.js b/g3wsdk/editing/editor.js index af687128..a0f2cd07 100644 --- a/g3wsdk/editing/editor.js +++ b/g3wsdk/editing/editor.js @@ -8,6 +8,8 @@ import { ToolBox } from '../../toolboxes/toolbox'; import { promisify, $promisify } from '../../utils/promisify'; +import { getRelationsInEditing } from "../../utils/getRelationsInEditing"; +import {getRelationId} from "editing/utils/getRelationId"; const { ApplicationState, G3WObject } = g3wsdk.core; const { FeaturesStore } = g3wsdk.core.layer.features; @@ -320,7 +322,7 @@ export default class Editor extends G3WObject { // properties - properties of feature returned by server response.response.new.forEach(({ clientid, id, properties } = {}) => { //get feature from current layer in editing - const feature = this._featuresstore.getFeatureById(clientid); + const feature = this.getEditingSource().getFeatureById(clientid); // set new id feature.setId(id); //set properties @@ -346,6 +348,33 @@ export default class Editor extends G3WObject { }); + //@since 3.9.0 take in account update properties returned by server (Useful in case of media input changes) + (response.response.update || []).forEach(({ id, properties } = {}) => { + //get feature from current layer in editing + const feature = this.getEditingSource().getFeatureById(id); + //set properties + feature.setProperties(properties); + //Loop on eventual relation updated or created + relations.forEach(r => { // handle relations (if provided) + Object + .entries(r) + .forEach(([ id, opts = {}]) => { // id - relation layer id, opts - Object contain relation properties + //get the editing source of relation layer + const source = ToolBox.get(id).getSession().getEditor().getEditingSource(); + // handle value to relation field saved on server + (opts.ids || []).forEach(id => { + const rFeature = source.getFeatureById(id); + if (rFeature) { + opts.fatherField.forEach((ff, i) => {// loop relation ids + rFeature.set(opts.childField[i], feature.get(ff)) // set father feature `value` and `name` + }) + } + }) + }); + }); + + }); + const features = this.readEditingFeatures(); features.forEach(f => f.clearState()); // reset state of the editing features (update, new etc..) @@ -439,10 +468,10 @@ export default class Editor extends G3WObject { */ stop() { return $promisify(async () => { - const response = await promisify(this._layer.unlock()); + const { result } = await promisify(this._layer.unlock()); this.clear(); - return response; - }); + return result; + }) } /** diff --git a/g3wsdk/workflow/workflow.js b/g3wsdk/workflow/workflow.js index 32e5a525..bd4a9c21 100644 --- a/g3wsdk/workflow/workflow.js +++ b/g3wsdk/workflow/workflow.js @@ -368,10 +368,10 @@ export class Workflow extends G3WObject { if (showUserMessage) { GUI.showUserMessage({ - title: 'plugins.editing.workflow.title.steps', - type: 'tool', + title: 'plugins.editing.workflow.title.steps', + type: 'tool', position: 'left', - size: 'small', + size: 'small', closable: false, hooks: { body: { diff --git a/i18n/de.js b/i18n/de.js index de265b8d..d7ad6480 100644 --- a/i18n/de.js +++ b/i18n/de.js @@ -42,6 +42,7 @@ export default { update_feature: "Feature-Attribut aktualisieren", update_multi_features: "Attribute ausgewählter Features aktualisieren", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Bearbeiten Sie Beziehungsdatensätze von einem oder mehreren übergeordneten features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/en.js b/i18n/en.js index 2b72cc7b..5f5a6cae 100644 --- a/i18n/en.js +++ b/i18n/en.js @@ -44,6 +44,7 @@ export default { update_feature: "Update feature attribute", update_multi_features: "Update attributes of selected features", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/fi.js b/i18n/fi.js index f1fd6af5..486a5126 100644 --- a/i18n/fi.js +++ b/i18n/fi.js @@ -42,6 +42,7 @@ export default { update_feature: "Päivitä ominaisuus", update_multi_features: "Muokkaa valittujen ominaisuuksien attribuutteja", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/fr.js b/i18n/fr.js index e495c1e9..4990dbd3 100644 --- a/i18n/fr.js +++ b/i18n/fr.js @@ -42,6 +42,7 @@ export default { update_feature: "Modifier les attributs des fonctionnalités", update_multi_features: "Modifier les attributs des fonctionnalités sélectionnées", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Modifier les enregistrements de relation à partir d'une ou plusieurs entités parents", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/it.js b/i18n/it.js index 9bffae24..6681e9fe 100644 --- a/i18n/it.js +++ b/i18n/it.js @@ -44,6 +44,7 @@ export default { update_feature: "Modifica attributi elemento", update_multi_features: "Modifica gli attributi degli elementi selezionati", update_multi_features_relations: "Modifica gli attributi di tutte le relazioni selezionate", + update_multi_features_relations_from_parents : "Edita i record relazionati di uno o più padri", copyfeaturefromexternallayer: "Crea elemento da un livello esterno" }, toolsoftool: { diff --git a/i18n/pl.js b/i18n/pl.js index 65f2b92c..e61416b0 100644 --- a/i18n/pl.js +++ b/i18n/pl.js @@ -39,6 +39,7 @@ export default { update_feature: "Update feature attribute", update_multi_features: "Update attributes of selected features", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/ro.js b/i18n/ro.js index 5a2a092d..3555cc26 100644 --- a/i18n/ro.js +++ b/i18n/ro.js @@ -42,6 +42,7 @@ export default { update_feature: "Actualizează atributul entității", update_multi_features: "Actualizează atributele entităților selectate", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Editați înregistrările relațiilor de la una sau mai multe caracteristici părinte", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/se.js b/i18n/se.js index 43b60a11..48663441 100644 --- a/i18n/se.js +++ b/i18n/se.js @@ -42,6 +42,7 @@ export default { update_feature: "Uppdatera egenskap", update_multi_features: "Ändra attributen för de valda funktionerna", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/icons/EditMultiRelationFeatures.png b/icons/EditMultiRelationFeatures.png new file mode 100644 index 00000000..d521c4ab Binary files /dev/null and b/icons/EditMultiRelationFeatures.png differ diff --git a/toolboxes/toolbox.js b/toolboxes/toolbox.js index b2fba5b1..847751a3 100644 --- a/toolboxes/toolbox.js +++ b/toolboxes/toolbox.js @@ -80,15 +80,21 @@ export class ToolBox extends G3WObject { constructor(layer, dependencies = []) { super(); - const is_vector = [undefined, Layer.LayerTypes.VECTOR].includes(layer.getType()); - const geometryType = is_vector && layer.getGeometryType(); - const is_point = is_vector && Geometry.isPointGeometryType(geometryType); - const is_line = is_vector && Geometry.isLineGeometryType(geometryType); - const is_poly = is_vector && Geometry.isPolygonGeometryType(geometryType); - const is_table = Layer.LayerTypes.TABLE === layer.getType(); - const isMultiGeometry = geometryType && Geometry.isMultiGeometry(geometryType); - const iconGeometry = is_vector && (is_point ? 'Point' : is_line ? 'Line' : 'Polygon'); - + const is_vector = [undefined, Layer.LayerTypes.VECTOR].includes(layer.getType()); + const geometryType = is_vector && layer.getGeometryType(); + const is_point = is_vector && Geometry.isPointGeometryType(geometryType); + const is_line = is_vector && Geometry.isLineGeometryType(geometryType); + const is_poly = is_vector && Geometry.isPolygonGeometryType(geometryType); + const is_table = Layer.LayerTypes.TABLE === layer.getType(); + const isMultiGeometry = geometryType && Geometry.isMultiGeometry(geometryType); + const iconGeometry = is_vector && (is_point ? 'Point' : is_line ? 'Line' : 'Polygon'); + //@since 3.9.0 Check if layer has relation layers editable + const editable_relations = layer.getRelations().getArray() + .filter(relation => { + const l = CatalogLayersStoresRegistry.getLayerById(getRelationId({ layerId: layer.getId(), relation })); + return l.isEditable(); + }) + .map(r => r); this._start = false; /** constraint loading features to a filter set */ @@ -103,7 +109,7 @@ export class ToolBox extends G3WObject { * _states: [ * { * id: unique key - * state: [state] // example: history contsins features state + * state: [state] // example: history contains features state * // array because a tool can apply changes to more than one features at time (split di una feature) * }, * { @@ -396,11 +402,12 @@ export class ToolBox extends G3WObject { description: `editing.workflow.steps.${ApplicationState.ismobile ? 'selectDrawBoxAtLeast2Feature' : 'selectMultiPointSHIFTAtLeast2Feature'}`, buttonnext: { disabled: true, - condition:({ features=[] }) => features.length < 2, - done: () => { Workflow.Stack.getCurrent().clearUserMessagesSteps(); } + condition:({ features = [] }) => features.length < 2, + done: () => { Workflow.Stack.getCurrent().clearUserMessagesSteps(); }, }, dynamic: 0, - done: false + done: false, + reset() { this.dynamic = 0; }, } } }), @@ -408,6 +415,160 @@ export class ToolBox extends G3WObject { ], }), }, + // @since 3.9.0 Edit Attributes of relations features to Multi features + (is_vector) && capabilities.includes('change_attr_feature') && editable_relations.filter(r => 'ONE' !== r.getType()).length > 0 && { + id: 'editmultiattributesrelationfeatures', + type: ['change_attr_feature'], + name: "editing.tools.update_multi_features_relations_from_parents", + icon: "EditMultiRelationFeatures.png", + /** ORIGINAL SOURCE: g3w-client-plugin-editing/workflows/editmultifeatureattributesworkflow.js@v3.7.1 */ + op: new Workflow({ + layer, + type: 'editmultiattributesrelationfeatures', + helpMessage: 'editing.tools.update_multi_features_relations_from_parents', + registerEscKeyEvent: true, + runOnce: true, + steps: [ + new SelectElementsStep({ + type: 'multiple', + steps: { + select: { + description: `editing.workflow.steps.${ApplicationState.ismobile ? 'selectDrawBoxAtLeast2Feature' : 'selectMultiPointSHIFTAtLeast2Feature'}`, + buttonnext: { + disabled: true, + condition: ({ features = [] }) => features.length < 2, + done: () => { Workflow.Stack.getCurrent().clearUserMessagesSteps(); } + }, + dynamic: 0, + done: false, + reset() { this.dynamic = 0; }, + } + } + }), + new Step({ + run: async (inputs, context) => { + GUI.setModal(true); + const relations = editable_relations.filter(r => 'ONE' !== r.getType()); + //get relation features from feature parent layer + await Promise.allSettled(inputs.features.map(feature => getLayersDependencyFeatures(inputs.layer.getId(), { + relations, + feature, + filterType: 'fid', + }))) + //get first relation layer id + let relationLayerId = relations[0].getChild(); + + //In case of multi relation in editing + if (relations.length > 1) { + //ser relation layer id + try { + await new Promise((resolve, reject) => { + const vueInstance = new (Vue.extend({ + name: 'multi-relations-fetures', + template: `
+ +
+ `, + data() { + return { + relations: this.$options.relations, + relationId: this.$options.relationId + } + } + }))({ relations, relationId: relations[0].state.id }) + + GUI.showModalDialog({ + title: tPlugin('editing.relations'), + className: 'modal-left', + closeButton: false, + message: vueInstance.$mount().$el, + buttons: { + cancel: { + label: 'Cancel', + className: 'btn-danger', + callback() { reject(); } + }, + ok: { + label: 'Ok', + className: 'btn-success', + callback: async () => { + //set relation layer id to editin + relationLayerId = relations.find(r => vueInstance.relationId === r.state.id).getChild(); + resolve(); + } + } + } + }).on('hide.bs.modal', () => vueInstance.$destroy()); //destroy vue instance after dialog is a closed + //hide user message step + }) + } catch(e) { + console.warn(e); + GUI.setModal(false); + return $promisify(Promise.reject(e)); + } + } + + //start child workflow + const workflow = new Workflow({ + type: 'editmultiattributes', + steps: [ + new OpenFormStep({ multi: true }), + ], + }); + //Relations layer + const rLayer = getEditingLayerById(relationLayerId); + + if (0 === rLayer.readFeatures().length) { + GUI.setModal(false); + + GUI.showUserMessage({ + type: 'warning', + message: 'plugins.editing.no_relations_found', + autoclose: true, + }) + return $promisify(Promise.reject()); + } + + const fields = getRelationFieldsFromRelation({ + layerId: relations[0].getChild(), + relation: relations[0] + }); + + const options = { + context: { + session: Workflow.Stack.getCurrent().getSession(), // get parent workflow + excludeFields: fields.ownField, // array of fields to be excluded + isContentChild: false, //@since 3.9.0 force child to flase + }, + inputs: { + features: rLayer.readFeatures(), + layer: rLayer + } + } + + try { + //set eventually unique values + await setLayerUniqueFieldValues(relationLayerId); + await promisify(workflow.start(options)); + } catch(e) { + console.warn(e); + } + + workflow.stop(); + + GUI.setModal(false); + return $promisify(Promise.resolve(inputs, context)); + } + }), + ], + }), + }, // Move Feature (is_vector) && capabilities.includes('change_feature') && { id: 'movefeature', @@ -489,7 +650,17 @@ export class ToolBox extends G3WObject { steps: [ new Step({ layer, - help: 'editing.steps.help.draw_new_feature', + //@since 3.9.0 to show user message steps + steps: { + chooselayer: { + description: `editing.modal.tools.copyfeaturefromotherlayer.title`, + done: false, + }, + selectgeometry: { + description: `editing.workflow.steps.selectPoint`, + done: false, + } + }, run(inputs, context) { return $promisify(new Promise((resolve, reject) => { const originalLayer = inputs.layer; @@ -518,36 +689,38 @@ export class ToolBox extends G3WObject { label: 'Ok', className: 'btn-success', callback: async () => { + //set choose layer step done + this.setUserMessageStepDone('chooselayer'); try { + const feature = await $promisify(async () => { //get selected layer const layer = layers.find(l => l.selected); - const feature = await $promisify(async () => { const features = await (new Promise(async resolve => { this.addInteraction( layer.external - ? new PickFeaturesInteraction({ layer: GUI.getService('map').getLayerById(layer.id) }) - : new g3wsdk.ol.interactions.PickCoordinatesInteraction(), { - 'picked': async e => { - try { - resolve(convertToGeometry( - layer.external - ? e.features // external layer - : ((await DataRouterService.getData('query:coordinates', { // TOC/PROJECT layer - inputs: { - coordinates: e.coordinate, - query_point_tolerance: ProjectsRegistry.getCurrentProject().getQueryPointTolerance(), - layerIds: [layer.id], - multilayers: false - }, - outputs: null - })).data[0] || { features: [] }).features, - geometryType, - )) - } catch(e) { - console.warn(e); - } + ? new PickFeaturesInteraction({ layer: GUI.getService('map').getLayerById(layer.id) }) + : new g3wsdk.ol.interactions.PickCoordinatesInteraction(), { + 'picked': async e => { + try { + resolve(convertToGeometry( + layer.external + ? e.features // external layer + : ((await DataRouterService.getData('query:coordinates', { // TOC/PROJECT layer + inputs: { + coordinates: e.coordinate, + query_point_tolerance: ProjectsRegistry.getCurrentProject().getQueryPointTolerance(), + layerIds: [layer.id], + multilayers: false + }, + outputs: null + })).data[0] || { features: [] }).features, + geometryType, + )) + } catch(e) { + console.warn(e); } } + } ); })); @@ -725,7 +898,8 @@ export class ToolBox extends G3WObject { feature.getGeometry().translate(deltaXY.x, deltaXY.y) } // set media fields to null - layer.getEditingMediaFields({}).forEach(f => feature.set(f, null)); + //@since 3.9.0 Comment + //layer.getEditingMediaFields({}).forEach(f => feature.set(f, null)); /** * evaluated geometry expression */ @@ -1115,48 +1289,6 @@ export class ToolBox extends G3WObject { registerEscKeyEvent: true }), }, - // Copy Features from external layer - (is_line || is_poly) && capabilities.includes('add_feature') && { - id: 'copyfeaturefromexternallayer', - type: ['add_feature'], - name: "editing.tools.copyfeaturefromexternallayer", - icon: "copyPolygonFromFeature.png", - visible: tool => { - const map = GUI.getService('map'); - const type = this.getLayer().getGeometryType(); - const has_same_geom = layer => { - // check if tool is visible and the layer is a Vector - const features = 'VECTOR' === layer.getType() && layer.getSource().getFeatures(); - return features && features.length ? isSameBaseGeometryType(features[0].getGeometry().getType(), type) : true; - }; - map.onbefore('loadExternalLayer', layer => !tool.visible && (tool.visible = has_same_geom(layer))); - map.onafter('unloadExternalLayer', layer => { - const features = tool.visible && 'VECTOR' === layer.getType() && layer.getSource().getFeatures(); - if (features && features.length && isSameBaseGeometryType(features[0].getGeometry().getType(), type)) { - tool.visible = map.getExternalLayers().find(l => undefined !== has_same_geom(l)); - } - }); - return false; - }, - /** ORIGINAL SOURCE: g3w-client-plugin-editing/workflows/addfeaturefrommapvectorlayersworkflow.js@v3.7.1 */ - op: new Workflow({ - layer, - type: 'addfeaturefrommapvectorlayers', - runOnce: true, - steps: [ - new SelectElementsStep({ - layer, - type: 'external', - help: 'editing.steps.help.copy' - }, false), - new OpenFormStep({ - layer, - help: 'editing.steps.help.copy' - }), - ], - registerEscKeyEvent: true - }), - }, // Add Table feature (alphanumerical layer - No geometry) is_table && capabilities.includes('add_feature') && { id: 'addfeature', @@ -1197,7 +1329,7 @@ export class ToolBox extends G3WObject { this.state._tools.forEach(tool => { Object.assign(tool, { disabledtoolsoftools: [], - enabled: false, + enabled: !!tool.enabled, active: false, message: null, messages: tool.op.getMessages(), @@ -1496,7 +1628,7 @@ export class ToolBox extends G3WObject { this.startLoading(); this.setFeaturesOptions({ filter }); try { - handlerAfterSessionGetFeatures(await promisify(this._session.start(this.state._getFeaturesOption))) + await handlerAfterSessionGetFeatures(promisify(this._session.start(this.state._getFeaturesOption))) } catch(e) { console.warn(e); this.setEditing(false); @@ -1509,12 +1641,12 @@ export class ToolBox extends G3WObject { if (!is_started && !GIVE_ME_A_NAME) { this._start = true; this.startLoading(); - this._session.start(this.state._getFeaturesOption).then(handlerAfterSessionGetFeatures) + await handlerAfterSessionGetFeatures(promisify(this._session.start(this.state._getFeaturesOption))) } if (is_started && !this._start) { this.startLoading(); - this._session.getFeatures(this.state._getFeaturesOption).then(handlerAfterSessionGetFeatures); + await handlerAfterSessionGetFeatures(promisify(this._session.getFeatures(this.state._getFeaturesOption))) this._start = true; } @@ -1554,9 +1686,6 @@ export class ToolBox extends G3WObject { //eventually reset start resolve feature waiting promise this.startResolve = null; - //set start to false - this._start = false - this.state.editing.on = false; if (this.state._constraints.scale) { this._handleScaleConstraint(true); @@ -1596,6 +1725,9 @@ export class ToolBox extends G3WObject { try { await promisify(this._session.stop()); + //set start to false + this._start = false + this.state.editing.on = false; this.state.enabled = false; this.stopLoading(); this.state._getFeaturesOption = {}; @@ -1606,7 +1738,7 @@ export class ToolBox extends G3WObject { // clear layer unique field values g3wsdk.core.plugin.PluginsRegistry.getPlugin('editing').state.uniqueFieldsValues[this.getId()] = {}; return true; - } catch (e) { + } catch(e) { console.warn(e); return Promise.reject(e); } @@ -1660,16 +1792,16 @@ export class ToolBox extends G3WObject { return; } - const { new_relations = {} } = response.response; // check if new relations are saved on server + const { relations = {} } = response.response; // check if relations are saved on server // sync server data with local data - for (const id in new_relations) { + for (const id in relations) { const toolbox = ToolBox.get(id) toolbox .getSession() .getEditor() .applyCommitResponse({ // apply commit response to current editing relation layer - response: new_relations[id], + response: relations[id], result: true }); } @@ -1771,7 +1903,7 @@ export class ToolBox extends G3WObject { * * @param bool */ - setEditing(bool=true) { + setEditing(bool = true) { this.setEnable(bool); this.state.editing.on = bool; this.enableTools(bool); @@ -1796,7 +1928,7 @@ export class ToolBox extends G3WObject { * * @returns {boolean} */ - setEnable(bool=false) { + setEnable(bool = false) { this.state.enabled = bool; return this.state.enabled; } @@ -1999,9 +2131,9 @@ export class ToolBox extends G3WObject { const disabledtools = this.state._disabledtools || []; tools .forEach(tool => { - const enabled = undefined !== tool.enable ? tool.enable : bool; - tool.enabled = (bool && disabledtools.length) - ? disabledtools.indexOf(tool.getId()) === -1 + const enabled = undefined === tool.enable ? bool : tool.enable; + tool.enabled = (bool && disabledtools.length > 0) + ? !disabledtools.includes(tool.getId()) : toRawType(enabled) === 'Boolean' ? enabled : enabled({ bool, tool }); @@ -2766,11 +2898,11 @@ export class ToolBox extends G3WObject { if ((Layer.LayerTypes.VECTOR === this.state._layerType) && this.state._getFeaturesOption.filter.bbox) { const fnc = () => { if ( - //added ApplicationState.online - ApplicationState.online - && this.state.editing.canEdit - && this.state.selected //need to be selected - && 0 === GUI.getContentLength() + //added ApplicationState.online + ApplicationState.online + && this.state.editing.canEdit + && this.state.selected //need to be selected + && 0 === GUI.getContentLength() ) { this.state._getFeaturesOption.filter.bbox = GUI.getService('map').getMapBBOX(); this.state.loading = true; @@ -2805,7 +2937,6 @@ export class ToolBox extends G3WObject { console.warn(e); return Promise.reject(e); } finally { - if (!this.inEditing()) { return; } if (ApplicationState.online) { this._stopSessionChildren(this.state.id); } diff --git a/utils/handleSplitFeature.js b/utils/handleSplitFeature.js index 84e2a0fc..74362c30 100644 --- a/utils/handleSplitFeature.js +++ b/utils/handleSplitFeature.js @@ -52,7 +52,8 @@ export async function handleSplitFeature({ newFeature.setGeometry(splittedGeometry); // set media fields to null - layer.getEditingMediaFields({}).forEach(f => newFeature.set(f, null)); + //@since 3.9.0 Commented + //layer.getEditingMediaFields({}).forEach(f => newFeature.set(f, null)); feature = new Feature({ feature: newFeature }); diff --git a/workflows/index.js b/workflows/index.js index 2ebb81b3..ce07a906 100644 --- a/workflows/index.js +++ b/workflows/index.js @@ -403,7 +403,8 @@ export class OpenFormStep extends Step { */ run(inputs, context) { const promise = new Promise(async (resolve, reject) => { - this._isContentChild = Workflow.Stack.getLength() > 1; + //@since 3.9.0 can set isContentChild attribute to force it (case edit relation features from multi parent features) + this._isContentChild = undefined === context.isContentChild ? Workflow.Stack.getLength() > 1 : context.isContentChild; this.layerId = inputs.layer.getId(); GUI.setLoadingContent(false); @@ -479,7 +480,7 @@ export class OpenFormStep extends Step { formStructure: inputs.layer.hasFormStructure() && inputs.layer.getLayerEditingFormStructure() || undefined, modal: true, push: this._options.push || this._isContentChild, /** @since v3.7 force push content on top without clear previous content */ - showgoback: undefined !== this._options.showgoback ? this._options.showgoback : !this._isContentChild, /** @since v3.7 force show back button */ + showgoback: undefined === this._options.showgoback ? !this._isContentChild : this._options.showgoback, /** @since v3.7 force show back button */ /** @TODO make it straightforward: `headerComponent` vs `buttons` ? */ headerComponent: this._saveAll && { template: /* html */ ` @@ -603,7 +604,6 @@ export class OpenFormStep extends Step { // skip when no fields if (0 === fields.length) { - GUI.setModal(false); resolve(inputs); return; } @@ -649,7 +649,10 @@ export class OpenFormStep extends Step { this.fireEvent(`savedfeature_${this.layerId}`, newFeatures); // called after saved using layerId // In case of save of child it means that child is updated so also parent if (this._isContentChild) { - Workflow.Stack.getParents().forEach(w => w.getContextService().setUpdate(true, { force: true })); + Workflow.Stack.getParents() + //filter only with has getContextService to be sure + .filter(w => w.getContextService() && w.getContextService().setUpdate) + .forEach(w => w.getContextService().setUpdate(true, { force: true })); } //@TODO add field unique new value id not set resolve(inputs); @@ -772,11 +775,11 @@ export class OpenFormStep extends Step { const contextService = is_parent_table && Workflow.Stack.getCurrent().getContextService(); // force update parent form update - if (contextService && false === this._isContentChild) { + if (contextService && contextService.setUpdate && false === this._isContentChild) { contextService.setUpdate(false, { force: false }); } - - GUI.closeForm({ pop: this.push || this._isContentChild }); + //@since 3.9.0 add GUI.getContentLength() in case of edit multi relationfeatures tool + GUI.closeForm({ pop: this.push || this._isContentChild && GUI.getContentLength() > 1 }); g3wsdk.core.plugin.PluginsRegistry.getPlugin('editing').resetCurrentLayout(); @@ -1092,6 +1095,7 @@ export class SelectElementsStep extends Step { } stop() { + Object.values(this.getSteps() || {}).forEach(s => s.reset && s.reset() ); this._selectInteractions.forEach(i => this.removeInteraction(i)); if (this._vectorLayer) {