PageSourceSearch

https://cykloatlas.cz/assets/leaf/leaflet-sidebar.js

js cykloatlas.cz collected 2026-10-04 09:03:11 UTC 19,170 bytes, 526 lines download raw bytes

1// @ts-nocheck
2/**
3 * @name Sidebar
4 * @class L.Control.Sidebar
5 * @extends L.Control
6 * @param {string} id - The id of the sidebar element (without the # character)
7 * @param {Object} [options] - Optional options object
8 * @param {string} [options.autopan=false] - whether to move the map when opening the sidebar to make maintain the visible center point
9 * @param {string} [options.position=left] - Position of the sidebar: 'left' or 'right'
10 * @param {string} [options.id] - ID of a predefined sidebar container that should be used
11 * @param {boolean} [data.close=true] Whether to add a close button to the pane header
12 * @see L.control.sidebar
13 */
14L.Control.Sidebar = L.Control.extend(/** @lends L.Control.Sidebar.prototype */ {
15    includes: L.Evented ? L.Evented.prototype : L.Mixin.Events,
16
17    options: {
18        autopan: false,
19        closeButton: true,
20        container: null,
21        position: 'left'
22    },
23
24    /**
25     * Create a new sidebar on this object.
26     *
27     * @constructor
28     * @param {Object} [options] - Optional options object
29     * @param {string} [options.autopan=false] - whether to move the map when opening the sidebar to make maintain the visible center point
30     * @param {string} [options.position=left] - Position of the sidebar: 'left' or 'right'
31     * @param {string} [options.container] - ID of a predefined sidebar container that should be used
32     * @param {bool} [data.close=true] Whether to add a close button to the pane header
33     */
34    initialize: function(options, deprecatedOptions) {
35        if (typeof options === 'string') {
36            console.warn('this syntax is deprecated. please use L.control.sidebar({ container }) now');
37            options = { container: options };
38        }
39
40        if (typeof options === 'object' && options.id) {
41            console.warn('this syntax is deprecated. please use L.control.sidebar({ container }) now');
42            options.container = options.id;
43        }
44
45        this._tabitems = [];
46        this._panes = [];
47        this._closeButtons = [];
48
49        L.setOptions(this, options);
50        L.setOptions(this, deprecatedOptions);
51        return this;
52    },
53
54    /**
55     * Add this sidebar to the specified map.
56     *
57     * @param {L.Map} map
58     * @returns {Sidebar}
59     */
60    onAdd: function(map) {
61        var i, child, tabContainers, newContainer, container;
62
63        // use container from previous onAdd()
64        container = this._container
65
66        // use the container given via options.
67        if (!container) {
68            container = this._container || typeof this.options.container === 'string'
69            ? L.DomUtil.get(this.options.container)
70            : this.options.container;
71        }
72
73        // if no container was specified or not found, create it and apply an ID
74        if (!container) {
75            container = L.DomUtil.create('div', 'leaflet-sidebar collapsed');
76            if (typeof this.options.container === 'string')
77                container.id = this.options.container;
78        }
79
80        // Find paneContainer in DOM & store reference
81        this._paneContainer = container.querySelector('div.leaflet-sidebar-content');
82
83        // If none is found, create it
84        if (this._paneContainer === null)
85            this._paneContainer = L.DomUtil.create('div', 'leaflet-sidebar-content', container);
86
87        // Find tabContainerTop & tabContainerBottom in DOM & store reference
88        tabContainers = container.querySelectorAll('ul.leaflet-sidebar-tabs, div.leaflet-sidebar-tabs > ul');
89        this._tabContainerTop    = tabContainers[0] || null;
90        this._tabContainerBottom = tabContainers[1] || null;
91
92        // If no container was found, create it
93        if (this._tabContainerTop === null) {
94            newContainer = L.DomUtil.create('div', 'leaflet-sidebar-tabs', container);
95            newContainer.setAttribute('role', 'tablist');
96            this._tabContainerTop = L.DomUtil.create('ul', '', newContainer);
97        }
98        if (this._tabContainerBottom === null) {
99            newContainer = this._tabContainerTop.parentNode;
100            this._tabContainerBottom = L.DomUtil.create('ul', '', newContainer);
101        }
102
103        // Store Tabs in Collection for easier iteration
104        for (i = 0; i < this._tabContainerTop.children.length; i++) {
105            child = this._tabContainerTop.children[i];
106            child._sidebar = this;
107            child._id = child.querySelector('a').hash.slice(1); // FIXME: this could break for links!
108            this._tabitems.push(child);
109        }
110        for (i = 0; i < this._tabContainerBottom.children.length; i++) {
111            child = this._tabContainerBottom.children[i];
112            child._sidebar = this;
113            child._id = child.querySelector('a').hash.slice(1); // FIXME: this could break for links!
114            this._tabitems.push(child);
115        }
116
117        // Store Panes in Collection for easier iteration
118        for (i = 0; i < this._paneContainer.children.length; i++) {
119            child = this._paneContainer.children[i];
120            if (child.tagName === 'DIV' &&
121                L.DomUtil.hasClass(child, 'leaflet-sidebar-pane')) {
122                this._panes.push(child);
123
124                // Save references to close buttons
125                var closeButtons = child.querySelectorAll('.leaflet-sidebar-close');
126                if (closeButtons.length) {
127                    this._closeButtons.push(closeButtons[closeButtons.length - 1]);
128                    this._closeClick(closeButtons[closeButtons.length - 1], 'on');
129                }
130            }
131        }
132
133        // set click listeners for tab & close buttons
134        for (i = 0; i < this._tabitems.length; i++) {
135            this._tabClick(this._tabitems[i], 'on');
136        }
137
138        // leaflet moves the returned container to the right place in the DOM
139        return container;
140    },
141
142    /**
143     * Remove this sidebar from the map.
144     *
145     * @param {L.Map} map
146     * @returns {Sidebar}
147     */
148    onRemove: function (map) {
149        // Remove click listeners for tab & close buttons
150        for (var i = 0; i < this._tabitems.length; i++)
151            this._tabClick(this._tabitems[i], 'off');
152        for (var i = 0; i < this._closeButtons.length; i++)
153            this._closeClick(this._closeButtons[i], 'off');
154
155        this._tabitems = [];
156        this._panes = [];
157        this._closeButtons = [];
158
159        return this;
160    },
161
162    /**
163     * @method addTo(map: Map): this
164     * Adds the control to the given map. Overrides the implementation of L.Control,
165     * changing the DOM mount target from map._controlContainer.topleft to map._container
166     */
167    addTo: function (map) {
168        this.onRemove();
169        this._map = map;
170
171        this._container = this.onAdd(map);
172
173        L.DomUtil.addClass(this._container, 'leaflet-control');
174        L.DomUtil.addClass(this._container, 'leaflet-sidebar-' + this.getPosition());
175        if (L.Browser.touch)
176            L.DomUtil.addClass(this._container, 'leaflet-touch');
177
178        // when adding to the map container, we should stop event propagation
179        L.DomEvent.disableScrollPropagation(this._container);
180        L.DomEvent.disableClickPropagation(this._container);
181        L.DomEvent.on(this._container, 'contextmenu', L.DomEvent.stopPropagation);
182
183        // insert as first child of map container (important for css)
184        map._container.insertBefore(this._container, map._container.firstChild);
185
186        return this;
187    },
188
189    /**
190     * @deprecated - Please use remove() instead of removeFrom(), as of Leaflet 0.8-dev, the removeFrom() has been replaced with remove()
191     * Removes this sidebar from the map.
192     * @param {L.Map} map
193     * @returns {Sidebar}
194     */
195    removeFrom: function(map) {
196        console.warn('removeFrom() has been deprecated, please use remove() instead as support for this function will be ending soon.');
197        this._map._container.removeChild(this._container);
198        this.onRemove(map);
199
200        return this;
201    },
202
203   /**
204     * Open sidebar (if it's closed) and show the specified tab.
205     *
206     * @param {string} id - The ID of the tab to show (without the # character)
207     * @returns {L.Control.Sidebar}
208     */
209    open: function(id) {
210        var i, child, tab;
211
212        // If panel is disabled, stop right here
213        tab = this._getTab(id);
214        if (L.DomUtil.hasClass(tab, 'disabled'))
215            return this;
216
217        // Hide old active contents and show new content
218        for (i = 0; i < this._panes.length; i++) {
219            child = this._panes[i];
220            if (child.id === id)
221                L.DomUtil.addClass(child, 'active');
222            else if (L.DomUtil.hasClass(child, 'active'))
223                L.DomUtil.removeClass(child, 'active');
224        }
225
226        // Remove old active highlights and set new highlight
227        for (i = 0; i < this._tabitems.length; i++) {
228            child = this._tabitems[i];
229            if (child.querySelector('a').hash === '#' + id)
230                L.DomUtil.addClass(child, 'active');
231            else if (L.DomUtil.hasClass(child, 'active'))
232                L.DomUtil.removeClass(child, 'active');
233        }
234
235        this.fire('content', { id: id });
236
237        // Open sidebar if it's closed
238        if (L.DomUtil.hasClass(this._container, 'collapsed')) {
239            this.fire('opening');
240            L.DomUtil.removeClass(this._container, 'collapsed');
241            if (this.options.autopan) this._panMap('open');
242        }
243
244        return this;
245    },
246
247    /**
248     * Close the sidebar (if it's open).
249     *
250     * @returns {L.Control.Sidebar}
251     */
252    close: function() {
253        var i;
254
255        // Remove old active highlights
256        for (i = 0; i < this._tabitems.length; i++) {
257            var child = this._tabitems[i];
258            if (L.DomUtil.hasClass(child, 'active'))
259                L.DomUtil.removeClass(child, 'active');
260        }
261
262        // close sidebar, if it's opened
263        if (!L.DomUtil.hasClass(this._container, 'collapsed')) {
264            this.fire('closing');
265            L.DomUtil.addClass(this._container, 'collapsed');
266            if (this.options.autopan) this._panMap('close');
267        }
268
269        return this;
270    },
271
272    /**
273     * Add a panel to the sidebar
274     *
275     * @example
276     * sidebar.addPanel({
277     *     id: 'userinfo',
278     *     tab: '<i class="fa fa-gear"></i>',
279     *     pane: someDomNode.innerHTML,
280     *     position: 'bottom'
281     * });
282     *
283     * @param {Object} [data] contains the data for the new Panel:
284     * @param {String} [data.id] the ID for the new Panel, must be unique for the whole page
285     * @param {String} [data.position='top'] where the tab will appear:
286     *                                       on the top or the bottom of the sidebar. 'top' or 'bottom'
287     * @param {HTMLString} {DOMnode} [data.tab]  content of the tab item, as HTMLstring or DOM node
288     * @param {HTMLString} {DOMnode} [data.pane] content of the panel, as HTMLstring or DOM node
289     * @param {String} [data.link] URL to an (external) link that will be opened instead of a panel
290     * @param {String} [data.title] Title for the pane header
291     * @param {String} {Function} [data.button] URL to an (external) link or a click listener function that will be opened instead of a panel
292     * @param {bool} [data.disabled] If the tab should be disabled by default
293     *
294     * @returns {L.Control.Sidebar}
295     */
296    addPanel: function(data) {
297        var pane, tab, tabHref, closeButtons, content;
298
299        // Create tab node
300        tab = L.DomUtil.create('li', data.disabled ? 'disabled' : '');
301        tabHref = L.DomUtil.create('a', '', tab);
302        tabHref.href = '#' + data.id;
303        tabHref.setAttribute('role', 'tab');
304        tabHref.innerHTML = data.tab;
305        tab._sidebar = this;
306        tab._id = data.id;
307        tab._button = data.button; // to allow links to be disabled, the href cannot be used
308        if (data.title && data.title[0] !== '<') tab.title = data.title;
309
310        // append it to the DOM and store JS references
311        if (data.position === 'bottom')
312            this._tabContainerBottom.appendChild(tab);
313        else
314            this._tabContainerTop.appendChild(tab);
315
316        this._tabitems.push(tab);
317
318        // Create pane node
319        if (data.pane) {
320            if (typeof data.pane === 'string') {
321                // pane is given as HTML string
322                pane = L.DomUtil.create('DIV', 'leaflet-sidebar-pane', this._paneContainer);
323                content = '';
324                if (data.title)
325                    content += '<h1 class="leaflet-sidebar-header">' + data.title;
326                if (this.options.closeButton)
327                    content += '<span class="leaflet-sidebar-close"><i class="fa fa-caret-' + this.options.position + '"></i></span>';
328                if (data.title)
329                    content += '</h1>';
330                pane.innerHTML = content + data.pane;
331            } else {
332                // pane is given as DOM object
333                pane = data.pane;
334                this._paneContainer.appendChild(pane);
335            }
336            pane.id = data.id;
337
338            this._panes.push(pane);
339
340            // Save references to close button & register click listener
341            closeButtons = pane.querySelectorAll('.leaflet-sidebar-close');
342            if (closeButtons.length) {
343                // select last button, because thats rendered on top
344                this._closeButtons.push(closeButtons[closeButtons.length - 1]);
345                this._closeClick(closeButtons[closeButtons.length - 1], 'on');
346            }
347        }
348
349        // Register click listeners, if the sidebar is on the map
350        this._tabClick(tab, 'on');
351
352        return this;
353    },
354
355    /**
356     * Removes a panel from the sidebar
357     *
358     * @example
359     * sidebar.remove('userinfo');
360     *
361     * @param {String} [id] the ID of the panel that is to be removed
362     * @returns {L.Control.Sidebar}
363     */
364    removePanel: function(id) {
365        var i, j, tab, pane, closeButtons;
366
367        // find the tab & panel by ID, remove them, and clean up
368        for (i = 0; i < this._tabitems.length; i++) {
369            if (this._tabitems[i]._id === id) {
370                tab = this._tabitems[i];
371
372                // Remove click listeners
373                this._tabClick(tab, 'off');
374
375                tab.remove();
376                this._tabitems.splice(i, 1);
377                break;
378            }
379        }
380
381        for (i = 0; i < this._panes.length; i++) {
382            if (this._panes[i].id === id) {
383                pane = this._panes[i];
384                closeButtons = pane.querySelectorAll('.leaflet-sidebar-close');
385                for (j = 0; j < closeButtons.length; j++) {
386                    this._closeClick(closeButtons[j], 'off');
387                }
388
389                pane.remove();
390                this._panes.splice(i, 1);
391
392                break;
393            }
394        }
395
396        return this;
397    },
398
399    /**
400     * enables a disabled tab/panel
401     *
402     * @param {String} [id] ID of the panel to enable
403     * @returns {L.Control.Sidebar}
404     */
405    enablePanel: function(id) {
406        var tab = this._getTab(id);
407        L.DomUtil.removeClass(tab, 'disabled');
408
409        return this;
410    },
411
412    /**
413     * disables an enabled tab/panel
414     *
415     * @param {String} [id] ID of the panel to disable
416     * @returns {L.Control.Sidebar}
417     */
418    disablePanel: function(id) {
419        var tab = this._getTab(id);
420        L.DomUtil.addClass(tab, 'disabled');
421
422        return this;
423    },
424
425    onTabClick: function(e) {
426        // `this` points to the tab DOM element!
427        if (L.DomUtil.hasClass(this, 'active')) {
428            this._sidebar.close();
429        } else if (!L.DomUtil.hasClass(this, 'disabled')) {
430            if (typeof this._button === 'string') // an url
431                window.location.href = this._button;
432            else if (typeof this._button === 'function') // a clickhandler
433                this._button(e);
434            else // a normal pane
435                this._sidebar.open(this.querySelector('a').hash.slice(1));
436        }
437    },
438
439    /**
440     * (un)registers the onclick event for the given tab,
441     * depending on the second argument.
442     * @private
443     *
444     * @param {DOMelement} [tab]
445     * @param {String} [on] 'on' or 'off'
446     */
447    _tabClick: function(tab, on) {
448        var link = tab.querySelector('a');
449        if (!link.hasAttribute('href') || link.getAttribute('href')[0] !== '#')
450            return;
451
452        if (on === 'on') {
453            L.DomEvent
454                .on(tab.querySelector('a'), 'click', L.DomEvent.preventDefault, tab)
455                .on(tab.querySelector('a'), 'click', this.onTabClick, tab);
456        } else {
457            L.DomEvent.off(tab.querySelector('a'), 'click', this.onTabClick, tab);
458        }
459    },
460
461    onCloseClick: function() {
462        this.close();
463    },
464
465    /**
466     * (un)registers the onclick event for the given close button
467     * depending on the second argument
468     * @private
469     *
470     * @param {DOMelement} [closeButton]
471     * @param {String} [on] 'on' or 'off'
472     */
473    _closeClick: function(closeButton, on) {
474        if (on === 'on') {
475            L.DomEvent.on(closeButton, 'click', this.onCloseClick, this);
476        } else {
477            L.DomEvent.off(closeButton, 'click', this.onCloseClick);
478        }
479    },
480
481    /**
482     * Finds & returns the DOMelement of a tab
483     *
484     * @param {String} [id] the id of the tab
485     * @returns {DOMelement} the tab specified by id, null if not found
486     */
487    _getTab: function(id) {
488        for (var i = 0; i < this._tabitems.length; i++) {
489            if (this._tabitems[i]._id === id)
490                return this._tabitems[i];
491        }
492
493        throw Error('tab "' + id + '" not found');
494    },
495
496    /**
497     * Helper for autopan: Pans the map for open/close events
498     *
499     * @param {String} [openClose] The behaviour to enact ('open' | 'close')
500     */
501   _panMap: function(openClose) {
502        var panWidth = Number.parseInt(L.DomUtil.getStyle(this._container, 'max-width')) / 2;
503        if (
504            openClose === 'open' && this.options.position === 'left' ||
505            openClose === 'close' && this.options.position === 'right'
506        ) panWidth *= -1;
507        this._map.panBy([panWidth, 0], { duration: 0.5 });
508   }
509});
510
511/**
512 * Create a new sidebar.
513 *
514 * @example
515 * var sidebar = L.control.sidebar({ container: 'sidebar' }).addTo(map);
516 *
517 * @param {Object} [options] - Optional options object
518 * @param {string} [options.autopan=false] - whether to move the map when opening the sidebar to make maintain the visible center point
519 * @param {string} [options.position=left] - Position of the sidebar: 'left' or 'right'
520 * @param {string} [options.container] - ID of a predefined sidebar container that should be used
521 * @param {boolean} [data.close=true] Whether to add a close button to the pane header
522 * @returns {Sidebar} A new sidebar instance
523 */
524L.control.sidebar = function(options, deprecated) {
525    return new L.Control.Sidebar(options, deprecated);
526};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.