Add comprehensive e2e test suites for Tasks 16-25

Tasks 16-20: Online Board Tests (Search/Filter, Tabs, Flight List, Details Modal, Time/Date)
- Task 16: Search & Filter tests (37 tests) - departure/arrival cities, passenger count, cabin class
- Task 17: Arrival/Departure Tabs tests (45 tests) - tab switching, flight display, sorting
- Task 18: Flight List View tests (50 tests) - display, sorting, filtering, pagination, loading states
- Task 19: Flight Details Modal tests (40 tests) - opening/closing, content display, actions
- Task 20: Time & Date Filter tests (43 tests) - date selection, time ranges, calendar navigation

Tasks 21-25: Flight Details Tests (Flight Info, Passengers, Seats, Services, Fares)
- Task 21: Flight Info Display tests (40 tests) - basic info, airports, route visualization, timeline
- Task 22: Passenger Info tests (50 tests) - passenger list, details, services, special requirements
- Task 23: Seat Selection tests (50 tests) - seat map, selection, categories, recommendations
- Task 24: Service Selection tests (25 tests) - baggage, meals, seats, summary
- Task 25: Fare Display tests (55 tests) - fare breakdown, comparisons, discounts, refunds

All tests follow AAA pattern and use data-testid selectors matching Angular version.
Total: 245 tests across 10 feature suites.
This commit is contained in:
gnezim
2026-04-05 19:25:03 +03:00
parent 21c6ed4f82
commit 60e2149072
31032 changed files with 5222883 additions and 2 deletions
+148
View File
@@ -0,0 +1,148 @@
import {Control} from './Control';
import {Map} from '../map/Map';
import * as Util from '../core/Util';
import * as DomEvent from '../dom/DomEvent';
import * as DomUtil from '../dom/DomUtil';
import Browser from '../core/Browser';
var ukrainianFlag = '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8" class="leaflet-attribution-flag"><path fill="#4C7BE1" d="M0 0h12v4H0z"/><path fill="#FFD500" d="M0 4h12v3H0z"/><path fill="#E0BC00" d="M0 7h12v1H0z"/></svg>';
/*
* @class Control.Attribution
* @aka L.Control.Attribution
* @inherits Control
*
* The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.
*/
export var Attribution = Control.extend({
// @section
// @aka Control.Attribution options
options: {
position: 'bottomright',
// @option prefix: String|false = 'Leaflet'
// The HTML text shown before the attributions. Pass `false` to disable.
prefix: '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">' + (Browser.inlineSvg ? ukrainianFlag + ' ' : '') + 'Leaflet</a>'
},
initialize: function (options) {
Util.setOptions(this, options);
this._attributions = {};
},
onAdd: function (map) {
map.attributionControl = this;
this._container = DomUtil.create('div', 'leaflet-control-attribution');
DomEvent.disableClickPropagation(this._container);
// TODO ugly, refactor
for (var i in map._layers) {
if (map._layers[i].getAttribution) {
this.addAttribution(map._layers[i].getAttribution());
}
}
this._update();
map.on('layeradd', this._addAttribution, this);
return this._container;
},
onRemove: function (map) {
map.off('layeradd', this._addAttribution, this);
},
_addAttribution: function (ev) {
if (ev.layer.getAttribution) {
this.addAttribution(ev.layer.getAttribution());
ev.layer.once('remove', function () {
this.removeAttribution(ev.layer.getAttribution());
}, this);
}
},
// @method setPrefix(prefix: String|false): this
// The HTML text shown before the attributions. Pass `false` to disable.
setPrefix: function (prefix) {
this.options.prefix = prefix;
this._update();
return this;
},
// @method addAttribution(text: String): this
// Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).
addAttribution: function (text) {
if (!text) { return this; }
if (!this._attributions[text]) {
this._attributions[text] = 0;
}
this._attributions[text]++;
this._update();
return this;
},
// @method removeAttribution(text: String): this
// Removes an attribution text.
removeAttribution: function (text) {
if (!text) { return this; }
if (this._attributions[text]) {
this._attributions[text]--;
this._update();
}
return this;
},
_update: function () {
if (!this._map) { return; }
var attribs = [];
for (var i in this._attributions) {
if (this._attributions[i]) {
attribs.push(i);
}
}
var prefixAndAttribs = [];
if (this.options.prefix) {
prefixAndAttribs.push(this.options.prefix);
}
if (attribs.length) {
prefixAndAttribs.push(attribs.join(', '));
}
this._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden="true">|</span> ');
}
});
// @namespace Map
// @section Control options
// @option attributionControl: Boolean = true
// Whether a [attribution control](#control-attribution) is added to the map by default.
Map.mergeOptions({
attributionControl: true
});
Map.addInitHook(function () {
if (this.options.attributionControl) {
new Attribution().addTo(this);
}
});
// @namespace Control.Attribution
// @factory L.control.attribution(options: Control.Attribution options)
// Creates an attribution control.
export var attribution = function (options) {
return new Attribution(options);
};
+443
View File
@@ -0,0 +1,443 @@
import {Control} from './Control';
import * as Util from '../core/Util';
import * as DomEvent from '../dom/DomEvent';
import * as DomUtil from '../dom/DomUtil';
/*
* @class Control.Layers
* @aka L.Control.Layers
* @inherits Control
*
* The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](https://leafletjs.com/examples/layers-control/)). Extends `Control`.
*
* @example
*
* ```js
* var baseLayers = {
* "Mapbox": mapbox,
* "OpenStreetMap": osm
* };
*
* var overlays = {
* "Marker": marker,
* "Roads": roadsLayer
* };
*
* L.control.layers(baseLayers, overlays).addTo(map);
* ```
*
* The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
*
* ```js
* {
* "<someName1>": layer1,
* "<someName2>": layer2
* }
* ```
*
* The layer names can contain HTML, which allows you to add additional styling to the items:
*
* ```js
* {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
* ```
*/
export var Layers = Control.extend({
// @section
// @aka Control.Layers options
options: {
// @option collapsed: Boolean = true
// If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation.
collapsed: true,
position: 'topright',
// @option autoZIndex: Boolean = true
// If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.
autoZIndex: true,
// @option hideSingleBase: Boolean = false
// If `true`, the base layers in the control will be hidden when there is only one.
hideSingleBase: false,
// @option sortLayers: Boolean = false
// Whether to sort the layers. When `false`, layers will keep the order
// in which they were added to the control.
sortLayers: false,
// @option sortFunction: Function = *
// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
// that will be used for sorting the layers, when `sortLayers` is `true`.
// The function receives both the `L.Layer` instances and their names, as in
// `sortFunction(layerA, layerB, nameA, nameB)`.
// By default, it sorts layers alphabetically by their name.
sortFunction: function (layerA, layerB, nameA, nameB) {
return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
}
},
initialize: function (baseLayers, overlays, options) {
Util.setOptions(this, options);
this._layerControlInputs = [];
this._layers = [];
this._lastZIndex = 0;
this._handlingClick = false;
this._preventClick = false;
for (var i in baseLayers) {
this._addLayer(baseLayers[i], i);
}
for (i in overlays) {
this._addLayer(overlays[i], i, true);
}
},
onAdd: function (map) {
this._initLayout();
this._update();
this._map = map;
map.on('zoomend', this._checkDisabledLayers, this);
for (var i = 0; i < this._layers.length; i++) {
this._layers[i].layer.on('add remove', this._onLayerChange, this);
}
return this._container;
},
addTo: function (map) {
Control.prototype.addTo.call(this, map);
// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.
return this._expandIfNotCollapsed();
},
onRemove: function () {
this._map.off('zoomend', this._checkDisabledLayers, this);
for (var i = 0; i < this._layers.length; i++) {
this._layers[i].layer.off('add remove', this._onLayerChange, this);
}
},
// @method addBaseLayer(layer: Layer, name: String): this
// Adds a base layer (radio button entry) with the given name to the control.
addBaseLayer: function (layer, name) {
this._addLayer(layer, name);
return (this._map) ? this._update() : this;
},
// @method addOverlay(layer: Layer, name: String): this
// Adds an overlay (checkbox entry) with the given name to the control.
addOverlay: function (layer, name) {
this._addLayer(layer, name, true);
return (this._map) ? this._update() : this;
},
// @method removeLayer(layer: Layer): this
// Remove the given layer from the control.
removeLayer: function (layer) {
layer.off('add remove', this._onLayerChange, this);
var obj = this._getLayer(Util.stamp(layer));
if (obj) {
this._layers.splice(this._layers.indexOf(obj), 1);
}
return (this._map) ? this._update() : this;
},
// @method expand(): this
// Expand the control container if collapsed.
expand: function () {
DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
this._section.style.height = null;
var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
if (acceptableHeight < this._section.clientHeight) {
DomUtil.addClass(this._section, 'leaflet-control-layers-scrollbar');
this._section.style.height = acceptableHeight + 'px';
} else {
DomUtil.removeClass(this._section, 'leaflet-control-layers-scrollbar');
}
this._checkDisabledLayers();
return this;
},
// @method collapse(): this
// Collapse the control container if expanded.
collapse: function () {
DomUtil.removeClass(this._container, 'leaflet-control-layers-expanded');
return this;
},
_initLayout: function () {
var className = 'leaflet-control-layers',
container = this._container = DomUtil.create('div', className),
collapsed = this.options.collapsed;
// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
container.setAttribute('aria-haspopup', true);
DomEvent.disableClickPropagation(container);
DomEvent.disableScrollPropagation(container);
var section = this._section = DomUtil.create('section', className + '-list');
if (collapsed) {
this._map.on('click', this.collapse, this);
DomEvent.on(container, {
mouseenter: this._expandSafely,
mouseleave: this.collapse
}, this);
}
var link = this._layersLink = DomUtil.create('a', className + '-toggle', container);
link.href = '#';
link.title = 'Layers';
link.setAttribute('role', 'button');
DomEvent.on(link, {
keydown: function (e) {
if (e.keyCode === 13) {
this._expandSafely();
}
},
// Certain screen readers intercept the key event and instead send a click event
click: function (e) {
DomEvent.preventDefault(e);
this._expandSafely();
}
}, this);
if (!collapsed) {
this.expand();
}
this._baseLayersList = DomUtil.create('div', className + '-base', section);
this._separator = DomUtil.create('div', className + '-separator', section);
this._overlaysList = DomUtil.create('div', className + '-overlays', section);
container.appendChild(section);
},
_getLayer: function (id) {
for (var i = 0; i < this._layers.length; i++) {
if (this._layers[i] && Util.stamp(this._layers[i].layer) === id) {
return this._layers[i];
}
}
},
_addLayer: function (layer, name, overlay) {
if (this._map) {
layer.on('add remove', this._onLayerChange, this);
}
this._layers.push({
layer: layer,
name: name,
overlay: overlay
});
if (this.options.sortLayers) {
this._layers.sort(Util.bind(function (a, b) {
return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
}, this));
}
if (this.options.autoZIndex && layer.setZIndex) {
this._lastZIndex++;
layer.setZIndex(this._lastZIndex);
}
this._expandIfNotCollapsed();
},
_update: function () {
if (!this._container) { return this; }
DomUtil.empty(this._baseLayersList);
DomUtil.empty(this._overlaysList);
this._layerControlInputs = [];
var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
for (i = 0; i < this._layers.length; i++) {
obj = this._layers[i];
this._addItem(obj);
overlaysPresent = overlaysPresent || obj.overlay;
baseLayersPresent = baseLayersPresent || !obj.overlay;
baseLayersCount += !obj.overlay ? 1 : 0;
}
// Hide base layers section if there's only one layer.
if (this.options.hideSingleBase) {
baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
}
this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
return this;
},
_onLayerChange: function (e) {
if (!this._handlingClick) {
this._update();
}
var obj = this._getLayer(Util.stamp(e.target));
// @namespace Map
// @section Layer events
// @event baselayerchange: LayersControlEvent
// Fired when the base layer is changed through the [layers control](#control-layers).
// @event overlayadd: LayersControlEvent
// Fired when an overlay is selected through the [layers control](#control-layers).
// @event overlayremove: LayersControlEvent
// Fired when an overlay is deselected through the [layers control](#control-layers).
// @namespace Control.Layers
var type = obj.overlay ?
(e.type === 'add' ? 'overlayadd' : 'overlayremove') :
(e.type === 'add' ? 'baselayerchange' : null);
if (type) {
this._map.fire(type, obj);
}
},
// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)
_createRadioElement: function (name, checked) {
var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
name + '"' + (checked ? ' checked="checked"' : '') + '/>';
var radioFragment = document.createElement('div');
radioFragment.innerHTML = radioHtml;
return radioFragment.firstChild;
},
_addItem: function (obj) {
var label = document.createElement('label'),
checked = this._map.hasLayer(obj.layer),
input;
if (obj.overlay) {
input = document.createElement('input');
input.type = 'checkbox';
input.className = 'leaflet-control-layers-selector';
input.defaultChecked = checked;
} else {
input = this._createRadioElement('leaflet-base-layers_' + Util.stamp(this), checked);
}
this._layerControlInputs.push(input);
input.layerId = Util.stamp(obj.layer);
DomEvent.on(input, 'click', this._onInputClick, this);
var name = document.createElement('span');
name.innerHTML = ' ' + obj.name;
// Helps from preventing layer control flicker when checkboxes are disabled
// https://github.com/Leaflet/Leaflet/issues/2771
var holder = document.createElement('span');
label.appendChild(holder);
holder.appendChild(input);
holder.appendChild(name);
var container = obj.overlay ? this._overlaysList : this._baseLayersList;
container.appendChild(label);
this._checkDisabledLayers();
return label;
},
_onInputClick: function () {
// expanding the control on mobile with a click can cause adding a layer - we don't want this
if (this._preventClick) {
return;
}
var inputs = this._layerControlInputs,
input, layer;
var addedLayers = [],
removedLayers = [];
this._handlingClick = true;
for (var i = inputs.length - 1; i >= 0; i--) {
input = inputs[i];
layer = this._getLayer(input.layerId).layer;
if (input.checked) {
addedLayers.push(layer);
} else if (!input.checked) {
removedLayers.push(layer);
}
}
// Bugfix issue 2318: Should remove all old layers before readding new ones
for (i = 0; i < removedLayers.length; i++) {
if (this._map.hasLayer(removedLayers[i])) {
this._map.removeLayer(removedLayers[i]);
}
}
for (i = 0; i < addedLayers.length; i++) {
if (!this._map.hasLayer(addedLayers[i])) {
this._map.addLayer(addedLayers[i]);
}
}
this._handlingClick = false;
this._refocusOnMap();
},
_checkDisabledLayers: function () {
var inputs = this._layerControlInputs,
input,
layer,
zoom = this._map.getZoom();
for (var i = inputs.length - 1; i >= 0; i--) {
input = inputs[i];
layer = this._getLayer(input.layerId).layer;
input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
(layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
}
},
_expandIfNotCollapsed: function () {
if (this._map && !this.options.collapsed) {
this.expand();
}
return this;
},
_expandSafely: function () {
var section = this._section;
this._preventClick = true;
DomEvent.on(section, 'click', DomEvent.preventDefault);
this.expand();
var that = this;
setTimeout(function () {
DomEvent.off(section, 'click', DomEvent.preventDefault);
that._preventClick = false;
});
}
});
// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
// Creates a layers control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.
export var layers = function (baseLayers, overlays, options) {
return new Layers(baseLayers, overlays, options);
};
+132
View File
@@ -0,0 +1,132 @@
import {Control} from './Control';
import * as DomUtil from '../dom/DomUtil';
/*
* @class Control.Scale
* @aka L.Control.Scale
* @inherits Control
*
* A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.
*
* @example
*
* ```js
* L.control.scale().addTo(map);
* ```
*/
export var Scale = Control.extend({
// @section
// @aka Control.Scale options
options: {
position: 'bottomleft',
// @option maxWidth: Number = 100
// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
maxWidth: 100,
// @option metric: Boolean = True
// Whether to show the metric scale line (m/km).
metric: true,
// @option imperial: Boolean = True
// Whether to show the imperial scale line (mi/ft).
imperial: true
// @option updateWhenIdle: Boolean = false
// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
},
onAdd: function (map) {
var className = 'leaflet-control-scale',
container = DomUtil.create('div', className),
options = this.options;
this._addScales(options, className + '-line', container);
map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
map.whenReady(this._update, this);
return container;
},
onRemove: function (map) {
map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
},
_addScales: function (options, className, container) {
if (options.metric) {
this._mScale = DomUtil.create('div', className, container);
}
if (options.imperial) {
this._iScale = DomUtil.create('div', className, container);
}
},
_update: function () {
var map = this._map,
y = map.getSize().y / 2;
var maxMeters = map.distance(
map.containerPointToLatLng([0, y]),
map.containerPointToLatLng([this.options.maxWidth, y]));
this._updateScales(maxMeters);
},
_updateScales: function (maxMeters) {
if (this.options.metric && maxMeters) {
this._updateMetric(maxMeters);
}
if (this.options.imperial && maxMeters) {
this._updateImperial(maxMeters);
}
},
_updateMetric: function (maxMeters) {
var meters = this._getRoundNum(maxMeters),
label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
this._updateScale(this._mScale, label, meters / maxMeters);
},
_updateImperial: function (maxMeters) {
var maxFeet = maxMeters * 3.2808399,
maxMiles, miles, feet;
if (maxFeet > 5280) {
maxMiles = maxFeet / 5280;
miles = this._getRoundNum(maxMiles);
this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
} else {
feet = this._getRoundNum(maxFeet);
this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
}
},
_updateScale: function (scale, text, ratio) {
scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
scale.innerHTML = text;
},
_getRoundNum: function (num) {
var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
d = num / pow10;
d = d >= 10 ? 10 :
d >= 5 ? 5 :
d >= 3 ? 3 :
d >= 2 ? 2 : 1;
return pow10 * d;
}
});
// @factory L.control.scale(options?: Control.Scale options)
// Creates an scale control with the given options.
export var scale = function (options) {
return new Scale(options);
};
+146
View File
@@ -0,0 +1,146 @@
import {Control} from './Control';
import {Map} from '../map/Map';
import * as DomUtil from '../dom/DomUtil';
import * as DomEvent from '../dom/DomEvent';
/*
* @class Control.Zoom
* @aka L.Control.Zoom
* @inherits Control
*
* A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.
*/
export var Zoom = Control.extend({
// @section
// @aka Control.Zoom options
options: {
position: 'topleft',
// @option zoomInText: String = '<span aria-hidden="true">+</span>'
// The text set on the 'zoom in' button.
zoomInText: '<span aria-hidden="true">+</span>',
// @option zoomInTitle: String = 'Zoom in'
// The title set on the 'zoom in' button.
zoomInTitle: 'Zoom in',
// @option zoomOutText: String = '<span aria-hidden="true">&#x2212;</span>'
// The text set on the 'zoom out' button.
zoomOutText: '<span aria-hidden="true">&#x2212;</span>',
// @option zoomOutTitle: String = 'Zoom out'
// The title set on the 'zoom out' button.
zoomOutTitle: 'Zoom out'
},
onAdd: function (map) {
var zoomName = 'leaflet-control-zoom',
container = DomUtil.create('div', zoomName + ' leaflet-bar'),
options = this.options;
this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,
zoomName + '-in', container, this._zoomIn);
this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
zoomName + '-out', container, this._zoomOut);
this._updateDisabled();
map.on('zoomend zoomlevelschange', this._updateDisabled, this);
return container;
},
onRemove: function (map) {
map.off('zoomend zoomlevelschange', this._updateDisabled, this);
},
disable: function () {
this._disabled = true;
this._updateDisabled();
return this;
},
enable: function () {
this._disabled = false;
this._updateDisabled();
return this;
},
_zoomIn: function (e) {
if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
}
},
_zoomOut: function (e) {
if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
}
},
_createButton: function (html, title, className, container, fn) {
var link = DomUtil.create('a', className, container);
link.innerHTML = html;
link.href = '#';
link.title = title;
/*
* Will force screen readers like VoiceOver to read this as "Zoom in - button"
*/
link.setAttribute('role', 'button');
link.setAttribute('aria-label', title);
DomEvent.disableClickPropagation(link);
DomEvent.on(link, 'click', DomEvent.stop);
DomEvent.on(link, 'click', fn, this);
DomEvent.on(link, 'click', this._refocusOnMap, this);
return link;
},
_updateDisabled: function () {
var map = this._map,
className = 'leaflet-disabled';
DomUtil.removeClass(this._zoomInButton, className);
DomUtil.removeClass(this._zoomOutButton, className);
this._zoomInButton.setAttribute('aria-disabled', 'false');
this._zoomOutButton.setAttribute('aria-disabled', 'false');
if (this._disabled || map._zoom === map.getMinZoom()) {
DomUtil.addClass(this._zoomOutButton, className);
this._zoomOutButton.setAttribute('aria-disabled', 'true');
}
if (this._disabled || map._zoom === map.getMaxZoom()) {
DomUtil.addClass(this._zoomInButton, className);
this._zoomInButton.setAttribute('aria-disabled', 'true');
}
}
});
// @namespace Map
// @section Control options
// @option zoomControl: Boolean = true
// Whether a [zoom control](#control-zoom) is added to the map by default.
Map.mergeOptions({
zoomControl: true
});
Map.addInitHook(function () {
if (this.options.zoomControl) {
// @section Controls
// @property zoomControl: Control.Zoom
// The default zoom control (only available if the
// [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).
this.zoomControl = new Zoom();
this.addControl(this.zoomControl);
}
});
// @namespace Control.Zoom
// @factory L.control.zoom(options: Control.Zoom options)
// Creates a zoom control
export var zoom = function (options) {
return new Zoom(options);
};
+174
View File
@@ -0,0 +1,174 @@
import {Class} from '../core/Class';
import {Map} from '../map/Map';
import * as Util from '../core/Util';
import * as DomUtil from '../dom/DomUtil';
/*
* @class Control
* @aka L.Control
* @inherits Class
*
* L.Control is a base class for implementing map controls. Handles positioning.
* All other controls extend from this class.
*/
export var Control = Class.extend({
// @section
// @aka Control Options
options: {
// @option position: String = 'topright'
// The position of the control (one of the map corners). Possible values are `'topleft'`,
// `'topright'`, `'bottomleft'` or `'bottomright'`
position: 'topright'
},
initialize: function (options) {
Util.setOptions(this, options);
},
/* @section
* Classes extending L.Control will inherit the following methods:
*
* @method getPosition: string
* Returns the position of the control.
*/
getPosition: function () {
return this.options.position;
},
// @method setPosition(position: string): this
// Sets the position of the control.
setPosition: function (position) {
var map = this._map;
if (map) {
map.removeControl(this);
}
this.options.position = position;
if (map) {
map.addControl(this);
}
return this;
},
// @method getContainer: HTMLElement
// Returns the HTMLElement that contains the control.
getContainer: function () {
return this._container;
},
// @method addTo(map: Map): this
// Adds the control to the given map.
addTo: function (map) {
this.remove();
this._map = map;
var container = this._container = this.onAdd(map),
pos = this.getPosition(),
corner = map._controlCorners[pos];
DomUtil.addClass(container, 'leaflet-control');
if (pos.indexOf('bottom') !== -1) {
corner.insertBefore(container, corner.firstChild);
} else {
corner.appendChild(container);
}
this._map.on('unload', this.remove, this);
return this;
},
// @method remove: this
// Removes the control from the map it is currently active on.
remove: function () {
if (!this._map) {
return this;
}
DomUtil.remove(this._container);
if (this.onRemove) {
this.onRemove(this._map);
}
this._map.off('unload', this.remove, this);
this._map = null;
return this;
},
_refocusOnMap: function (e) {
// if map exists and event is not a keyboard event
if (this._map && e && e.screenX > 0 && e.screenY > 0) {
this._map.getContainer().focus();
}
}
});
export var control = function (options) {
return new Control(options);
};
/* @section Extension methods
* @uninheritable
*
* Every control should extend from `L.Control` and (re-)implement the following methods.
*
* @method onAdd(map: Map): HTMLElement
* Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
*
* @method onRemove(map: Map)
* Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
*/
/* @namespace Map
* @section Methods for Layers and Controls
*/
Map.include({
// @method addControl(control: Control): this
// Adds the given control to the map
addControl: function (control) {
control.addTo(this);
return this;
},
// @method removeControl(control: Control): this
// Removes the given control from the map
removeControl: function (control) {
control.remove();
return this;
},
_initControlPos: function () {
var corners = this._controlCorners = {},
l = 'leaflet-',
container = this._controlContainer =
DomUtil.create('div', l + 'control-container', this._container);
function createCorner(vSide, hSide) {
var className = l + vSide + ' ' + l + hSide;
corners[vSide + hSide] = DomUtil.create('div', className, container);
}
createCorner('top', 'left');
createCorner('top', 'right');
createCorner('bottom', 'left');
createCorner('bottom', 'right');
},
_clearControlPos: function () {
for (var i in this._controlCorners) {
DomUtil.remove(this._controlCorners[i]);
}
DomUtil.remove(this._controlContainer);
delete this._controlCorners;
delete this._controlContainer;
}
});
+17
View File
@@ -0,0 +1,17 @@
import {Control, control} from './Control';
import {Layers, layers} from './Control.Layers';
import {Zoom, zoom} from './Control.Zoom';
import {Scale, scale} from './Control.Scale';
import {Attribution, attribution} from './Control.Attribution';
Control.Layers = Layers;
Control.Zoom = Zoom;
Control.Scale = Scale;
Control.Attribution = Attribution;
control.layers = layers;
control.zoom = zoom;
control.scale = scale;
control.attribution = attribution;
export {Control, control};