diff --git a/src/mapml-viewer.js b/src/mapml-viewer.js
index 965fcf066..7c7462abf 100644
--- a/src/mapml-viewer.js
+++ b/src/mapml-viewer.js
@@ -209,13 +209,12 @@ export class MapViewer extends HTMLElement {
// there is a better configuration than that, but at this moment
// I'm not sure how to approach that issue.
// See https://github.com/Maps4HTML/MapML-Leaflet-Client/issues/24
- fadeAnimation: true
+ fadeAnimation: true,
+ attributionControl: false
});
this._addToHistory();
// the attribution control is not optional
- this._attributionControl = this._map.attributionControl.setPrefix('Maps4HTML | Leaflet');
- this._attributionControl.getContainer().setAttribute("role","group");
- this._attributionControl.getContainer().setAttribute("aria-label","Map data attribution");
+ this._attributionControl = M.attributionButton().addTo(this._map);
this.setControls(false,false,true);
this._crosshair = M.crosshair().addTo(this._map);
diff --git a/src/mapml.css b/src/mapml.css
index 3f23276ec..b1f67c6ac 100644
--- a/src/mapml.css
+++ b/src/mapml.css
@@ -140,13 +140,9 @@
.leaflet-tooltip-pane .leaflet-tooltip,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar,
-.leaflet-popup-tip {
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), 0 1px 2px rgb(0, 0, 0, 0.3);
-}
-
-/* Increase contrast between the attribution container and the underlying content. */
+.leaflet-popup-tip,
.leaflet-container .leaflet-control-attribution {
- background-color: rgba(255, 255, 255, 0.95);
+ box-shadow: rgb(0 0 0 / 30%) 0px 1px 4px -1px;
}
/* Remove opinionated styles of attribution links. */
@@ -155,6 +151,43 @@
text-decoration: revert;
}
+
+/*
+ * Attribution.
+ */
+
+.leaflet-container .leaflet-control-attribution {
+ background-color: #fff;
+ border-radius: 1.5em;
+ color: currentColor;
+ margin: 5px;
+ min-height: 30px;
+ min-width: 30px;
+ padding: 0;
+}
+
+.leaflet-control-attribution summary {
+ display: block;
+ list-style: none;
+ border-radius: 100%;
+ position: absolute;
+ bottom: 0;
+ left: calc(100% - 30px);
+ line-height: 0;
+ width: 30px;
+ height: 30px;
+}
+
+.leaflet-control-attribution summary svg {
+ border-radius: 100%;
+ width: inherit;
+ height: inherit;
+}
+
+.mapml-attribution-container {
+ padding: 5px 35px 5px 10px;
+}
+
/*
* Zoom controls.
*/
diff --git a/src/mapml/control/AttributionButton.js b/src/mapml/control/AttributionButton.js
new file mode 100644
index 000000000..a8681e12a
--- /dev/null
+++ b/src/mapml/control/AttributionButton.js
@@ -0,0 +1,110 @@
+export var AttributionButton = L.Control.extend({
+ options: {
+ position: 'bottomright',
+ prefix: 'Maps for HTML Community Group Leaflet'
+ },
+
+ initialize: function (options) {
+ L.Util.setOptions(this, options);
+ this._attributions = {};
+ },
+
+ onAdd: function (map) {
+ map.attributionControl = this;
+ this._container = L.DomUtil.create('details', 'leaflet-control-attribution');
+ L.DomEvent.disableClickPropagation(this._container);
+
+ 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);
+ }
+ },
+
+ setPrefix: function (prefix) {
+ this.options.prefix = prefix;
+ this._update();
+ return this;
+ },
+
+ addAttribution: function (text) {
+ if (!text) { return this; }
+
+ if (!this._attributions[text]) {
+ this._attributions[text] = 0;
+ }
+ this._attributions[text]++;
+
+ this._update();
+
+ return this;
+ },
+
+ 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 = '