spotlight-frontend 3.5.0-beta.1

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.
Files changed (153) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +114 -0
  3. package/app/assets/images/blacklight/arrow-alt-circle-left.svg +1 -0
  4. package/app/assets/images/blacklight/arrow-alt-circle-right.svg +1 -0
  5. package/app/assets/images/blacklight/arrow_back_ios.svg +1 -0
  6. package/app/assets/images/blacklight/arrow_forward_ios.svg +1 -0
  7. package/app/assets/images/blacklight/check.svg +1 -0
  8. package/app/assets/images/blacklight/check_circle.svg +1 -0
  9. package/app/assets/images/blacklight/chevron_right.svg +1 -0
  10. package/app/assets/images/blacklight/close.svg +1 -0
  11. package/app/assets/images/blacklight/edit.svg +1 -0
  12. package/app/assets/images/blacklight/error.svg +1 -0
  13. package/app/assets/images/blacklight/highlight_off.svg +1 -0
  14. package/app/assets/images/blacklight/info.svg +1 -0
  15. package/app/assets/images/blacklight/warning.svg +1 -0
  16. package/app/assets/images/blacklight/zoom_in.svg +1 -0
  17. package/app/assets/images/blacklight/zoom_out.svg +1 -0
  18. package/app/assets/images/spotlight/.keep +0 -0
  19. package/app/assets/images/spotlight/blocks/sir-trevor-icons.svg +320 -0
  20. package/app/assets/images/spotlight/default_browse_thumbnail.jpg +0 -0
  21. package/app/assets/images/spotlight/default_thumbnail.jpg +0 -0
  22. package/app/assets/images/spotlight/fallback/default.png +0 -0
  23. package/app/assets/javascripts/spotlight/admin/add_another.js +22 -0
  24. package/app/assets/javascripts/spotlight/admin/add_new_button.js +81 -0
  25. package/app/assets/javascripts/spotlight/admin/appearance.js +24 -0
  26. package/app/assets/javascripts/spotlight/admin/attachments.js +2 -0
  27. package/app/assets/javascripts/spotlight/admin/blacklight_configuration.js +63 -0
  28. package/app/assets/javascripts/spotlight/admin/block_mixins/autocompleteable.js +72 -0
  29. package/app/assets/javascripts/spotlight/admin/block_mixins/formable.js +78 -0
  30. package/app/assets/javascripts/spotlight/admin/block_mixins/plustextable.js +57 -0
  31. package/app/assets/javascripts/spotlight/admin/blocks/block.js +23 -0
  32. package/app/assets/javascripts/spotlight/admin/blocks/browse_block.js +87 -0
  33. package/app/assets/javascripts/spotlight/admin/blocks/browse_group_categories_block.js +88 -0
  34. package/app/assets/javascripts/spotlight/admin/blocks/iframe_block.js +34 -0
  35. package/app/assets/javascripts/spotlight/admin/blocks/link_to_search_block.js +16 -0
  36. package/app/assets/javascripts/spotlight/admin/blocks/oembed_block.js +40 -0
  37. package/app/assets/javascripts/spotlight/admin/blocks/pages_block.js +22 -0
  38. package/app/assets/javascripts/spotlight/admin/blocks/resources_block.js +145 -0
  39. package/app/assets/javascripts/spotlight/admin/blocks/rule_block.js +25 -0
  40. package/app/assets/javascripts/spotlight/admin/blocks/search_result_block.js +44 -0
  41. package/app/assets/javascripts/spotlight/admin/blocks/solr_documents_base_block.js +108 -0
  42. package/app/assets/javascripts/spotlight/admin/blocks/solr_documents_block.js +25 -0
  43. package/app/assets/javascripts/spotlight/admin/blocks/solr_documents_carousel_block.js +103 -0
  44. package/app/assets/javascripts/spotlight/admin/blocks/solr_documents_embed_block.js +17 -0
  45. package/app/assets/javascripts/spotlight/admin/blocks/solr_documents_features_block.js +41 -0
  46. package/app/assets/javascripts/spotlight/admin/blocks/solr_documents_grid_block.js +14 -0
  47. package/app/assets/javascripts/spotlight/admin/blocks/uploaded_items_block.js +145 -0
  48. package/app/assets/javascripts/spotlight/admin/catalog_edit.js +16 -0
  49. package/app/assets/javascripts/spotlight/admin/copy_email_addresses.js +9 -0
  50. package/app/assets/javascripts/spotlight/admin/crop.es6 +310 -0
  51. package/app/assets/javascripts/spotlight/admin/croppable.js +25 -0
  52. package/app/assets/javascripts/spotlight/admin/edit_in_place.js +54 -0
  53. package/app/assets/javascripts/spotlight/admin/exhibit_tag_autocomplete.js +37 -0
  54. package/app/assets/javascripts/spotlight/admin/exhibits.js +58 -0
  55. package/app/assets/javascripts/spotlight/admin/form_observer.js +86 -0
  56. package/app/assets/javascripts/spotlight/admin/iiif.es6 +54 -0
  57. package/app/assets/javascripts/spotlight/admin/index.js +16 -0
  58. package/app/assets/javascripts/spotlight/admin/locks.js +12 -0
  59. package/app/assets/javascripts/spotlight/admin/multi_image_selector.js +158 -0
  60. package/app/assets/javascripts/spotlight/admin/pages.js.erb +40 -0
  61. package/app/assets/javascripts/spotlight/admin/progress_monitor.js +148 -0
  62. package/app/assets/javascripts/spotlight/admin/readonly_checkbox.js +6 -0
  63. package/app/assets/javascripts/spotlight/admin/search_typeahead.js +108 -0
  64. package/app/assets/javascripts/spotlight/admin/select_related_input.js +34 -0
  65. package/app/assets/javascripts/spotlight/admin/sir-trevor/block_controls.js +120 -0
  66. package/app/assets/javascripts/spotlight/admin/sir-trevor/block_limits.js +37 -0
  67. package/app/assets/javascripts/spotlight/admin/sir-trevor/locales.js +120 -0
  68. package/app/assets/javascripts/spotlight/admin/spotlight_nestable.js +72 -0
  69. package/app/assets/javascripts/spotlight/admin/tabs.js +6 -0
  70. package/app/assets/javascripts/spotlight/admin/translation_progress.js +23 -0
  71. package/app/assets/javascripts/spotlight/admin/users.js +79 -0
  72. package/app/assets/javascripts/spotlight/application.js +14 -0
  73. package/app/assets/javascripts/spotlight/spotlight.js +23 -0
  74. package/app/assets/javascripts/spotlight/user/analytics.js +9 -0
  75. package/app/assets/javascripts/spotlight/user/browse_group_categories.js +59 -0
  76. package/app/assets/javascripts/spotlight/user/carousel.js +3 -0
  77. package/app/assets/javascripts/spotlight/user/clear_form_button.js +27 -0
  78. package/app/assets/javascripts/spotlight/user/index.js +8 -0
  79. package/app/assets/javascripts/spotlight/user/report_a_problem.js +39 -0
  80. package/app/assets/javascripts/spotlight/user/zpr_links.js.erb +45 -0
  81. package/app/assets/stylesheets/spotlight/_accessibility.scss +8 -0
  82. package/app/assets/stylesheets/spotlight/_attachments.css +4 -0
  83. package/app/assets/stylesheets/spotlight/_blacklight_configuration.scss +82 -0
  84. package/app/assets/stylesheets/spotlight/_blacklight_overrides.scss +21 -0
  85. package/app/assets/stylesheets/spotlight/_bootstrap_overrides.scss +105 -0
  86. package/app/assets/stylesheets/spotlight/_breadcrumbs.scss +6 -0
  87. package/app/assets/stylesheets/spotlight/_browse.scss +158 -0
  88. package/app/assets/stylesheets/spotlight/_catalog.scss +161 -0
  89. package/app/assets/stylesheets/spotlight/_collapse_toggle.scss +14 -0
  90. package/app/assets/stylesheets/spotlight/_croppable.scss +4 -0
  91. package/app/assets/stylesheets/spotlight/_curation.scss +224 -0
  92. package/app/assets/stylesheets/spotlight/_edit_in_place.scss +9 -0
  93. package/app/assets/stylesheets/spotlight/_exhibit_admin.scss +81 -0
  94. package/app/assets/stylesheets/spotlight/_exhibit_navbar.scss +10 -0
  95. package/app/assets/stylesheets/spotlight/_exhibits_index.scss +147 -0
  96. package/app/assets/stylesheets/spotlight/_featured_browse_categories_block.scss +269 -0
  97. package/app/assets/stylesheets/spotlight/_footer.scss +12 -0
  98. package/app/assets/stylesheets/spotlight/_header.scss +155 -0
  99. package/app/assets/stylesheets/spotlight/_item_text_block.scss +50 -0
  100. package/app/assets/stylesheets/spotlight/_mixins.scss +17 -0
  101. package/app/assets/stylesheets/spotlight/_modals.scss +3 -0
  102. package/app/assets/stylesheets/spotlight/_multi_image_selector.scss +22 -0
  103. package/app/assets/stylesheets/spotlight/_multi_up_item_grid.scss +63 -0
  104. package/app/assets/stylesheets/spotlight/_nestable.scss +124 -0
  105. package/app/assets/stylesheets/spotlight/_pages.scss +282 -0
  106. package/app/assets/stylesheets/spotlight/_report_a_problem.scss +14 -0
  107. package/app/assets/stylesheets/spotlight/_sir-trevor_overrides.scss +87 -0
  108. package/app/assets/stylesheets/spotlight/_slideshow_block.scss +87 -0
  109. package/app/assets/stylesheets/spotlight/_spotlight.scss +49 -0
  110. package/app/assets/stylesheets/spotlight/_translations.scss +86 -0
  111. package/app/assets/stylesheets/spotlight/_upload.scss +0 -0
  112. package/app/assets/stylesheets/spotlight/_uploaded_items_block.scss +7 -0
  113. package/app/assets/stylesheets/spotlight/_utilities.scss +7 -0
  114. package/app/assets/stylesheets/spotlight/_variables.scss +42 -0
  115. package/app/assets/stylesheets/spotlight/_variables_bootstrap.scss +7 -0
  116. package/app/assets/stylesheets/spotlight/_view_larger.scss +22 -0
  117. package/app/assets/stylesheets/spotlight/browse_group_categories_block.scss +92 -0
  118. package/app/assets/stylesheets/spotlight/typeahead.css +77 -0
  119. package/package.json +29 -0
  120. package/vendor/assets/images/sir-trevor-icons.svg +263 -0
  121. package/vendor/assets/javascripts/Leaflet.Editable.js +1917 -0
  122. package/vendor/assets/javascripts/MutationObserver.js +625 -0
  123. package/vendor/assets/javascripts/Path.Drag.js +137 -0
  124. package/vendor/assets/javascripts/bootstrap-tagsinput.js +530 -0
  125. package/vendor/assets/javascripts/eventable.js +205 -0
  126. package/vendor/assets/javascripts/jquery.serializejson.js +234 -0
  127. package/vendor/assets/javascripts/jquery.waitforimages.min.js +2 -0
  128. package/vendor/assets/javascripts/leaflet-iiif.js +323 -0
  129. package/vendor/assets/javascripts/nestable.js +645 -0
  130. package/vendor/assets/javascripts/parameterize.js +137 -0
  131. package/vendor/assets/javascripts/polyfill.min.js +4 -0
  132. package/vendor/assets/javascripts/sir-trevor.js +21639 -0
  133. package/vendor/assets/javascripts/tiny-slider.js +3218 -0
  134. package/vendor/assets/javascripts/typeahead.bundle.min.js +7 -0
  135. package/vendor/assets/stylesheets/bootstrap-tagsinput.css +46 -0
  136. package/vendor/assets/stylesheets/leaflet-areaselect.css +15 -0
  137. package/vendor/assets/stylesheets/sir-trevor/_icons.scss +6 -0
  138. package/vendor/assets/stylesheets/sir-trevor/_variables.scss +22 -0
  139. package/vendor/assets/stylesheets/sir-trevor/base.scss +17 -0
  140. package/vendor/assets/stylesheets/sir-trevor/block-addition-top.scss +95 -0
  141. package/vendor/assets/stylesheets/sir-trevor/block-addition.scss +72 -0
  142. package/vendor/assets/stylesheets/sir-trevor/block-controls.scss +34 -0
  143. package/vendor/assets/stylesheets/sir-trevor/block-positioner.scss +34 -0
  144. package/vendor/assets/stylesheets/sir-trevor/block-replacer.scss +43 -0
  145. package/vendor/assets/stylesheets/sir-trevor/block-ui.scss +120 -0
  146. package/vendor/assets/stylesheets/sir-trevor/block.scss +300 -0
  147. package/vendor/assets/stylesheets/sir-trevor/errors.scss +21 -0
  148. package/vendor/assets/stylesheets/sir-trevor/format-bar.scss +65 -0
  149. package/vendor/assets/stylesheets/sir-trevor/inputs.scss +45 -0
  150. package/vendor/assets/stylesheets/sir-trevor/main.scss +24 -0
  151. package/vendor/assets/stylesheets/sir-trevor/patterns/ui-popup.scss +38 -0
  152. package/vendor/assets/stylesheets/sir-trevor/utils.scss +10 -0
  153. package/vendor/assets/stylesheets/tiny-slider.css +1 -0
