neo.mjs 4.4.13 → 4.4.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
- import Button from '../../../../src/button/Base.mjs';
2
- import GoogleMapsComponent from '../../../../src/component/wrapper/GoogleMaps.mjs';
1
+ import Button from '../../../../node_modules/neo.mjs/src/button/Base.mjs';
2
+ import NumberField from '../../../../node_modules/neo.mjs/src/form/field/Number.mjs';
3
+ import Toolbar from '../../../../node_modules/neo.mjs/src/toolbar/Base.mjs';
4
+ import Viewport from '../../../../node_modules/neo.mjs/src/container/Viewport.mjs';
5
+ import MapComponent from "./MapComponent.mjs";
3
6
  import MainContainerController from './MainContainerController.mjs';
4
- import NumberField from '../../../../src/form/field/Number.mjs';
5
- import Toolbar from '../../../../src/toolbar/Base.mjs';
6
- import Viewport from '../../../../src/container/Viewport.mjs';
7
7
 
8
8
  /**
9
9
  * @class Neo.examples.component.wrapper.googleMaps.MainContainer
@@ -17,25 +17,9 @@ class MainContainer extends Viewport {
17
17
  layout : {ntype: 'vbox', align: 'stretch'},
18
18
 
19
19
  items: [{
20
- module : GoogleMapsComponent,
20
+ module : MapComponent,
21
21
  flex : 1,
22
- reference: 'google-maps-component',
23
-
24
- listeners: {
25
- zoomChange: 'onMapZoomChance'
26
- },
27
-
28
- markerStoreConfig: {
29
- data: [{
30
- id : '1',
31
- position: {lat: -33.397, lng: 150.644},
32
- title : 'Hello neo'
33
- }, {
34
- id : '2',
35
- position: {lat: -34.397, lng: 150.644},
36
- title : 'Hello Max'
37
- }]
38
- }
22
+ reference: 'google-maps-component'
39
23
  }, {
40
24
  module: Toolbar,
41
25
  flex : 'none',
@@ -46,6 +30,12 @@ class MainContainer extends Viewport {
46
30
  height : 27,
47
31
  iconCls: 'fa-solid fa-plane',
48
32
  text : 'Fly to San Fran'
33
+ }, {
34
+ module : Button,
35
+ handler: 'onFlyToIslandButtonClick',
36
+ height : 27,
37
+ iconCls: 'fa-solid fa-plane',
38
+ text : 'Fly to Island'
49
39
  }, {
50
40
  module : NumberField,
51
41
  clearToOriginalValue: true,
@@ -56,7 +46,7 @@ class MainContainer extends Viewport {
56
46
  maxValue : 10,
57
47
  reference : 'zoom-field',
58
48
  style : {marginLeft: '10px'},
59
- value : 8,
49
+ value : 6,
60
50
  width : 100
61
51
  }, {
62
52
  module : Button,
@@ -65,7 +55,7 @@ class MainContainer extends Viewport {
65
55
  iconCls: 'fa-solid fa-trash',
66
56
  mode : 'hide',
67
57
  style : {marginLeft: '10px'},
68
- text : 'Hide marker 1'
58
+ text : 'Hide marker'
69
59
  }]
70
60
  }]
71
61
  }}
@@ -1,4 +1,4 @@
1
- import ComponentController from '../../../../src/controller/Component.mjs';
1
+ import ComponentController from '../../../../node_modules/neo.mjs/src/controller/Component.mjs';
2
2
 
3
3
  /**
4
4
  * @class Neo.examples.component.wrapper.googleMaps.MainContainerController
@@ -20,6 +20,13 @@ class MainContainerController extends ComponentController {
20
20
  this.getReference('google-maps-component').panTo({lat: 37.655, lng: -122.4175})
21
21
  }
22
22
 
23
+ /**
24
+ * @param {Object} data
25
+ */
26
+ onFlyToIslandButtonClick(data) {
27
+ this.getReference('google-maps-component').panTo({ lat: 64.963051,lng: -19.020835})
28
+ }
29
+
23
30
  /**
24
31
  * @param {Object} data
25
32
  */
@@ -38,18 +45,18 @@ class MainContainerController extends ComponentController {
38
45
  button.set({
39
46
  iconCls: 'fa fa-location-dot',
40
47
  mode : 'show',
41
- text : 'Show marker 1'
48
+ text : 'Show marker'
42
49
  });
43
50
 
44
- map.hideMarker('1')
51
+ map.hideMarker('-13')
45
52
  } else {
46
53
  button.set({
47
54
  iconCls: 'fa-solid fa-trash',
48
55
  mode : 'hide',
49
- text : 'Hide marker 1'
56
+ text : 'Hide marker'
50
57
  });
51
58
 
52
- map.showMarker('1')
59
+ map.showMarker('-13')
53
60
  }
54
61
  }
55
62
 
@@ -0,0 +1,168 @@
1
+ import GoogleMapsComponent from '../../../../node_modules/neo.mjs/src/component/wrapper/GoogleMaps.mjs';
2
+ import MapComponentController from "./MapComponentController.mjs";
3
+ import MarkerPopup from "./MarkerPopup.mjs";
4
+
5
+ /**
6
+ * @class Neo.examples.component.wrapper.googleMaps.MapComponent
7
+ * @extends Neo.component.wrapper.GoogleMaps
8
+ */
9
+ class MapComponent extends GoogleMapsComponent {
10
+ static getConfig() {return {
11
+ className: 'Neo.examples.component.wrapper.googleMaps.MapComponent',
12
+ ntype: 'worldmap',
13
+
14
+ controller: MapComponentController,
15
+
16
+ // Center the map initially to Island
17
+ center: {
18
+ lat: 64.963051,
19
+ lng: -19.020835
20
+ },
21
+
22
+ // Ensure only Island is visible
23
+ zoom: 6,
24
+
25
+ // Adding record to keep the original data
26
+ markerStore: {
27
+ model: {
28
+ fields: [{
29
+ name: 'id',
30
+ type: 'Number'
31
+ }, {
32
+ name: 'icon',
33
+ type: 'Object'
34
+ }, {
35
+ name: 'position',
36
+ type: 'Object'
37
+ }, {
38
+ name: 'record',
39
+ type: 'Object'
40
+ }, {
41
+ name: 'title',
42
+ type: 'String'
43
+ }]
44
+ }
45
+ },
46
+
47
+ onMarkerClick(data) {
48
+ let me = this,
49
+ record = data.record.record,
50
+ event = data.event;
51
+
52
+ me.disabled = true;
53
+
54
+ me.dialog = Neo.create(MarkerPopup, {
55
+ appName : me.appName,
56
+ record : record,
57
+ domEvent : data.domEvent,
58
+ boundaryContainerId : me.id
59
+ });
60
+ },
61
+
62
+ // todo Not working
63
+ // listeners: {
64
+ // zoomChange: 'onMapZoomChance'
65
+ // }
66
+ }}
67
+
68
+ construct(config) {
69
+ super.construct(config);
70
+
71
+ this.fetchData();
72
+ }
73
+
74
+ /**
75
+ * Ajax request to get the Marker Data
76
+ */
77
+ fetchData() {
78
+ let me = this,
79
+ url = '../../../../examples/component/wrapper/googleMaps/earthquakes.json',
80
+ callbackFn = me.createMarkersAndAddToMarkerStore.bind(me);
81
+
82
+ fetch(url)
83
+ .then(response => response.json())
84
+ .catch(err => console.log("Can't access + url, err"))
85
+ .then(data => callbackFn(data));
86
+ }
87
+
88
+ /**
89
+ * Create Marker records from the Server result and
90
+ * push all Markers to the MarkerStore
91
+ *
92
+ * @param {Object} data from earthquake.json
93
+ */
94
+ createMarkersAndAddToMarkerStore (data) {
95
+ let me = this;
96
+
97
+ const markers = data.results.map(function(record) {
98
+ const date = new Date(record.timestamp),
99
+ // DATE
100
+ day = date.toLocaleDateString('en-US', { day: 'numeric' }),
101
+ month = date.toLocaleDateString('en-US', { month: 'short' }),
102
+ year = date.toLocaleDateString('en-US', { year: 'numeric' }),
103
+ hour = date.toLocaleTimeString('en-US', { hour: 'numeric', hour12: true }),
104
+ minute = date.toLocaleTimeString('en-US', { minute: 'numeric' }),
105
+ // ICON
106
+ icon = me.getIcon(undefined, undefined, record.size);
107
+
108
+ // Create a single Marker
109
+ return {
110
+ position: {
111
+ lat: record.latitude,
112
+ lng: record.longitude
113
+ },
114
+ title: `${day}, ${month} ${year}\n[${hour}:${minute}] ${record.humanReadableLocation}`,
115
+ record: record,
116
+ icon: icon
117
+ }
118
+ });
119
+
120
+ // Add to MarkerStore
121
+ me.markerStore.add(markers);
122
+ }
123
+
124
+ /**
125
+ * google.maps.SymbolPaths are not available in the worker.
126
+ * Therefore we are solving it here
127
+ *
128
+ * @param {String} symbol
129
+ * @returns {Number}
130
+ */
131
+ getType(symbol) {
132
+ // google.maps.SymbolPath...
133
+ const symbolPaths = {
134
+ "CIRCLE": 0,
135
+ "FORWARD_CLOSED_ARROW": 1,
136
+ "FORWARD_OPEN_ARROW": 2,
137
+ "BACKWARD_CLOSED_ARROW": 3,
138
+ "BACKWARD_OPEN_ARROW": 4
139
+ }
140
+
141
+ return symbolPaths[symbol]
142
+ }
143
+
144
+ /**
145
+ * Create an icon based on color, symbol and size
146
+ *
147
+ * @param {String} [color=red]
148
+ * @param {'CIRCLE' | 'FORWARD_CLOSED_ARROW' | 'FORWARD_OPEN_ARROW' | 'BACKWARD_CLOSED_ARROW' | 'BACKWARD_OPEN_ARROW'} [symbol=CIRCLE]
149
+ * @param {Number} [scaleMultiplier=1]
150
+ * @returns {{fillColor: string, path: Number, fillOpacity: number, strokeWeight: number, scale: number, strokeColor: string}}
151
+ */
152
+ getIcon(color='red', symbol = 'CIRCLE', scaleMultiplier = 1) {
153
+ const path = this.getType(symbol);
154
+
155
+ return {
156
+ path: path,
157
+ scale: 10 * scaleMultiplier,
158
+ strokeColor: `dark${color}`,
159
+ strokeWeight: 2,
160
+ fillColor: color,
161
+ fillOpacity: 1.0
162
+ }
163
+ }
164
+ }
165
+
166
+ Neo.applyClassConfig(MapComponent);
167
+
168
+ export default MapComponent;
@@ -0,0 +1,26 @@
1
+ import ComponentController from '../../../../node_modules/neo.mjs/src/controller/Component.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.component.wrapper.googleMaps.MainContainerController
5
+ * @extends Neo.controller.Component
6
+ */
7
+ class MapComponentController extends ComponentController {
8
+ static getConfig() {return {
9
+ /**
10
+ * @member {String} className='Neo.examples.component.wrapper.googleMaps.MapComponentController'
11
+ * @protected
12
+ */
13
+ className: 'Neo.examples.component.wrapper.googleMaps.MapComponentController'
14
+ }}
15
+
16
+ /**
17
+ * @param {Object} data
18
+ */
19
+ onMapZoomChance(data) {
20
+ this.getReference('zoom-field').value = data.value;
21
+ }
22
+ }
23
+
24
+ Neo.applyClassConfig(MapComponentController);
25
+
26
+ export default MapComponentController;
@@ -0,0 +1,113 @@
1
+ import DialogBase from '../../../../node_modules/neo.mjs/src/dialog/Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.component.wrapper.googleMaps.MarkerPopup
5
+ * @extends Neo.container.Base
6
+ */
7
+ class MarkerPopup extends DialogBase {
8
+ static getConfig() {return {
9
+ className: 'Neo.examples.component.wrapper.googleMaps.MarkerPopup',
10
+
11
+ // turn off dragging and resizing
12
+ draggable : false,
13
+ resizable : false,
14
+
15
+ // custom property
16
+ record_: null,
17
+
18
+ containerConfig: {style: {padding: '10px'}},
19
+ headerConfig: {actions: ['close']},
20
+ // custom config used to align the popup
21
+ offsetConfig: {x: -15,y: -15},
22
+
23
+ items: [{
24
+ ntype: 'component',
25
+ cls: ['detail-container'],
26
+ vdom: {/* here goes the itemTpl */}
27
+ }],
28
+
29
+ itemTpl: data => [{
30
+ cls: 'detail-depth',
31
+ innerHTML: `Depth: ${data.depth}`
32
+ }, {
33
+ cls: 'detail-date',
34
+ innerHTML: `${data.visualDate}`
35
+ }, {
36
+ cls: 'detail-quality',
37
+ innerHTML: `Quality: ${data.quality}`
38
+ }, {
39
+ cls: 'detail-quality',
40
+ innerHTML: `Size: ${data.size}`
41
+ }]
42
+ }}
43
+
44
+ /**
45
+ * Update the view based on the data
46
+ * @param value
47
+ * @param oldValue
48
+ *
49
+ * @example
50
+ * depth: 11.9
51
+ * humanReadableLocation: "19,9 km N af Sigöldustöð"
52
+ * latitude: 64.35
53
+ * longitude : -19.173
54
+ * quality: 53.79
55
+ * size: 0.9
56
+ * timestamp: "2017-10-11T18:34:56.000Z"
57
+ */
58
+ afterSetRecord(value, oldValue) {
59
+ let me = this,
60
+ outputContainer = me.items[0],
61
+ vdom = outputContainer.vdom;
62
+
63
+ value.visualDate = me.calcVisualDate(value.timestamp);
64
+
65
+ me.title = `${value.humanReadableLocation}$ | ${value.size}`;
66
+ vdom.cn = me.itemTpl(value);
67
+ }
68
+
69
+ calcVisualDate(dateString) {
70
+ const date = new Date(dateString),
71
+ day = date.toLocaleDateString('en-US', { day: 'numeric' }),
72
+ month = date.toLocaleDateString('en-US', { month: 'short' }),
73
+ year = date.toLocaleDateString('en-US', { year: 'numeric' }),
74
+ hour = date.toLocaleTimeString('en-US', { hour: 'numeric', hour12: false }),
75
+ minute = date.toLocaleTimeString('en-US', { minute: 'numeric' });
76
+
77
+ return `${day}.${month}.<b>${year}</b> ${hour}:${minute}`
78
+ }
79
+
80
+ async onRender(data, automount) {
81
+ super.onRender(data, automount)
82
+
83
+ let me = this;
84
+
85
+ /**
86
+ * Center on Map
87
+ */
88
+ // let futureParent = Neo.getComponent(me.boundaryContainerId),
89
+ // futureParentRect = await futureParent.getDomRect(),
90
+ // rect = await me.getDomRect();
91
+ //
92
+ // me.wrapperStyle = {
93
+ // top: (futureParentRect.top + (futureParentRect.height - rect.height) / 2) + 'px',
94
+ // left: (futureParentRect.left + (futureParentRect.width - rect.width) / 2) + 'px',
95
+ // height: me.height,
96
+ // width: me.width
97
+ // }
98
+
99
+ /**
100
+ * Add to click position
101
+ */
102
+ me.wrapperStyle = {
103
+ top: me.domEvent.clientY + me.offsetConfig.y + 'px',
104
+ left: me.domEvent.clientX + me.offsetConfig.x + 'px',
105
+ height: me.height,
106
+ width: me.width
107
+ }
108
+ }
109
+ }
110
+
111
+ Neo.applyClassConfig(MarkerPopup);
112
+
113
+ export default MarkerPopup;
@@ -0,0 +1,463 @@
1
+ {
2
+ "results":[
3
+ {
4
+ "timestamp":"2017-10-13T12:07:24.000Z",
5
+ "latitude":63.976,
6
+ "longitude":-21.949,
7
+ "depth":1.1,
8
+ "size":0.6,
9
+ "quality":58.73,
10
+ "humanReadableLocation":"6,1 km SV af Helgafelli"
11
+ },
12
+ {
13
+ "timestamp":"2017-10-13T09:50:50.000Z",
14
+ "latitude":65.124,
15
+ "longitude":-16.288,
16
+ "depth":7.2,
17
+ "size":0.9,
18
+ "quality":78.51,
19
+ "humanReadableLocation":"6,1 km NA af Herðubreiðartöglum"
20
+ },
21
+ {
22
+ "timestamp":"2017-10-13T09:41:09.000Z",
23
+ "latitude":63.945,
24
+ "longitude":-21.143,
25
+ "depth":7.4,
26
+ "size":0.2,
27
+ "quality":33.12,
28
+ "humanReadableLocation":"6,5 km SSA af Hveragerði"
29
+ },
30
+ {
31
+ "timestamp":"2017-10-13T09:37:45.000Z",
32
+ "latitude":65.114,
33
+ "longitude":-16.3,
34
+ "depth":6.3,
35
+ "size":1.2,
36
+ "quality":90.01,
37
+ "humanReadableLocation":"5,0 km NA af Herðubreiðartöglum"
38
+ },
39
+ {
40
+ "timestamp":"2017-10-13T09:37:21.000Z",
41
+ "latitude":65.113,
42
+ "longitude":-16.301,
43
+ "depth":5.9,
44
+ "size":1.4,
45
+ "quality":90.01,
46
+ "humanReadableLocation":"4,9 km NA af Herðubreiðartöglum"
47
+ },
48
+ {
49
+ "timestamp":"2017-10-13T07:51:29.000Z",
50
+ "latitude":65.182,
51
+ "longitude":-16.358,
52
+ "depth":5,
53
+ "size":0.7,
54
+ "quality":39.63,
55
+ "humanReadableLocation":"1,0 km NNV af Herðubreið"
56
+ },
57
+ {
58
+ "timestamp":"2017-10-13T07:49:40.000Z",
59
+ "latitude":65.165,
60
+ "longitude":-16.354,
61
+ "depth":13.7,
62
+ "size":1.2,
63
+ "quality":90.01,
64
+ "humanReadableLocation":"1,0 km SSV af Herðubreið"
65
+ },
66
+ {
67
+ "timestamp":"2017-10-13T07:22:49.000Z",
68
+ "latitude":64.012,
69
+ "longitude":-20.58,
70
+ "depth":6,
71
+ "size":0.3,
72
+ "quality":63.77,
73
+ "humanReadableLocation":"4,6 km A af Hestfjalli"
74
+ },
75
+ {
76
+ "timestamp":"2017-10-13T07:05:44.000Z",
77
+ "latitude":66.534,
78
+ "longitude":-18.013,
79
+ "depth":6.3,
80
+ "size":1.2,
81
+ "quality":42.6,
82
+ "humanReadableLocation":"0,8 km S af Grímsey"
83
+ },
84
+ {
85
+ "timestamp":"2017-10-13T06:41:34.000Z",
86
+ "latitude":63.954,
87
+ "longitude":-21.255,
88
+ "depth":7.4,
89
+ "size":0.9,
90
+ "quality":57.5,
91
+ "humanReadableLocation":"5,4 km SA af Skálafelli á Hellisheiði"
92
+ },
93
+ {
94
+ "timestamp":"2017-10-13T06:23:10.000Z",
95
+ "latitude":64.659,
96
+ "longitude":-17.533,
97
+ "depth":4.3,
98
+ "size":1.2,
99
+ "quality":90.01,
100
+ "humanReadableLocation":"2,1 km N af Bárðarbungu"
101
+ },
102
+ {
103
+ "timestamp":"2017-10-13T05:33:43.000Z",
104
+ "latitude":64.022,
105
+ "longitude":-16.613,
106
+ "depth":1.1,
107
+ "size":1.1,
108
+ "quality":48.2,
109
+ "humanReadableLocation":"3,4 km ANA af Hvannadalshnjúk"
110
+ },
111
+ {
112
+ "timestamp":"2017-10-13T05:18:22.000Z",
113
+ "latitude":64.621,
114
+ "longitude":-17.348,
115
+ "depth":1.1,
116
+ "size":2.4,
117
+ "quality":90.15,
118
+ "humanReadableLocation":"8,8 km ASA af Bárðarbungu"
119
+ },
120
+ {
121
+ "timestamp":"2017-10-13T04:05:44.000Z",
122
+ "latitude":65.708,
123
+ "longitude":-16.833,
124
+ "depth":2.9,
125
+ "size":0.3,
126
+ "quality":38.43,
127
+ "humanReadableLocation":"3,6 km V af Kröfluvirkjun"
128
+ },
129
+ {
130
+ "timestamp":"2017-10-13T03:46:36.000Z",
131
+ "latitude":65.712,
132
+ "longitude":-16.817,
133
+ "depth":2.9,
134
+ "size":1.1,
135
+ "quality":90.01,
136
+ "humanReadableLocation":"2,8 km V af Kröfluvirkjun"
137
+ },
138
+ {
139
+ "timestamp":"2017-10-13T02:56:40.000Z",
140
+ "latitude":63.972,
141
+ "longitude":-21.56,
142
+ "depth":10.1,
143
+ "size":0.5,
144
+ "quality":64.38,
145
+ "humanReadableLocation":"4,5 km ASA af Bláfjallaskála"
146
+ },
147
+ {
148
+ "timestamp":"2017-10-13T02:12:22.000Z",
149
+ "latitude":65.215,
150
+ "longitude":-16.363,
151
+ "depth":10.2,
152
+ "size":1.4,
153
+ "quality":90.02,
154
+ "humanReadableLocation":"4,6 km N af Herðubreið"
155
+ },
156
+ {
157
+ "timestamp":"2017-10-13T01:39:43.000Z",
158
+ "latitude":65.216,
159
+ "longitude":-16.349,
160
+ "depth":5.8,
161
+ "size":1.1,
162
+ "quality":90.01,
163
+ "humanReadableLocation":"4,6 km N af Herðubreið"
164
+ },
165
+ {
166
+ "timestamp":"2017-10-13T01:38:32.000Z",
167
+ "latitude":65.215,
168
+ "longitude":-16.358,
169
+ "depth":6.3,
170
+ "size":1.1,
171
+ "quality":90.02,
172
+ "humanReadableLocation":"4,6 km N af Herðubreið"
173
+ },
174
+ {
175
+ "timestamp":"2017-10-13T00:22:11.000Z",
176
+ "latitude":64.669,
177
+ "longitude":-17.38,
178
+ "depth":1.1,
179
+ "size":2.7,
180
+ "quality":90.14,
181
+ "humanReadableLocation":"7,7 km ANA af Bárðarbungu"
182
+ },
183
+ {
184
+ "timestamp":"2017-10-13T00:01:12.000Z",
185
+ "latitude":64.632,
186
+ "longitude":-20.636,
187
+ "depth":1.7,
188
+ "size":1.5,
189
+ "quality":64.89,
190
+ "humanReadableLocation":"13,4 km ASA af Húsafelli"
191
+ },
192
+ {
193
+ "timestamp":"2017-10-12T20:08:36.000Z",
194
+ "latitude":64.673,
195
+ "longitude":-17.541,
196
+ "depth":3.1,
197
+ "size":0.9,
198
+ "quality":30.43,
199
+ "humanReadableLocation":"3,7 km N af Bárðarbungu"
200
+ },
201
+ {
202
+ "timestamp":"2017-10-12T20:01:04.000Z",
203
+ "latitude":63.925,
204
+ "longitude":-20.163,
205
+ "depth":8.2,
206
+ "size":1.1,
207
+ "quality":90.01,
208
+ "humanReadableLocation":"13,7 km SSA af Árnesi"
209
+ },
210
+ {
211
+ "timestamp":"2017-10-12T17:49:38.000Z",
212
+ "latitude":63.613,
213
+ "longitude":-19.308,
214
+ "depth":4.9,
215
+ "size":0.8,
216
+ "quality":30.83,
217
+ "humanReadableLocation":"4,1 km SV af Goðabungu"
218
+ },
219
+ {
220
+ "timestamp":"2017-10-12T14:48:47.000Z",
221
+ "latitude":63.818,
222
+ "longitude":-20.659,
223
+ "depth":8.1,
224
+ "size":1.8,
225
+ "quality":49.76,
226
+ "humanReadableLocation":"12,6 km S af Þjórsárbrú"
227
+ },
228
+ {
229
+ "timestamp":"2017-10-12T14:47:07.000Z",
230
+ "latitude":63.672,
231
+ "longitude":-19.674,
232
+ "depth":1.3,
233
+ "size":2,
234
+ "quality":45.93,
235
+ "humanReadableLocation":"9,5 km V af Básum"
236
+ },
237
+ {
238
+ "timestamp":"2017-10-12T14:27:55.000Z",
239
+ "latitude":64.354,
240
+ "longitude":-20.674,
241
+ "depth":3.3,
242
+ "size":1.2,
243
+ "quality":90.01,
244
+ "humanReadableLocation":"6,8 km SSA af Skjaldbreið"
245
+ },
246
+ {
247
+ "timestamp":"2017-10-12T13:27:11.000Z",
248
+ "latitude":65.229,
249
+ "longitude":-16.357,
250
+ "depth":12.8,
251
+ "size":0.5,
252
+ "quality":32.22,
253
+ "humanReadableLocation":"6,1 km N af Herðubreið"
254
+ },
255
+ {
256
+ "timestamp":"2017-10-12T12:48:05.000Z",
257
+ "latitude":65.024,
258
+ "longitude":-16.677,
259
+ "depth":5.2,
260
+ "size":1.5,
261
+ "quality":41.19,
262
+ "humanReadableLocation":"3,7 km VSV af Dreka"
263
+ },
264
+ {
265
+ "timestamp":"2017-10-12T12:47:38.000Z",
266
+ "latitude":65.018,
267
+ "longitude":-16.672,
268
+ "depth":4.4,
269
+ "size":1,
270
+ "quality":44.51,
271
+ "humanReadableLocation":"3,9 km SV af Dreka"
272
+ },
273
+ {
274
+ "timestamp":"2017-10-12T12:46:20.000Z",
275
+ "latitude":65.036,
276
+ "longitude":-16.691,
277
+ "depth":2.3,
278
+ "size":0.6,
279
+ "quality":47.96,
280
+ "humanReadableLocation":"4,1 km V af Dreka"
281
+ },
282
+ {
283
+ "timestamp":"2017-10-12T11:45:39.000Z",
284
+ "latitude":63.513,
285
+ "longitude":-19.268,
286
+ "depth":1.1,
287
+ "size":1.3,
288
+ "quality":90.01,
289
+ "humanReadableLocation":"11,2 km SV af Hábungu"
290
+ },
291
+ {
292
+ "timestamp":"2017-10-12T11:40:49.000Z",
293
+ "latitude":63.628,
294
+ "longitude":-19.072,
295
+ "depth":1.1,
296
+ "size":-0.1,
297
+ "quality":44.18,
298
+ "humanReadableLocation":"5,5 km NNA af Hábungu"
299
+ },
300
+ {
301
+ "timestamp":"2017-10-12T08:25:28.000Z",
302
+ "latitude":63.618,
303
+ "longitude":-19.102,
304
+ "depth":0.6,
305
+ "size":0,
306
+ "quality":79.03,
307
+ "humanReadableLocation":"4,2 km N af Hábungu"
308
+ },
309
+ {
310
+ "timestamp":"2017-10-12T08:21:54.000Z",
311
+ "latitude":63.618,
312
+ "longitude":-19.094,
313
+ "depth":1.1,
314
+ "size":-0.5,
315
+ "quality":48.38,
316
+ "humanReadableLocation":"4,2 km N af Hábungu"
317
+ },
318
+ {
319
+ "timestamp":"2017-10-12T06:38:38.000Z",
320
+ "latitude":65.168,
321
+ "longitude":-16.417,
322
+ "depth":7.6,
323
+ "size":1.2,
324
+ "quality":68.29,
325
+ "humanReadableLocation":"3,3 km VSV af Herðubreið"
326
+ },
327
+ {
328
+ "timestamp":"2017-10-12T04:17:38.000Z",
329
+ "latitude":64.033,
330
+ "longitude":-21.221,
331
+ "depth":6.4,
332
+ "size":0.4,
333
+ "quality":85.02,
334
+ "humanReadableLocation":"4,0 km NNV af Hveragerði"
335
+ },
336
+ {
337
+ "timestamp":"2017-10-12T04:00:31.000Z",
338
+ "latitude":63.804,
339
+ "longitude":-22.793,
340
+ "depth":6.7,
341
+ "size":2.2,
342
+ "quality":90.02,
343
+ "humanReadableLocation":"4,3 km V af Reykjanestá"
344
+ },
345
+ {
346
+ "timestamp":"2017-10-12T03:19:07.000Z",
347
+ "latitude":64.014,
348
+ "longitude":-16.603,
349
+ "depth":1.2,
350
+ "size":0.9,
351
+ "quality":43.19,
352
+ "humanReadableLocation":"3,8 km A af Hvannadalshnjúk"
353
+ },
354
+ {
355
+ "timestamp":"2017-10-12T02:05:45.000Z",
356
+ "latitude":63.919,
357
+ "longitude":-21.719,
358
+ "depth":2.9,
359
+ "size":1,
360
+ "quality":90.01,
361
+ "humanReadableLocation":"8,0 km SSV af Bláfjallaskála"
362
+ },
363
+ {
364
+ "timestamp":"2017-10-12T01:50:54.000Z",
365
+ "latitude":63.798,
366
+ "longitude":-22.793,
367
+ "depth":6.6,
368
+ "size":1.4,
369
+ "quality":90.01,
370
+ "humanReadableLocation":"4,3 km V af Reykjanestá"
371
+ },
372
+ {
373
+ "timestamp":"2017-10-12T01:15:10.000Z",
374
+ "latitude":63.635,
375
+ "longitude":-19.142,
376
+ "depth":1.1,
377
+ "size":2,
378
+ "quality":90.01,
379
+ "humanReadableLocation":"5,4 km A af Goðabungu"
380
+ },
381
+ {
382
+ "timestamp":"2017-10-12T00:14:48.000Z",
383
+ "latitude":63.674,
384
+ "longitude":-19.125,
385
+ "depth":4.1,
386
+ "size":0.2,
387
+ "quality":34.25,
388
+ "humanReadableLocation":"7,2 km ANA af Goðabungu"
389
+ },
390
+ {
391
+ "timestamp":"2017-10-11T22:40:01.000Z",
392
+ "latitude":66.251,
393
+ "longitude":-16.709,
394
+ "depth":4.4,
395
+ "size":1,
396
+ "quality":34.97,
397
+ "humanReadableLocation":"12,8 km VSV af Kópaskeri"
398
+ },
399
+ {
400
+ "timestamp":"2017-10-11T21:09:29.000Z",
401
+ "latitude":66.283,
402
+ "longitude":-16.751,
403
+ "depth":5.6,
404
+ "size":1.1,
405
+ "quality":55.62,
406
+ "humanReadableLocation":"13,5 km V af Kópaskeri"
407
+ },
408
+ {
409
+ "timestamp":"2017-10-11T21:08:48.000Z",
410
+ "latitude":66.282,
411
+ "longitude":-16.743,
412
+ "depth":4.5,
413
+ "size":1.1,
414
+ "quality":80.86,
415
+ "humanReadableLocation":"13,2 km V af Kópaskeri"
416
+ },
417
+ {
418
+ "timestamp":"2017-10-11T19:21:13.000Z",
419
+ "latitude":66.559,
420
+ "longitude":-18.052,
421
+ "depth":9.1,
422
+ "size":2.8,
423
+ "quality":90.03,
424
+ "humanReadableLocation":"2,7 km NV af Grímsey"
425
+ },
426
+ {
427
+ "timestamp":"2017-10-11T18:34:56.000Z",
428
+ "latitude":64.35,
429
+ "longitude":-19.173,
430
+ "depth":11.9,
431
+ "size":0.9,
432
+ "quality":53.79,
433
+ "humanReadableLocation":"19,9 km N af Sigöldustöð"
434
+ },
435
+ {
436
+ "timestamp":"2017-10-11T17:28:01.000Z",
437
+ "latitude":64.794,
438
+ "longitude":-16.906,
439
+ "depth":2.8,
440
+ "size":0.9,
441
+ "quality":36.64,
442
+ "humanReadableLocation":"14,4 km A af Kistufelli"
443
+ },
444
+ {
445
+ "timestamp":"2017-10-11T14:34:29.000Z",
446
+ "latitude":65.234,
447
+ "longitude":-16.33,
448
+ "depth":6.2,
449
+ "size":0.9,
450
+ "quality":42.59,
451
+ "humanReadableLocation":"6,6 km NV af Herðubreiðarlindum"
452
+ },
453
+ {
454
+ "timestamp":"2017-10-11T14:16:22.000Z",
455
+ "latitude":64.662,
456
+ "longitude":-17.082,
457
+ "depth":2.3,
458
+ "size":0.7,
459
+ "quality":39.3,
460
+ "humanReadableLocation":"14,5 km SSA af Kistufelli"
461
+ }
462
+ ]
463
+ }
@@ -70,7 +70,7 @@ class MainContainer extends Viewport {
70
70
  iconCls: 'fa fa-home',
71
71
 
72
72
  bind: {
73
- text: data => `${data.button1Text}`
73
+ text: data => data.button1Text
74
74
  }
75
75
  }, {
76
76
  handler: 'onButton2Click',
@@ -91,11 +91,7 @@ class MainContainer extends Viewport {
91
91
  width : 300,
92
92
 
93
93
  bind: {
94
- value: data => `${data.button1Text}`
95
- },
96
-
97
- listeners: {
98
- change: 'onTextField1Change'
94
+ value: {twoWay: true, value: data => data.button1Text}
99
95
  }
100
96
  }, {
101
97
  module : TextField,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "4.4.13",
3
+ "version": "4.4.15",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -104,9 +104,9 @@ class Base extends Component {
104
104
  route_: null,
105
105
  /**
106
106
  * The text displayed on the button [optional]
107
- * @member {String} text_=''
107
+ * @member {String|null} text_=null
108
108
  */
109
- text_: '',
109
+ text_: null,
110
110
  /**
111
111
  * Transforms the button tag into an a tag [optional]
112
112
  * @member {String|null} url_=null
@@ -271,8 +271,8 @@ class Base extends Component {
271
271
 
272
272
  /**
273
273
  * Triggered after the text config got changed
274
- * @param {String} value
275
- * @param {String} oldValue
274
+ * @param {String|null} value
275
+ * @param {String|null} oldValue
276
276
  * @protected
277
277
  */
278
278
  afterSetText(value, oldValue) {
@@ -280,7 +280,7 @@ class Base extends Component {
280
280
  vdomRoot = me.getVdomRoot(),
281
281
  textNode = vdomRoot.cn[1];
282
282
 
283
- if (value === '') {
283
+ if (!value || value === '') {
284
284
  NeoArray.add(me._cls, 'no-text');
285
285
  NeoArray.add(vdomRoot.cls, 'no-text');
286
286
  textNode.removeDom = true;
@@ -425,9 +425,11 @@ class Base extends CoreBase {
425
425
  * @protected
426
426
  */
427
427
  afterSetConfig(key, value, oldValue) {
428
- if (Neo.currentWorker.isUsingViewModels) {
429
- if (this.bind?.[key]?.twoWay) {
430
- this.getModel()?.setData(key, value);
428
+ if (Neo.currentWorker.isUsingViewModels && oldValue !== undefined) {
429
+ let binding = this.bind?.[key];
430
+
431
+ if (binding?.twoWay) {
432
+ this.getModel()?.setData(binding.key, value);
431
433
  }
432
434
  }
433
435
  }
@@ -44,6 +44,11 @@ class GoogleMaps extends Base {
44
44
  */
45
45
  className: 'Neo.component.wrapper.GoogleMaps',
46
46
  /**
47
+ * @member {String} ntype='googlemaps'
48
+ * @protected
49
+ */
50
+ ntype: 'googlemaps',
51
+ /**
47
52
  * Specify lat & lng for the current focus position
48
53
  * @member {Object} center_={lat: -34.397, lng: 150.644}
49
54
  */
@@ -58,6 +63,9 @@ class GoogleMaps extends Base {
58
63
  fields: [{
59
64
  name: 'id',
60
65
  type: 'String'
66
+ }, {
67
+ name: 'icon',
68
+ type: 'Object'
61
69
  }, {
62
70
  name: 'position',
63
71
  type: 'Object'
@@ -285,11 +293,13 @@ class GoogleMaps extends Base {
285
293
  let me = this,
286
294
  record = me.markerStore.get(data.id);
287
295
 
288
- me.onMarkerClick(record);
296
+ data.record = record;
297
+
298
+ me.onMarkerClick(data);
289
299
 
290
300
  me.fire('markerClick', {
291
301
  id: me.id,
292
- record
302
+ data
293
303
  })
294
304
  }
295
305
 
@@ -164,13 +164,13 @@ class GoogleMaps extends Base {
164
164
  * @param {Object} event.domEvent
165
165
  */
166
166
  onMarkerClick(marker, event) {
167
- // in theory, we could parse and pass the entire DOM event.
168
- // feel free to open a feature request ticket, in case you need more data into the app worker.
167
+ let transformedEvent = DomEvents.getMouseEventData(event.domEvent);
169
168
 
170
169
  DomEvents.sendMessageToApp({
171
170
  id : marker.neoId,
172
171
  path: [{cls: [], id: marker.neoMapId}],
173
- type: 'googleMarkerClick'
172
+ type: 'googleMarkerClick',
173
+ domEvent: transformedEvent
174
174
  })
175
175
  }
176
176
 
@@ -26,6 +26,7 @@ class Component extends Base {
26
26
  construct(config) {
27
27
  super.construct(config);
28
28
  Neo.getComponent = this.getById.bind(this); // alias
29
+ Neo.first = this.getFirst.bind(this); // alias
29
30
  }
30
31
 
31
32
  /**
@@ -61,7 +62,9 @@ class Component extends Base {
61
62
  configLength = configArray.length;
62
63
 
63
64
  configArray.forEach(([key, value]) => {
64
- if (component[key] === value) {
65
+ if ((component[key] === value)
66
+ || (key === 'ntype' && me.hasPrototypePropertyValue(component, key, value)))
67
+ {
65
68
  matchArray.push(true);
66
69
  }
67
70
  });
@@ -144,6 +147,88 @@ class Component extends Base {
144
147
 
145
148
  return childComponents;
146
149
  }
150
+
151
+ /**
152
+ * !! For debugging purposes only !!
153
+ *
154
+ * Get the first component based on the nytpe or other properties
155
+ *
156
+ * @param {String|Object|Array} componentDescription
157
+ * @returns {Neo.component.Base|null|Neo.component.Base[]}
158
+ *
159
+ * @example
160
+ // as String: ntype[comma separated propterties]
161
+ Neo.first('toolbar button[text=Try me,icon=people]')
162
+ // as Object: Add properties. ntype is optional
163
+ Neo.first({
164
+ icon: 'people'
165
+ })
166
+ // as Array: An Array of Objects. No Strings allowed
167
+ Neo.first([{
168
+ ntype: 'toolbar'
169
+ },{
170
+ ntype: 'button', text: 'Try me', icon: 'people
171
+ }])
172
+
173
+ * The returnFirstMatch flag allows to return all items and
174
+ * not stop after the first result.
175
+ *
176
+ * @example
177
+ Neo.first('button', false) // => [Button, Button, Button]
178
+ */
179
+ getFirst(componentDescription, returnFirstMatch = true) {
180
+ let objects = [],
181
+ app = Neo.apps[Object.keys(Neo.apps)[0]],
182
+ root = app.mainView;
183
+
184
+ /* create an array of objects from string */
185
+ if(Neo.isString(componentDescription)) {
186
+ const regex = /(\w*)(\[[^\]]*\])|(\w*)/g;
187
+ let match;
188
+
189
+ /* generate objects which contain the information */
190
+ while (match = regex.exec(componentDescription)) {
191
+ let [, ntype, pairs, ntypeOnly] = match, obj;
192
+
193
+ ntype = ntype || ntypeOnly;
194
+ obj = {ntype};
195
+
196
+ if(pairs) {
197
+ const pairsRegex = /\[(.*?)\]/,
198
+ pairsMatch = pairs.match(pairsRegex);
199
+
200
+ if(pairsMatch) {
201
+ const pairs = pairsMatch[1].split(',');
202
+ pairs.forEach((pair) => {
203
+ const [key, value] = pair.split('=');
204
+ obj[key] = value.replace(/"/g, '');
205
+ });
206
+ }
207
+ }
208
+ objects.push(obj);
209
+
210
+ regex.lastIndex++;
211
+ }
212
+ } else if (Neo.isObject(componentDescription)){
213
+ objects.push(componentDescription);
214
+ } else if (Neo.isArray(componentDescription)) {
215
+ objects = componentDescription;
216
+ }
217
+
218
+ /* find the correct child using down() */
219
+ const result = objects.reduce((acc, key) => {
220
+ if(acc) {
221
+ let child = acc.down(key, returnFirstMatch);
222
+
223
+ if(!!child) {
224
+ return child;
225
+ }
226
+ }
227
+ return null;
228
+ }, root);
229
+
230
+ return result
231
+ }
147
232
 
148
233
  /**
149
234
  * Returns an Array containing the ids of all parent components for a given component
@@ -205,6 +290,25 @@ class Component extends Base {
205
290
 
206
291
  return parents;
207
292
  }
293
+
294
+ /**
295
+ * Check if the component had a property of any value somewhere in the Prototype chain
296
+ *
297
+ * @param {Neo.component.Base} component
298
+ * @param {String} property
299
+ * @param {*} value
300
+ * @returns {boolean}
301
+ */
302
+ hasPrototypePropertyValue(component, property, value) {
303
+ while (component !== null) {
304
+ if (component.hasOwnProperty(property) && component[property] === value) {
305
+ return true;
306
+ }
307
+ component = component.__proto__;
308
+ }
309
+
310
+ return false;
311
+ }
208
312
 
209
313
  /**
210
314
  * Returns the first component which matches the config-selector.
@@ -564,6 +564,7 @@ class Component extends Base {
564
564
 
565
565
  Object.entries(component.bind).forEach(([key, value]) => {
566
566
  if (Neo.isObject(value)) {
567
+ value.key = me.getFormatterVariables(value.value)[0];
567
568
  value = value.value;
568
569
  }
569
570