Completed
Push — master ( f2c63f...720388 )
by Donata
02:09
created

src/javascript/blocks/maps/modules/GoogleMapEditor.js   A

Size

Lines of Code 341

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
nc 1
dl 0
loc 341
rs 10
noi 26
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A GoogleMapEditor.js ➔ ??? 0 71 1
1
import {createNavigationButton} from '../functions/createNavigationButton';
2
import {createAddnewContainer} from '../functions/createAddnewContainer';
3
import {createEditorContainer} from '../functions/createEditorContainer';
4
import {createRandomId} from '../functions/createRandomId';
5
import Marker from './Marker';
6
7
class GoogleMapEditor {
8
9
    constructor(container, options = {}) {
10
        this._instance = null;
11
        this._container = container;
12
        this._markers = [];
13
        this._options = {};
14
        this._navigationButton = null;
15
16
        this._defaults = {
17
            map: {
18
                center: {
19
                    lat: 55.1309504,
20
                    lng: 24.5499231
21
                },
22
                zoom: 7,
23
                scrollwheel: false,
24
                navigationControl: true,
25
                mapTypeControl: false,
26
                scaleControl: true,
27
                draggable: true,
28
                streetViewControl: false
29
            },
30
            sprite: 'assets/images/sprite.png',
31
            closures: {
32
                onLoad: function (instance) {
0 ignored issues
show
Unused Code introduced by
The parameter instance is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
33
34
                },
35
36
                onClickNavigationButton: function (instance) {
37
                    instance.onClickNavigationButton();
38
                },
39
40
                onMarkerClick: function (instance, marker) {
41
                    instance.onMarkerClick(marker);
42
                },
43
44
                onMarkerPlaced: function (instance, marker) {
0 ignored issues
show
Unused Code introduced by
The parameter instance is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter marker is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
45
46
                },
47
48
                onMarkerSave: function (instance, marker) {
0 ignored issues
show
Unused Code introduced by
The parameter marker is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter instance is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
49
50
                },
51
52
                onMarkerDelete: function (instance, marker) {
0 ignored issues
show
Unused Code introduced by
The parameter marker is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter instance is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
53
54
                },
55
56
                onZoomChanged: function (instance, zoomLevel) {
0 ignored issues
show
Unused Code introduced by
The parameter instance is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter zoomLevel is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
57
58
                },
59
60
                onCoordinatesChanged: function (instance, coordinates) {
0 ignored issues
show
Unused Code introduced by
The parameter coordinates is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter instance is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
61
62
                },
63
            },
64
            translations: {
65
                close: 'Close',
66
                address: 'Type your address',
67
                editMarker: 'Edit marker',
68
                displayInfo: 'Display info window?',
69
                content: 'Content',
70
                delete: 'Delete',
71
                save: 'Save'
72
            }
73
        };
74
75
        this.populateOptions(options);
76
        this.createInstance();
77
        this.populateMarkers();
78
        this.bindEvents();
79
    }
80
81
    getOptions() {
82
        return this._options;
83
    }
84
85
    bindEvents() {
86
        google.maps.event.addListenerOnce(this._instance, 'tilesloaded', () => {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
87
            this._options.closures.onLoad(this);
88
89
            let sprite = this._options.sprite;
90
            let container = this._container;
91
92
            this._navigationButton = createNavigationButton(sprite, container);
93
94
            // initialize navigation button events
95
            this._navigationButton.addEventListener('click', () => {
96
                this._options.closures.onClickNavigationButton(this);
97
            });
98
        });
99
100
        google.maps.event.addListener(this._instance, 'zoom_changed', () => {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
101
            this._options.closures.onZoomChanged(this, this._instance.getZoom());
102
        });
103
104
        google.maps.event.addListener(this._instance, 'dragend', () => {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
105
            let center = this._instance.getCenter();
106
            this._options.closures.onCoordinatesChanged(this._instance, `${center.lat()},${center.lng()}`);
107
        });
108
109
        google.maps.event.addListener(this._instance, 'click', (event) => {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
110
            this.placeMarker(event.latLng);
111
        });
112
    }
113
114
    onClickNavigationButton() {
115
        let container = createAddnewContainer(this._container, this._options.translations);
116
        let addressField = container.querySelector('input[name="address"]');
117
118
        addressField.focus();
119
120
        let searchBox = this.createSearchBox(addressField);
121
122
        searchBox.addListener('places_changed', () => {
123
            let places = searchBox.getPlaces();
124
125
            if (places.length == 0) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
126
127
            let bounds = new google.maps.LatLngBounds();
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
128
129
            places.forEach(place => {
130
                if (!place.geometry) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
131
132
                this.placeMarker(place.geometry.location, {address: place.formatted_address});
133
134
                if (place.geometry.viewport) {
135
                    bounds.union(place.geometry.viewport);
136
                } else {
137
                    bounds.extend(place.geometry.location);
138
                }
139
            });
140
141
            this._instance.fitBounds(bounds);
142
            container.parentNode.removeChild(container);
143
        });
144
    }
145
146
    collectFieldsData(container) {
147
        return {
148
            content: container.querySelector('textarea[name="content"]').value,
149
            displayWindow: container.querySelector('input[type="checkbox"]').checked
150
        };
151
    }
152
153
    onMarkerClick(marker) {
154
        if (!(marker instanceof Marker)) {
155
            return;
156
        }
157
158
        let container = createEditorContainer(this._container, this._options.translations, {
159
            address: marker.options.address,
160
            content: marker.options.content,
161
            displayWindow: marker.options.displayWindow
162
        });
163
164
        let searchBox = this.createSearchBox(container.querySelector('input[name="address"]'), container, false, marker);
165
        let bounds = null;
166
167
        searchBox.addListener('places_changed', () => {
168
            let places = searchBox.getPlaces();
169
170
            bounds = new google.maps.LatLngBounds();
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
171
172
            places.forEach(place => {
173
                if (!place.geometry) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
174
175
                marker.temporary = Object.assign(marker.temporary, {
176
                    location: place.geometry.location,
177
                    address: place.formatted_address
178
                });
179
180
                if (place.geometry.viewport) {
181
                    bounds.union(place.geometry.viewport);
182
                } else {
183
                    bounds.extend(place.geometry.location);
184
                }
185
            });
186
        });
187
188
        container.querySelector('button[name="save"]').addEventListener('click', () => {
189
            let data = this.collectFieldsData(container);
190
            // save all temporary object to options and fit bounds if location was changed
191
            marker.options = Object.assign(marker.options, marker.temporary, data);
192
193
            if ('location' in marker.temporary) {
194
                marker.instance.setPosition(marker.options.location);
195
                this._instance.fitBounds(bounds);
196
            }
197
198
            if ('content' in data) {
199
                marker.instance.infoWindow.setContent(data.content);
200
            }
201
202
            marker.temporary = {};
203
204
            this._options.closures.onMarkerSave(this, marker);
205
206
            container.parentNode.removeChild(container);
207
        });
208
209
        container.querySelector('button[name="delete"]').addEventListener('click', () => {
210
            this._options.closures.onMarkerDelete(this, marker);
211
            this.removeMarker(marker);
212
            container.parentNode.removeChild(container);
213
        });
214
    }
215
216
    createSearchBox(inputField) {
217
        return new google.maps.places.SearchBox(inputField);
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
218
    }
219
220
    populateOptions(options = {}) {
221
        if ('map' in options) {
222
            options.map = Object.assign(this._defaults.map, options.map);
223
        }
224
225
        if ('closures' in options) {
226
            options.closures = Object.assign(this._defaults.closures, options.closures);
227
        }
228
229
        this._options = Object.assign(this._defaults, options);
230
231
        let data = this.getJSONOrEmpty(this._container.getAttribute('data-options'));
232
233
        if ('map' in data) {
234
            this._options.map = Object.assign(this._options.map, data.map);
235
            delete data['map'];
236
        }
237
238
        if ('closures' in data) {
239
            this._options.closures = Object.assign(this._options.closures, data.closures);
240
            delete data['closures'];
241
        }
242
243
        this._options = Object.assign(this._options, data);
244
    }
245
246
    populateMarkers() {
247
        let markers = this.getJSONOrEmpty(this._container.getAttribute('data-markers'));
248
249
        if(markers) {
250
            markers.forEach(marker => {
251
                let coordinates = marker.coordinates.split(',').map(Number).filter(x => !isNaN(x));
252
253
                this.placeMarker(new google.maps.LatLng(coordinates[0], coordinates[1]), {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
254
                    address: marker.address || '',
255
                    content: marker.content || '',
256
                    displayWindow: marker.displayWindow,
257
                    instanceId: marker.instanceId
258
                }, false);
259
            });
260
        }
261
    }
262
263
    createInstance() {
264
        this._instance = new google.maps.Map(this._container, this._options.map);
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
265
    }
266
267
    placeMarker(location, settings = {}, useClosure = true) {
268
        let icons = {
269
            default: new google.maps.MarkerImage(
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
270
                this._options.sprite,
271
                new google.maps.Size(26, 32),
272
                new google.maps.Point(0, 32)
273
            ),
274
            active: new google.maps.MarkerImage(
275
                this._options.sprite,
276
                new google.maps.Size(26, 32),
277
                new google.maps.Point(32, 32)
278
            )
279
        };
280
281
        let marker = new Marker(Object.assign({
282
            instanceId: createRandomId(),
283
            markerImage: icons.default,
284
            location: location,
285
            draggable: true,
286
            infoWindowOn: 'hover',
287
            events: {
288
                onMouseover: (currentMarker) => {
289
                    currentMarker.instance.setIcon(icons.active);
290
                },
291
292
                onMouseout: (currentMarker) => {
293
                    currentMarker.instance.setIcon(icons.default);
294
                }
295
            }
296
        }, settings), this._instance);
297
298
        google.maps.event.addListener(marker.instance, 'click', () => {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
299
            this._options.closures.onMarkerClick(this, marker);
300
        });
301
302
        google.maps.event.addListener(marker.instance, 'dragend', () => {
0 ignored issues
show
Bug introduced by
The variable google seems to be never declared. If this is a global, consider adding a /** global: google */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
303
            this._options.closures.onMarkerSave(this, marker);
304
        });
305
306
        if (useClosure) {
307
            this._options.closures.onMarkerPlaced(this, marker);
308
        }
309
310
        this._markers.push(marker);
311
    }
312
313
    removeMarker(marker) {
314
        marker.instance.setMap(null);
315
        let key = false;
316
317
        this._markers.forEach((item, index) => {
318
            if (marker.instanceId == item.instanceId) {
319
                key = index;
320
            }
321
        });
322
323
        if (!isNaN(key)) {
324
            delete this._markers[key];
325
        }
326
    }
327
328
    getMarkers() {
329
        return this._markers;
330
    }
331
332
    getJSONOrEmpty(input) {
333
        if (typeof input == 'undefined' || input == '') {
334
            return {};
335
        }
336
337
        return JSON.parse(input);
338
    }
339
}
340
341
export default GoogleMapEditor;