@@ -0,0 +1,1917 @@
1
+ 'use strict';
2
+ (function (factory, window) {
3
+ /*globals define, module, require*/
4
+
5
+ // define an AMD module that relies on 'leaflet'
6
+ if (typeof define === 'function' && define.amd) {
7
+ define(['leaflet'], factory);
8
+
9
+
10
+ // define a Common JS module that relies on 'leaflet'
11
+ } else if (typeof exports === 'object') {
12
+ module.exports = factory(require('leaflet'));
13
+ }
14
+
15
+ // attach your plugin to the global 'L' variable
16
+ if(typeof window !== 'undefined' && window.L){
17
+ factory(window.L);
18
+ }
19
+
20
+ }(function (L) {
21
+ // 🍂miniclass CancelableEvent (Event objects)
22
+ // 🍂method cancel()
23
+ // Cancel any subsequent action.
24
+
25
+ // 🍂miniclass VertexEvent (Event objects)
26
+ // 🍂property vertex: VertexMarker
27
+ // The vertex that fires the event.
28
+
29
+ // 🍂miniclass ShapeEvent (Event objects)
30
+ // 🍂property shape: Array
31
+ // The shape (LatLngs array) subject of the action.
32
+
33
+ // 🍂miniclass CancelableVertexEvent (Event objects)
34
+ // 🍂inherits VertexEvent
35
+ // 🍂inherits CancelableEvent
36
+
37
+ // 🍂miniclass CancelableShapeEvent (Event objects)
38
+ // 🍂inherits ShapeEvent
39
+ // 🍂inherits CancelableEvent
40
+
41
+ // 🍂miniclass LayerEvent (Event objects)
42
+ // 🍂property layer: object
43
+ // The Layer (Marker, Polyline…) subject of the action.
44
+
45
+ // 🍂namespace Editable; 🍂class Editable; 🍂aka L.Editable
46
+ // Main edition handler. By default, it is attached to the map
47
+ // as `map.editTools` property.
48
+ // Leaflet.Editable is made to be fully extendable. You have three ways to customize
49
+ // the behaviour: using options, listening to events, or extending.
50
+ L.Editable = L.Evented.extend({
51
+
52
+ statics: {
53
+ FORWARD: 1,
54
+ BACKWARD: -1
55
+ },
56
+
57
+ options: {
58
+
59
+ // You can pass them when creating a map using the `editOptions` key.
60
+ // 🍂option zIndex: int = 1000
61
+ // The default zIndex of the editing tools.
62
+ zIndex: 1000,
63
+
64
+ // 🍂option polygonClass: class = L.Polygon
65
+ // Class to be used when creating a new Polygon.
66
+ polygonClass: L.Polygon,
67
+
68
+ // 🍂option polylineClass: class = L.Polyline
69
+ // Class to be used when creating a new Polyline.
70
+ polylineClass: L.Polyline,
71
+
72
+ // 🍂option markerClass: class = L.Marker
73
+ // Class to be used when creating a new Marker.
74
+ markerClass: L.Marker,
75
+
76
+ // 🍂option rectangleClass: class = L.Rectangle
77
+ // Class to be used when creating a new Rectangle.
78
+ rectangleClass: L.Rectangle,
79
+
80
+ // 🍂option circleClass: class = L.Circle
81
+ // Class to be used when creating a new Circle.
82
+ circleClass: L.Circle,
83
+
84
+ // 🍂option drawingCSSClass: string = 'leaflet-editable-drawing'
85
+ // CSS class to be added to the map container while drawing.
86
+ drawingCSSClass: 'leaflet-editable-drawing',
87
+
88
+ // 🍂option drawingCursor: const = 'crosshair'
89
+ // Cursor mode set to the map while drawing.
90
+ drawingCursor: 'crosshair',
91
+
92
+ // 🍂option editLayer: Layer = new L.LayerGroup()
93
+ // Layer used to store edit tools (vertex, line guide…).
94
+ editLayer: undefined,
95
+
96
+ // 🍂option featuresLayer: Layer = new L.LayerGroup()
97
+ // Default layer used to store drawn features (Marker, Polyline…).
98
+ featuresLayer: undefined,
99
+
100
+ // 🍂option polylineEditorClass: class = PolylineEditor
101
+ // Class to be used as Polyline editor.
102
+ polylineEditorClass: undefined,
103
+
104
+ // 🍂option polygonEditorClass: class = PolygonEditor
105
+ // Class to be used as Polygon editor.
106
+ polygonEditorClass: undefined,
107
+
108
+ // 🍂option markerEditorClass: class = MarkerEditor
109
+ // Class to be used as Marker editor.
110
+ markerEditorClass: undefined,
111
+
112
+ // 🍂option rectangleEditorClass: class = RectangleEditor
113
+ // Class to be used as Rectangle editor.
114
+ rectangleEditorClass: undefined,
115
+
116
+ // 🍂option circleEditorClass: class = CircleEditor
117
+ // Class to be used as Circle editor.
118
+ circleEditorClass: undefined,
119
+
120
+ // 🍂option lineGuideOptions: hash = {}
121
+ // Options to be passed to the line guides.
122
+ lineGuideOptions: {},
123
+
124
+ // 🍂option skipMiddleMarkers: boolean = false
125
+ // Set this to true if you don't want middle markers.
126
+ skipMiddleMarkers: false
127
+
128
+ },
129
+
130
+ initialize: function (map, options) {
131
+ L.setOptions(this, options);
132
+ this._lastZIndex = this.options.zIndex;
133
+ this.map = map;
134
+ this.editLayer = this.createEditLayer();
135
+ this.featuresLayer = this.createFeaturesLayer();
136
+ this.forwardLineGuide = this.createLineGuide();
137
+ this.backwardLineGuide = this.createLineGuide();
138
+ },
139
+
140
+ fireAndForward: function (type, e) {
141
+ e = e || {};
142
+ e.editTools = this;
143
+ this.fire(type, e);
144
+ this.map.fire(type, e);
145
+ },
146
+
147
+ createLineGuide: function () {
148
+ var options = L.extend({dashArray: '5,10', weight: 1, interactive: false}, this.options.lineGuideOptions);
149
+ return L.polyline([], options);
150
+ },
151
+
152
+ createVertexIcon: function (options) {
153
+ return L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options);
154
+ },
155
+
156
+ createEditLayer: function () {
157
+ return this.options.editLayer || new L.LayerGroup().addTo(this.map);
158
+ },
159
+
160
+ createFeaturesLayer: function () {
161
+ return this.options.featuresLayer || new L.LayerGroup().addTo(this.map);
162
+ },
163
+
164
+ moveForwardLineGuide: function (latlng) {
165
+ if (this.forwardLineGuide._latlngs.length) {
166
+ this.forwardLineGuide._latlngs[1] = latlng;
167
+ this.forwardLineGuide._bounds.extend(latlng);
168
+ this.forwardLineGuide.redraw();
169
+ }
170
+ },
171
+
172
+ moveBackwardLineGuide: function (latlng) {
173
+ if (this.backwardLineGuide._latlngs.length) {
174
+ this.backwardLineGuide._latlngs[1] = latlng;
175
+ this.backwardLineGuide._bounds.extend(latlng);
176
+ this.backwardLineGuide.redraw();
177
+ }
178
+ },
179
+
180
+ anchorForwardLineGuide: function (latlng) {
181
+ this.forwardLineGuide._latlngs[0] = latlng;
182
+ this.forwardLineGuide._bounds.extend(latlng);
183
+ this.forwardLineGuide.redraw();
184
+ },
185
+
186
+ anchorBackwardLineGuide: function (latlng) {
187
+ this.backwardLineGuide._latlngs[0] = latlng;
188
+ this.backwardLineGuide._bounds.extend(latlng);
189
+ this.backwardLineGuide.redraw();
190
+ },
191
+
192
+ attachForwardLineGuide: function () {
193
+ this.editLayer.addLayer(this.forwardLineGuide);
194
+ },
195
+
196
+ attachBackwardLineGuide: function () {
197
+ this.editLayer.addLayer(this.backwardLineGuide);
198
+ },
199
+
200
+ detachForwardLineGuide: function () {
201
+ this.forwardLineGuide.setLatLngs([]);
202
+ this.editLayer.removeLayer(this.forwardLineGuide);
203
+ },
204
+
205
+ detachBackwardLineGuide: function () {
206
+ this.backwardLineGuide.setLatLngs([]);
207
+ this.editLayer.removeLayer(this.backwardLineGuide);
208
+ },
209
+
210
+ blockEvents: function () {
211
+ // Hack: force map not to listen to other layers events while drawing.
212
+ if (!this._oldTargets) {
213
+ this._oldTargets = this.map._targets;
214
+ this.map._targets = {};
215
+ }
216
+ },
217
+
218
+ unblockEvents: function () {
219
+ if (this._oldTargets) {
220
+ // Reset, but keep targets created while drawing.
221
+ this.map._targets = L.extend(this.map._targets, this._oldTargets);
222
+ delete this._oldTargets;
223
+ }
224
+ },
225
+
226
+ registerForDrawing: function (editor) {
227
+ if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor);
228
+ this.blockEvents();
229
+ editor.reset(); // Make sure editor tools still receive events.
230
+ this._drawingEditor = editor;
231
+ this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor);
232
+ this.map.on('mousedown', this.onMousedown, this);
233
+ this.map.on('mouseup', this.onMouseup, this);
234
+ L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass);
235
+ this.defaultMapCursor = this.map._container.style.cursor;
236
+ this.map._container.style.cursor = this.options.drawingCursor;
237
+ },
238
+
239
+ unregisterForDrawing: function (editor) {
240
+ this.unblockEvents();
241
+ L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass);
242
+ this.map._container.style.cursor = this.defaultMapCursor;
243
+ editor = editor || this._drawingEditor;
244
+ if (!editor) return;
245
+ this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor);
246
+ this.map.off('mousedown', this.onMousedown, this);
247
+ this.map.off('mouseup', this.onMouseup, this);
248
+ if (editor !== this._drawingEditor) return;
249
+ delete this._drawingEditor;
250
+ if (editor._drawing) editor.cancelDrawing();
251
+ },
252
+
253
+ onMousedown: function (e) {
254
+ this._mouseDown = e;
255
+ this._drawingEditor.onDrawingMouseDown(e);
256
+ },
257
+
258
+ onMouseup: function (e) {
259
+ if (this._mouseDown) {
260
+ var editor = this._drawingEditor,
261
+ mouseDown = this._mouseDown;
262
+ this._mouseDown = null;
263
+ editor.onDrawingMouseUp(e);
264
+ if (this._drawingEditor !== editor) return; // onDrawingMouseUp may call unregisterFromDrawing.
265
+ var origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY);
266
+ var distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin);
267
+ if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e);
268
+ }
269
+ },
270
+
271
+ // 🍂section Public methods
272
+ // You will generally access them by the `map.editTools`
273
+ // instance:
274
+ //
275
+ // `map.editTools.startPolyline();`
276
+
277
+ // 🍂method drawing(): boolean
278
+ // Return true if any drawing action is ongoing.
279
+ drawing: function () {
280
+ return this._drawingEditor && this._drawingEditor.drawing();
281
+ },
282
+
283
+ // 🍂method stopDrawing()
284
+ // When you need to stop any ongoing drawing, without needing to know which editor is active.
285
+ stopDrawing: function () {
286
+ this.unregisterForDrawing();
287
+ },
288
+
289
+ // 🍂method commitDrawing()
290
+ // When you need to commit any ongoing drawing, without needing to know which editor is active.
291
+ commitDrawing: function (e) {
292
+ if (!this._drawingEditor) return;
293
+ this._drawingEditor.commitDrawing(e);
294
+ },
295
+
296
+ connectCreatedToMap: function (layer) {
297
+ return this.featuresLayer.addLayer(layer);
298
+ },
299
+
300
+ // 🍂method startPolyline(latlng: L.LatLng, options: hash): L.Polyline
301
+ // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click.
302
+ // If `options` is given, it will be passed to the Polyline class constructor.
303
+ startPolyline: function (latlng, options) {
304
+ var line = this.createPolyline([], options);
305
+ line.enableEdit(this.map).newShape(latlng);
306
+ return line;
307
+ },
308
+
309
+ // 🍂method startPolygon(latlng: L.LatLng, options: hash): L.Polygon
310
+ // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click.
311
+ // If `options` is given, it will be passed to the Polygon class constructor.
312
+ startPolygon: function (latlng, options) {
313
+ var polygon = this.createPolygon([], options);
314
+ polygon.enableEdit(this.map).newShape(latlng);
315
+ return polygon;
316
+ },
317
+
318
+ // 🍂method startMarker(latlng: L.LatLng, options: hash): L.Marker
319
+ // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point.
320
+ // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch).
321
+ // If `options` is given, it will be passed to the Marker class constructor.
322
+ startMarker: function (latlng, options) {
323
+ latlng = latlng || this.map.getCenter().clone();
324
+ var marker = this.createMarker(latlng, options);
325
+ marker.enableEdit(this.map).startDrawing();
326
+ return marker;
327
+ },
328
+
329
+ // 🍂method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle
330
+ // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag.
331
+ // If `options` is given, it will be passed to the Rectangle class constructor.
332
+ startRectangle: function(latlng, options) {
333
+ var corner = latlng || L.latLng([0, 0]);
334
+ var bounds = new L.LatLngBounds(corner, corner);
335
+ var rectangle = this.createRectangle(bounds, options);
336
+ rectangle.enableEdit(this.map).startDrawing();
337
+ return rectangle;
338
+ },
339
+
340
+ // 🍂method startCircle(latlng: L.LatLng, options: hash): L.Circle
341
+ // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag.
342
+ // If `options` is given, it will be passed to the Circle class constructor.
343
+ startCircle: function (latlng, options) {
344
+ latlng = latlng || this.map.getCenter().clone();
345
+ var circle = this.createCircle(latlng, options);
346
+ circle.enableEdit(this.map).startDrawing();
347
+ return circle;
348
+ },
349
+
350
+ startHole: function (editor, latlng) {
351
+ editor.newHole(latlng);
352
+ },
353
+
354
+ createLayer: function (klass, latlngs, options) {
355
+ options = L.Util.extend({editOptions: {editTools: this}}, options);
356
+ var layer = new klass(latlngs, options);
357
+ // 🍂namespace Editable
358
+ // 🍂event editable:created: LayerEvent
359
+ // Fired when a new feature (Marker, Polyline…) is created.
360
+ this.fireAndForward('editable:created', {layer: layer});
361
+ return layer;
362
+ },
363
+
364
+ createPolyline: function (latlngs, options) {
365
+ return this.createLayer(options && options.polylineClass || this.options.polylineClass, latlngs, options);
366
+ },
367
+
368
+ createPolygon: function (latlngs, options) {
369
+ return this.createLayer(options && options.polygonClass || this.options.polygonClass, latlngs, options);
370
+ },
371
+
372
+ createMarker: function (latlng, options) {
373
+ return this.createLayer(options && options.markerClass || this.options.markerClass, latlng, options);
374
+ },
375
+
376
+ createRectangle: function (bounds, options) {
377
+ return this.createLayer(options && options.rectangleClass || this.options.rectangleClass, bounds, options);
378
+ },
379
+
380
+ createCircle: function (latlng, options) {
381
+ return this.createLayer(options && options.circleClass || this.options.circleClass, latlng, options);
382
+ }
383
+
384
+ });
385
+
386
+ L.extend(L.Editable, {
387
+
388
+ makeCancellable: function (e) {
389
+ e.cancel = function () {
390
+ e._cancelled = true;
391
+ };
392
+ }
393
+
394
+ });
395
+
396
+ // 🍂namespace Map; 🍂class Map
397
+ // Leaflet.Editable add options and events to the `L.Map` object.
398
+ // See `Editable` events for the list of events fired on the Map.
399
+ // 🍂example
400
+ //
401
+ // ```js
402
+ // var map = L.map('map', {
403
+ // editable: true,
404
+ // editOptions: {
405
+ // …
406
+ // }
407
+ // });
408
+ // ```
409
+ // 🍂section Editable Map Options
410
+ L.Map.mergeOptions({
411
+
412
+ // 🍂namespace Map
413
+ // 🍂section Map Options
414
+ // 🍂option editToolsClass: class = L.Editable
415
+ // Class to be used as vertex, for path editing.
416
+ editToolsClass: L.Editable,
417
+
418
+ // 🍂option editable: boolean = false
419
+ // Whether to create a L.Editable instance at map init.
420
+ editable: false,
421
+
422
+ // 🍂option editOptions: hash = {}
423
+ // Options to pass to L.Editable when instanciating.
424
+ editOptions: {}
425
+
426
+ });
427
+
428
+ L.Map.addInitHook(function () {
429
+
430
+ this.whenReady(function () {
431
+ if (this.options.editable) {
432
+ this.editTools = new this.options.editToolsClass(this, this.options.editOptions);
433
+ }
434
+ });
435
+
436
+ });
437
+
438
+ L.Editable.VertexIcon = L.DivIcon.extend({
439
+
440
+ options: {
441
+ iconSize: new L.Point(8, 8)
442
+ }
443
+
444
+ });
445
+
446
+ L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({
447
+
448
+ options: {
449
+ iconSize: new L.Point(20, 20)
450
+ }
451
+
452
+ });
453
+
454
+
455
+ // 🍂namespace Editable; 🍂class VertexMarker; Handler for dragging path vertices.
456
+ L.Editable.VertexMarker = L.Marker.extend({
457
+
458
+ options: {
459
+ draggable: true,
460
+ className: 'leaflet-div-icon leaflet-vertex-icon'
461
+ },
462
+
463
+
464
+ // 🍂section Public methods
465
+ // The marker used to handle path vertex. You will usually interact with a `VertexMarker`
466
+ // instance when listening for events like `editable:vertex:ctrlclick`.
467
+
468
+ initialize: function (latlng, latlngs, editor, options) {
469
+ // We don't use this._latlng, because on drag Leaflet replace it while
470
+ // we want to keep reference.
471
+ this.latlng = latlng;
472
+ this.latlngs = latlngs;
473
+ this.editor = editor;
474
+ L.Marker.prototype.initialize.call(this, latlng, options);
475
+ this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className});
476
+ this.latlng.__vertex = this;
477
+ this.editor.editLayer.addLayer(this);
478
+ this.setZIndexOffset(editor.tools._lastZIndex + 1);
479
+ },
480
+
481
+ onAdd: function (map) {
482
+ L.Marker.prototype.onAdd.call(this, map);
483
+ this.on('drag', this.onDrag);
484
+ this.on('dragstart', this.onDragStart);
485
+ this.on('dragend', this.onDragEnd);
486
+ this.on('mouseup', this.onMouseup);
487
+ this.on('click', this.onClick);
488
+ this.on('contextmenu', this.onContextMenu);
489
+ this.on('mousedown touchstart', this.onMouseDown);
490
+ this.addMiddleMarkers();
491
+ },
492
+
493
+ onRemove: function (map) {
494
+ if (this.middleMarker) this.middleMarker.delete();
495
+ delete this.latlng.__vertex;
496
+ this.off('drag', this.onDrag);
497
+ this.off('dragstart', this.onDragStart);
498
+ this.off('dragend', this.onDragEnd);
499
+ this.off('mouseup', this.onMouseup);
500
+ this.off('click', this.onClick);
501
+ this.off('contextmenu', this.onContextMenu);
502
+ this.off('mousedown touchstart', this.onMouseDown);
503
+ L.Marker.prototype.onRemove.call(this, map);
504
+ },
505
+
506
+ onDrag: function (e) {
507
+ e.vertex = this;
508
+ this.editor.onVertexMarkerDrag(e);
509
+ var iconPos = L.DomUtil.getPosition(this._icon),
510
+ latlng = this._map.layerPointToLatLng(iconPos);
511
+ this.latlng.update(latlng);
512
+ this._latlng = this.latlng; // Push back to Leaflet our reference.
513
+ this.editor.refresh();
514
+ if (this.middleMarker) this.middleMarker.updateLatLng();
515
+ var next = this.getNext();
516
+ if (next && next.middleMarker) next.middleMarker.updateLatLng();
517
+ },
518
+
519
+ onDragStart: function (e) {
520
+ e.vertex = this;
521
+ this.editor.onVertexMarkerDragStart(e);
522
+ },
523
+
524
+ onDragEnd: function (e) {
525
+ e.vertex = this;
526
+ this.editor.onVertexMarkerDragEnd(e);
527
+ },
528
+
529
+ onClick: function (e) {
530
+ e.vertex = this;
531
+ this.editor.onVertexMarkerClick(e);
532
+ },
533
+
534
+ onMouseup: function (e) {
535
+ L.DomEvent.stop(e);
536
+ e.vertex = this;
537
+ this.editor.map.fire('mouseup', e);
538
+ },
539
+
540
+ onContextMenu: function (e) {
541
+ e.vertex = this;
542
+ this.editor.onVertexMarkerContextMenu(e);
543
+ },
544
+
545
+ onMouseDown: function (e) {
546
+ e.vertex = this;
547
+ this.editor.onVertexMarkerMouseDown(e);
548
+ },
549
+
550
+ // 🍂method delete()
551
+ // Delete a vertex and the related LatLng.
552
+ delete: function () {
553
+ var next = this.getNext(); // Compute before changing latlng
554
+ this.latlngs.splice(this.getIndex(), 1);
555
+ this.editor.editLayer.removeLayer(this);
556
+ this.editor.onVertexDeleted({latlng: this.latlng, vertex: this});
557
+ if (!this.latlngs.length) this.editor.deleteShape(this.latlngs);
558
+ if (next) next.resetMiddleMarker();
559
+ this.editor.refresh();
560
+ },
561
+
562
+ // 🍂method getIndex(): int
563
+ // Get the index of the current vertex among others of the same LatLngs group.
564
+ getIndex: function () {
565
+ return this.latlngs.indexOf(this.latlng);
566
+ },
567
+
568
+ // 🍂method getLastIndex(): int
569
+ // Get last vertex index of the LatLngs group of the current vertex.
570
+ getLastIndex: function () {
571
+ return this.latlngs.length - 1;
572
+ },
573
+
574
+ // 🍂method getPrevious(): VertexMarker
575
+ // Get the previous VertexMarker in the same LatLngs group.
576
+ getPrevious: function () {
577
+ if (this.latlngs.length < 2) return;
578
+ var index = this.getIndex(),
579
+ previousIndex = index - 1;
580
+ if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex();
581
+ var previous = this.latlngs[previousIndex];
582
+ if (previous) return previous.__vertex;
583
+ },
584
+
585
+ // 🍂method getNext(): VertexMarker
586
+ // Get the next VertexMarker in the same LatLngs group.
587
+ getNext: function () {
588
+ if (this.latlngs.length < 2) return;
589
+ var index = this.getIndex(),
590
+ nextIndex = index + 1;
591
+ if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0;
592
+ var next = this.latlngs[nextIndex];
593
+ if (next) return next.__vertex;
594
+ },
595
+
596
+ addMiddleMarker: function (previous) {
597
+ if (!this.editor.hasMiddleMarkers()) return;
598
+ previous = previous || this.getPrevious();
599
+ if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor);
600
+ },
601
+
602
+ addMiddleMarkers: function () {
603
+ if (!this.editor.hasMiddleMarkers()) return;
604
+ var previous = this.getPrevious();
605
+ if (previous) this.addMiddleMarker(previous);
606
+ var next = this.getNext();
607
+ if (next) next.resetMiddleMarker();
608
+ },
609
+
610
+ resetMiddleMarker: function () {
611
+ if (this.middleMarker) this.middleMarker.delete();
612
+ this.addMiddleMarker();
613
+ },
614
+
615
+ // 🍂method split()
616
+ // Split the vertex LatLngs group at its index, if possible.
617
+ split: function () {
618
+ if (!this.editor.splitShape) return; // Only for PolylineEditor
619
+ this.editor.splitShape(this.latlngs, this.getIndex());
620
+ },
621
+
622
+ // 🍂method continue()
623
+ // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline.
624
+ continue: function () {
625
+ if (!this.editor.continueBackward) return; // Only for PolylineEditor
626
+ var index = this.getIndex();
627
+ if (index === 0) this.editor.continueBackward(this.latlngs);
628
+ else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs);
629
+ }
630
+
631
+ });
632
+
633
+ L.Editable.mergeOptions({
634
+
635
+ // 🍂namespace Editable
636
+ // 🍂option vertexMarkerClass: class = VertexMarker
637
+ // Class to be used as vertex, for path editing.
638
+ vertexMarkerClass: L.Editable.VertexMarker
639
+
640
+ });
641
+
642
+ L.Editable.MiddleMarker = L.Marker.extend({
643
+
644
+ options: {
645
+ opacity: 0.5,
646
+ className: 'leaflet-div-icon leaflet-middle-icon',
647
+ draggable: true
648
+ },
649
+
650
+ initialize: function (left, right, latlngs, editor, options) {
651
+ this.left = left;
652
+ this.right = right;
653
+ this.editor = editor;
654
+ this.latlngs = latlngs;
655
+ L.Marker.prototype.initialize.call(this, this.computeLatLng(), options);
656
+ this._opacity = this.options.opacity;
657
+ this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className});
658
+ this.editor.editLayer.addLayer(this);
659
+ this.setVisibility();
660
+ },
661
+
662
+ setVisibility: function () {
663
+ var leftPoint = this._map.latLngToContainerPoint(this.left.latlng),
664
+ rightPoint = this._map.latLngToContainerPoint(this.right.latlng),
665
+ size = L.point(this.options.icon.options.iconSize);
666
+ if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide();
667
+ else this.show();
668
+ },
669
+
670
+ show: function () {
671
+ this.setOpacity(this._opacity);
672
+ },
673
+
674
+ hide: function () {
675
+ this.setOpacity(0);
676
+ },
677
+
678
+ updateLatLng: function () {
679
+ this.setLatLng(this.computeLatLng());
680
+ this.setVisibility();
681
+ },
682
+
683
+ computeLatLng: function () {
684
+ var leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng),
685
+ rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng),
686
+ y = (leftPoint.y + rightPoint.y) / 2,
687
+ x = (leftPoint.x + rightPoint.x) / 2;
688
+ return this.editor.map.containerPointToLatLng([x, y]);
689
+ },
690
+
691
+ onAdd: function (map) {
692
+ L.Marker.prototype.onAdd.call(this, map);
693
+ L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this);
694
+ map.on('zoomend', this.setVisibility, this);
695
+ },
696
+
697
+ onRemove: function (map) {
698
+ delete this.right.middleMarker;
699
+ L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this);
700
+ map.off('zoomend', this.setVisibility, this);
701
+ L.Marker.prototype.onRemove.call(this, map);
702
+ },
703
+
704
+ onMouseDown: function (e) {
705
+ var iconPos = L.DomUtil.getPosition(this._icon),
706
+ latlng = this.editor.map.layerPointToLatLng(iconPos);
707
+ e = {
708
+ originalEvent: e,
709
+ latlng: latlng
710
+ };
711
+ if (this.options.opacity === 0) return;
712
+ L.Editable.makeCancellable(e);
713
+ this.editor.onMiddleMarkerMouseDown(e);
714
+ if (e._cancelled) return;
715
+ this.latlngs.splice(this.index(), 0, e.latlng);
716
+ this.editor.refresh();
717
+ var icon = this._icon;
718
+ var marker = this.editor.addVertexMarker(e.latlng, this.latlngs);
719
+ this.editor.onNewVertex(marker);
720
+ /* Hack to workaround browser not firing touchend when element is no more on DOM */
721
+ var parent = marker._icon.parentNode;
722
+ parent.removeChild(marker._icon);
723
+ marker._icon = icon;
724
+ parent.appendChild(marker._icon);
725
+ marker._initIcon();
726
+ marker._initInteraction();
727
+ marker.setOpacity(1);
728
+ /* End hack */
729
+ // Transfer ongoing dragging to real marker
730
+ L.Draggable._dragging = false;
731
+ marker.dragging._draggable._onDown(e.originalEvent);
732
+ this.delete();
733
+ },
734
+
735
+ delete: function () {
736
+ this.editor.editLayer.removeLayer(this);
737
+ },
738
+
739
+ index: function () {
740
+ return this.latlngs.indexOf(this.right.latlng);
741
+ }
742
+
743
+ });
744
+
745
+ L.Editable.mergeOptions({
746
+
747
+ // 🍂namespace Editable
748
+ // 🍂option middleMarkerClass: class = VertexMarker
749
+ // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path.
750
+ middleMarkerClass: L.Editable.MiddleMarker
751
+
752
+ });
753
+
754
+ // 🍂namespace Editable; 🍂class BaseEditor; 🍂aka L.Editable.BaseEditor
755
+ // When editing a feature (Marker, Polyline…), an editor is attached to it. This
756
+ // editor basically knows how to handle the edition.
757
+ L.Editable.BaseEditor = L.Handler.extend({
758
+
759
+ initialize: function (map, feature, options) {
760
+ L.setOptions(this, options);
761
+ this.map = map;
762
+ this.feature = feature;
763
+ this.feature.editor = this;
764
+ this.editLayer = new L.LayerGroup();
765
+ this.tools = this.options.editTools || map.editTools;
766
+ },
767
+
768
+ // 🍂method enable(): this
769
+ // Set up the drawing tools for the feature to be editable.
770
+ addHooks: function () {
771
+ if (this.isConnected()) this.onFeatureAdd();
772
+ else this.feature.once('add', this.onFeatureAdd, this);
773
+ this.onEnable();
774
+ this.feature.on(this._getEvents(), this);
775
+ return;
776
+ },
777
+
778
+ // 🍂method disable(): this
779
+ // Remove the drawing tools for the feature.
780
+ removeHooks: function () {
781
+ this.feature.off(this._getEvents(), this);
782
+ if (this.feature.dragging) this.feature.dragging.disable();
783
+ this.editLayer.clearLayers();
784
+ this.tools.editLayer.removeLayer(this.editLayer);
785
+ this.onDisable();
786
+ if (this._drawing) this.cancelDrawing();
787
+ return;
788
+ },
789
+
790
+ // 🍂method drawing(): boolean
791
+ // Return true if any drawing action is ongoing with this editor.
792
+ drawing: function () {
793
+ return !!this._drawing;
794
+ },
795
+
796
+ reset: function () {},
797
+
798
+ onFeatureAdd: function () {
799
+ this.tools.editLayer.addLayer(this.editLayer);
800
+ if (this.feature.dragging) this.feature.dragging.enable();
801
+ },
802
+
803
+ hasMiddleMarkers: function () {
804
+ return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers;
805
+ },
806
+
807
+ fireAndForward: function (type, e) {
808
+ e = e || {};
809
+ e.layer = this.feature;
810
+ this.feature.fire(type, e);
811
+ this.tools.fireAndForward(type, e);
812
+ },
813
+
814
+ onEnable: function () {
815
+ // 🍂namespace Editable
816
+ // 🍂event editable:enable: Event
817
+ // Fired when an existing feature is ready to be edited.
818
+ this.fireAndForward('editable:enable');
819
+ },
820
+
821
+ onDisable: function () {
822
+ // 🍂namespace Editable
823
+ // 🍂event editable:disable: Event
824
+ // Fired when an existing feature is not ready anymore to be edited.
825
+ this.fireAndForward('editable:disable');
826
+ },
827
+
828
+ onEditing: function () {
829
+ // 🍂namespace Editable
830
+ // 🍂event editable:editing: Event
831
+ // Fired as soon as any change is made to the feature geometry.
832
+ this.fireAndForward('editable:editing');
833
+ },
834
+
835
+ onStartDrawing: function () {
836
+ // 🍂namespace Editable
837
+ // 🍂section Drawing events
838
+ // 🍂event editable:drawing:start: Event
839
+ // Fired when a feature is to be drawn.
840
+ this.fireAndForward('editable:drawing:start');
841
+ },
842
+
843
+ onEndDrawing: function () {
844
+ // 🍂namespace Editable
845
+ // 🍂section Drawing events
846
+ // 🍂event editable:drawing:end: Event
847
+ // Fired when a feature is not drawn anymore.
848
+ this.fireAndForward('editable:drawing:end');
849
+ },
850
+
851
+ onCancelDrawing: function () {
852
+ // 🍂namespace Editable
853
+ // 🍂section Drawing events
854
+ // 🍂event editable:drawing:cancel: Event
855
+ // Fired when user cancel drawing while a feature is being drawn.
856
+ this.fireAndForward('editable:drawing:cancel');
857
+ },
858
+
859
+ onCommitDrawing: function (e) {
860
+ // 🍂namespace Editable
861
+ // 🍂section Drawing events
862
+ // 🍂event editable:drawing:commit: Event
863
+ // Fired when user finish drawing a feature.
864
+ this.fireAndForward('editable:drawing:commit', e);
865
+ },
866
+
867
+ onDrawingMouseDown: function (e) {
868
+ // 🍂namespace Editable
869
+ // 🍂section Drawing events
870
+ // 🍂event editable:drawing:mousedown: Event
871
+ // Fired when user `mousedown` while drawing.
872
+ this.fireAndForward('editable:drawing:mousedown', e);
873
+ },
874
+
875
+ onDrawingMouseUp: function (e) {
876
+ // 🍂namespace Editable
877
+ // 🍂section Drawing events
878
+ // 🍂event editable:drawing:mouseup: Event
879
+ // Fired when user `mouseup` while drawing.
880
+ this.fireAndForward('editable:drawing:mouseup', e);
881
+ },
882
+
883
+ startDrawing: function () {
884
+ if (!this._drawing) this._drawing = L.Editable.FORWARD;
885
+ this.tools.registerForDrawing(this);
886
+ this.onStartDrawing();
887
+ },
888
+
889
+ commitDrawing: function (e) {
890
+ this.onCommitDrawing(e);
891
+ this.endDrawing();
892
+ },
893
+
894
+ cancelDrawing: function () {
895
+ // If called during a vertex drag, the vertex will be removed before
896
+ // the mouseup fires on it. This is a workaround. Maybe better fix is
897
+ // To have L.Draggable reset it's status on disable (Leaflet side).
898
+ L.Draggable._dragging = false;
899
+ this.onCancelDrawing();
900
+ this.endDrawing();
901
+ },
902
+
903
+ endDrawing: function () {
904
+ this._drawing = false;
905
+ this.tools.unregisterForDrawing(this);
906
+ this.onEndDrawing();
907
+ },
908
+
909
+ onDrawingClick: function (e) {
910
+ if (!this.drawing()) return;
911
+ L.Editable.makeCancellable(e);
912
+ // 🍂namespace Editable
913
+ // 🍂section Drawing events
914
+ // 🍂event editable:drawing:click: CancelableEvent
915
+ // Fired when user `click` while drawing, before any internal action is being processed.
916
+ this.fireAndForward('editable:drawing:click', e);
917
+ if (e._cancelled) return;
918
+ if (!this.isConnected()) this.connect(e);
919
+ this.processDrawingClick(e);
920
+ },
921
+
922
+ isConnected: function () {
923
+ return this.map.hasLayer(this.feature);
924
+ },
925
+
926
+ connect: function (e) {
927
+ this.tools.connectCreatedToMap(this.feature);
928
+ this.tools.editLayer.addLayer(this.editLayer);
929
+ },
930
+
931
+ onMove: function (e) {
932
+ // 🍂namespace Editable
933
+ // 🍂section Drawing events
934
+ // 🍂event editable:drawing:move: Event
935
+ // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex.
936
+ this.fireAndForward('editable:drawing:move', e);
937
+ },
938
+
939
+ onDrawingMouseMove: function (e) {
940
+ this.onMove(e);
941
+ },
942
+
943
+ _getEvents: function () {
944
+ return {
945
+ dragstart: this.onDragStart,
946
+ drag: this.onDrag,
947
+ dragend: this.onDragEnd,
948
+ remove: this.disable
949
+ };
950
+ },
951
+
952
+ onDragStart: function (e) {
953
+ this.onEditing();
954
+ // 🍂namespace Editable
955
+ // 🍂event editable:dragstart: Event
956
+ // Fired before a path feature is dragged.
957
+ this.fireAndForward('editable:dragstart', e);
958
+ },
959
+
960
+ onDrag: function (e) {
961
+ this.onMove(e);
962
+ // 🍂namespace Editable
963
+ // 🍂event editable:drag: Event
964
+ // Fired when a path feature is being dragged.
965
+ this.fireAndForward('editable:drag', e);
966
+ },
967
+
968
+ onDragEnd: function (e) {
969
+ // 🍂namespace Editable
970
+ // 🍂event editable:dragend: Event
971
+ // Fired after a path feature has been dragged.
972
+ this.fireAndForward('editable:dragend', e);
973
+ }
974
+
975
+ });
976
+
977
+ // 🍂namespace Editable; 🍂class MarkerEditor; 🍂aka L.Editable.MarkerEditor
978
+ // 🍂inherits BaseEditor
979
+ // Editor for Marker.
980
+ L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({
981
+
982
+ onDrawingMouseMove: function (e) {
983
+ L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e);
984
+ if (this._drawing) this.feature.setLatLng(e.latlng);
985
+ },
986
+
987
+ processDrawingClick: function (e) {
988
+ // 🍂namespace Editable
989
+ // 🍂section Drawing events
990
+ // 🍂event editable:drawing:clicked: Event
991
+ // Fired when user `click` while drawing, after all internal actions.
992
+ this.fireAndForward('editable:drawing:clicked', e);
993
+ this.commitDrawing(e);
994
+ },
995
+
996
+ connect: function (e) {
997
+ // On touch, the latlng has not been updated because there is
998
+ // no mousemove.
999
+ if (e) this.feature._latlng = e.latlng;
1000
+ L.Editable.BaseEditor.prototype.connect.call(this, e);
1001
+ }
1002
+
1003
+ });
1004
+
1005
+ // 🍂namespace Editable; 🍂class PathEditor; 🍂aka L.Editable.PathEditor
1006
+ // 🍂inherits BaseEditor
1007
+ // Base class for all path editors.
1008
+ L.Editable.PathEditor = L.Editable.BaseEditor.extend({
1009
+
1010
+ CLOSED: false,
1011
+ MIN_VERTEX: 2,
1012
+
1013
+ addHooks: function () {
1014
+ L.Editable.BaseEditor.prototype.addHooks.call(this);
1015
+ if (this.feature) this.initVertexMarkers();
1016
+ return this;
1017
+ },
1018
+
1019
+ initVertexMarkers: function (latlngs) {
1020
+ if (!this.enabled()) return;
1021
+ latlngs = latlngs || this.getLatLngs();
1022
+ if (isFlat(latlngs)) this.addVertexMarkers(latlngs);
1023
+ else for (var i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i]);
1024
+ },
1025
+
1026
+ getLatLngs: function () {
1027
+ return this.feature.getLatLngs();
1028
+ },
1029
+
1030
+ // 🍂method reset()
1031
+ // Rebuild edit elements (Vertex, MiddleMarker, etc.).
1032
+ reset: function () {
1033
+ this.editLayer.clearLayers();
1034
+ this.initVertexMarkers();
1035
+ },
1036
+
1037
+ addVertexMarker: function (latlng, latlngs) {
1038
+ return new this.tools.options.vertexMarkerClass(latlng, latlngs, this);
1039
+ },
1040
+
1041
+ onNewVertex: function (vertex) {
1042
+ // 🍂namespace Editable
1043
+ // 🍂section Vertex events
1044
+ // 🍂event editable:vertex:new: VertexEvent
1045
+ // Fired when a new vertex is created.
1046
+ this.fireAndForward('editable:vertex:new', {latlng: vertex.latlng, vertex: vertex});
1047
+ },
1048
+
1049
+ addVertexMarkers: function (latlngs) {
1050
+ for (var i = 0; i < latlngs.length; i++) {
1051
+ this.addVertexMarker(latlngs[i], latlngs);
1052
+ }
1053
+ },
1054
+
1055
+ refreshVertexMarkers: function (latlngs) {
1056
+ latlngs = latlngs || this.getDefaultLatLngs();
1057
+ for (var i = 0; i < latlngs.length; i++) {
1058
+ latlngs[i].__vertex.update();
1059
+ }
1060
+ },
1061
+
1062
+ addMiddleMarker: function (left, right, latlngs) {
1063
+ return new this.tools.options.middleMarkerClass(left, right, latlngs, this);
1064
+ },
1065
+
1066
+ onVertexMarkerClick: function (e) {
1067
+ L.Editable.makeCancellable(e);
1068
+ // 🍂namespace Editable
1069
+ // 🍂section Vertex events
1070
+ // 🍂event editable:vertex:click: CancelableVertexEvent
1071
+ // Fired when a `click` is issued on a vertex, before any internal action is being processed.
1072
+ this.fireAndForward('editable:vertex:click', e);
1073
+ if (e._cancelled) return;
1074
+ if (this.tools.drawing() && this.tools._drawingEditor !== this) return;
1075
+ var index = e.vertex.getIndex(), commit;
1076
+ if (e.originalEvent.ctrlKey) {
1077
+ this.onVertexMarkerCtrlClick(e);
1078
+ } else if (e.originalEvent.altKey) {
1079
+ this.onVertexMarkerAltClick(e);
1080
+ } else if (e.originalEvent.shiftKey) {
1081
+ this.onVertexMarkerShiftClick(e);
1082
+ } else if (e.originalEvent.metaKey) {
1083
+ this.onVertexMarkerMetaKeyClick(e);
1084
+ } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) {
1085
+ if (index >= this.MIN_VERTEX - 1) commit = true;
1086
+ } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) {
1087
+ commit = true;
1088
+ } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) {
1089
+ commit = true; // Allow to close on first point also for polygons
1090
+ } else {
1091
+ this.onVertexRawMarkerClick(e);
1092
+ }
1093
+ // 🍂namespace Editable
1094
+ // 🍂section Vertex events
1095
+ // 🍂event editable:vertex:clicked: VertexEvent
1096
+ // Fired when a `click` is issued on a vertex, after all internal actions.
1097
+ this.fireAndForward('editable:vertex:clicked', e);
1098
+ if (commit) this.commitDrawing(e);
1099
+ },
1100
+
1101
+ onVertexRawMarkerClick: function (e) {
1102
+ // 🍂namespace Editable
1103
+ // 🍂section Vertex events
1104
+ // 🍂event editable:vertex:rawclick: CancelableVertexEvent
1105
+ // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode.
1106
+ this.fireAndForward('editable:vertex:rawclick', e);
1107
+ if (e._cancelled) return;
1108
+ if (!this.vertexCanBeDeleted(e.vertex)) return;
1109
+ e.vertex.delete();
1110
+ },
1111
+
1112
+ vertexCanBeDeleted: function (vertex) {
1113
+ return vertex.latlngs.length > this.MIN_VERTEX;
1114
+ },
1115
+
1116
+ onVertexDeleted: function (e) {
1117
+ // 🍂namespace Editable
1118
+ // 🍂section Vertex events
1119
+ // 🍂event editable:vertex:deleted: VertexEvent
1120
+ // Fired after a vertex has been deleted by user.
1121
+ this.fireAndForward('editable:vertex:deleted', e);
1122
+ },
1123
+
1124
+ onVertexMarkerCtrlClick: function (e) {
1125
+ // 🍂namespace Editable
1126
+ // 🍂section Vertex events
1127
+ // 🍂event editable:vertex:ctrlclick: VertexEvent
1128
+ // Fired when a `click` with `ctrlKey` is issued on a vertex.
1129
+ this.fireAndForward('editable:vertex:ctrlclick', e);
1130
+ },
1131
+
1132
+ onVertexMarkerShiftClick: function (e) {
1133
+ // 🍂namespace Editable
1134
+ // 🍂section Vertex events
1135
+ // 🍂event editable:vertex:shiftclick: VertexEvent
1136
+ // Fired when a `click` with `shiftKey` is issued on a vertex.
1137
+ this.fireAndForward('editable:vertex:shiftclick', e);
1138
+ },
1139
+
1140
+ onVertexMarkerMetaKeyClick: function (e) {
1141
+ // 🍂namespace Editable
1142
+ // 🍂section Vertex events
1143
+ // 🍂event editable:vertex:metakeyclick: VertexEvent
1144
+ // Fired when a `click` with `metaKey` is issued on a vertex.
1145
+ this.fireAndForward('editable:vertex:metakeyclick', e);
1146
+ },
1147
+
1148
+ onVertexMarkerAltClick: function (e) {
1149
+ // 🍂namespace Editable
1150
+ // 🍂section Vertex events
1151
+ // 🍂event editable:vertex:altclick: VertexEvent
1152
+ // Fired when a `click` with `altKey` is issued on a vertex.
1153
+ this.fireAndForward('editable:vertex:altclick', e);
1154
+ },
1155
+
1156
+ onVertexMarkerContextMenu: function (e) {
1157
+ // 🍂namespace Editable
1158
+ // 🍂section Vertex events
1159
+ // 🍂event editable:vertex:contextmenu: VertexEvent
1160
+ // Fired when a `contextmenu` is issued on a vertex.
1161
+ this.fireAndForward('editable:vertex:contextmenu', e);
1162
+ },
1163
+
1164
+ onVertexMarkerMouseDown: function (e) {
1165
+ // 🍂namespace Editable
1166
+ // 🍂section Vertex events
1167
+ // 🍂event editable:vertex:mousedown: VertexEvent
1168
+ // Fired when user `mousedown` a vertex.
1169
+ this.fireAndForward('editable:vertex:mousedown', e);
1170
+ },
1171
+
1172
+ onMiddleMarkerMouseDown: function (e) {
1173
+ // 🍂namespace Editable
1174
+ // 🍂section MiddleMarker events
1175
+ // 🍂event editable:middlemarker:mousedown: VertexEvent
1176
+ // Fired when user `mousedown` a middle marker.
1177
+ this.fireAndForward('editable:middlemarker:mousedown', e);
1178
+ },
1179
+
1180
+ onVertexMarkerDrag: function (e) {
1181
+ this.onMove(e);
1182
+ if (this.feature._bounds) this.extendBounds(e);
1183
+ // 🍂namespace Editable
1184
+ // 🍂section Vertex events
1185
+ // 🍂event editable:vertex:drag: VertexEvent
1186
+ // Fired when a vertex is dragged by user.
1187
+ this.fireAndForward('editable:vertex:drag', e);
1188
+ },
1189
+
1190
+ onVertexMarkerDragStart: function (e) {
1191
+ // 🍂namespace Editable
1192
+ // 🍂section Vertex events
1193
+ // 🍂event editable:vertex:dragstart: VertexEvent
1194
+ // Fired before a vertex is dragged by user.
1195
+ this.fireAndForward('editable:vertex:dragstart', e);
1196
+ },
1197
+
1198
+ onVertexMarkerDragEnd: function (e) {
1199
+ // 🍂namespace Editable
1200
+ // 🍂section Vertex events
1201
+ // 🍂event editable:vertex:dragend: VertexEvent
1202
+ // Fired after a vertex is dragged by user.
1203
+ this.fireAndForward('editable:vertex:dragend', e);
1204
+ },
1205
+
1206
+ setDrawnLatLngs: function (latlngs) {
1207
+ this._drawnLatLngs = latlngs || this.getDefaultLatLngs();
1208
+ },
1209
+
1210
+ startDrawing: function () {
1211
+ if (!this._drawnLatLngs) this.setDrawnLatLngs();
1212
+ L.Editable.BaseEditor.prototype.startDrawing.call(this);
1213
+ },
1214
+
1215
+ startDrawingForward: function () {
1216
+ this.startDrawing();
1217
+ },
1218
+
1219
+ endDrawing: function () {
1220
+ this.tools.detachForwardLineGuide();
1221
+ this.tools.detachBackwardLineGuide();
1222
+ if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs);
1223
+ L.Editable.BaseEditor.prototype.endDrawing.call(this);
1224
+ delete this._drawnLatLngs;
1225
+ },
1226
+
1227
+ addLatLng: function (latlng) {
1228
+ if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng);
1229
+ else this._drawnLatLngs.unshift(latlng);
1230
+ this.feature._bounds.extend(latlng);
1231
+ var vertex = this.addVertexMarker(latlng, this._drawnLatLngs);
1232
+ this.onNewVertex(vertex);
1233
+ this.refresh();
1234
+ },
1235
+
1236
+ newPointForward: function (latlng) {
1237
+ this.addLatLng(latlng);
1238
+ this.tools.attachForwardLineGuide();
1239
+ this.tools.anchorForwardLineGuide(latlng);
1240
+ },
1241
+
1242
+ newPointBackward: function (latlng) {
1243
+ this.addLatLng(latlng);
1244
+ this.tools.anchorBackwardLineGuide(latlng);
1245
+ },
1246
+
1247
+ // 🍂namespace PathEditor
1248
+ // 🍂method push()
1249
+ // Programmatically add a point while drawing.
1250
+ push: function (latlng) {
1251
+ if (!latlng) return console.error('L.Editable.PathEditor.push expect a vaild latlng as parameter');
1252
+ if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng);
1253
+ else this.newPointBackward(latlng);
1254
+ },
1255
+
1256
+ removeLatLng: function (latlng) {
1257
+ latlng.__vertex.delete();
1258
+ this.refresh();
1259
+ },
1260
+
1261
+ // 🍂method pop(): L.LatLng or null
1262
+ // Programmatically remove last point (if any) while drawing.
1263
+ pop: function () {
1264
+ if (this._drawnLatLngs.length <= 1) return;
1265
+ var latlng;
1266
+ if (this._drawing === L.Editable.FORWARD) latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1];
1267
+ else latlng = this._drawnLatLngs[0];
1268
+ this.removeLatLng(latlng);
1269
+ if (this._drawing === L.Editable.FORWARD) this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1]);
1270
+ else this.tools.anchorForwardLineGuide(this._drawnLatLngs[0]);
1271
+ return latlng;
1272
+ },
1273
+
1274
+ processDrawingClick: function (e) {
1275
+ if (e.vertex && e.vertex.editor === this) return;
1276
+ if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng);
1277
+ else this.newPointBackward(e.latlng);
1278
+ this.fireAndForward('editable:drawing:clicked', e);
1279
+ },
1280
+
1281
+ onDrawingMouseMove: function (e) {
1282
+ L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e);
1283
+ if (this._drawing) {
1284
+ this.tools.moveForwardLineGuide(e.latlng);
1285
+ this.tools.moveBackwardLineGuide(e.latlng);
1286
+ }
1287
+ },
1288
+
1289
+ refresh: function () {
1290
+ this.feature.redraw();
1291
+ this.onEditing();
1292
+ },
1293
+
1294
+ // 🍂namespace PathEditor
1295
+ // 🍂method newShape(latlng?: L.LatLng)
1296
+ // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it;
1297
+ // if optional `latlng` is given, start a path at this point.
1298
+ newShape: function (latlng) {
1299
+ var shape = this.addNewEmptyShape();
1300
+ if (!shape) return;
1301
+ this.setDrawnLatLngs(shape[0] || shape); // Polygon or polyline
1302
+ this.startDrawingForward();
1303
+ // 🍂namespace Editable
1304
+ // 🍂section Shape events
1305
+ // 🍂event editable:shape:new: ShapeEvent
1306
+ // Fired when a new shape is created in a multi (Polygon or Polyline).
1307
+ this.fireAndForward('editable:shape:new', {shape: shape});
1308
+ if (latlng) this.newPointForward(latlng);
1309
+ },
1310
+
1311
+ deleteShape: function (shape, latlngs) {
1312
+ var e = {shape: shape};
1313
+ L.Editable.makeCancellable(e);
1314
+ // 🍂namespace Editable
1315
+ // 🍂section Shape events
1316
+ // 🍂event editable:shape:delete: CancelableShapeEvent
1317
+ // Fired before a new shape is deleted in a multi (Polygon or Polyline).
1318
+ this.fireAndForward('editable:shape:delete', e);
1319
+ if (e._cancelled) return;
1320
+ shape = this._deleteShape(shape, latlngs);
1321
+ if (this.ensureNotFlat) this.ensureNotFlat(); // Polygon.
1322
+ this.feature.setLatLngs(this.getLatLngs()); // Force bounds reset.
1323
+ this.refresh();
1324
+ this.reset();
1325
+ // 🍂namespace Editable
1326
+ // 🍂section Shape events
1327
+ // 🍂event editable:shape:deleted: ShapeEvent
1328
+ // Fired after a new shape is deleted in a multi (Polygon or Polyline).
1329
+ this.fireAndForward('editable:shape:deleted', {shape: shape});
1330
+ return shape;
1331
+ },
1332
+
1333
+ _deleteShape: function (shape, latlngs) {
1334
+ latlngs = latlngs || this.getLatLngs();
1335
+ if (!latlngs.length) return;
1336
+ var self = this,
1337
+ inplaceDelete = function (latlngs, shape) {
1338
+ // Called when deleting a flat latlngs
1339
+ shape = latlngs.splice(0, Number.MAX_VALUE);
1340
+ return shape;
1341
+ },
1342
+ spliceDelete = function (latlngs, shape) {
1343
+ // Called when removing a latlngs inside an array
1344
+ latlngs.splice(latlngs.indexOf(shape), 1);
1345
+ if (!latlngs.length) self._deleteShape(latlngs);
1346
+ return shape;
1347
+ };
1348
+ if (latlngs === shape) return inplaceDelete(latlngs, shape);
1349
+ for (var i = 0; i < latlngs.length; i++) {
1350
+ if (latlngs[i] === shape) return spliceDelete(latlngs, shape);
1351
+ else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape);
1352
+ }
1353
+ },
1354
+
1355
+ // 🍂namespace PathEditor
1356
+ // 🍂method deleteShapeAt(latlng: L.LatLng): Array
1357
+ // Remove a path shape at the given `latlng`.
1358
+ deleteShapeAt: function (latlng) {
1359
+ var shape = this.feature.shapeAt(latlng);
1360
+ if (shape) return this.deleteShape(shape);
1361
+ },
1362
+
1363
+ // 🍂method appendShape(shape: Array)
1364
+ // Append a new shape to the Polygon or Polyline.
1365
+ appendShape: function (shape) {
1366
+ this.insertShape(shape);
1367
+ },
1368
+
1369
+ // 🍂method prependShape(shape: Array)
1370
+ // Prepend a new shape to the Polygon or Polyline.
1371
+ prependShape: function (shape) {
1372
+ this.insertShape(shape, 0);
1373
+ },
1374
+
1375
+ // 🍂method insertShape(shape: Array, index: int)
1376
+ // Insert a new shape to the Polygon or Polyline at given index (default is to append).
1377
+ insertShape: function (shape, index) {
1378
+ this.ensureMulti();
1379
+ shape = this.formatShape(shape);
1380
+ if (typeof index === 'undefined') index = this.feature._latlngs.length;
1381
+ this.feature._latlngs.splice(index, 0, shape);
1382
+ this.feature.redraw();
1383
+ if (this._enabled) this.reset();
1384
+ },
1385
+
1386
+ extendBounds: function (e) {
1387
+ this.feature._bounds.extend(e.vertex.latlng);
1388
+ },
1389
+
1390
+ onDragStart: function (e) {
1391
+ this.editLayer.clearLayers();
1392
+ L.Editable.BaseEditor.prototype.onDragStart.call(this, e);
1393
+ },
1394
+
1395
+ onDragEnd: function (e) {
1396
+ this.initVertexMarkers();
1397
+ L.Editable.BaseEditor.prototype.onDragEnd.call(this, e);
1398
+ }
1399
+
1400
+ });
1401
+
1402
+ // 🍂namespace Editable; 🍂class PolylineEditor; 🍂aka L.Editable.PolylineEditor
1403
+ // 🍂inherits PathEditor
1404
+ L.Editable.PolylineEditor = L.Editable.PathEditor.extend({
1405
+
1406
+ startDrawingBackward: function () {
1407
+ this._drawing = L.Editable.BACKWARD;
1408
+ this.startDrawing();
1409
+ },
1410
+
1411
+ // 🍂method continueBackward(latlngs?: Array)
1412
+ // Set up drawing tools to continue the line backward.
1413
+ continueBackward: function (latlngs) {
1414
+ if (this.drawing()) return;
1415
+ latlngs = latlngs || this.getDefaultLatLngs();
1416
+ this.setDrawnLatLngs(latlngs);
1417
+ if (latlngs.length > 0) {
1418
+ this.tools.attachBackwardLineGuide();
1419
+ this.tools.anchorBackwardLineGuide(latlngs[0]);
1420
+ }
1421
+ this.startDrawingBackward();
1422
+ },
1423
+
1424
+ // 🍂method continueForward(latlngs?: Array)
1425
+ // Set up drawing tools to continue the line forward.
1426
+ continueForward: function (latlngs) {
1427
+ if (this.drawing()) return;
1428
+ latlngs = latlngs || this.getDefaultLatLngs();
1429
+ this.setDrawnLatLngs(latlngs);
1430
+ if (latlngs.length > 0) {
1431
+ this.tools.attachForwardLineGuide();
1432
+ this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1]);
1433
+ }
1434
+ this.startDrawingForward();
1435
+ },
1436
+
1437
+ getDefaultLatLngs: function (latlngs) {
1438
+ latlngs = latlngs || this.feature._latlngs;
1439
+ if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs;
1440
+ else return this.getDefaultLatLngs(latlngs[0]);
1441
+ },
1442
+
1443
+ ensureMulti: function () {
1444
+ if (this.feature._latlngs.length && isFlat(this.feature._latlngs)) {
1445
+ this.feature._latlngs = [this.feature._latlngs];
1446
+ }
1447
+ },
1448
+
1449
+ addNewEmptyShape: function () {
1450
+ if (this.feature._latlngs.length) {
1451
+ var shape = [];
1452
+ this.appendShape(shape);
1453
+ return shape;
1454
+ } else {
1455
+ return this.feature._latlngs;
1456
+ }
1457
+ },
1458
+
1459
+ formatShape: function (shape) {
1460
+ if (isFlat(shape)) return shape;
1461
+ else if (shape[0]) return this.formatShape(shape[0]);
1462
+ },
1463
+
1464
+ // 🍂method splitShape(latlngs?: Array, index: int)
1465
+ // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`.
1466
+ splitShape: function (shape, index) {
1467
+ if (!index || index >= shape.length - 1) return;
1468
+ this.ensureMulti();
1469
+ var shapeIndex = this.feature._latlngs.indexOf(shape);
1470
+ if (shapeIndex === -1) return;
1471
+ var first = shape.slice(0, index + 1),
1472
+ second = shape.slice(index);
1473
+ // We deal with reference, we don't want twice the same latlng around.
1474
+ second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt);
1475
+ this.feature._latlngs.splice(shapeIndex, 1, first, second);
1476
+ this.refresh();
1477
+ this.reset();
1478
+ }
1479
+
1480
+ });
1481
+
1482
+ // 🍂namespace Editable; 🍂class PolygonEditor; 🍂aka L.Editable.PolygonEditor
1483
+ // 🍂inherits PathEditor
1484
+ L.Editable.PolygonEditor = L.Editable.PathEditor.extend({
1485
+
1486
+ CLOSED: true,
1487
+ MIN_VERTEX: 3,
1488
+
1489
+ newPointForward: function (latlng) {
1490
+ L.Editable.PathEditor.prototype.newPointForward.call(this, latlng);
1491
+ if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng);
1492
+ if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide();
1493
+ },
1494
+
1495
+ addNewEmptyHole: function (latlng) {
1496
+ this.ensureNotFlat();
1497
+ var latlngs = this.feature.shapeAt(latlng);
1498
+ if (!latlngs) return;
1499
+ var holes = [];
1500
+ latlngs.push(holes);
1501
+ return holes;
1502
+ },
1503
+
1504
+ // 🍂method newHole(latlng?: L.LatLng, index: int)
1505
+ // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created.
1506
+ newHole: function (latlng) {
1507
+ var holes = this.addNewEmptyHole(latlng);
1508
+ if (!holes) return;
1509
+ this.setDrawnLatLngs(holes);
1510
+ this.startDrawingForward();
1511
+ if (latlng) this.newPointForward(latlng);
1512
+ },
1513
+
1514
+ addNewEmptyShape: function () {
1515
+ if (this.feature._latlngs.length && this.feature._latlngs[0].length) {
1516
+ var shape = [];
1517
+ this.appendShape(shape);
1518
+ return shape;
1519
+ } else {
1520
+ return this.feature._latlngs;
1521
+ }
1522
+ },
1523
+
1524
+ ensureMulti: function () {
1525
+ if (this.feature._latlngs.length && isFlat(this.feature._latlngs[0])) {
1526
+ this.feature._latlngs = [this.feature._latlngs];
1527
+ }
1528
+ },
1529
+
1530
+ ensureNotFlat: function () {
1531
+ if (!this.feature._latlngs.length || isFlat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs];
1532
+ },
1533
+
1534
+ vertexCanBeDeleted: function (vertex) {
1535
+ var parent = this.feature.parentShape(vertex.latlngs),
1536
+ idx = L.Util.indexOf(parent, vertex.latlngs);
1537
+ if (idx > 0) return true; // Holes can be totally deleted without removing the layer itself.
1538
+ return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex);
1539
+ },
1540
+
1541
+ getDefaultLatLngs: function () {
1542
+ if (!this.feature._latlngs.length) this.feature._latlngs.push([]);
1543
+ return this.feature._latlngs[0];
1544
+ },
1545
+
1546
+ formatShape: function (shape) {
1547
+ // [[1, 2], [3, 4]] => must be nested
1548
+ // [] => must be nested
1549
+ // [[]] => is already nested
1550
+ if (isFlat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape];
1551
+ else return shape;
1552
+ }
1553
+
1554
+ });
1555
+
1556
+ // 🍂namespace Editable; 🍂class RectangleEditor; 🍂aka L.Editable.RectangleEditor
1557
+ // 🍂inherits PathEditor
1558
+ L.Editable.RectangleEditor = L.Editable.PathEditor.extend({
1559
+
1560
+ CLOSED: true,
1561
+ MIN_VERTEX: 4,
1562
+
1563
+ options: {
1564
+ skipMiddleMarkers: true
1565
+ },
1566
+
1567
+ extendBounds: function (e) {
1568
+ var index = e.vertex.getIndex(),
1569
+ next = e.vertex.getNext(),
1570
+ previous = e.vertex.getPrevious(),
1571
+ oppositeIndex = (index + 2) % 4,
1572
+ opposite = e.vertex.latlngs[oppositeIndex],
1573
+ bounds = new L.LatLngBounds(e.latlng, opposite);
1574
+ // Update latlngs by hand to preserve order.
1575
+ previous.latlng.update([e.latlng.lat, opposite.lng]);
1576
+ next.latlng.update([opposite.lat, e.latlng.lng]);
1577
+ this.updateBounds(bounds);
1578
+ this.refreshVertexMarkers();
1579
+ },
1580
+
1581
+ onDrawingMouseDown: function (e) {
1582
+ L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e);
1583
+ this.connect();
1584
+ var latlngs = this.getDefaultLatLngs();
1585
+ // L.Polygon._convertLatLngs removes last latlng if it equals first point,
1586
+ // which is the case here as all latlngs are [0, 0]
1587
+ if (latlngs.length === 3) latlngs.push(e.latlng);
1588
+ var bounds = new L.LatLngBounds(e.latlng, e.latlng);
1589
+ this.updateBounds(bounds);
1590
+ this.updateLatLngs(bounds);
1591
+ this.refresh();
1592
+ this.reset();
1593
+ // Stop dragging map.
1594
+ // L.Draggable has two workflows:
1595
+ // - mousedown => mousemove => mouseup
1596
+ // - touchstart => touchmove => touchend
1597
+ // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only
1598
+ // can deal with mousedown, but then when in a touch device, we are dealing with
1599
+ // simulated events (actually simulated by L.Map.Tap), which are no more taken
1600
+ // into account by L.Draggable.
1601
+ // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103
1602
+ e.originalEvent._simulated = false;
1603
+ this.map.dragging._draggable._onUp(e.originalEvent);
1604
+ // Now transfer ongoing drag action to the bottom right corner.
1605
+ // Should we refine which corne will handle the drag according to
1606
+ // drag direction?
1607
+ latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent);
1608
+ },
1609
+
1610
+ onDrawingMouseUp: function (e) {
1611
+ this.commitDrawing(e);
1612
+ e.originalEvent._simulated = false;
1613
+ L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e);
1614
+ },
1615
+
1616
+ onDrawingMouseMove: function (e) {
1617
+ e.originalEvent._simulated = false;
1618
+ L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e);
1619
+ },
1620
+
1621
+
1622
+ getDefaultLatLngs: function (latlngs) {
1623
+ return latlngs || this.feature._latlngs[0];
1624
+ },
1625
+
1626
+ updateBounds: function (bounds) {
1627
+ this.feature._bounds = bounds;
1628
+ },
1629
+
1630
+ updateLatLngs: function (bounds) {
1631
+ var latlngs = this.getDefaultLatLngs(),
1632
+ newLatlngs = this.feature._boundsToLatLngs(bounds);
1633
+ // Keep references.
1634
+ for (var i = 0; i < latlngs.length; i++) {
1635
+ latlngs[i].update(newLatlngs[i]);
1636
+ };
1637
+ }
1638
+
1639
+ });
1640
+
1641
+ // 🍂namespace Editable; 🍂class CircleEditor; 🍂aka L.Editable.CircleEditor
1642
+ // 🍂inherits PathEditor
1643
+ L.Editable.CircleEditor = L.Editable.PathEditor.extend({
1644
+
1645
+ MIN_VERTEX: 2,
1646
+
1647
+ options: {
1648
+ skipMiddleMarkers: true
1649
+ },
1650
+
1651
+ initialize: function (map, feature, options) {
1652
+ L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options);
1653
+ this._resizeLatLng = this.computeResizeLatLng();
1654
+ },
1655
+
1656
+ computeResizeLatLng: function () {
1657
+ // While circle is not added to the map, _radius is not set.
1658
+ var delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4),
1659
+ point = this.map.project(this.feature._latlng);
1660
+ return this.map.unproject([point.x + delta, point.y - delta]);
1661
+ },
1662
+
1663
+ updateResizeLatLng: function () {
1664
+ this._resizeLatLng.update(this.computeResizeLatLng());
1665
+ this._resizeLatLng.__vertex.update();
1666
+ },
1667
+
1668
+ getLatLngs: function () {
1669
+ return [this.feature._latlng, this._resizeLatLng];
1670
+ },
1671
+
1672
+ getDefaultLatLngs: function () {
1673
+ return this.getLatLngs();
1674
+ },
1675
+
1676
+ onVertexMarkerDrag: function (e) {
1677
+ if (e.vertex.getIndex() === 1) this.resize(e);
1678
+ else this.updateResizeLatLng(e);
1679
+ L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e);
1680
+ },
1681
+
1682
+ resize: function (e) {
1683
+ var radius = this.feature._latlng.distanceTo(e.latlng)
1684
+ this.feature.setRadius(radius);
1685
+ },
1686
+
1687
+ onDrawingMouseDown: function (e) {
1688
+ L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e);
1689
+ this._resizeLatLng.update(e.latlng);
1690
+ this.feature._latlng.update(e.latlng);
1691
+ this.connect();
1692
+ // Stop dragging map.
1693
+ e.originalEvent._simulated = false;
1694
+ this.map.dragging._draggable._onUp(e.originalEvent);
1695
+ // Now transfer ongoing drag action to the radius handler.
1696
+ this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent);
1697
+ },
1698
+
1699
+ onDrawingMouseUp: function (e) {
1700
+ this.commitDrawing(e);
1701
+ e.originalEvent._simulated = false;
1702
+ L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e);
1703
+ },
1704
+
1705
+ onDrawingMouseMove: function (e) {
1706
+ e.originalEvent._simulated = false;
1707
+ L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e);
1708
+ },
1709
+
1710
+ onDrag: function (e) {
1711
+ L.Editable.PathEditor.prototype.onDrag.call(this, e);
1712
+ this.feature.dragging.updateLatLng(this._resizeLatLng);
1713
+ }
1714
+
1715
+ });
1716
+
1717
+ // 🍂namespace Editable; 🍂class EditableMixin
1718
+ // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle`
1719
+ // and `L.Marker`. It adds some methods to them.
1720
+ // *When editing is enabled, the editor is accessible on the instance with the
1721
+ // `editor` property.*
1722
+ var EditableMixin = {
1723
+
1724
+ createEditor: function (map) {
1725
+ map = map || this._map;
1726
+ var tools = (this.options.editOptions || {}).editTools || map.editTools;
1727
+ if (!tools) throw Error('Unable to detect Editable instance.')
1728
+ var Klass = this.options.editorClass || this.getEditorClass(tools);
1729
+ return new Klass(map, this, this.options.editOptions);
1730
+ },
1731
+
1732
+ // 🍂method enableEdit(map?: L.Map): this.editor
1733
+ // Enable editing, by creating an editor if not existing, and then calling `enable` on it.
1734
+ enableEdit: function (map) {
1735
+ if (!this.editor) this.createEditor(map);
1736
+ this.editor.enable();
1737
+ return this.editor;
1738
+ },
1739
+
1740
+ // 🍂method editEnabled(): boolean
1741
+ // Return true if current instance has an editor attached, and this editor is enabled.
1742
+ editEnabled: function () {
1743
+ return this.editor && this.editor.enabled();
1744
+ },
1745
+
1746
+ // 🍂method disableEdit()
1747
+ // Disable editing, also remove the editor property reference.
1748
+ disableEdit: function () {
1749
+ if (this.editor) {
1750
+ this.editor.disable();
1751
+ delete this.editor;
1752
+ }
1753
+ },
1754
+
1755
+ // 🍂method toggleEdit()
1756
+ // Enable or disable editing, according to current status.
1757
+ toggleEdit: function () {
1758
+ if (this.editEnabled()) this.disableEdit();
1759
+ else this.enableEdit();
1760
+ },
1761
+
1762
+ _onEditableAdd: function () {
1763
+ if (this.editor) this.enableEdit();
1764
+ }
1765
+
1766
+ };
1767
+
1768
+ var PolylineMixin = {
1769
+
1770
+ getEditorClass: function (tools) {
1771
+ return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor;
1772
+ },
1773
+
1774
+ shapeAt: function (latlng, latlngs) {
1775
+ // We can have those cases:
1776
+ // - latlngs are just a flat array of latlngs, use this
1777
+ // - latlngs is an array of arrays of latlngs, loop over
1778
+ var shape = null;
1779
+ latlngs = latlngs || this._latlngs;
1780
+ if (!latlngs.length) return shape;
1781
+ else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs;
1782
+ else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i];
1783
+ return shape;
1784
+ },
1785
+
1786
+ isInLatLngs: function (l, latlngs) {
1787
+ if (!latlngs) return false;
1788
+ var i, k, len, part = [], p,
1789
+ w = this._clickTolerance();
1790
+ this._projectLatlngs(latlngs, part, this._pxBounds);
1791
+ part = part[0];
1792
+ p = this._map.latLngToLayerPoint(l);
1793
+
1794
+ if (!this._pxBounds.contains(p)) { return false; }
1795
+ for (i = 1, len = part.length, k = 0; i < len; k = i++) {
1796
+
1797
+ if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) {
1798
+ return true;
1799
+ }
1800
+ }
1801
+ return false;
1802
+ }
1803
+
1804
+ };
1805
+
1806
+ var PolygonMixin = {
1807
+
1808
+ getEditorClass: function (tools) {
1809
+ return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor;
1810
+ },
1811
+
1812
+ shapeAt: function (latlng, latlngs) {
1813
+ // We can have those cases:
1814
+ // - latlngs are just a flat array of latlngs, use this
1815
+ // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first
1816
+ // - latlngs is an array of arrays of arrays, this is a multi, loop over
1817
+ var shape = null;
1818
+ latlngs = latlngs || this._latlngs;
1819
+ if (!latlngs.length) return shape;
1820
+ else if (isFlat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs;
1821
+ else if (isFlat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) shape = latlngs;
1822
+ else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i];
1823
+ return shape;
1824
+ },
1825
+
1826
+ isInLatLngs: function (l, latlngs) {
1827
+ var inside = false, l1, l2, j, k, len2;
1828
+
1829
+ for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) {
1830
+ l1 = latlngs[j];
1831
+ l2 = latlngs[k];
1832
+
1833
+ if (((l1.lat > l.lat) !== (l2.lat > l.lat)) &&
1834
+ (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) {
1835
+ inside = !inside;
1836
+ }
1837
+ }
1838
+
1839
+ return inside;
1840
+ },
1841
+
1842
+ parentShape: function (shape, latlngs) {
1843
+ latlngs = latlngs || this._latlngs;
1844
+ if (!latlngs) return;
1845
+ var idx = L.Util.indexOf(latlngs, shape);
1846
+ if (idx !== -1) return latlngs;
1847
+ for (var i = 0; i < latlngs.length; i++) {
1848
+ idx = L.Util.indexOf(latlngs[i], shape);
1849
+ if (idx !== -1) return latlngs[i];
1850
+ }
1851
+ }
1852
+
1853
+ };
1854
+
1855
+
1856
+ var MarkerMixin = {
1857
+
1858
+ getEditorClass: function (tools) {
1859
+ return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor;
1860
+ }
1861
+
1862
+ };
1863
+
1864
+ var RectangleMixin = {
1865
+
1866
+ getEditorClass: function (tools) {
1867
+ return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor;
1868
+ }
1869
+
1870
+ };
1871
+
1872
+ var CircleMixin = {
1873
+
1874
+ getEditorClass: function (tools) {
1875
+ return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor;
1876
+ }
1877
+
1878
+ };
1879
+
1880
+ var keepEditable = function () {
1881
+ // Make sure you can remove/readd an editable layer.
1882
+ this.on('add', this._onEditableAdd);
1883
+ };
1884
+
1885
+ var isFlat = L.LineUtil.isFlat || L.LineUtil._flat || L.Polyline._flat; // <=> 1.1 compat.
1886
+
1887
+
1888
+ if (L.Polyline) {
1889
+ L.Polyline.include(EditableMixin);
1890
+ L.Polyline.include(PolylineMixin);
1891
+ L.Polyline.addInitHook(keepEditable);
1892
+ }
1893
+ if (L.Polygon) {
1894
+ L.Polygon.include(EditableMixin);
1895
+ L.Polygon.include(PolygonMixin);
1896
+ }
1897
+ if (L.Marker) {
1898
+ L.Marker.include(EditableMixin);
1899
+ L.Marker.include(MarkerMixin);
1900
+ L.Marker.addInitHook(keepEditable);
1901
+ }
1902
+ if (L.Rectangle) {
1903
+ L.Rectangle.include(EditableMixin);
1904
+ L.Rectangle.include(RectangleMixin);
1905
+ }
1906
+ if (L.Circle) {
1907
+ L.Circle.include(EditableMixin);
1908
+ L.Circle.include(CircleMixin);
1909
+ }
1910
+
1911
+ L.LatLng.prototype.update = function (latlng) {
1912
+ latlng = L.latLng(latlng);
1913
+ this.lat = latlng.lat;
1914
+ this.lng = latlng.lng;
1915
+ }
1916
+
1917
+ }, window));