jenkins-bot has submitted this change and it was merged.
Change subject: Static map page for non-JS support of maplinks
......................................................................
Static map page for non-JS support of maplinks
Special:Map/{zoom}/{latitude}/{longitude}
Bug: T144003
Change-Id: I90fcd2fb0e458c9d5a805b441f5114157ea470a4
---
A Kartographer.alias.php
M extension.json
M i18n/en.json
M i18n/qqq.json
A includes/Projection/EPSG3857.php
A includes/Projection/SphericalMercator.php
A includes/Projection/Transformation.php
A includes/SpecialMap.php
M includes/Tag/MapLink.php
A styles/specialMap.less
M tests/parserTests.txt
A tests/phpunit/SpecialMapTest.php
12 files changed, 474 insertions(+), 24 deletions(-)
Approvals:
Yurik: Looks good to me, approved
jenkins-bot: Verified
diff --git a/Kartographer.alias.php b/Kartographer.alias.php
new file mode 100644
index 0000000..c788e1a
--- /dev/null
+++ b/Kartographer.alias.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Aliases for special pages for extension Echo
+ *
+ * @file
+ * @ingroup Extensions
+ */
+// @codingStandardsIgnoreFile
+
+$specialPageAliases = array();
+
+/** English (English) */
+$specialPageAliases['en'] = [
+ 'Map' => [ 'Map' ],
+];
diff --git a/extension.json b/extension.json
index 0af590a..ea345dd 100644
--- a/extension.json
+++ b/extension.json
@@ -16,6 +16,12 @@
"modules/wikivoyage/i18n"
]
},
+ "ExtensionMessagesFiles": {
+ "KartogrpaherAliases": "Kartographer.alias.php"
+ },
+ "SpecialPages": {
+ "Map": "Kartographer\\SpecialMap"
+ },
"AutoloadClasses": {
"Kartographer\\ApiQueryMapData": "includes/ApiQueryMapData.php",
"Kartographer\\ApiSanitizeMapData":
"includes/ApiSanitizeMapData.php",
@@ -23,10 +29,14 @@
"Kartographer\\DataModule": "includes/DataModule.php",
"Kartographer\\Hooks": "includes/Hooks.php",
"Kartographer\\SimpleStyleParser":
"includes/SimpleStyleParser.php",
+ "Kartographer\\SpecialMap": "includes/SpecialMap.php",
"Kartographer\\State": "includes/State.php",
"Kartographer\\Tag\\MapFrame": "includes/Tag/MapFrame.php",
"Kartographer\\Tag\\MapLink": "includes/Tag/MapLink.php",
- "Kartographer\\Tag\\TagHandler": "includes/Tag/TagHandler.php"
+ "Kartographer\\Tag\\TagHandler": "includes/Tag/TagHandler.php",
+ "Kartographer\\Projection\\EPSG3857":
"includes/Projection/EPSG3857.php",
+ "Kartographer\\Projection\\SphericalMercator":
"includes/Projection/SphericalMercator.php",
+ "Kartographer\\Projection\\Transformation":
"includes/Projection/Transformation.php"
},
"APIModules": {
"sanitize-mapdata": "Kartographer\\ApiSanitizeMapData"
@@ -324,6 +334,15 @@
"mobile",
"desktop"
]
+ },
+ "ext.kartographer.specialMap": {
+ "styles": [
+ "styles/specialMap.less"
+ ],
+ "targets": [
+ "mobile",
+ "desktop"
+ ]
}
},
"ResourceFileModulePaths": {
diff --git a/i18n/en.json b/i18n/en.json
index 6249d19..7740904 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -33,6 +33,7 @@
"kartographer-coord-lat-negative": "$1S",
"kartographer-coord-lon-positive": "$1E",
"kartographer-coord-lon-negative": "$1W",
+ "kartographer-specialmap-invalid-coordinates": "Invalid coordinates
supplied",
"kartographer.css": "/* CSS placed here will be applied to all pages
with maps */",
"kartographer.js": "/* Any JavaScript here will be loaded for all users
on load of the map-containing pages */",
"leafletdraw-draw-handlers-circle-radius": "Radius",
@@ -67,6 +68,7 @@
"leafletdraw-edit-toolbar-buttons-editdisabled": "No layers to edit",
"leafletdraw-edit-toolbar-buttons-remove": "Delete layers",
"leafletdraw-edit-toolbar-buttons-removedisabled": "No layers to
delete",
+ "map": "Coordinates information",
"mapbox-control-zoomin-title": "Zoom in",
"mapbox-control-zoomout-title": "Zoom out",
"kartographer-fullscreen-close": "Close",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 92b856c..1c1e886 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -35,7 +35,8 @@
"kartographer-coord-lat-positive": "{{optional}}\nNorth latitude suffix
for geographical coordinates. $1 is value in degrees/minutes/seconds, see
{{msg-mw|kartographer-coord-dms}}",
"kartographer-coord-lat-negative": "{{optional}}\nSouth latitude suffix
for geographical coordinates. $1 is value in degrees/minutes/seconds, see
{{msg-mw|kartographer-coord-dms}}",
"kartographer-coord-lon-positive": "{{optional}}\nEast longitude suffix
for geographical coordinates. $1 is value in degrees/minutes/seconds, see
{{msg-mw|kartographer-coord-dms}}",
- "kartographer-coord-lon-negative": "{{optional}}\nWest longitude suffix
for geographical coordinates. $1 is value in degrees/minutes/seconds, see
{{msg-mw|kartographer-coord-dms}}",
+ "kartographer-coord-lon-negative": "{`{optional}}\nWest longitude
suffix for geographical coordinates. $1 is value in degrees/minutes/seconds,
see {{msg-mw|kartographer-coord-dms}}",
+ "kartographer-specialmap-invalid-coordinates": "Displayed by
Special:Map when no valid coordinates are supplied",
"kartographer.css": "{{optional}}",
"kartographer.js": "{{optional}}",
"leafletdraw-draw-handlers-circle-radius": "Label for circle
radius\n{{Identical|Radius}}",
@@ -70,6 +71,7 @@
"leafletdraw-edit-toolbar-buttons-editdisabled": "Tooltip for edit
layers button when disabled",
"leafletdraw-edit-toolbar-buttons-remove": "Tooltip for delete layers
button",
"leafletdraw-edit-toolbar-buttons-removedisabled": "Tooltip for delete
layers button when disabled",
+ "map": "Page title for Special:Map",
"mapbox-control-zoomin-title": "Title for map zoom in
button\n{{Identical|Zoom in}}",
"mapbox-control-zoomout-title": "Title for map zoom out
button\n{{Identical|Zoom out}}",
"kartographer-fullscreen-close": "Title of the fullscreen close
button\n{{Identical|Close}}",
diff --git a/includes/Projection/EPSG3857.php b/includes/Projection/EPSG3857.php
new file mode 100644
index 0000000..5303f38
--- /dev/null
+++ b/includes/Projection/EPSG3857.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Kartographer\Projection;
+
+/**
+ * EPSG3857 (Spherical Mercator) is the most common CRS for web mapping
+ * and is used by Leaflet by default.
+ *
+ * Converted to PHP from L.CRS.EPSG3857 (leaflet.js)
+ */
+class EPSG3857 {
+
+ const EARTH_RADIUS = 6378137;
+
+ /**
+ * (LatLon) -> Point
+ *
+ * @param float[] $latLon
+ * @return float[]
+ */
+ public static function project( $latLon ) {
+ $projectedPoint = SphericalMercator::project( $latLon );
+
+ return [ $projectedPoint * self::EARTH_RADIUS, $projectedPoint
* self::EARTH_RADIUS ];
+ }
+
+ /**
+ * (LatLon, Number) -> Point
+ *
+ * @param float[] $latLon
+ * @param int $zoom
+ * @return array
+ */
+ public static function latLonToPoint( $latLon, $zoom ) {
+ $projectedPoint = SphericalMercator::project( $latLon );
+ $scale = self::scale( $zoom );
+
+ return Transformation::transform( $projectedPoint, $scale );
+ }
+
+ /**
+ * (Point, Number[, Boolean]) -> LatLon
+ *
+ * @param $point
+ * @param $zoom
+ * @return array
+ */
+ public static function pointToLatLon( $point, $zoom ) {
+ $scale = self::scale( $zoom );
+ $untransformedPoint = Transformation::untransform( $point,
$scale );
+
+ return SphericalMercator::unproject( $untransformedPoint );
+ }
+
+ public static function scale( $zoom ) {
+ return 256 * pow( 2, $zoom );
+ }
+
+ public static function getSize( $zoom ) {
+ $size = self::scale( $zoom );
+
+ return [ $size, $size ];
+ }
+}
diff --git a/includes/Projection/SphericalMercator.php
b/includes/Projection/SphericalMercator.php
new file mode 100644
index 0000000..33d9c48
--- /dev/null
+++ b/includes/Projection/SphericalMercator.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Kartographer\Projection;
+
+/**
+ * Spherical Mercator is the most popular map projection,
+ * used by EPSG:3857 CRS.
+ *
+ * Converted to PHP from L.Projection.SphericalMercator (leaflet.js)
+ */
+class SphericalMercator {
+
+ const MAX_LATITUDE = 85.0511287798;
+
+ /**
+ * (LatLon) -> Point
+ *
+ * @param float[] $latLon
+ * @return array
+ */
+ public static function project( $latLon ) {
+
+ $lat = max( min( self::MAX_LATITUDE, $latLon[0] ),
-self::MAX_LATITUDE );
+ $x = deg2rad( $latLon[1] );
+ $y = deg2rad( $lat );
+
+ $y = log( tan( ( pi() / 4 ) + ( $y / 2 ) ) );
+
+ return [ $x, $y ];
+ }
+
+ /**
+ * (Point, Boolean) -> LatLon
+ *
+ * @param float[] $point
+ * @return array
+ */
+ public static function unproject( $point ) {
+ $lon = rad2deg( $point[0] );
+ $lat = rad2deg( 2 * atan( exp( $point[1] ) ) - ( pi() / 2 ) );
+
+ return [ $lat, $lon ];
+ }
+}
diff --git a/includes/Projection/Transformation.php
b/includes/Projection/Transformation.php
new file mode 100644
index 0000000..04d8380
--- /dev/null
+++ b/includes/Projection/Transformation.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Kartographer\Projection;
+
+/**
+ * Transformation is an utility class to perform simple point transformations
+ * through a 2d-matrix.
+ *
+ * Converted to PHP from L.Transformation (leaflet.js)
+ */
+class Transformation {
+// @fixme: cleanup
+ const A = 0.159154943; // 0.5 * pi()
+ const C = -0.159154943; // -0.5 * pi()
+
+ /**
+ * (LatLon) -> Point
+ *
+ * @param float[] $point
+ * @param int $scale
+ * @return float[]
+ */
+ public static function transform( $point, $scale = 1 ) {
+
+ $x = $point[0];
+ $y = $point[1];
+
+ $x = $scale * ( self::A * $x + 0.5);
+ $y = $scale * ( self::C * $y + 0.5 );
+
+ return [ $x, $y ];
+ }
+
+ public static function untransform( $point, $scale = 1 ) {
+ $x = $point[0];
+ $y = $point[1];
+
+ $x = ( $x / $scale - 0.5 ) / self::A;
+ $y = ( $y / $scale - 0.5 ) / self::C;
+
+ return [ $x, $y ];
+ }
+}
diff --git a/includes/SpecialMap.php b/includes/SpecialMap.php
new file mode 100644
index 0000000..651e7a1
--- /dev/null
+++ b/includes/SpecialMap.php
@@ -0,0 +1,95 @@
+<?php
+
+namespace Kartographer;
+
+use GeoData\Globe;
+use Html;
+use SpecialPage;
+use Title;
+use Kartographer\Projection\EPSG3857;
+
+/**
+ * Special page that works as a fallback destination for non-JS users
+ * who click on map links. It displays a world map with a dot for the given
location.
+ * URL format: Special:Map/<zoom>/<lat>/<lon>
+ * Zoom isn't used anywhere yet.
+ */
+class SpecialMap extends SpecialPage {
+ public function __construct( $name = 'Map' ) {
+ parent::__construct( $name, /* $restriction */ '', /* $listed
*/ false );
+ }
+
+ public function execute( $par ) {
+ $this->setHeaders();
+ $this->getOutput()->addModuleStyles(
'ext.kartographer.specialMap' );
+
+ $coord = self::parseSubpage( $par );
+ if ( !$coord ) {
+ $coordText = wfMessage(
'kartographer-specialmap-invalid-coordinates' )->text();
+ $markerHtml = '';
+ } else {
+ list( , $lat, $lon ) = $coord;
+ $coordText = CoordFormatter::format( $lat, $lon,
$this->getLanguage() );
+ list( $x, $y ) = EPSG3857::latLonToPoint( [ $lat, $lon
], 0 );
+ $markerHtml = Html::element( 'div',
+ [
+ 'id' => 'mw-specialMap-marker',
+ 'style' => "left:{$x}px; top:{$y}px;"
+ ]
+ );
+ }
+
+ $attributions = Html::rawElement( 'div', [ 'id' =>
'mw-specialMap-attributions' ],
+ wfMessage( 'kartographer-attribution' )->parse() );
+
+ $this->getOutput()->addHTML(
+ Html::openElement( 'div', [ 'id' =>
'mw-specialMap-container', 'class' => 'thumb' ] )
+ . Html::openElement( 'div', [ 'class' =>
'thumbinner' ] )
+ . Html::openElement( 'div', [ 'id' =>
'mw-specialMap-inner' ] )
+ . Html::element( 'div', [ 'id'
=> 'mw-specialMap-map' ] )
+ . $markerHtml
+ . $attributions
+ . Html::closeElement( 'div' )
+ . Html::openElement( 'div', [ 'id' =>
'mw-specialMap-caption', 'class' => 'thumbcaption' ] )
+ . Html::element( 'span', [ 'id'
=> 'mw-specialMap-icon' ] )
+ . Html::element( 'span', [ 'id'
=> 'mw-specialMap-coords' ], $coordText )
+ . Html::closeElement( 'div' )
+ . Html::closeElement( 'div' )
+ . Html::closeElement( 'div' )
+ );
+ }
+
+ /**
+ * Parses subpage parameter to this special page into zoom / lat /lon
+ *
+ * @param $par
+ * @return array|bool
+ */
+ public static function parseSubpage( $par ) {
+ if ( !preg_match(
'#^(?<zoom>\d+)/(?<lat>-?\d+(\.\d+)?)/(?<lon>-?\d+(\.\d+)?)$#', $par, $matches
) ) {
+ return false;
+ }
+
+ if ( class_exists( Globe::class ) ) {
+ $globe = new Globe( 'earth' );
+
+ if ( !$globe->coordinatesAreValid( $matches['lat'],
$matches['lon'] ) ) {
+ return false;
+ }
+ }
+
+ return [ (int)$matches['zoom'], (float)$matches['lat'],
(float)$matches['lon'] ];
+ }
+
+ /**
+ * Returns a Title for a link to the coordinates provided
+ *
+ * @param float $lat
+ * @param float $lon
+ * @param int $zoom
+ * @return Title
+ */
+ public static function link( $lat, $lon, $zoom ) {
+ return SpecialPage::getTitleFor( 'Map', "$zoom/$lat/$lon" );
+ }
+}
diff --git a/includes/Tag/MapLink.php b/includes/Tag/MapLink.php
index f11c667..a55a5ca 100644
--- a/includes/Tag/MapLink.php
+++ b/includes/Tag/MapLink.php
@@ -5,6 +5,7 @@
use FormatJson;
use Html;
use Kartographer\CoordFormatter;
+use Kartographer\SpecialMap;
/**
* The <maplink> tag creates a link that, when clicked,
@@ -35,6 +36,7 @@
'class' => 'mw-kartographer-maplink',
'mw-data' => 'interface',
'data-style' => $this->mapStyle,
+ 'href' => SpecialMap::link( $this->lat, $this->lon,
$this->zoom )->getLocalURL()
];
if ( $this->zoom !== null ) {
$attrs['data-zoom'] = $this->zoom;
diff --git a/styles/specialMap.less b/styles/specialMap.less
new file mode 100644
index 0000000..f2cb16c
--- /dev/null
+++ b/styles/specialMap.less
@@ -0,0 +1,92 @@
+@mapWidth: 256px;
+@mapHeight: 256px;
+@markerColor: #7b4e10;
+@markerSize: 10px;
+
+/* stylelint-disable selector-no-id */
+
+div#mw-specialMap-container {
+
+ position: relative;
+
+ .thumbinner {
+ display: inline-block;
+ position: relative;
+ width: @mapWidth;
+ }
+}
+
+div#mw-specialMap-inner {
+ height: @mapHeight;
+ position: relative;
+}
+
+div#mw-specialMap-map {
+ position: absolute;
+ width: @mapWidth;
+ height: @mapHeight;
+ /* stylelint-disable function-parentheses-space-inside */
+ background-image: url(//maps.wikimedia.org/osm-intl/0/0/0.png);
+ /* stylelint-enable function-parentheses-space-inside */
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: @mapWidth @mapHeight;
+}
+
+/* stylelint-disable media-feature-name-no-vendor-prefix */
+@media ( -webkit-min-device-pixel-ratio: 1.5 ),
+ ( min--moz-device-pixel-ratio: 1.5 ),
+ ( min-resolution: 1.5dppx ),
+ ( min-resolution: 144dpi ) {
+ div#mw-specialMap-map {
+ /* stylelint-disable function-parentheses-space-inside */
+ background-image:
url(//maps.wikimedia.org/osm-intl/0/0/[email protected]);
+ /* stylelint-enable function-parentheses-space-inside */
+ }
+}
+
+@media ( -webkit-min-device-pixel-ratio: 2 ),
+ ( min--moz-device-pixel-ratio: 2 ),
+ ( min-resolution: 2dppx ),
+ ( min-resolution: 192dpi ) {
+ div#mw-specialMap-map {
+ /* stylelint-disable function-parentheses-space-inside */
+ background-image:
url(//maps.wikimedia.org/osm-intl/0/0/[email protected]);
+ /* stylelint-enable function-parentheses-space-inside */
+ }
+}
+/* stylelint-enable media-feature-name-no-vendor-prefix */
+
+div#mw-specialMap-marker {
+ position: absolute;
+ background-color: @markerColor;
+ height: @markerSize;
+ width: @markerSize;
+ margin-top: -1 * (@markerSize/2);
+ margin-left: -1 * (@markerSize/2);
+ border-radius: @markerSize/2;
+}
+
+div#mw-specialMap-caption {
+ display: block;
+ padding-top: 0.5em;
+}
+
+span#mw-specialMap-icon {
+ display: inline-block;
+ margin: 0 12px 0 0;
+ background-color: @markerColor;
+ height: @markerSize;
+ width: @markerSize;
+ margin-top: -1 * (@markerSize/2);
+ margin-left: 0.5em;
+ border-radius: @markerSize/2;
+}
+
+div#mw-specialMap-attributions {
+ position: absolute;
+ bottom: 0;
+ font-size: 9px;
+ right: 0;
+ text-align: right;
+}
diff --git a/tests/parserTests.txt b/tests/parserTests.txt
index 856ed8d..0448d48 100644
--- a/tests/parserTests.txt
+++ b/tests/parserTests.txt
@@ -4,8 +4,8 @@
<maplink />
<maplink latitude=10 longitude=20 zoom=13 text='Foo & bar'/>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl">0°0′0″N 0°0′0″E</a>
-<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
data-zoom="13" data-lat="10" data-lon="20">Foo & bar</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map///">0°0′0″N 0°0′0″E</a>
+<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
href="/wiki/Special:Map/13/10/20" data-zoom="13" data-lat="10"
data-lon="20">Foo & bar</a>
</p>
!! end
@@ -14,14 +14,14 @@
!! input
<maplink latitude=10 longitude=20 zoom=13 text='<&'/>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="13" data-lat="10" data-lon="20"><&</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/13/10/20" data-zoom="13"
data-lat="10" data-lon="20"><&</a>
</p>
!! end
!! test
<maplink> - counters and markers
!! input
-<maplink latitude=10 longitude=20 zoom=13 text='Foo'>
+<maplink latitude=10.123 longitude=20.456 zoom=13 text='Foo'>
{
"type": "Feature",
"geometry": {
@@ -73,10 +73,10 @@
}
</maplink>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="13" data-lat="10" data-lon="20"
data-overlays="["_b34053f88dea58fe70a7da09c558f792394f6e11"]">Foo</a>
-</p><p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="13" data-lat="10" data-lon="20"
data-overlays="["_2e4133dc429eb3c3abf4e45916c073e841f9d193"]">2</a>
-</p><p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="13" data-lat="10" data-lon="20"
data-overlays="["_dd3c7bae539f7c3747c64d043c97e1a8834fbc8f"]">A</a>
-</p><p><a class="mw-kartographer-maplink" mw-data="interface" data-style="osm"
data-zoom="13" data-lat="10" data-lon="20"
data-overlays="["_8ce73f7395e427bd6f462824717c0a214b3ca564"]">B</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/13/10.123/20.456" data-zoom="13"
data-lat="10.123" data-lon="20.456"
data-overlays="["_b34053f88dea58fe70a7da09c558f792394f6e11"]">Foo</a>
+</p><p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/13/10/20" data-zoom="13"
data-lat="10" data-lon="20"
data-overlays="["_2e4133dc429eb3c3abf4e45916c073e841f9d193"]">2</a>
+</p><p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/13/10/20" data-zoom="13"
data-lat="10" data-lon="20"
data-overlays="["_dd3c7bae539f7c3747c64d043c97e1a8834fbc8f"]">A</a>
+</p><p><a class="mw-kartographer-maplink" mw-data="interface" data-style="osm"
href="/wiki/Special:Map/13/10/20" data-zoom="13" data-lat="10" data-lon="20"
data-overlays="["_8ce73f7395e427bd6f462824717c0a214b3ca564"]">B</a>
</p>
!! end
@@ -85,7 +85,7 @@
!! input
<maplink latitude=10 longitude=20 zoom=13 />
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="13" data-lat="10" data-lon="20">10°0′0″N
20°0′0″E</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/13/10/20" data-zoom="13"
data-lat="10" data-lon="20">10°0′0″N 20°0′0″E</a>
</p>
!! end
@@ -99,9 +99,9 @@
<maplink zoom=0 latitude=0 longitude=0 class="class1 class2" text="Multiple
classes aren't allowed for now"/>
<maplink zoom=0 latitude=0 longitude=0 class="-Invalid-cl@ss-symbols"/>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="0" data-lat="0" data-lon="0">Empty class - do
nothing</a>
-<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
data-zoom="0" data-lat="0" data-lon="0">Whitespace only class - do nothing</a>
-<a class="mw-kartographer-maplink Valid-link_class_123" mw-data="interface"
data-style="osm-intl" data-zoom="0" data-lat="0" data-lon="0">Valid class</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0"
data-lon="0">Empty class - do nothing</a>
+<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0"
data-lon="0">Whitespace only class - do nothing</a>
+<a class="mw-kartographer-maplink Valid-link_class_123" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0"
data-lon="0">Valid class</a>
</p>
<div class="mw-kartographer-error"><maplink>: Attribute "class" has an
invalid value</div>
<div class="mw-kartographer-error"><maplink>: Attribute "class" has an
invalid value</div>
@@ -228,7 +228,7 @@
!! input
<maplink latitude=10 longitude=20 zoom=10 style="color: red;" text="<span
style='foo: bar; background-image:
url(https://example.com);'>foo</span>"/><!-- style=... was removed -->
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="10" data-lat="10" data-lon="20"><span
style="/* insecure input */">foo</span></a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/10/10/20" data-zoom="10"
data-lat="10" data-lon="20"><span style="/* insecure input */">foo</span></a>
</p>
!! end
@@ -269,7 +269,7 @@
}
]</maplink>
!! result
-<p><a class="mw-kartographer-maplink mw-kartographer-autostyled"
mw-data="interface" data-style="osm-intl" data-zoom="13" data-lat="10"
data-lon="20" style="background: #abcdef;"
data-overlays="["_0d28e3b8954f29b4a6af62bd43a9cacc70ce0261"]">A</a>
+<p><a class="mw-kartographer-maplink mw-kartographer-autostyled"
mw-data="interface" data-style="osm-intl" href="/wiki/Special:Map/13/10/20"
data-zoom="13" data-lat="10" data-lon="20" style="background: #abcdef;"
data-overlays="["_0d28e3b8954f29b4a6af62bd43a9cacc70ce0261"]">A</a>
</p>
!! end
@@ -292,7 +292,7 @@
}
</maplink>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="13" data-lat="10" data-lon="20"
data-overlays="["_a724df91b09b20c8c7ea0dc28127eaed1727511b"]">A</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/13/10/20" data-zoom="13"
data-lat="10" data-lon="20"
data-overlays="["_a724df91b09b20c8c7ea0dc28127eaed1727511b"]">A</a>
</p>
!! end
@@ -316,7 +316,7 @@
}
</mapframe>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="0" data-lat="0" data-lon="0"
data-overlays="["ponies"]">0°0′0″N 0°0′0″E</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0"
data-lon="0" data-overlays="["ponies"]">0°0′0″N 0°0′0″E</a>
</p>
<div class="mw-kartographer-container thumb tright"><div class="thumbinner"
style="width: 300px;"><div class="mw-kartographer-map" mw-data="interface"
data-style="osm-intl" data-width="300" data-height="300" data-zoom="0"
data-lat="0" data-lon="0" data-overlays="["ponies"]" style="height:
300px;"></div><div class="thumbcaption"></div></div></div>
@@ -342,7 +342,7 @@
}
</mapframe>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="0" data-lat="0" data-lon="0">0°0′0″N
0°0′0″E</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0"
data-lon="0">0°0′0″N 0°0′0″E</a>
</p>
<div class="mw-kartographer-container thumb tright"><div class="thumbinner"
style="width: 300px;"><div class="mw-kartographer-map" mw-data="interface"
data-style="osm-intl" data-width="300" data-height="300" data-zoom="0"
data-lat="0" data-lon="0"
data-overlays="["_a724df91b09b20c8c7ea0dc28127eaed1727511b"]"
style="height: 300px;"></div><div class="thumbcaption"></div></div></div>
@@ -360,11 +360,11 @@
<maplink zoom=0 latitude=0 longitude=0 show=""/>
<maplink zoom=0 latitude=0 longitude=0 show='йа криветко'/>
!! result
-<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" data-zoom="0" data-lat="0" data-lon="0"
data-overlays="["foo"]">0°0′0″N 0°0′0″E</a>
-<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
data-zoom="0" data-lat="0" data-lon="0"
data-overlays="["foo","bar"]">0°0′0″N 0°0′0″E</a>
-<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
data-zoom="0" data-lat="0" data-lon="0"
data-overlays="["foo"]">0°0′0″N 0°0′0″E</a>
-<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
data-zoom="0" data-lat="0" data-lon="0">0°0′0″N 0°0′0″E</a>
-<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
data-zoom="0" data-lat="0" data-lon="0">0°0′0″N 0°0′0″E</a>
+<p><a class="mw-kartographer-maplink" mw-data="interface"
data-style="osm-intl" href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0"
data-lon="0" data-overlays="["foo"]">0°0′0″N 0°0′0″E</a>
+<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0" data-lon="0"
data-overlays="["foo","bar"]">0°0′0″N 0°0′0″E</a>
+<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0" data-lon="0"
data-overlays="["foo"]">0°0′0″N 0°0′0″E</a>
+<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0" data-lon="0">0°0′0″N
0°0′0″E</a>
+<a class="mw-kartographer-maplink" mw-data="interface" data-style="osm-intl"
href="/wiki/Special:Map/0/0/0" data-zoom="0" data-lat="0" data-lon="0">0°0′0″N
0°0′0″E</a>
</p>
<div class="mw-kartographer-error"><maplink>: Attribute "show" has an
invalid value</div>
diff --git a/tests/phpunit/SpecialMapTest.php b/tests/phpunit/SpecialMapTest.php
new file mode 100644
index 0000000..4f2c79a
--- /dev/null
+++ b/tests/phpunit/SpecialMapTest.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Kartographer\Tests;
+
+use GeoData\Globe;
+use Kartographer\SpecialMap;
+use MediaWikiTestCase;
+use Title;
+
+/**
+ * @group Kartographer
+ */
+class SpecialMapTest extends MediaWikiTestCase {
+
+ /**
+ * @dataProvider provideParseSubpage
+ *
+ * @param string $par
+ * @param float $expectedLat
+ * @param float $expectedLon
+ */
+ public function testParseSubpage( $par, $expectedLat = null,
$expectedLon = null ) {
+ $res = SpecialMap::parseSubpage( $par );
+ if ( $expectedLat === null || $expectedLon === null ) {
+ $this->assertFalse( $res, 'Parsing is expected to fail'
);
+ } else {
+ list( , $lat, $lon ) = $res;
+ $this->assertSame( $expectedLat, $lat, 'Comparing
latitudes' );
+ $this->assertSame( $expectedLon, $lon, 'Comparing
longitudes' );
+ }
+ }
+
+ public function provideParseSubpage() {
+ $tests = [
+ [ '' ],
+ [ 'foo' ],
+ [ 'foo/bar/baz' ],
+ [ '123' ],
+ [ '1/2' ],
+ [ '1/2/3/4' ],
+ [ '1.0/2/3' ],
+ [ '-1/2/3' ],
+ [ '1/2/.3' ],
+ [ '1/2/3.45e+6' ],
+ [ '1/2,3/4,5' ],
+
+ [ '0/0/-0', 0.0, 0.0 ],
+ [ '12/-34.56/0.78', -34.56, 0.78 ],
+ [ '18/89.9/179.9', 89.9, 179.9 ],
+ [ '18/-89.9/-179.9', -89.9, -179.9 ],
+ [ '18/90/-180', 90.0, -180.0 ],
+ ];
+
+ if ( class_exists( Globe::class ) ) {
+ $tests = array_merge( $tests,
+ [
+ [ '0/90.000001/10' ],
+ [ '0/10/180.000000001' ],
+ ]
+ );
+ }
+
+ return $tests;
+ }
+
+ public function testLink() {
+ $this->setMwGlobals( 'wgArticlePath', '/wiki/$1' );
+ $title = SpecialMap::link( 12, -34.5, 6 );
+ $this->assertType( Title::class, $title );
+ $this->assertEquals( '/wiki/Special:Map/6/12/-34.5',
$title->getLocalURL() );
+ }
+}
--
To view, visit https://gerrit.wikimedia.org/r/306315
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I90fcd2fb0e458c9d5a805b441f5114157ea470a4
Gerrit-PatchSet: 9
Gerrit-Project: mediawiki/extensions/Kartographer
Gerrit-Branch: master
Gerrit-Owner: MaxSem <[email protected]>
Gerrit-Reviewer: JGirault <[email protected]>
Gerrit-Reviewer: MaxSem <[email protected]>
Gerrit-Reviewer: Yurik <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits