• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

compassinformatics / cpsi-mapview / 15022980938

14 May 2025 02:11PM UTC coverage: 26.333% (+0.04%) from 26.29%
15022980938

push

github

geographika
Move describe to test globals

492 of 2344 branches covered (20.99%)

Branch coverage included in aggregate %.

1464 of 5084 relevant lines covered (28.8%)

1.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.88
/app/controller/button/SplitByClickButtonController.js
1
/**
2
 * This class is the controller for the SplitByClick button.
3
 */
4
Ext.define('CpsiMapview.controller.button.SplitByClickButtonController', {
1✔
5
    extend: 'Ext.app.ViewController',
6
    requires: [
7
        'BasiGX.util.Map',
8
        'GeoExt.component.FeatureRenderer',
9
        'GeoExt.data.store.Features'
10
    ],
11

12
    alias: 'controller.cmv_split_by_click_button',
13

14
    /**
15
     * The OpenLayers map. If not given, will be auto-detected
16
     */
17
    map: null,
18

19
    /**
20
     * The BasiGX mapComponent. If not given, will be auto-detected
21
     */
22
    mapComponent: null,
23

24
    /**
25
     * Temporary vector layer used to display the response split features
26
     */
27
    resultLayer: null,
28

29
    constructor: function () {
30
        const me = this;
5✔
31
        me.splitOnClickedPosition = me.splitOnClickedPosition.bind(me);
5✔
32

33
        me.callParent(arguments);
5✔
34
    },
35

36
    /**
37
     * Set the layer used to store features returned by the split service
38
     * @param {ol.Layer} layer
39
     */
40
    setResultLayer: function (layer) {
41
        const me = this;
×
42

43
        if (!me.map) {
×
44
            return;
×
45
        }
46

47
        if (me.resultLayer) {
×
48
            me.map.removeLayer(me.resultLayer);
×
49
        }
50

51
        me.resultLayer = layer;
×
52
    },
53

54
    /**
55
     * Main handler which activates or deactivates the click listener for the
56
     * map.
57
     *
58
     * @param {Ext.button.Button} btn The button that has been pressed
59
     * @param {boolean} pressed The toggle state of the button
60
     */
61
    onToggle: function (btn, pressed) {
62
        const me = this;
×
63
        const view = me.getView();
×
64

65
        // guess the map if not given
66
        if (!me.map) {
×
67
            me.map = BasiGX.util.Map.getMapComponent().map;
×
68
        }
69

70
        // create a result layer unless one has already been set
71
        if (!me.resultLayer) {
×
72
            me.resultLayer = view.resultLayer;
×
73
        }
74

75
        if (pressed) {
×
76
            me.map.on('click', me.splitOnClickedPosition);
×
77
        } else {
78
            me.map.un('click', me.splitOnClickedPosition);
×
79
        }
80
    },
81

82
    /**
83
     * Asynchronously request and proceed split features depending on clicked
84
     * position.
85
     *
86
     * @param {Event} evt OpenLayers click event
87
     * @returns {Ext.Promise<any|undefined>}
88
     */
89
    splitOnClickedPosition: function (evt) {
90
        const me = this;
×
91
        const map = me.map;
×
92
        const proj = map.getView().getProjection().getCode();
×
93
        const coordinates = evt.coordinate;
×
94
        const point = new ol.Feature(new ol.geom.Point(coordinates));
×
95
        const extent = point.getGeometry().getExtent();
×
96
        const associatedWin = this.getView().up('window');
×
97
        const associatedVm = associatedWin.getViewModel();
×
98
        const parentId = associatedVm.get('currentRecord.publicPrivateSplitId');
×
99
        const buffered = ol.extent.buffer(
×
100
            extent,
101
            me.getView().getPointExtentBuffer()
102
        );
103
        // transform to ITM since this projection is expected by backend.
104
        const bufferedITM = ol.proj.transformExtent(
×
105
            buffered,
106
            proj,
107
            'EPSG:2157'
108
        );
109
        const bboxSearchParam =
110
            '&bbox=' + encodeURIComponent(bufferedITM.join(','));
×
111
        let idParam = 'publicPrivateSplitId=';
×
112

113
        if (isNaN(parentId)) {
×
114
            // we're going to create a new split
115
            idParam += '0';
×
116
        } else {
117
            // we're going to edit the existing one
118
            idParam += parentId;
×
119
        }
120
        const searchParams = idParam + bboxSearchParam;
×
121

122
        return me
×
123
            .doAjaxRequest(searchParams)
124
            .then(me.parseSplitResponse.bind(me))
125
            .then(me.handleFinalResult.bind(me));
126
    },
127

128
    /**
129
     * Parses the split result to OpenLayers features
130
     *
131
     * @param {XMLHttpRequest} response
132
     * @returns {ol.Feature[]}
133
     */
134
    parseSplitResponse: function (response) {
135
        if (response) {
×
136
            let json;
137

138
            if (!Ext.isEmpty(response.responseText)) {
×
139
                try {
×
140
                    json = Ext.decode(response.responseText);
×
141
                } catch (e) {
142
                    BasiGX.error(
×
143
                        'Could not parse the response: ' + response.responseText
144
                    );
145
                    Ext.log.error(e);
×
146
                    return;
×
147
                }
148

149
                if (json.success && json.data) {
×
150
                    const existingPpSplitId =
151
                        json.data.existingPublicPrivateSplitId;
×
152
                    if (existingPpSplitId !== null) {
×
153
                        this.handleExistingSplit(existingPpSplitId);
×
154
                    } else {
155
                        const splitEdgeFeats = json.data.splitEdgeFeatures;
×
156
                        if (
×
157
                            splitEdgeFeats.features &&
×
158
                            splitEdgeFeats.features.length === 2
159
                        ) {
160
                            const format = new ol.format.GeoJSON();
×
161
                            return format.readFeaturesFromObject(
×
162
                                splitEdgeFeats
163
                            );
164
                        }
165
                    }
166
                } else {
167
                    BasiGX.error(
×
168
                        'Could not perform the split: ' +
169
                            (json.message ? json.message : JSON.stringify(json))
×
170
                    );
171
                }
172
            } else {
173
                BasiGX.error(
×
174
                    'Could not perform the split: ' +
175
                        (json.message ? json.message : JSON.stringify(json))
×
176
                );
177
            }
178
        } else {
179
            BasiGX.error('Response was empty');
×
180
        }
181
    },
182

183
    /**
184
     * Issues an Ext.Ajax.request against the configured endpoint with
185
     * the given params.
186
     *
187
     * @param {string} searchParams The serarchParams which will be
188
     *   appended to the request url
189
     * @returns {Ext.request.Base}
190
     */
191
    doAjaxRequest: function (searchParams) {
192
        const me = this;
×
193
        const mapComponent =
194
            me.mapComponent || BasiGX.util.Map.getMapComponent();
×
195
        const view = me.getView();
×
196
        let url = view.getApiUrl();
×
197

198
        if (!url) {
×
199
            Ext.log.warn('No API URL passed - split is not possible.');
×
200
            return;
×
201
        }
202

203
        if (searchParams) {
×
204
            url = Ext.urlAppend(url, searchParams);
×
205
        }
206

207
        mapComponent.setLoading(true);
×
208

209
        return new Ext.Promise(function (resolve) {
×
210
            Ext.Ajax.request({
×
211
                url: url,
212
                method: 'GET',
213
                success: function (response) {
214
                    mapComponent.setLoading(false);
×
215
                    resolve(response);
×
216
                },
217
                failure: function (response) {
218
                    mapComponent.setLoading(false);
×
219

220
                    if (response.aborted !== true) {
×
221
                        let errorMessage =
222
                            'Error while requesting the API endpoint';
×
223

224
                        if (
×
225
                            response.responseText &&
×
226
                            response.responseText.message
227
                        ) {
228
                            errorMessage +=
×
229
                                ': ' + response.responseText.message;
230
                        }
231

232
                        BasiGX.error(errorMessage);
×
233
                    }
234
                }
235
            });
236
        });
237
    },
238

239
    /**
240
     * Show confirm dialog to decide, whether the found existing split should be
241
     * opened for edit.
242
     * @param {number} splitId
243
     */
244
    handleExistingSplit: function (splitId) {
245
        const msg =
246
            'This edge has already been split. Open existing split record?';
×
247
        const me = this;
×
248

249
        BasiGX.confirm(msg, {
×
250
            title: 'Open Existing Split?',
251
            fn: function (buttonId) {
252
                if (buttonId === 'yes') {
×
253
                    const win = me.getView().up('window');
×
254
                    win.fireEvent('splitedgesupdate', splitId);
×
255
                }
256
            }
257
        });
258
    },
259

260
    /**
261
     * Handles the final result from endopoint. Refreshes the result layer with
262
     * retrieved split features.
263
     *
264
     * @param {undefined|ol.Feature[]} features The features returned from the API.
265
     */
266
    handleFinalResult: function (features) {
267
        if (features) {
×
268
            const me = this;
×
269
            const resultSource = me.resultLayer.getSource();
×
270
            resultSource.clear();
×
271
            resultSource.addFeatures(features);
×
272
        }
273
    },
274

275
    /**
276
     * Remove the result layer when this component gets destroyed.
277
     */
278
    onBeforeDestroy: function () {
279
        const me = this;
×
280
        const btn = me.getView();
×
281

282
        // detoggle button
283
        me.onToggle(btn, false);
×
284

285
        if (me.resultLayer) {
×
286
            me.map.removeLayer(me.resultLayer);
×
287
        }
288
    }
289
});
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc