|
1 /** |
|
2 * @class L.Draw.Toolbar |
|
3 * @aka Toolbar |
|
4 * |
|
5 * The toolbar class of the API — it is used to create the ui |
|
6 * This will be depreciated |
|
7 * |
|
8 * @example |
|
9 * |
|
10 * ```js |
|
11 * var toolbar = L.Toolbar(); |
|
12 * toolbar.addToolbar(map); |
|
13 * ``` |
|
14 * |
|
15 * ### Disabling a toolbar |
|
16 * |
|
17 * If you do not want a particular toolbar in your app you can turn it off by setting the toolbar to false. |
|
18 * |
|
19 * ```js |
|
20 * var drawControl = new L.Control.Draw({ |
|
21 * draw: false, |
|
22 * edit: { |
|
23 * featureGroup: editableLayers |
|
24 * } |
|
25 * }); |
|
26 * ``` |
|
27 * |
|
28 * ### Disabling a toolbar item |
|
29 * |
|
30 * If you want to turn off a particular toolbar item, set it to false. The following disables drawing polygons and |
|
31 * markers. It also turns off the ability to edit layers. |
|
32 * |
|
33 * ```js |
|
34 * var drawControl = new L.Control.Draw({ |
|
35 * draw: { |
|
36 * polygon: false, |
|
37 * marker: false |
|
38 * }, |
|
39 * edit: { |
|
40 * featureGroup: editableLayers, |
|
41 * edit: false |
|
42 * } |
|
43 * }); |
|
44 * ``` |
|
45 */ |
|
46 L.Toolbar = L.Class.extend({ |
|
47 // @section Methods for modifying the toolbar |
|
48 |
|
49 // @method initialize(options): void |
|
50 // Toolbar constructor |
|
51 initialize: function (options) { |
|
52 L.setOptions(this, options); |
|
53 |
|
54 this._modes = {}; |
|
55 this._actionButtons = []; |
|
56 this._activeMode = null; |
|
57 |
|
58 var version = L.version.split('.'); |
|
59 //If Version is >= 1.2.0 |
|
60 if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) { |
|
61 L.Toolbar.include(L.Evented.prototype); |
|
62 } else { |
|
63 L.Toolbar.include(L.Mixin.Events); |
|
64 } |
|
65 }, |
|
66 |
|
67 // @method enabled(): boolean |
|
68 // Gets a true/false of whether the toolbar is enabled |
|
69 enabled: function () { |
|
70 return this._activeMode !== null; |
|
71 }, |
|
72 |
|
73 // @method disable(): void |
|
74 // Disables the toolbar |
|
75 disable: function () { |
|
76 if (!this.enabled()) { |
|
77 return; |
|
78 } |
|
79 |
|
80 this._activeMode.handler.disable(); |
|
81 }, |
|
82 |
|
83 // @method addToolbar(map): L.DomUtil |
|
84 // Adds the toolbar to the map and returns the toolbar dom element |
|
85 addToolbar: function (map) { |
|
86 var container = L.DomUtil.create('div', 'leaflet-draw-section'), |
|
87 buttonIndex = 0, |
|
88 buttonClassPrefix = this._toolbarClass || '', |
|
89 modeHandlers = this.getModeHandlers(map), |
|
90 i; |
|
91 |
|
92 this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar'); |
|
93 this._map = map; |
|
94 |
|
95 for (i = 0; i < modeHandlers.length; i++) { |
|
96 if (modeHandlers[i].enabled) { |
|
97 this._initModeHandler( |
|
98 modeHandlers[i].handler, |
|
99 this._toolbarContainer, |
|
100 buttonIndex++, |
|
101 buttonClassPrefix, |
|
102 modeHandlers[i].title |
|
103 ); |
|
104 } |
|
105 } |
|
106 |
|
107 // if no buttons were added, do not add the toolbar |
|
108 if (!buttonIndex) { |
|
109 return; |
|
110 } |
|
111 |
|
112 // Save button index of the last button, -1 as we would have ++ after the last button |
|
113 this._lastButtonIndex = --buttonIndex; |
|
114 |
|
115 // Create empty actions part of the toolbar |
|
116 this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions'); |
|
117 |
|
118 // Add draw and cancel containers to the control container |
|
119 container.appendChild(this._toolbarContainer); |
|
120 container.appendChild(this._actionsContainer); |
|
121 |
|
122 return container; |
|
123 }, |
|
124 |
|
125 // @method removeToolbar(): void |
|
126 // Removes the toolbar and drops the handler event listeners |
|
127 removeToolbar: function () { |
|
128 // Dispose each handler |
|
129 for (var handlerId in this._modes) { |
|
130 if (this._modes.hasOwnProperty(handlerId)) { |
|
131 // Unbind handler button |
|
132 this._disposeButton( |
|
133 this._modes[handlerId].button, |
|
134 this._modes[handlerId].handler.enable, |
|
135 this._modes[handlerId].handler |
|
136 ); |
|
137 |
|
138 // Make sure is disabled |
|
139 this._modes[handlerId].handler.disable(); |
|
140 |
|
141 // Unbind handler |
|
142 this._modes[handlerId].handler |
|
143 .off('enabled', this._handlerActivated, this) |
|
144 .off('disabled', this._handlerDeactivated, this); |
|
145 } |
|
146 } |
|
147 this._modes = {}; |
|
148 |
|
149 // Dispose the actions toolbar |
|
150 for (var i = 0, l = this._actionButtons.length; i < l; i++) { |
|
151 this._disposeButton( |
|
152 this._actionButtons[i].button, |
|
153 this._actionButtons[i].callback, |
|
154 this |
|
155 ); |
|
156 } |
|
157 this._actionButtons = []; |
|
158 this._actionsContainer = null; |
|
159 }, |
|
160 |
|
161 _initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) { |
|
162 var type = handler.type; |
|
163 |
|
164 this._modes[type] = {}; |
|
165 |
|
166 this._modes[type].handler = handler; |
|
167 |
|
168 this._modes[type].button = this._createButton({ |
|
169 type: type, |
|
170 title: buttonTitle, |
|
171 className: classNamePredix + '-' + type, |
|
172 container: container, |
|
173 callback: this._modes[type].handler.enable, |
|
174 context: this._modes[type].handler |
|
175 }); |
|
176 |
|
177 this._modes[type].buttonIndex = buttonIndex; |
|
178 |
|
179 this._modes[type].handler |
|
180 .on('enabled', this._handlerActivated, this) |
|
181 .on('disabled', this._handlerDeactivated, this); |
|
182 }, |
|
183 |
|
184 /* Detect iOS based on browser User Agent, based on: |
|
185 * http://stackoverflow.com/a/9039885 */ |
|
186 _detectIOS: function () { |
|
187 var iOS = (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream); |
|
188 return iOS; |
|
189 }, |
|
190 |
|
191 _createButton: function (options) { |
|
192 |
|
193 var link = L.DomUtil.create('a', options.className || '', options.container); |
|
194 // Screen reader tag |
|
195 var sr = L.DomUtil.create('span', 'sr-only', options.container); |
|
196 |
|
197 link.href = '#'; |
|
198 link.appendChild(sr); |
|
199 |
|
200 if (options.title) { |
|
201 link.title = options.title; |
|
202 sr.innerHTML = options.title; |
|
203 } |
|
204 |
|
205 if (options.text) { |
|
206 link.innerHTML = options.text; |
|
207 sr.innerHTML = options.text; |
|
208 } |
|
209 |
|
210 /* iOS does not use click events */ |
|
211 var buttonEvent = this._detectIOS() ? 'touchstart' : 'click'; |
|
212 |
|
213 L.DomEvent |
|
214 .on(link, 'click', L.DomEvent.stopPropagation) |
|
215 .on(link, 'mousedown', L.DomEvent.stopPropagation) |
|
216 .on(link, 'dblclick', L.DomEvent.stopPropagation) |
|
217 .on(link, 'touchstart', L.DomEvent.stopPropagation) |
|
218 .on(link, 'click', L.DomEvent.preventDefault) |
|
219 .on(link, buttonEvent, options.callback, options.context); |
|
220 |
|
221 return link; |
|
222 }, |
|
223 |
|
224 _disposeButton: function (button, callback) { |
|
225 /* iOS does not use click events */ |
|
226 var buttonEvent = this._detectIOS() ? 'touchstart' : 'click'; |
|
227 |
|
228 L.DomEvent |
|
229 .off(button, 'click', L.DomEvent.stopPropagation) |
|
230 .off(button, 'mousedown', L.DomEvent.stopPropagation) |
|
231 .off(button, 'dblclick', L.DomEvent.stopPropagation) |
|
232 .off(button, 'touchstart', L.DomEvent.stopPropagation) |
|
233 .off(button, 'click', L.DomEvent.preventDefault) |
|
234 .off(button, buttonEvent, callback); |
|
235 }, |
|
236 |
|
237 _handlerActivated: function (e) { |
|
238 // Disable active mode (if present) |
|
239 this.disable(); |
|
240 |
|
241 // Cache new active feature |
|
242 this._activeMode = this._modes[e.handler]; |
|
243 |
|
244 L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled'); |
|
245 |
|
246 this._showActionsToolbar(); |
|
247 |
|
248 this.fire('enable'); |
|
249 }, |
|
250 |
|
251 _handlerDeactivated: function () { |
|
252 this._hideActionsToolbar(); |
|
253 |
|
254 L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled'); |
|
255 |
|
256 this._activeMode = null; |
|
257 |
|
258 this.fire('disable'); |
|
259 }, |
|
260 |
|
261 _createActions: function (handler) { |
|
262 var container = this._actionsContainer, |
|
263 buttons = this.getActions(handler), |
|
264 l = buttons.length, |
|
265 li, di, dl, button; |
|
266 |
|
267 // Dispose the actions toolbar (todo: dispose only not used buttons) |
|
268 for (di = 0, dl = this._actionButtons.length; di < dl; di++) { |
|
269 this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback); |
|
270 } |
|
271 this._actionButtons = []; |
|
272 |
|
273 // Remove all old buttons |
|
274 while (container.firstChild) { |
|
275 container.removeChild(container.firstChild); |
|
276 } |
|
277 |
|
278 for (var i = 0; i < l; i++) { |
|
279 if ('enabled' in buttons[i] && !buttons[i].enabled) { |
|
280 continue; |
|
281 } |
|
282 |
|
283 li = L.DomUtil.create('li', '', container); |
|
284 |
|
285 button = this._createButton({ |
|
286 title: buttons[i].title, |
|
287 text: buttons[i].text, |
|
288 container: li, |
|
289 callback: buttons[i].callback, |
|
290 context: buttons[i].context |
|
291 }); |
|
292 |
|
293 this._actionButtons.push({ |
|
294 button: button, |
|
295 callback: buttons[i].callback |
|
296 }); |
|
297 } |
|
298 }, |
|
299 |
|
300 _showActionsToolbar: function () { |
|
301 var buttonIndex = this._activeMode.buttonIndex, |
|
302 lastButtonIndex = this._lastButtonIndex, |
|
303 toolbarPosition = this._activeMode.button.offsetTop - 1; |
|
304 |
|
305 // Recreate action buttons on every click |
|
306 this._createActions(this._activeMode.handler); |
|
307 |
|
308 // Correctly position the cancel button |
|
309 this._actionsContainer.style.top = toolbarPosition + 'px'; |
|
310 |
|
311 if (buttonIndex === 0) { |
|
312 L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop'); |
|
313 L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top'); |
|
314 } |
|
315 |
|
316 if (buttonIndex === lastButtonIndex) { |
|
317 L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom'); |
|
318 L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom'); |
|
319 } |
|
320 |
|
321 this._actionsContainer.style.display = 'block'; |
|
322 this._map.fire(L.Draw.Event.TOOLBAROPENED); |
|
323 }, |
|
324 |
|
325 _hideActionsToolbar: function () { |
|
326 this._actionsContainer.style.display = 'none'; |
|
327 |
|
328 L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop'); |
|
329 L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom'); |
|
330 L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top'); |
|
331 L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom'); |
|
332 this._map.fire(L.Draw.Event.TOOLBARCLOSED); |
|
333 } |
|
334 }); |