MaxSem has uploaded a new change for review. https://gerrit.wikimedia.org/r/295317
Change subject: WIP: Wikivoyage maps ...................................................................... WIP: Wikivoyage maps Change-Id: Ib6f92eaedddb453fe6346d6f2e55e9de6d78f278 --- A modules/wikivoyage/controls/layers.js A modules/wikivoyage/controls/nearby.js A modules/wikivoyage/controls/scale.js A modules/wikivoyage/data/en-articles.js A modules/wikivoyage/data/maptiles.json A modules/wikivoyage/i18n/en.json A modules/wikivoyage/images/nearby.svg A modules/wikivoyage/index.js A modules/wikivoyage/map/control-layers.js A modules/wikivoyage/map/map.js A modules/wikivoyage/mw.message.js A modules/wikivoyage/mw.wikivoyage.js A modules/wikivoyage/styles/wikivoyage.css 13 files changed, 807 insertions(+), 0 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Kartographer refs/changes/17/295317/1 diff --git a/modules/wikivoyage/controls/layers.js b/modules/wikivoyage/controls/layers.js new file mode 100644 index 0000000..d6a2340 --- /dev/null +++ b/modules/wikivoyage/controls/layers.js @@ -0,0 +1,46 @@ +import L from 'leaflet'; +import wikivoyage from '../mw.wikivoyage'; + +/*jscs:disable disallowDanglingUnderscores, requireVarDeclFirst */ +var ControlLayers = L.Control.Layers.extend( { + + _addItem: function ( obj ) { + var label = L.Control.Layers.prototype._addItem.call( this, obj ); + if ( !obj.overlay && label.childNodes[ 0 ].checked ) { + this._previousSelected = label.childNodes[ 0 ]; + } + }, + + _onInputClick: function ( event ) { + var self = this, + proto = L.Control.Layers.prototype._onInputClick, + input = event && event.target, + obj; + + if ( input && + event.type === 'click' && + /leaflet-control-layers-selector/.test( input.className ) ) { + + obj = this._layers[ input.layerId ]; + if ( this._map.hasLayer( obj.layer ) ) { + proto.call( self ); + } else { + event.stopPropagation(); + if ( !obj.overlay && this._previousSelected ) { + this._previousSelected.checked = true; + } + input.checked = false; + this._expand(); + wikivoyage.isAllowed( obj.layer ) + .done( function () { + input.checked = true; + proto.call( self ); + } ); + } + } else { + proto.call( this ); + } + } +} ); + +export default ControlLayers; diff --git a/modules/wikivoyage/controls/nearby.js b/modules/wikivoyage/controls/nearby.js new file mode 100644 index 0000000..b265c6d --- /dev/null +++ b/modules/wikivoyage/controls/nearby.js @@ -0,0 +1,105 @@ +import L from 'leaflet'; +import $ from 'jquery'; +import wikivoyage from '../mw.wikivoyage'; +import getArticles from '../data/en-articles'; + +function mousepopup( marker, data ) { + marker.bindPopup( data.title, { minWidth: 120, maxWidth: 120 } ); + marker.on( 'click', function ( e ) { + this.openPopup(); + } ); +} + +/*jscs:disable disallowDanglingUnderscores, requireVarDeclFirst */ +var ControlNearby = L.Control.extend( { + options: { + // Do not switch for RTL because zoom also stays in place + position: 'topleft' + }, + + onAdd: function ( map ) { + var container = L.DomUtil.create( 'div', 'leaflet-bar' ), + link = L.DomUtil.create( 'a', 'mw-kartographer-icon-nearby', container ), + pruneCluster = new PruneClusterForLeaflet( 70 ), + control = this; + + link.href = '#'; + link.title = mw.msg( 'kartographer-wv-nearby-articles-control' ); + pruneCluster.options = { + wvIsOverlay: true, + wvIsExternal: true, + wvName: 'nearby-articles' + }; + + this.map = map; + this.link = link; + this.pruneCluster = pruneCluster; + + L.DomEvent.addListener( link, 'click', this._onToggleNearbyLayer, this ); + L.DomEvent.disableClickPropagation( container ); + + map.on( 'overlayadd', this._onOverlayAdd, this ); + map.on( 'overlayremove', this._onOverlayRemove, this ); + + return container; + }, + + _onOverlayAdd: function ( obj ) { + var pruneCluster = this.pruneCluster; + if ( pruneCluster !== obj.layer ) { + return; + } + // Zoom out to get a better picture of the markers nearby. + if ( this.map.getZoom() >= 12 ) { + this.map.setZoom( 10 ); + } + this._toggleActiveClass( true ); + if ( pruneCluster._objectsOnMap.length > 0 ) { + return; + } + getArticles().done( function ( addressPoints ) { + var nr = addressPoints.length, + a, jslang = 'en', + tp = '//upload.wikimedia.org/wikipedia/commons/thumb/', // thumbnail path + ap = '//' + jslang + '.wikivoyage.org/wiki/', // WV article path + i = 0; + + for ( i = 0; i < nr; i++ ) { + a = addressPoints[ i ]; + pruneCluster.RegisterMarker( new PruneCluster.Marker( a[ 0 ], a[ 1 ], { title: '<img src="' + tp + a[ 3 ] + '/120px-' + a[ 3 ].substring( 5 ) + '"> <a href="' + ap + a[ 2 ] + '" target="_blank">' + a[ 2 ] + '</a>' } ) ); + pruneCluster.PrepareLeafletMarker = mousepopup; + } + pruneCluster.ProcessView(); + } ); + }, + + _onOverlayRemove: function ( obj ) { + if ( this.pruneCluster !== obj.layer ) { + return; + } + this._toggleActiveClass( false ); + }, + + _toggleActiveClass: function ( enabled ) { + enabled = ( enabled !== undefined ) ? enabled : this.map.hasLayer( this.pruneCluster ); + $( this.link ).toggleClass( 'mapbox-icon-nearby-active', enabled ); + }, + + _onToggleNearbyLayer: function ( e ) { + var control = this, + enabled = this.map.hasLayer( this.pruneCluster ); + + L.DomEvent.stop( e ); + + if ( !enabled ) { + wikivoyage.isAllowed( this.pruneCluster ) + .done( function () { + control.map.addLayer( control.pruneCluster ); + } ); + } else { + this.map[ enabled ? 'removeLayer' : 'addLayer' ]( this.pruneCluster ); + } + } +} ); + +export default ControlNearby; diff --git a/modules/wikivoyage/controls/scale.js b/modules/wikivoyage/controls/scale.js new file mode 100644 index 0000000..2d94c88 --- /dev/null +++ b/modules/wikivoyage/controls/scale.js @@ -0,0 +1,38 @@ +import L from 'leaflet'; + +/*jscs:disable disallowDanglingUnderscores, requireVarDeclFirst */ +var ControlScale = L.Control.Scale.extend( { + + isMetric: true, + + _updateScales: function ( options, maxMeters ) { + + L.Control.Scale.prototype._updateScales.call( this, options, maxMeters ); + + this._toggleScale(); + }, + + _addScales: function ( options, className, container ) { + L.Control.Scale.prototype._addScales.call( this, options, className, container ); + + if ( options.metric && options.imperial ) { + L.DomEvent.addListener( this._mScale, 'click', this._onToggleScale, this ); + L.DomEvent.addListener( this._iScale, 'click', this._onToggleScale, this ); + L.DomEvent.disableClickPropagation( container ); + } + }, + + _toggleScale: function () { + if ( this.options.metric && this.options.imperial ) { + this._mScale.style.display = this.isMetric ? 'block' : 'none'; + this._iScale.style.display = !this.isMetric ? 'block' : 'none'; + } + }, + + _onToggleScale: function () { + this.isMetric = !this.isMetric; + this._toggleScale(); + } +} ); + +export default ControlScale; diff --git a/modules/wikivoyage/data/en-articles.js b/modules/wikivoyage/data/en-articles.js new file mode 100644 index 0000000..984c307 --- /dev/null +++ b/modules/wikivoyage/data/en-articles.js @@ -0,0 +1,22 @@ +var fetchArticlesDeferred, + data; + +export default function () { + if ( fetchArticlesDeferred ) { + return fetchArticlesDeferred; + } else { + fetchArticlesDeferred = $.Deferred(); + } + + if ( !data ) { + // fetch + $.getScript( 'https://tools.wmflabs.org/wikivoyage/w/data/en-articles.js' ) + .done( function ( script, textStatus ) { + data = window.addressPoints; + fetchArticlesDeferred.resolve( data ).promise(); + } ); + } else { + fetchArticlesDeferred.resolve( data ); + } + return fetchArticlesDeferred.promise(); +} diff --git a/modules/wikivoyage/data/maptiles.json b/modules/wikivoyage/data/maptiles.json new file mode 100644 index 0000000..5b9823a --- /dev/null +++ b/modules/wikivoyage/data/maptiles.json @@ -0,0 +1,177 @@ +{ + "mapnik": { + "tilesUrl": "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + "options": { + "wvIsExternal": true, + "wvName": "Mapnik", + "subdomains": [ + "a", + "b", + "c" + ], + "attribs": [ + { + "url": "http://www.openstreetmap.org/copyright", + "name": "OpenStreetMap", + "label": "Map data" + } + ] + } + }, + "mapquestopen": { + "tilesUrl": "https://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png", + "options": { + "wvIsExternal": true, + "wvName": "Mapquest open", + "subdomains": [ + "otile1-s", + "otile2-s", + "otile3-s", + "otile4-s" + ], + "attribs": [ + { + "url": "http://www.openstreetmap.org/copyright", + "name": "OpenStreetMap", + "label": "Map data" + }, + { + "url": "http://open.mapquest.co.uk", + "name": "Mapquest", + "label": "Tiles" + } + ] + } + }, + "mapquest": { + "tilesUrl": "https://{s}.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg", + "options": { + "wvIsExternal": true, + "wvName": "Mapquest", + "subdomains": [ + "otile1-s", + "otile2-s", + "otile3-s", + "otile4-s" + ], + "attribs": [ + { + "url": "http://open.mapquest.co.uk", + "name": "Mapquest", + "label": "Data, imagery and map information provided by" + } + ] + } + }, + "landscape": { + "tilesUrl": "http://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png", + "options": { + "wvIsExternal": true, + "wvName": "Relief map", + "attribs": [ + { + "url": "http://www.openstreetmap.org/copyright", + "name": "OpenStreetMap", + "label": "Map data" + }, + { + "url": "http://www.opencyclemap.org/", + "name": "Andy Allan", + "label": "Tiles" + } + ] + } + }, + "traffic": { + "tilesUrl": "http://www.openptmap.org/tiles/{z}/{x}/{y}.png", + "options": { + "wvIsOverlay": true, + "wvIsExternal": true, + "wvName": "Traffic line network", + "attribs": [ + { + "url": "http://openptmap.org/", + "name": "Openptmap.org", + "label": "Traffic lines" + } + ], + "opacity": 0.5, + "maxNativeZoom": 17 + } + }, + "maplabels": { + "tilesUrl": "https://{s}.mqcdn.com/tiles/1.0.0/hyb/{z}/{x}/{y}.png", + "options": { + "wvIsOverlay": true, + "wvIsExternal": true, + "wvName": "Mapquest (labels)", + "subdomains": [ + "otile1-s", + "otile2-s", + "otile3-s", + "otile4-s" + ], + "attribs": [ + { + "url": "http://open.mapquest.co.uk", + "name": "Mapquest", + "label": "Data, imagery and map information provided by" + } + ] + } + }, + "boundaries": { + "tilesUrl": "http://korona.geog.uni-heidelberg.de/tiles/adminb/x={x}&y={y}&z={z}", + "options": { + "wvIsOverlay": true, + "wvIsExternal": true, + "wvName": "Boundaries", + "attribs": [] + } + }, + "cycling": { + "tilesUrl": "http://tile.lonvia.de/cycling/{z}/{x}/{y}.png", + "options": { + "wvIsOverlay": true, + "wvIsExternal": true, + "wvName": "Cycling", + "attribs": [ + { + "url": "http://cycling.lonvia.de", + "name": "Cycling Map", + "label": "Cycling routes" + } + ] + } + }, + "hiking": { + "tilesUrl": "http://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png", + "options": { + "wvIsOverlay": true, + "wvIsExternal": true, + "wvName": "Hiking", + "attribs": [ + { + "url": "http://hiking.waymarkedtrails.org/de/", + "name": "Hiking Map", + "label": "Hiking trails" + } + ] + } + }, + "hill": { + "tilesUrl": "http://{s}.tiles.wmflabs.org/hillshading/{z}/{x}/{y}.png", + "options": { + "wvIsOverlay": true, + "wvIsExternal": true, + "wvName": "Hill shading", + "attribs": [ + { + "url": "http://www2.jpl.nasa.gov/srtm/", + "name": "NASA", + "label": "Hill shading" + } + ] + } + } +} diff --git a/modules/wikivoyage/i18n/en.json b/modules/wikivoyage/i18n/en.json new file mode 100644 index 0000000..d1d9ecf --- /dev/null +++ b/modules/wikivoyage/i18n/en.json @@ -0,0 +1,20 @@ +{ + "kartographer-wv-group": "Group: ", + "kartographer-wv-Mapnik": "Mapnik", + "kartographer-wv-Hiking": "Hiking", + "kartographer-wv-Wikimedia": "Wikimedia", + "kartographer-wv-nearby-articles": "Nearby articles", + "kartographer-wv-Mapquest open": "Mapquest open", + "kartographer-wv-Mapquest": "Mapquest", + "kartographer-wv-Relief map": "Relief map", + "kartographer-wv-Traffic line network": "Traffic line network", + "kartographer-wv-Mapquest (labels)": "Mapquest (labels)", + "kartographer-wv-Boundaries": "Boundaries", + "kartographer-wv-Hill shading": "Hill shading", + "kartographer-wv-Cycling": "Cycling", + "kartographer-wv-warning-external-source-title": "External data source", + "kartographer-wv-warning-external-source-message": "This content is hosted externally, so enabling it shares your data with other sites.", + "kartographer-wv-warning-external-source-agree": "It's okay", + "kartographer-wv-warning-external-source-disagree": "Cancel", + "kartographer-wv-nearby-articles-control": "Explore nearby destinations" +} diff --git a/modules/wikivoyage/images/nearby.svg b/modules/wikivoyage/images/nearby.svg new file mode 100644 index 0000000..4e32fe3 --- /dev/null +++ b/modules/wikivoyage/images/nearby.svg @@ -0,0 +1,9 @@ +<svg width="24px" height="24px" viewBox="-3195 -3703 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-3194.000000, -3692.000000)"> + <path d="M12.0543874,8.84786092 C16.7188107,8.84786092 20.5000728,7.08703806 20.5000728,4.91495298 C20.5000728,2.74286791 16.7188107,0.982045042 12.0543874,0.982045042 C7.38996415,0.982045042 3.60870199,2.74286791 3.60870199,4.91495298 C3.60870199,7.08703806 7.38996415,8.84786092 12.0543874,8.84786092 Z M11.7850466,11.0592528 C17.1891786,11.0592528 21.5700932,8.58355477 21.5700932,5.52962642 C21.5700932,2.47569808 17.1891786,0 11.7850466,0 C6.38091459,0 2,2.47569808 2,5.52962642 C2,8.58355477 6.38091459,11.0592528 11.7850466,11.0592528 Z" fill="#000000"></path> + <ellipse stroke="#FFFFFF" stroke-width="1.4" fill="#000000" cx="15.9394612" cy="9.58434489" rx="2.93946123" ry="2.58434489"></ellipse> + <path d="M2.5,8.18444824 C3.88071187,8.18444824 5,7.2477276 5,6.09222412 C5,4.93672065 3.88071187,4 2.5,4 C1.11928813,4 0,4.93672065 0,6.09222412 C0,7.2477276 1.11928813,8.18444824 2.5,8.18444824 Z" stroke="#FFFFFF" stroke-width="1.3" fill="#000000"></path> + <path d="M19.375,4.65244141 C20.6866763,4.65244141 21.75,3.75701091 21.75,2.65244141 C21.75,1.54787191 20.6866763,0.652441406 19.375,0.652441406 C18.0633237,0.652441406 17,1.54787191 17,2.65244141 C17,3.75701091 18.0633237,4.65244141 19.375,4.65244141 Z" stroke="#FFFFFF" fill="#000000"></path> + </g> + <path d="M-3181.5562,-3703 C-3184.56299,-3703 -3187,-3700.25757 -3187,-3696.87395 C-3187,-3693.49032 -3183.97506,-3688.70587 -3181.5562,-3687.34453 C-3179.13613,-3688.70587 -3176.1124,-3693.49032 -3176.1124,-3696.87395 C-3176.1124,-3700.25757 -3178.54941,-3703 -3181.5562,-3703 L-3181.5562,-3703 Z M-3181.5562,-3694.49159 C-3183.05869,-3694.49159 -3184.2781,-3695.86247 -3184.2781,-3697.55462 C-3184.2781,-3699.24541 -3183.05869,-3700.61765 -3181.5562,-3700.61765 C-3180.05311,-3700.61765 -3178.8343,-3699.24541 -3178.8343,-3697.55462 C-3178.8343,-3695.86247 -3180.05311,-3694.49159 -3181.5562,-3694.49159 L-3181.5562,-3694.49159 Z" stroke="none" fill="#000000" fill-rule="evenodd"></path> +</svg> diff --git a/modules/wikivoyage/index.js b/modules/wikivoyage/index.js new file mode 100644 index 0000000..be45fee --- /dev/null +++ b/modules/wikivoyage/index.js @@ -0,0 +1,47 @@ +import $ from 'jquery'; +import mw from 'mediawiki'; +import wikivoyage from './mw.wikivoyage.js'; +import maptiles from './data/maptiles.json'; + +mw.wikivoyage = wikivoyage; + +function wikivoyageMe( map, isFullScreen ) { + + var wvmap = wikivoyage.map( map ); + + // wvmap.controlLayers() + // .basemap( 'mapnik' ) + // .basemap( 'mapquestopen' ) + // .basemap( 'mapquest' ) + // .basemap( 'landscape' ) + // .overlay( 'traffic' ) + // .overlay( 'maplabels' ) + // .overlay( 'boundaries' ) + // .overlay( 'hill' ) + // .overlay( 'cycling' ) + // .overlay( 'hiking' ) + // .datalayer( this.map.dataLayers ) + // .update(); + + wvmap.controlLayers().addAll(); + wvmap.scale(); + wvmap.nearby(); + + return wvmap; +} + +mw.hook( 'wikipage.maps' ).add( function ( map, isFullScreen ) { + + $.each( maptiles, function ( i, tile ) { + wikivoyage.addTileLayer( i, tile.tilesUrl, tile.options ); + } ); + + // init ? + if ( $.isArray( map ) ) { + $.each( map, function ( i, m ) { + wikivoyageMe( m, isFullScreen ); + } ) + } else { + wikivoyageMe( map, isFullScreen ); + } +} ); diff --git a/modules/wikivoyage/map/control-layers.js b/modules/wikivoyage/map/control-layers.js new file mode 100644 index 0000000..c9bd9b3 --- /dev/null +++ b/modules/wikivoyage/map/control-layers.js @@ -0,0 +1,74 @@ +import $ from 'jquery'; +import ControlLayers from '../controls/layers'; +import wikivoyage from '../mw.wikivoyage'; +import message from '../mw.message'; + +/*jscs:disable disallowDanglingUnderscores, requireVarDeclFirst */ +var MapControl = function ( map ) { + this.map = map; + this.control = new ControlLayers(); + this.control.addTo( this.map ); + + // Add wikimedia basemap + this.addLayer( + this.map.wikimediaLayer, + wikivoyage.formatLayerName( message( 'Wikimedia' ), { wvIsWMF: true } ) + ); +}; + +MapControl.prototype.addLayer = function ( layer, name, overlay ) { + this.control._addLayer( layer, name, overlay ); + return this; +}; + +MapControl.prototype.addAll = function () { + this + .basemap( 'mapnik' ) + .basemap( 'mapquestopen' ) + .basemap( 'mapquest' ) + .basemap( 'landscape' ) + .overlay( 'traffic' ) + .overlay( 'maplabels' ) + .overlay( 'boundaries' ) + .overlay( 'hill' ) + .overlay( 'cycling' ) + .overlay( 'hiking' ) + .datalayer( this.map.dataLayers ) + .update(); + return this; +}; + +MapControl.prototype.update = function () { + this.control._update(); + return this; +}; + +MapControl.prototype.basemap = function ( id ) { + var tileLayer = wikivoyage.createTileLayer( id ); + this.addLayer( tileLayer.layer, tileLayer.name ); + return this; +}; + +MapControl.prototype.overlay = function ( id ) { + var tileLayer = wikivoyage.createTileLayer( id ); + this.addLayer( tileLayer.layer, tileLayer.name, true ); + return this; +}; + +MapControl.prototype.datalayer = function ( id, layer ) { + if ( typeof id === 'object' ) { + var self = this; + $.each( id, function ( group, groupLayer ) { + self.datalayer( group, groupLayer ); + } ); + return this; + } + this.addLayer( + layer, + wikivoyage.formatLayerName( message( 'group' ) + id ), + true + ); + return this; +}; + +export default MapControl; diff --git a/modules/wikivoyage/map/map.js b/modules/wikivoyage/map/map.js new file mode 100644 index 0000000..783e0b8 --- /dev/null +++ b/modules/wikivoyage/map/map.js @@ -0,0 +1,41 @@ +import L from 'leaflet'; +import ControlLayers from './control-layers.js'; +import ControlNearby from '../controls/nearby'; +import ControlScale from '../controls/scale'; +import wikivoyage from '../mw.wikivoyage'; +import message from '../mw.message'; + +/*jscs:disable disallowDanglingUnderscores, requireVarDeclFirst */ +var Map = function ( map ) { + this.map = map; +}; + +Map.prototype.nearby = function () { + var control = this._controlNearby; + if ( control ) { + return control; + } + + control = this._controlNearby = new ControlNearby(); + control.addTo( this.map ); + + this.controlLayers().addLayer( + control.pruneCluster, + wikivoyage.formatLayerName( message( control.pruneCluster.options.wvName ), control.pruneCluster.options ), + true + ).update(); + + return control; +}; + +Map.prototype.controlLayers = function () { + this._controlLayers = this._controlLayers || new ControlLayers( this.map ); + return this._controlLayers; +}; + +Map.prototype.scale = function () { + this._controlScale = this._controlScale || new ControlScale( { position: 'bottomright' } ).addTo( this.map ); + return this._controlScale; +}; + +export default Map; diff --git a/modules/wikivoyage/mw.message.js b/modules/wikivoyage/mw.message.js new file mode 100644 index 0000000..de9d088 --- /dev/null +++ b/modules/wikivoyage/mw.message.js @@ -0,0 +1,9 @@ +import mw from 'mediawiki'; +import labels from './i18n/en.json'; + +mw.messages.set( labels ); + +export default function ( key, action ) { + action = action || 'escaped'; + return mw.message( 'kartographer-wv-' + key )[ action ](); +}; diff --git a/modules/wikivoyage/mw.wikivoyage.js b/modules/wikivoyage/mw.wikivoyage.js new file mode 100644 index 0000000..f905ec9 --- /dev/null +++ b/modules/wikivoyage/mw.wikivoyage.js @@ -0,0 +1,107 @@ +import WikivoyageMap from './map/map'; +import $ from 'jquery'; +import mw from 'mediawiki'; +import message from './mw.message'; + +/*jscs:disable requireVarDeclFirst */ +var maps = [], + tileLayerDefs = {}, + areExternalAllowed, + windowManager, + messageDialog, + STORAGE_KEY = 'mwKartographerExternalSources'; + +mw.loader.using( 'oojs-ui' ); + +function getWindowManager() { + if ( windowManager ) { + return windowManager; + } + messageDialog = new OO.ui.MessageDialog(); + windowManager = new OO.ui.WindowManager(); + $( 'body' ).append( windowManager.$element ); + windowManager.addWindows( [ messageDialog ] ); + return windowManager; +} + +function alertExternalData() { + return getWindowManager().openWindow( messageDialog, { + title: message( 'warning-external-source-title', 'text' ), + message: message( 'warning-external-source-message', 'text' ), + actions: [ + { label: message( 'warning-external-source-disagree', 'text' ), action: 'bad' }, + { + label: message( 'warning-external-source-agree', 'text' ), + action: 'good' + } + ] + } ); +} + +export default { + map: function ( map ) { + var wikivoyageMap = new WikivoyageMap( map ); + return wikivoyageMap; + }, + + addTileLayer: function ( id, url, options ) { + options.wvLayerId = id; + options.attribution = options.attribution || ''; + $.each( options.attribs, function ( i, attrib ) { + options.attribution += attrib.label + ' '; + options.attribution += ' <a href="' + attrib.url + '">' + attrib.name + '</a>'; + } ); + + tileLayerDefs[ id.toString() ] = { + url: url, + options: options + }; + return this; + }, + + createTileLayer: function ( id ) { + var layerDefs = tileLayerDefs[ id ]; + return { + layer: new L.TileLayer( layerDefs.url, layerDefs.options ), + name: this.formatLayerName( message( layerDefs.options.wvName ), layerDefs.options ) + }; + }, + + formatLayerName: function ( name, options ) { + var icon; + options = options || {}; + if ( options.wvIsExternal ) { + icon = '/w/skins/Vector/images/external-link-ltr-icon.png?325de'; + } else if ( options.wvIsWMF ) { + icon = '//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Wikimedia-logo.svg/12px-Wikimedia-logo.svg.png'; + } + return name + ( icon ? ' <img src="' + icon + '" />' : '' ); + }, + + isAllowed: function ( layer ) { + var deferred = $.Deferred(); + + if ( areExternalAllowed === undefined ) { + areExternalAllowed = mw.storage.get( STORAGE_KEY ) === '1'; + } + + if ( !layer.options.wvIsExternal || areExternalAllowed ) { + deferred.resolve(); + } else { + alertExternalData() + .then( function ( opened ) { + opened.then( function ( closing, data ) { + if ( data && data.action && data.action === 'good' ) { + areExternalAllowed = true; + mw.storage.set( STORAGE_KEY, '1' ); + deferred.resolve(); + } else { + deferred.reject(); + } + } ); + } ); + } + + return deferred.promise(); + } +}; diff --git a/modules/wikivoyage/styles/wikivoyage.css b/modules/wikivoyage/styles/wikivoyage.css new file mode 100644 index 0000000..5c436f5 --- /dev/null +++ b/modules/wikivoyage/styles/wikivoyage.css @@ -0,0 +1,112 @@ +/* = Wikivoyage Customization = */ + +/* == Top Right controls == */ + +/* Top Right controls won't overlap over left and bottom controls */ +.leaflet-right.leaflet-top { + left: 50px; + bottom: 20px; + overflow: hidden; +} + +/* Expand the dropdown as wide as possible */ +.leaflet-control-layers-expanded { + max-height: calc(100% - 50px); + max-width: calc(100% - 10px); + text-align: left; + overflow: scroll; +} + +/* Add ellipsis to long layer labels */ +.leaflet-control-layers-expanded label { + text-overflow: ellipsis; + white-space: nowrap; + overflow-x: hidden; +} + +/* Removes ellipsis on hover */ +.leaflet-control-layers-expanded .leaflet-control-layers-overlays:hover label, +.leaflet-control-layers-expanded .leaflet-control-layers-base:hover label { + overflow-x: visible; +} + +/* == Bottom Right controls == */ + +/* Bottom right container style */ +.leaflet-right.leaflet-bottom { + background-color: rgba(255, 255, 255, 0.6); + left: auto; + cursor: default; + max-width: 100%; +} + +/* Bottom right container style on hover */ +.leaflet-right.leaflet-bottom:hover { + background-color: rgba(255, 255, 255, 0.9); +} + +/* === Scale control === */ + +/** Override initial properties */ +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-scale { + float: left; + clear: none; + margin: 1px 5px; + line-height: initial; +} + +/* Scale Line style */ +.leaflet-control-scale.leaflet-control .leaflet-control-scale-line { + background-color: transparent; + padding: 0 5px; + font-size: 10px; + font-family: sans-serif; +} + +/* Scale Line style on hover */ +.leaflet-right.leaflet-bottom .leaflet-control-scale .leaflet-control-scale-line:hover { + border-color: black; + cursor: pointer; +} + +/** Override initial properties */ +.leaflet-right.leaflet-bottom .leaflet-control-scale .leaflet-control-scale-line:not(:first-child) { + border: 1px solid #999; + border-color: black; + border-top: none; + margin-top: 0; +} + +/* === Attribution control === */ + +/** Override initial properties */ +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-attribution { + float: none; + clear: none; + font-size: 10px; + font-family: sans-serif; + line-height: 1.6; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Removes ellipsis on hover */ +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-attribution:hover { + white-space: normal; + overflow: hidden; + text-overflow: clip; +} + +/* == New icons == */ +/* New nearby POIs icon */ +.mapbox-icon-nearby-active, .mapbox-icon-nearby-active:hover { + background-color: #999999; + border-color: #999999; +} + +.leaflet-control-container .leaflet-control .mw-kartographer-icon-nearby { + background-image: url(https://people.wikimedia.org/~jgirault/maps/icons/nearby.svg); + background-size: 20px; +} -- To view, visit https://gerrit.wikimedia.org/r/295317 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ib6f92eaedddb453fe6346d6f2e55e9de6d78f278 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Kartographer Gerrit-Branch: master Gerrit-Owner: MaxSem <maxsem.w...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits