diff --git a/.gitreview b/.gitreview deleted file mode 100644 index a4240ea1c..000000000 --- a/.gitreview +++ /dev/null @@ -1,5 +0,0 @@ -[gerrit] -host=gerrit.wikimedia.org -port=29418 -project=mediawiki/extensions/Maps.git -defaultbranch=master diff --git a/build/travis/before_script.sh b/.travis.install.sh similarity index 92% rename from build/travis/before_script.sh rename to .travis.install.sh index 308438b4e..5c4a744a3 100644 --- a/build/travis/before_script.sh +++ b/.travis.install.sh @@ -29,7 +29,8 @@ cp -r $originalDirectory Maps cd Maps composer install --prefer-source -composer require 'phpunit/phpunit=3.7.*' --prefer-source + +[[ ! -z $SMW ]] && composer require "mediawiki/semantic-media-wiki=$SMW" --prefer-source cd ../.. diff --git a/.travis.yml b/.travis.yml index 63b599a69..217c92c5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,32 @@ language: php -env: - - THENEEDFORTHIS=FAIL +sudo: false matrix: include: - - env: DBTYPE=mysql; MW=master - php: 5.6 - - env: DBTYPE=mysql; MW=master + - env: DBTYPE=mysql; MW=1.27.3 php: 7 - - env: DBTYPE=sqlite; MW=1.21.0 - php: 5.3 - - env: DBTYPE=mysql; MW=1.23.0 - php: 5.5 - - env: DBTYPE=sqlite; MW=master; TYPE=coverage + - env: DBTYPE=mysql; MW=master; SMW=2.5.2 + php: 7.1 + - env: DBTYPE=sqlite; MW=1.28.2; SMW=2.1.3 php: 5.6 - exclude: - - env: THENEEDFORTHIS=FAIL + - env: DBTYPE=mysql; MW=1.27.3; SMW=2.4.6 + php: 5.6 + - env: DBTYPE=sqlite; MW=master; TYPE=coverage + php: 7.1 -install: travis_retry composer self-update +install: + - travis_retry composer self-update + - bash .travis.install.sh -before_script: bash ./build/travis/before_script.sh +script: ../phase3/tests/phpunit/phpunit.php -c ../phase3/extensions/Maps/phpunit.xml.dist -script: bash ./build/travis/script.sh +after_success: + - if [[ "$TYPE" != "coverage" ]]; then exit 0; fi + - ../phase3/tests/phpunit/phpunit.php -c ../phase3/extensions/Maps/phpunit.xml.dist --coverage-clover coverage.clover + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover -after_success: bash ./build/travis/after_success.sh +cache: + directories: + - $HOME/.composer/cache diff --git a/INSTALL.md b/INSTALL.md index 2101f3ad3..d8363da47 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,78 +2,124 @@ These are the installation and configuration instructions for the [Maps extension](README.md). -## Versions +**Table of contents** + +* [Download and installation](INSTALL.md#download-and-installation) +* [Configuration](INSTALL.md#configuration) +* [Platform compatibility and release status](INSTALL.md#platform-compatibility-and-release-status) + +## Download and installation + +Go to the root directory of your MediaWiki installation. + +If you have previously installed Composer skip to step 2. + +To install Composer, just download http://getcomposer.org/composer.phar into your +current directory. + + wget http://getcomposer.org/composer.phar + +#### Step 2 + +Now using Composer, install Maps + + php composer.phar require mediawiki/maps "*" + +#### Verify installation success + +As final step, you can verify Maps got installed by looking at the Special:Version page on your wiki +and verifying the Maps extension is listed. + +If you want to use the Semantic MediaWiki integration, you will also need to install Semantic MediaWiki. + +## Configuration + +At present, minimal configuration is needed to get Maps running. Configuration is done like in most +MediaWiki extensions, by placing some simple snippets of PHP code at the bottom of MediaWiki's +LocalSettings.php. + +As of June 2016, Google requires you to provide an API key when you where not already using their +maps API. This means that you will either need to configure this key, or use another of the +supported mapping services. + +### Required configuration for Google Maps + +$GLOBALS['egMapsGMaps3ApiKey'] = 'your-api-key'; + +### Not using Google Maps by default + +For OpenLayers: + +$GLOBALS['egMapsDefaultService'] = 'openlayers'; + +For Leaflet: + +$GLOBALS['egMapsDefaultService'] = 'leaflet'; + +You might also want to fully disable Google Maps by placing a copy of the `egMapsAvailableServices` +setting in LocalSettings, and removing the `googlemaps3` line. + +See the [Maps settings file](Maps_Settings.php) for all available configuration options. + +### Platform compatibility and release status + +The PHP and MediaWiki version ranges listed are those in which Maps is known to work. It might also +work with more recent versions of PHP and MediaWiki, though this is not guaranteed. Increases of +minimum requirements are indicated in bold. For a detailed list of changes, see the [release notes](RELEASE-NOTES.md). - - - + + + + - - - - + + + + + - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - + + + + + - - - - + + + + + - - - - - + + + + + +
StatusRelease dateGit branchPHPMediaWikiSemantic MediaWikiRelease status
Maps 3.6.xDevelopment versionFuturemasterMaps 4.4.x5.6 - 7.1+1.27 - 1.29+TBD - 2.5+In development
Maps 3.5.xMaps 4.3.x5.6 - 7.11.27 - 1.292.1 - 2.5 Stable release2016-04-013.5.0
Maps 3.4.1Obsolete release2016-01-303.4.1
Maps 3.4Obsolete release2015-07-253.4.0
Maps 3.3Obsolete release2015-06-293.3.0
Maps 3.2Obsolete release2014-09-123.2.0
Maps 3.1Obsolete release2014-06-303.1.0Maps 4.2.x5.5 - 7.11.23 - 1.292.1 - 2.5Legacy release
Maps 3.0.1Obsolete release2014-03-273.0.1Maps 4.1.x5.5 - 7.11.23 - 1.282.1 - 2.5Legacy release
Maps 2.0.xObsolete release2012-12-132.0.xMaps 4.0.x5.5 - 7.01.23 - 1.282.1 - 2.4Legacy release
Maps 1.0.5Obsolete release2011-11-301.0.5
Maps 3.8.x5.5 - 7.01.23 - 1.27Not applicableLegacy release
-### Platform compatibility +Older versions (no longer supported): @@ -84,44 +130,65 @@ These are the installation and configuration instructions for the [Maps extensio - - + + + + + + + + + + + + + + + + - + - - + + - + - + + + + + + + + - + - + - + - - + + @@ -134,60 +201,6 @@ These are the installation and configuration instructions for the [Maps extensio
Validator
3.5.x5.3.2 - 7.xMaps 3.7.x5.5 - 7.01.23 - 1.27RequiredHandled by Composer
Maps 3.6.x5.5 - 7.01.23 - 1.27RequiredHandled by Composer
Maps 3.5.x5.3.2 - 7.0 1.18 - 1.27 Required2.x (handled by Composer)Handled by Composer
3.4.x5.3.2 - 7.xMaps 3.4.x5.3.2 - 7.0 1.18 - 1.27 Required2.x (handled by Composer)Handled by Composer
Maps 3.3.x 5.3.2 - 5.6.x 1.18 - 1.25 Required2.x (handled by Composer)Handled by Composer
Maps 3.2.x5.3.2 - 5.6.x1.18 - 1.24RequiredHandled by Composer
Maps 3.1.x & 3.2.xMaps 3.1.x 5.3.2 - 5.6.x 1.18 - 1.24 Required2.x (handled by Composer)Handled by Composer
Maps 3.0.x 5.3.2 - 5.6.x 1.18 - 1.23 Required1.x (handled by Composer)Handled by Composer
Maps 2.0.x5.3.2 - 5.5.x1.18 - 1.235.3.2 - 5.5.x1.18 - 1.23 Not supported 0.5.1
-When installing Maps 2.x, see the installation instructions that come bundled with it. Also -make use of Validator 0.5.x. More recent versions of Validator will not work. - ### Database support All current versions of Maps have full support for all databases that can be used with MediaWiki. - -## Download and installation - -The recommended way to download and install Maps is with [Composer](http://getcomposer.org) using -[MediaWiki 1.22 built-in support for Composer](https://www.mediawiki.org/wiki/Composer). MediaWiki -versions prior to 1.22 can use Composer via the -[Extension Installer](https://github.com/JeroenDeDauw/ExtensionInstaller/blob/master/README.md) -extension. - -#### Step 1 - -If you have MediaWiki 1.22 or later, go to the root directory of your MediaWiki installation, -and go to step 2. You do not need to install any extensions to support composer. - -For MediaWiki 1.21.x and earlier you need to install the -[Extension Installer](https://github.com/JeroenDeDauw/ExtensionInstaller/blob/master/README.md) extension. - -Once you are done installing the Extension Installer, go to its directory so composer.phar -is installed in the right place. - - cd extensions/ExtensionInstaller - -#### Step 2 - -If you have previously installed Composer skip to step 3. - -To install Composer, just download http://getcomposer.org/composer.phar into your -current directory. - - wget http://getcomposer.org/composer.phar - -#### Step 3 - -Now using Composer, install Maps - - php composer.phar require mediawiki/maps "*" - -#### Verify installation success - -As final step, you can verify Maps got installed by looking at the Special:Version page on your wiki and verifying the -Maps extension is listed. - -#### Custom image layers support (experimental) - -For support of the experimental custom image layers feature you have to run the MediaWiki update script. - - php maintenance/update.php - -## Configuration - -See the [Maps settings file](Maps_Settings.php) for the available configuration options. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..12cd946c7 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,16 @@ +### Setup + +- MW version: +- DB (MySQL etc.): +- PHP version: +- Maps version: +- SMW version (if applicable): + +### Issue + +Detailed description of the issue and a [stack trace](https://www.semantic-mediawiki.org/wiki/Help:Identifying_bugs) if applicable: + +``` +``` + +Steps to reproduce the observation (recommendation is to use the [sandbox](http://sandbox.semantic-mediawiki.org)): diff --git a/Maps.hooks.php b/Maps.hooks.php index d64f2277c..aac97fe25 100644 --- a/Maps.hooks.php +++ b/Maps.hooks.php @@ -7,17 +7,8 @@ * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > - * @author Daniel Werner */ final class MapsHooks { - /** - * Helper flag indicating whether the page has been purged. - * @var bool - * - * TODO: Figure out a better way to do this, not requiring this flag and make sure it works with - * later MW versions (purging mechanism got changed somewhat around 1.18). - */ - static $purgedBeforeStore = false; /** * Adds a link to Admin Links page. @@ -44,30 +35,14 @@ public static function addToAdminLinks( ALTree $admin_links_tree ) { return true; } - /** - * Intercept pages in the Layer namespace to handle them correctly. - * - * @param $title: Title - * @param $article: Article or null - * - * @return boolean - */ - public static function onArticleFromTitle( Title &$title, /* Article */ &$article ) { - if ( $title->getNamespace() == Maps_NS_LAYER ) { - $article = new MapsLayerPage( $title ); - } - - return true; - } - /** * Adds global JavaScript variables. * * @since 1.0 - * @see http://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript - * @param array &$vars Variables to be added into the output - * @param OutputPage $outputPage OutputPage instance calling the hook - * @return boolean true in all cases + * @see http://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript + * @param array &$vars Variables to be added into the output + * @param OutputPage $outputPage OutputPage instance calling the hook + * @return boolean true in all cases */ public static function onMakeGlobalVariablesScript( array &$vars, OutputPage $outputPage ) { global $egMapsGlobalJSVars; @@ -79,140 +54,4 @@ public static function onMakeGlobalVariablesScript( array &$vars, OutputPage $ou return true; } - - /** - * @since 0.7 - * - * @param array $list - * - * @return boolean - */ - public static function onCanonicalNamespaces( array &$list ) { - $list[Maps_NS_LAYER] = 'Layer'; - $list[Maps_NS_LAYER_TALK] = 'Layer_talk'; - return true; - } - - /** - * This will setup database tables for layer functionality. - * - * @since 3.0 - * - * @param DatabaseUpdater $updater - * - * @return true - */ - public static function onLoadExtensionSchemaUpdates( DatabaseUpdater $updater ) { - switch( $GLOBALS['wgDBtype'] ) { - case 'mysql': - case 'sqlite': - $updater->addExtensionTable( 'maps_layers', __DIR__ . '/schema/MapsLayers.sql' ); - break; - case 'postgres': - $updater->addExtensionTable( 'maps_layers', __DIR__ . '/schema/MapsLayers-postgres.sql' ); - break; - } - - return true; - } - - /** - * Make sure layer data will be stored into database when purging the page - * - * @since 3.0 - * - * @param $article WikiPage|Article (depending on MW version, WikiPage in 1.18+) - * @return type - */ - public static function onArticlePurge( WikiPage $article ) { - self::$purgedBeforeStore = true; - return true; - } - - /** - * At the end of article parsing, in case of layer page, save layers to database - * - * @since 3.0 - * - * @param Parser &$parser - * @param string &$text - * - * @return true - */ - public static function onParserAfterTidy( Parser $parser, &$text ) { - - $title = $parser->getTitle(); - - if( $title === null - || self::$purgedBeforeStore !== true - ) { - // just preprocessing some stuff or no purge - return true; - } - - self::processLayersStoreCandidate( $parser->getOutput(), $title ); - - // Set helper to false immediately so we won't run into job-processing weirdness: - self::$purgedBeforeStore = false; - - return true; - } - - /** - * After article was edited and parsed, in case of layer page, save layers to database - * - * @since 3.0 - * - * @param LinksUpdate &$linksUpdate - * - * @return true - */ - public static function onLinksUpdateConstructed( LinksUpdate $linksUpdate ) { - $title = $linksUpdate->getTitle(); - - self::processLayersStoreCandidate( $linksUpdate->mParserOutput, $title ); - - return true; - } - - /** - * Checks whether the parser output has some layer data which should be stored of the - * given title and performs the task. - * - * @since 3.0 - * - * @param ParserOutput $parserOutput - * @param Title $title - */ - protected static function processLayersStoreCandidate( ParserOutput $parserOutput, Title $title ) { - - // if site which is being parsed is in maps namespace: - if( $title->getNamespace() === Maps_NS_LAYER ) { - - if( ! isset( $parserOutput->mExtMapsLayers ) ) { - $parserOutput->mExtMapsLayers = new MapsLayerGroup(); - } - - // get MapsLayerGroup object with layers to be stored: - $mapsForStore = $parserOutput->mExtMapsLayers; - - // store layers in database (also deletes previous definitions still in db): - MapsLayers::storeLayers( $mapsForStore, $title ); - } - } - - /** - * If a new parser process is getting started, clear collected layer data of the - * previous one. - * - * @since 3.0 - * - * @param Parser $parser - * - * @return true - */ - public static function onParserClearState( Parser $parser ) { - $parser->getOutput()->mExtMapsLayers = null; - return true; - } } diff --git a/Maps.i18n.alias.php b/Maps.i18n.alias.php index 3375ac8e2..0c89dec3c 100644 --- a/Maps.i18n.alias.php +++ b/Maps.i18n.alias.php @@ -1,129 +1,129 @@ array( 'MapEditor' ), -); +$specialPageAliases['en'] = [ + 'MapEditor' => [ 'MapEditor' ], +]; /** Arabic (العربية) */ -$specialPageAliases['ar'] = array( - 'MapEditor' => array( 'محرر_الخريطة' ), -); +$specialPageAliases['ar'] = [ + 'MapEditor' => [ 'محرر_الخريطة' ], +]; /** Egyptian Arabic (مصرى) */ -$specialPageAliases['arz'] = array( - 'MapEditor' => array( 'محرر_الخريطه' ), -); +$specialPageAliases['arz'] = [ + 'MapEditor' => [ 'محرر_الخريطه' ], +]; /** Assamese (অসমীয়া) */ -$specialPageAliases['as'] = array( - 'MapEditor' => array( 'মানচিত্ৰ_সম্পাদক' ), -); +$specialPageAliases['as'] = [ + 'MapEditor' => [ 'মানচিত্ৰ_সম্পাদক' ], +]; /** Western Balochi (بلوچی رخشانی) */ -$specialPageAliases['bgn'] = array( - 'MapEditor' => array( 'نخشه_ئی_ایڈیٹگر' ), -); +$specialPageAliases['bgn'] = [ + 'MapEditor' => [ 'نخشه_ئی_ایڈیٹگر' ], +]; /** German (Deutsch) */ -$specialPageAliases['de'] = array( - 'MapEditor' => array( 'Karteneditor' ), -); +$specialPageAliases['de'] = [ + 'MapEditor' => [ 'Karteneditor' ], +]; /** Zazaki (Zazaki) */ -$specialPageAliases['diq'] = array( - 'MapEditor' => array( 'VırneréXerita' ), -); +$specialPageAliases['diq'] = [ + 'MapEditor' => [ 'VırneréXerita' ], +]; /** Greek (Ελληνικά) */ -$specialPageAliases['el'] = array( - 'MapEditor' => array( 'ΕπεξεργαστήςΧαρτών' ), -); +$specialPageAliases['el'] = [ + 'MapEditor' => [ 'ΕπεξεργαστήςΧαρτών' ], +]; /** Persian (فارسی) */ -$specialPageAliases['fa'] = array( - 'MapEditor' => array( 'ویرایشگر_نقشه' ), -); +$specialPageAliases['fa'] = [ + 'MapEditor' => [ 'ویرایشگر_نقشه' ], +]; /** Galician (galego) */ -$specialPageAliases['gl'] = array( - 'MapEditor' => array( 'Editor_do_mapa' ), -); +$specialPageAliases['gl'] = [ + 'MapEditor' => [ 'Editor_do_mapa' ], +]; /** Hebrew (עברית) */ -$specialPageAliases['he'] = array( - 'MapEditor' => array( 'עורך_מפה' ), -); +$specialPageAliases['he'] = [ + 'MapEditor' => [ 'עורך_מפה' ], +]; /** Upper Sorbian (hornjoserbsce) */ -$specialPageAliases['hsb'] = array( - 'MapEditor' => array( 'Kartowy_editor' ), -); +$specialPageAliases['hsb'] = [ + 'MapEditor' => [ 'Kartowy_editor' ], +]; /** Italian (italiano) */ -$specialPageAliases['it'] = array( - 'MapEditor' => array( 'EditorMappa' ), -); +$specialPageAliases['it'] = [ + 'MapEditor' => [ 'EditorMappa' ], +]; /** Japanese (日本語) */ -$specialPageAliases['ja'] = array( - 'MapEditor' => array( '地図編集', 'マップ編集' ), -); +$specialPageAliases['ja'] = [ + 'MapEditor' => [ '地図編集', 'マップ編集' ], +]; /** Korean (한국어) */ -$specialPageAliases['ko'] = array( - 'MapEditor' => array( '지도편집기' ), -); +$specialPageAliases['ko'] = [ + 'MapEditor' => [ '지도편집기' ], +]; /** Luxembourgish (Lëtzebuergesch) */ -$specialPageAliases['lb'] = array( - 'MapEditor' => array( 'Kaartenediteur' ), -); +$specialPageAliases['lb'] = [ + 'MapEditor' => [ 'Kaartenediteur' ], +]; /** Macedonian (македонски) */ -$specialPageAliases['mk'] = array( - 'MapEditor' => array( 'УредникНаКарти' ), -); +$specialPageAliases['mk'] = [ + 'MapEditor' => [ 'УредникНаКарти' ], +]; /** Malayalam (മലയാളം) */ -$specialPageAliases['ml'] = array( - 'MapEditor' => array( 'ഭൂപടതിരുത്തലുപാധി' ), -); +$specialPageAliases['ml'] = [ + 'MapEditor' => [ 'ഭൂപടതിരുത്തലുപാധി' ], +]; /** Dutch (Nederlands) */ -$specialPageAliases['nl'] = array( - 'MapEditor' => array( 'Kaarteditor' ), -); +$specialPageAliases['nl'] = [ + 'MapEditor' => [ 'Kaarteditor' ], +]; /** Sicilian (sicilianu) */ -$specialPageAliases['scn'] = array( - 'MapEditor' => array( 'EditorMappa' ), -); +$specialPageAliases['scn'] = [ + 'MapEditor' => [ 'EditorMappa' ], +]; /** Turkish (Türkçe) */ -$specialPageAliases['tr'] = array( - 'MapEditor' => array( 'HaritaDüzenleyici', 'HaritaEditörü' ), -); +$specialPageAliases['tr'] = [ + 'MapEditor' => [ 'HaritaDüzenleyici', 'HaritaEditörü' ], +]; /** Vietnamese (Tiếng Việt) */ -$specialPageAliases['vi'] = array( - 'MapEditor' => array( 'Sửa_đổi_bản_đồ' ), -); +$specialPageAliases['vi'] = [ + 'MapEditor' => [ 'Sửa_đổi_bản_đồ' ], +]; /** Simplified Chinese (中文(简体)‎) */ -$specialPageAliases['zh-hans'] = array( - 'MapEditor' => array( '地图编辑器' ), -); +$specialPageAliases['zh-hans'] = [ + 'MapEditor' => [ '地图编辑器' ], +]; /** Traditional Chinese (中文(繁體)‎) */ -$specialPageAliases['zh-hant'] = array( - 'MapEditor' => array( '地圖編輯器' ), -); \ No newline at end of file +$specialPageAliases['zh-hant'] = [ + 'MapEditor' => [ '地圖編輯器' ], +]; \ No newline at end of file diff --git a/Maps.i18n.magic.php b/Maps.i18n.magic.php index f572ac17b..b7065cee7 100644 --- a/Maps.i18n.magic.php +++ b/Maps.i18n.magic.php @@ -4,384 +4,384 @@ * Internationalisation file for Maps extension. */ -$magicWords = array(); +$magicWords = []; /** English (English) */ -$magicWords['en'] = array( - 'display_map' => array( 0, 'display_map' ), - 'display_point' => array( 0, 'display_point' ), - 'display_points' => array( 0, 'display_points' ), - 'display_line' => array( 0, 'display_line' ), - 'geocode' => array( 0, 'geocode' ), - 'geodistance' => array( 0, 'geodistance' ), - 'finddestination' => array( 0, 'finddestination' ), - 'coordinates' => array( 0, 'coordinates' ), - 'distance' => array( 0, 'distance' ), - 'mapsdoc' => array( 0, 'mapsdoc' ), -); +$magicWords['en'] = [ + 'display_map' => [ 0, 'display_map' ], + 'display_point' => [ 0, 'display_point' ], + 'display_points' => [ 0, 'display_points' ], + 'display_line' => [ 0, 'display_line' ], + 'geocode' => [ 0, 'geocode' ], + 'geodistance' => [ 0, 'geodistance' ], + 'finddestination' => [ 0, 'finddestination' ], + 'coordinates' => [ 0, 'coordinates' ], + 'distance' => [ 0, 'distance' ], + 'mapsdoc' => [ 0, 'mapsdoc' ], +]; /** Afrikaans (Afrikaans) */ -$magicWords['af'] = array( - 'geocode' => array( 0, 'geokode', 'geocode' ), - 'coordinates' => array( 0, 'koördinate', 'coordinates' ), -); +$magicWords['af'] = [ + 'geocode' => [ 0, 'geokode', 'geocode' ], + 'coordinates' => [ 0, 'koördinate', 'coordinates' ], +]; /** Arabic (العربية) */ -$magicWords['ar'] = array( - 'display_map' => array( 0, 'عرض_الخريطة' ), - 'display_point' => array( 0, 'نقطة_العرض' ), - 'display_points' => array( 0, 'نقاط_العرض' ), - 'display_line' => array( 0, 'خط_العرض' ), - 'geocode' => array( 0, 'كود_جغرافي' ), - 'geodistance' => array( 0, 'مسافة_جغرافية' ), - 'finddestination' => array( 0, 'إيجاد_الوجهة' ), - 'coordinates' => array( 0, 'إحداثيات' ), - 'distance' => array( 0, 'مسافة' ), - 'mapsdoc' => array( 0, 'توثيق_الخرائط' ), -); +$magicWords['ar'] = [ + 'display_map' => [ 0, 'عرض_الخريطة' ], + 'display_point' => [ 0, 'نقطة_العرض' ], + 'display_points' => [ 0, 'نقاط_العرض' ], + 'display_line' => [ 0, 'خط_العرض' ], + 'geocode' => [ 0, 'كود_جغرافي' ], + 'geodistance' => [ 0, 'مسافة_جغرافية' ], + 'finddestination' => [ 0, 'إيجاد_الوجهة' ], + 'coordinates' => [ 0, 'إحداثيات' ], + 'distance' => [ 0, 'مسافة' ], + 'mapsdoc' => [ 0, 'توثيق_الخرائط' ], +]; /** Egyptian Arabic (مصرى) */ -$magicWords['arz'] = array( - 'display_map' => array( 0, 'عرض_الخريطه', 'عرض_الخريطة' ), - 'display_point' => array( 0, 'نقطه_العرض' ), - 'display_points' => array( 0, 'نقط_العرض' ), - 'display_line' => array( 0, 'خط_العرض' ), - 'geocode' => array( 0, 'كود_جغرافي' ), - 'geodistance' => array( 0, 'مسافه_جغرافيه', 'مسافة_جغرافية' ), - 'finddestination' => array( 0, 'إيجاد_الوجهه', 'إيجاد_الوجهة' ), - 'coordinates' => array( 0, 'إحداثيات' ), - 'distance' => array( 0, 'مسافه' ), - 'mapsdoc' => array( 0, 'توثيق_الخرايط' ), -); +$magicWords['arz'] = [ + 'display_map' => [ 0, 'عرض_الخريطه', 'عرض_الخريطة' ], + 'display_point' => [ 0, 'نقطه_العرض' ], + 'display_points' => [ 0, 'نقط_العرض' ], + 'display_line' => [ 0, 'خط_العرض' ], + 'geocode' => [ 0, 'كود_جغرافي' ], + 'geodistance' => [ 0, 'مسافه_جغرافيه', 'مسافة_جغرافية' ], + 'finddestination' => [ 0, 'إيجاد_الوجهه', 'إيجاد_الوجهة' ], + 'coordinates' => [ 0, 'إحداثيات' ], + 'distance' => [ 0, 'مسافه' ], + 'mapsdoc' => [ 0, 'توثيق_الخرايط' ], +]; /** Assamese (অসমীয়া) */ -$magicWords['as'] = array( - 'display_point' => array( 0, 'মানচিত্ৰ_প্ৰদৰ্শন' ), -); +$magicWords['as'] = [ + 'display_point' => [ 0, 'মানচিত্ৰ_প্ৰদৰ্শন' ], +]; /** Breton (brezhoneg) */ -$magicWords['br'] = array( - 'coordinates' => array( 0, 'daveennoù' ), - 'distance' => array( 0, 'hed' ), -); +$magicWords['br'] = [ + 'coordinates' => [ 0, 'daveennoù' ], + 'distance' => [ 0, 'hed' ], +]; /** Chechen (нохчийн) */ -$magicWords['ce'] = array( - 'geocode' => array( 0, 'геагишар', 'геокод' ), -); +$magicWords['ce'] = [ + 'geocode' => [ 0, 'геагишар', 'геокод' ], +]; /** German (Deutsch) */ -$magicWords['de'] = array( - 'display_map' => array( 0, 'zeige_karte' ), - 'display_point' => array( 0, 'zeige_punkt' ), - 'display_points' => array( 0, 'zeige_punkte' ), - 'display_line' => array( 0, 'zeige_linie' ), - 'geocode' => array( 0, 'geokodiere' ), - 'geodistance' => array( 0, 'geoentfernung' ), - 'finddestination' => array( 0, 'finde_ziel' ), - 'coordinates' => array( 0, 'koordinaten' ), - 'distance' => array( 0, 'entfernung' ), - 'mapsdoc' => array( 0, 'mapsdok' ), -); +$magicWords['de'] = [ + 'display_map' => [ 0, 'zeige_karte' ], + 'display_point' => [ 0, 'zeige_punkt' ], + 'display_points' => [ 0, 'zeige_punkte' ], + 'display_line' => [ 0, 'zeige_linie' ], + 'geocode' => [ 0, 'geokodiere' ], + 'geodistance' => [ 0, 'geoentfernung' ], + 'finddestination' => [ 0, 'finde_ziel' ], + 'coordinates' => [ 0, 'koordinaten' ], + 'distance' => [ 0, 'entfernung' ], + 'mapsdoc' => [ 0, 'mapsdok' ], +]; /** Zazaki (Zazaki) */ -$magicWords['diq'] = array( - 'display_map' => array( 0, 'aseniya_ğerita' ), - 'display_point' => array( 0, 'aseniya_dewti' ), - 'display_points' => array( 0, 'aseniya_dawıtan' ), - 'display_line' => array( 0, 'aseniya_ğeter' ), - 'geocode' => array( 0, 'herunkodi' ), - 'geodistance' => array( 0, 'heruna_mesafi' ), - 'finddestination' => array( 0, 'menzilvinayış' ), - 'coordinates' => array( 0, 'koordinati' ), - 'distance' => array( 0, 'mesafe' ), - 'mapsdoc' => array( 0, 'dokumanéğerita' ), -); +$magicWords['diq'] = [ + 'display_map' => [ 0, 'aseniya_ğerita' ], + 'display_point' => [ 0, 'aseniya_dewti' ], + 'display_points' => [ 0, 'aseniya_dawıtan' ], + 'display_line' => [ 0, 'aseniya_ğeter' ], + 'geocode' => [ 0, 'herunkodi' ], + 'geodistance' => [ 0, 'heruna_mesafi' ], + 'finddestination' => [ 0, 'menzilvinayış' ], + 'coordinates' => [ 0, 'koordinati' ], + 'distance' => [ 0, 'mesafe' ], + 'mapsdoc' => [ 0, 'dokumanéğerita' ], +]; /** Esperanto (Esperanto) */ -$magicWords['eo'] = array( - 'coordinates' => array( 0, 'koordinatoj' ), - 'distance' => array( 0, 'distanco' ), -); +$magicWords['eo'] = [ + 'coordinates' => [ 0, 'koordinatoj' ], + 'distance' => [ 0, 'distanco' ], +]; /** Spanish (español) */ -$magicWords['es'] = array( - 'display_point' => array( 0, 'mostrar_punto' ), - 'geocode' => array( 0, 'geocodificar' ), - 'coordinates' => array( 0, 'coordenadas' ), - 'distance' => array( 0, 'distancia' ), -); +$magicWords['es'] = [ + 'display_point' => [ 0, 'mostrar_punto' ], + 'geocode' => [ 0, 'geocodificar' ], + 'coordinates' => [ 0, 'coordenadas' ], + 'distance' => [ 0, 'distancia' ], +]; /** French (français) */ -$magicWords['fr'] = array( - 'display_map' => array( 0, 'afficher_carte' ), - 'display_point' => array( 0, 'afficher_point' ), - 'display_points' => array( 0, 'afficher_points' ), - 'display_line' => array( 0, 'afficher_ligne' ), - 'geocode' => array( 0, 'codegéo' ), - 'geodistance' => array( 0, 'distancegéo' ), - 'finddestination' => array( 0, 'trouverdestination' ), - 'coordinates' => array( 0, 'coordonnées' ), - 'distance' => array( 0, 'distance' ), - 'mapsdoc' => array( 0, 'doccartes' ), -); +$magicWords['fr'] = [ + 'display_map' => [ 0, 'afficher_carte' ], + 'display_point' => [ 0, 'afficher_point' ], + 'display_points' => [ 0, 'afficher_points' ], + 'display_line' => [ 0, 'afficher_ligne' ], + 'geocode' => [ 0, 'codegéo' ], + 'geodistance' => [ 0, 'distancegéo' ], + 'finddestination' => [ 0, 'trouverdestination' ], + 'coordinates' => [ 0, 'coordonnées' ], + 'distance' => [ 0, 'distance' ], + 'mapsdoc' => [ 0, 'doccartes' ], +]; /** Hebrew (עברית) */ -$magicWords['he'] = array( - 'distance' => array( 0, 'מרחק' ), -); +$magicWords['he'] = [ + 'distance' => [ 0, 'מרחק' ], +]; /** Indonesian (Bahasa Indonesia) */ -$magicWords['id'] = array( - 'finddestination' => array( 0, 'petunjukarah' ), - 'coordinates' => array( 0, 'koordinat' ), - 'distance' => array( 0, 'jarak' ), -); +$magicWords['id'] = [ + 'finddestination' => [ 0, 'petunjukarah' ], + 'coordinates' => [ 0, 'koordinat' ], + 'distance' => [ 0, 'jarak' ], +]; /** Igbo (Igbo) */ -$magicWords['ig'] = array( - 'display_map' => array( 0, 'zí_otúzọr', 'display_map' ), -); +$magicWords['ig'] = [ + 'display_map' => [ 0, 'zí_otúzọr', 'display_map' ], +]; /** Italian (italiano) */ -$magicWords['it'] = array( - 'display_map' => array( 0, 'mostra_mappa' ), - 'display_point' => array( 0, 'mostra_punto' ), - 'display_points' => array( 0, 'mostra_punti' ), - 'geocode' => array( 0, 'geocodice' ), - 'geodistance' => array( 0, 'geodistanza' ), - 'finddestination' => array( 0, 'trovadestinazione' ), - 'coordinates' => array( 0, 'coordinate' ), - 'distance' => array( 0, 'distanza' ), - 'mapsdoc' => array( 0, 'docmappe' ), -); +$magicWords['it'] = [ + 'display_map' => [ 0, 'mostra_mappa' ], + 'display_point' => [ 0, 'mostra_punto' ], + 'display_points' => [ 0, 'mostra_punti' ], + 'geocode' => [ 0, 'geocodice' ], + 'geodistance' => [ 0, 'geodistanza' ], + 'finddestination' => [ 0, 'trovadestinazione' ], + 'coordinates' => [ 0, 'coordinate' ], + 'distance' => [ 0, 'distanza' ], + 'mapsdoc' => [ 0, 'docmappe' ], +]; /** Japanese (日本語) */ -$magicWords['ja'] = array( - 'display_map' => array( 0, '地図表示' ), - 'display_point' => array( 0, '地図点' ), - 'geocode' => array( 0, '地理的コード' ), - 'geodistance' => array( 0, '地理的距離' ), - 'finddestination' => array( 0, '目的地検索' ), - 'coordinates' => array( 0, '座標' ), - 'distance' => array( 0, '距離' ), -); +$magicWords['ja'] = [ + 'display_map' => [ 0, '地図表示' ], + 'display_point' => [ 0, '地図点' ], + 'geocode' => [ 0, '地理的コード' ], + 'geodistance' => [ 0, '地理的距離' ], + 'finddestination' => [ 0, '目的地検索' ], + 'coordinates' => [ 0, '座標' ], + 'distance' => [ 0, '距離' ], +]; /** Georgian (ქართული) */ -$magicWords['ka'] = array( - 'coordinates' => array( 0, 'კოორდინატები' ), - 'distance' => array( 0, 'მანძილი' ), -); +$magicWords['ka'] = [ + 'coordinates' => [ 0, 'კოორდინატები' ], + 'distance' => [ 0, 'მანძილი' ], +]; /** Korean (한국어) */ -$magicWords['ko'] = array( - 'display_map' => array( 0, '지도_표시' ), - 'display_point' => array( 0, '포인트_표시' ), - 'display_points' => array( 0, '포인트목록_표시' ), - 'display_line' => array( 0, '선_표시' ), - 'geocode' => array( 0, '지리코드' ), - 'geodistance' => array( 0, '지리거리' ), - 'finddestination' => array( 0, '목적지찾기' ), - 'coordinates' => array( 0, '좌표' ), - 'distance' => array( 0, '거리' ), - 'mapsdoc' => array( 0, '지도문서' ), -); +$magicWords['ko'] = [ + 'display_map' => [ 0, '지도_표시' ], + 'display_point' => [ 0, '포인트_표시' ], + 'display_points' => [ 0, '포인트목록_표시' ], + 'display_line' => [ 0, '선_표시' ], + 'geocode' => [ 0, '지리코드' ], + 'geodistance' => [ 0, '지리거리' ], + 'finddestination' => [ 0, '목적지찾기' ], + 'coordinates' => [ 0, '좌표' ], + 'distance' => [ 0, '거리' ], + 'mapsdoc' => [ 0, '지도문서' ], +]; /** Kurdish (Latin script) (Kurdî (latînî)‎) */ -$magicWords['ku-latn'] = array( - 'coordinates' => array( 0, 'koordînat' ), -); +$magicWords['ku-latn'] = [ + 'coordinates' => [ 0, 'koordînat' ], +]; /** Ladino (Ladino) */ -$magicWords['lad'] = array( - 'distance' => array( 0, 'distancia', 'distance' ), -); +$magicWords['lad'] = [ + 'distance' => [ 0, 'distancia', 'distance' ], +]; /** Luxembourgish (Lëtzebuergesch) */ -$magicWords['lb'] = array( - 'coordinates' => array( 0, 'Koordinaten' ), - 'distance' => array( 0, 'Distanz' ), -); +$magicWords['lb'] = [ + 'coordinates' => [ 0, 'Koordinaten' ], + 'distance' => [ 0, 'Distanz' ], +]; /** Minangkabau (Baso Minangkabau) */ -$magicWords['min'] = array( - 'finddestination' => array( 0, 'petunjukarah' ), - 'coordinates' => array( 0, 'koordinat' ), - 'distance' => array( 0, 'jarak' ), -); +$magicWords['min'] = [ + 'finddestination' => [ 0, 'petunjukarah' ], + 'coordinates' => [ 0, 'koordinat' ], + 'distance' => [ 0, 'jarak' ], +]; /** Macedonian (македонски) */ -$magicWords['mk'] = array( - 'display_map' => array( 0, 'прикажи_карта' ), - 'display_point' => array( 0, 'прикажи_точка' ), - 'display_points' => array( 0, 'прикажи_точки' ), - 'display_line' => array( 0, 'прикажи_линија' ), - 'geocode' => array( 0, 'геокод' ), - 'geodistance' => array( 0, 'георастојание' ), - 'finddestination' => array( 0, 'најдиодредница' ), - 'coordinates' => array( 0, 'координати' ), - 'distance' => array( 0, 'растојание' ), - 'mapsdoc' => array( 0, 'докумкарти' ), -); +$magicWords['mk'] = [ + 'display_map' => [ 0, 'прикажи_карта' ], + 'display_point' => [ 0, 'прикажи_точка' ], + 'display_points' => [ 0, 'прикажи_точки' ], + 'display_line' => [ 0, 'прикажи_линија' ], + 'geocode' => [ 0, 'геокод' ], + 'geodistance' => [ 0, 'георастојание' ], + 'finddestination' => [ 0, 'најдиодредница' ], + 'coordinates' => [ 0, 'координати' ], + 'distance' => [ 0, 'растојание' ], + 'mapsdoc' => [ 0, 'докумкарти' ], +]; /** Malayalam (മലയാളം) */ -$magicWords['ml'] = array( - 'display_map' => array( 0, 'ഭൂപടം_പ്രദർശിപ്പിക്കുക' ), - 'display_point' => array( 0, 'ബിന്ദു_പ്രദർശിപ്പിക്കുക' ), - 'display_points' => array( 0, 'ബിന്ദുക്കൾ_പ്രദർശിപ്പിക്കുക' ), - 'display_line' => array( 0, 'രേഖ_പ്രദർശിപ്പിക്കുക' ), - 'geocode' => array( 0, 'ജിയോകോഡ്' ), - 'geodistance' => array( 0, 'ഭൗമദൂരം' ), - 'finddestination' => array( 0, 'ലക്ഷ്യംതിരയുക' ), - 'coordinates' => array( 0, 'നിർദ്ദേശാങ്കങ്ങൾ' ), - 'distance' => array( 0, 'ദൂരം' ), -); +$magicWords['ml'] = [ + 'display_map' => [ 0, 'ഭൂപടം_പ്രദർശിപ്പിക്കുക' ], + 'display_point' => [ 0, 'ബിന്ദു_പ്രദർശിപ്പിക്കുക' ], + 'display_points' => [ 0, 'ബിന്ദുക്കൾ_പ്രദർശിപ്പിക്കുക' ], + 'display_line' => [ 0, 'രേഖ_പ്രദർശിപ്പിക്കുക' ], + 'geocode' => [ 0, 'ജിയോകോഡ്' ], + 'geodistance' => [ 0, 'ഭൗമദൂരം' ], + 'finddestination' => [ 0, 'ലക്ഷ്യംതിരയുക' ], + 'coordinates' => [ 0, 'നിർദ്ദേശാങ്കങ്ങൾ' ], + 'distance' => [ 0, 'ദൂരം' ], +]; /** Marathi (मराठी) */ -$magicWords['mr'] = array( - 'distance' => array( 0, 'अंतर' ), -); +$magicWords['mr'] = [ + 'distance' => [ 0, 'अंतर' ], +]; /** Low Saxon (Netherlands) (Nedersaksies) */ -$magicWords['nds-nl'] = array( - 'display_map' => array( 0, 'kaorte_laoten_zien' ), - 'geocode' => array( 0, 'geokoderen' ), - 'geodistance' => array( 0, 'geo-aofstaand' ), - 'finddestination' => array( 0, 'bestemmingzeuken' ), - 'coordinates' => array( 0, 'koordinaoten' ), - 'distance' => array( 0, 'aofstaand' ), -); +$magicWords['nds-nl'] = [ + 'display_map' => [ 0, 'kaorte_laoten_zien' ], + 'geocode' => [ 0, 'geokoderen' ], + 'geodistance' => [ 0, 'geo-aofstaand' ], + 'finddestination' => [ 0, 'bestemmingzeuken' ], + 'coordinates' => [ 0, 'koordinaoten' ], + 'distance' => [ 0, 'aofstaand' ], +]; /** Dutch (Nederlands) */ -$magicWords['nl'] = array( - 'display_map' => array( 0, 'kaart_weergeven' ), - 'display_point' => array( 0, 'punt_weergeven' ), - 'display_points' => array( 0, 'punten_weergeven' ), - 'display_line' => array( 0, 'lijn_weergeven' ), - 'geocode' => array( 0, 'geocoderen' ), - 'geodistance' => array( 0, 'geoafstand' ), - 'finddestination' => array( 0, 'bestemmingzoeken' ), - 'coordinates' => array( 0, 'coordinaten' ), - 'distance' => array( 0, 'afstand' ), - 'mapsdoc' => array( 0, 'kaartdoc' ), -); +$magicWords['nl'] = [ + 'display_map' => [ 0, 'kaart_weergeven' ], + 'display_point' => [ 0, 'punt_weergeven' ], + 'display_points' => [ 0, 'punten_weergeven' ], + 'display_line' => [ 0, 'lijn_weergeven' ], + 'geocode' => [ 0, 'geocoderen' ], + 'geodistance' => [ 0, 'geoafstand' ], + 'finddestination' => [ 0, 'bestemmingzoeken' ], + 'coordinates' => [ 0, 'coordinaten' ], + 'distance' => [ 0, 'afstand' ], + 'mapsdoc' => [ 0, 'kaartdoc' ], +]; /** Polish (polski) */ -$magicWords['pl'] = array( - 'display_map' => array( 0, 'wyświetl_mapę' ), - 'coordinates' => array( 0, 'współrzędne' ), - 'distance' => array( 0, 'odległość' ), -); +$magicWords['pl'] = [ + 'display_map' => [ 0, 'wyświetl_mapę' ], + 'coordinates' => [ 0, 'współrzędne' ], + 'distance' => [ 0, 'odległość' ], +]; /** Pashto (پښتو) */ -$magicWords['ps'] = array( - 'distance' => array( 0, 'واټن', 'distance' ), -); +$magicWords['ps'] = [ + 'distance' => [ 0, 'واټن', 'distance' ], +]; /** Portuguese (português) */ -$magicWords['pt'] = array( - 'display_map' => array( 0, 'mostrar_mapa' ), - 'display_point' => array( 0, 'mostrar_ponto' ), - 'display_points' => array( 0, 'mostrar_pontos' ), - 'geocode' => array( 0, 'geocódigo' ), - 'geodistance' => array( 0, 'geodistância' ), - 'finddestination' => array( 0, 'encontrardestino' ), - 'coordinates' => array( 0, 'coordenadas' ), - 'distance' => array( 0, 'distância' ), -); +$magicWords['pt'] = [ + 'display_map' => [ 0, 'mostrar_mapa' ], + 'display_point' => [ 0, 'mostrar_ponto' ], + 'display_points' => [ 0, 'mostrar_pontos' ], + 'geocode' => [ 0, 'geocódigo' ], + 'geodistance' => [ 0, 'geodistância' ], + 'finddestination' => [ 0, 'encontrardestino' ], + 'coordinates' => [ 0, 'coordenadas' ], + 'distance' => [ 0, 'distância' ], +]; /** Russian (русский) */ -$magicWords['ru'] = array( - 'display_map' => array( 0, 'показать_карту' ), - 'display_point' => array( 0, 'показать_точку' ), - 'display_points' => array( 0, 'показать_точки' ), - 'display_line' => array( 0, 'показать_линию' ), - 'geocode' => array( 0, 'геокод' ), - 'geodistance' => array( 0, 'георасстояние' ), - 'finddestination' => array( 0, 'найти_местоположение' ), - 'coordinates' => array( 0, 'координаты' ), - 'distance' => array( 0, 'расстояние' ), -); +$magicWords['ru'] = [ + 'display_map' => [ 0, 'показать_карту' ], + 'display_point' => [ 0, 'показать_точку' ], + 'display_points' => [ 0, 'показать_точки' ], + 'display_line' => [ 0, 'показать_линию' ], + 'geocode' => [ 0, 'геокод' ], + 'geodistance' => [ 0, 'георасстояние' ], + 'finddestination' => [ 0, 'найти_местоположение' ], + 'coordinates' => [ 0, 'координаты' ], + 'distance' => [ 0, 'расстояние' ], +]; /** Sinhala (සිංහල) */ -$magicWords['si'] = array( - 'finddestination' => array( 0, 'ගමනාන්තය_සෙවීම', 'finddestination' ), - 'coordinates' => array( 0, 'ඛණ්ඩාංක', 'coordinates' ), - 'distance' => array( 0, 'දුර', 'distance' ), -); +$magicWords['si'] = [ + 'finddestination' => [ 0, 'ගමනාන්තය_සෙවීම', 'finddestination' ], + 'coordinates' => [ 0, 'ඛණ්ඩාංක', 'coordinates' ], + 'distance' => [ 0, 'දුර', 'distance' ], +]; /** Serbian (Cyrillic script) (српски (ћирилица)‎) */ -$magicWords['sr-ec'] = array( - 'display_map' => array( 0, 'прикажи_мапу' ), - 'display_point' => array( 0, 'прикажи_тачку', 'прикажи_тачке' ), - 'finddestination' => array( 0, 'пронађиодредиште', 'пронађи_одредиште' ), - 'coordinates' => array( 0, 'координате' ), - 'distance' => array( 0, 'раздаљина' ), -); +$magicWords['sr-ec'] = [ + 'display_map' => [ 0, 'прикажи_мапу' ], + 'display_point' => [ 0, 'прикажи_тачку', 'прикажи_тачке' ], + 'finddestination' => [ 0, 'пронађиодредиште', 'пронађи_одредиште' ], + 'coordinates' => [ 0, 'координате' ], + 'distance' => [ 0, 'раздаљина' ], +]; /** Serbian (Latin script) (srpski (latinica)‎) */ -$magicWords['sr-el'] = array( - 'display_map' => array( 0, 'prikaži_mapu' ), - 'display_point' => array( 0, 'prikaži_tačku', 'prikaži_tačke' ), - 'geocode' => array( 0, 'geografski_kod' ), - 'geodistance' => array( 0, 'geografska_razdaljina' ), - 'finddestination' => array( 0, 'pronađi_odredište' ), - 'coordinates' => array( 0, 'koordinate' ), - 'distance' => array( 0, 'razdaljina' ), -); +$magicWords['sr-el'] = [ + 'display_map' => [ 0, 'prikaži_mapu' ], + 'display_point' => [ 0, 'prikaži_tačku', 'prikaži_tačke' ], + 'geocode' => [ 0, 'geografski_kod' ], + 'geodistance' => [ 0, 'geografska_razdaljina' ], + 'finddestination' => [ 0, 'pronađi_odredište' ], + 'coordinates' => [ 0, 'koordinate' ], + 'distance' => [ 0, 'razdaljina' ], +]; /** Talysh (толышә зывон) */ -$magicWords['tly'] = array( - 'display_map' => array( 0, 'хәритә_нишо_дој' ), -); +$magicWords['tly'] = [ + 'display_map' => [ 0, 'хәритә_нишо_дој' ], +]; /** Ukrainian (українська) */ -$magicWords['uk'] = array( - 'display_map' => array( 0, 'показати_карту' ), - 'display_point' => array( 0, 'показати_точку' ), - 'display_points' => array( 0, 'показати_точки' ), - 'geodistance' => array( 0, 'геовідстань' ), - 'finddestination' => array( 0, 'знайти_місцезнаходження' ), - 'coordinates' => array( 0, 'координати' ), - 'distance' => array( 0, 'відстань' ), -); +$magicWords['uk'] = [ + 'display_map' => [ 0, 'показати_карту' ], + 'display_point' => [ 0, 'показати_точку' ], + 'display_points' => [ 0, 'показати_точки' ], + 'geodistance' => [ 0, 'геовідстань' ], + 'finddestination' => [ 0, 'знайти_місцезнаходження' ], + 'coordinates' => [ 0, 'координати' ], + 'distance' => [ 0, 'відстань' ], +]; /** Uzbek (oʻzbekcha/ўзбекча) */ -$magicWords['uz'] = array( - 'coordinates' => array( 0, 'koordinatalar' ), -); +$magicWords['uz'] = [ + 'coordinates' => [ 0, 'koordinatalar' ], +]; /** Vietnamese (Tiếng Việt) */ -$magicWords['vi'] = array( - 'display_map' => array( 0, 'hiển_thị_bản_đồ', 'hiểnthịbảnđồ' ), - 'geocode' => array( 0, 'mã_hóa_địa_lý', 'mãhóađịalý', 'mã_hoá_địa_lý', 'mãhoáđịalý', 'mã_hóa_địa_lí', 'mãhóađịalí', 'mã_hoá_địa_lí', 'mãhoáđịalí' ), - 'coordinates' => array( 0, 'tọa_độ', 'tọađộ' ), -); +$magicWords['vi'] = [ + 'display_map' => [ 0, 'hiển_thị_bản_đồ', 'hiểnthịbảnđồ' ], + 'geocode' => [ 0, 'mã_hóa_địa_lý', 'mãhóađịalý', 'mã_hoá_địa_lý', 'mãhoáđịalý', 'mã_hóa_địa_lí', 'mãhóađịalí', 'mã_hoá_địa_lí', 'mãhoáđịalí' ], + 'coordinates' => [ 0, 'tọa_độ', 'tọađộ' ], +]; /** Simplified Chinese (中文(简体)‎) */ -$magicWords['zh-hans'] = array( - 'display_map' => array( 0, '显示地图' ), - 'display_point' => array( 0, '显示点' ), - 'display_points' => array( 0, '显示多个点' ), - 'display_line' => array( 0, '显示线' ), - 'geocode' => array( 0, '地理编码' ), - 'geodistance' => array( 0, '地理距离' ), - 'finddestination' => array( 0, '寻找目的地' ), - 'coordinates' => array( 0, '坐标' ), - 'distance' => array( 0, '距离' ), - 'mapsdoc' => array( 0, '地图文档' ), -); +$magicWords['zh-hans'] = [ + 'display_map' => [ 0, '显示地图' ], + 'display_point' => [ 0, '显示点' ], + 'display_points' => [ 0, '显示多个点' ], + 'display_line' => [ 0, '显示线' ], + 'geocode' => [ 0, '地理编码' ], + 'geodistance' => [ 0, '地理距离' ], + 'finddestination' => [ 0, '寻找目的地' ], + 'coordinates' => [ 0, '坐标' ], + 'distance' => [ 0, '距离' ], + 'mapsdoc' => [ 0, '地图文档' ], +]; /** Traditional Chinese (中文(繁體)‎) */ -$magicWords['zh-hant'] = array( - 'display_map' => array( 0, '顯示地圖' ), - 'display_point' => array( 0, '顯示位置' ), - 'display_points' => array( 0, '顯示多個位置' ), - 'display_line' => array( 0, '顯示線' ), - 'geocode' => array( 0, '地理編碼' ), - 'geodistance' => array( 0, '地理距離' ), - 'finddestination' => array( 0, '搜尋目的地' ), - 'coordinates' => array( 0, '坐標' ), - 'distance' => array( 0, '距離' ), - 'mapsdoc' => array( 0, '地圖檔案' ), -); \ No newline at end of file +$magicWords['zh-hant'] = [ + 'display_map' => [ 0, '顯示地圖' ], + 'display_point' => [ 0, '顯示位置' ], + 'display_points' => [ 0, '顯示多個位置' ], + 'display_line' => [ 0, '顯示線' ], + 'geocode' => [ 0, '地理編碼' ], + 'geodistance' => [ 0, '地理距離' ], + 'finddestination' => [ 0, '搜尋目的地' ], + 'coordinates' => [ 0, '坐標' ], + 'distance' => [ 0, '距離' ], + 'mapsdoc' => [ 0, '地圖檔案' ], +]; \ No newline at end of file diff --git a/Maps.i18n.namespaces.php b/Maps.i18n.namespaces.php deleted file mode 100644 index 893d9dee1..000000000 --- a/Maps.i18n.namespaces.php +++ /dev/null @@ -1,18 +0,0 @@ - 'Layer', - Maps_NS_LAYER_TALK => 'Layer_talk', -); - -$namespaceNames['de'] = array( - Maps_NS_LAYER_TALK => 'Layer_Diskussion', -); diff --git a/Maps.i18n.php b/Maps.i18n.php deleted file mode 100644 index eeb2776d6..000000000 --- a/Maps.i18n.php +++ /dev/null @@ -1,31 +0,0 @@ - */ -if ( !defined( 'MEDIAWIKI' ) ) { - die( 'Not an entry point.' ); -} - -if ( defined( 'Maps_VERSION' ) ) { +use DataValues\Geo\Parsers\GeoCoordinateParser; +use FileFetcher\SimpleFileFetcher; +use Maps\CircleParser; +use Maps\DistanceParser; +use Maps\SemanticMaps; +use Maps\ImageOverlayParser; +use Maps\LineParser; +use Maps\LocationParser; +use Maps\PolygonParser; +use Maps\RectangleParser; +use Maps\ServiceParam; +use Maps\WmsOverlayParser; + +if ( defined( 'Maps_COORDS_FLOAT' ) ) { // Do not initialize more than once. return 1; } -define( 'Maps_VERSION' , '3.5.0' ); +// The different coordinate notations. +define( 'Maps_COORDS_FLOAT' , 'float' ); +define( 'Maps_COORDS_DMS' , 'dms' ); +define( 'Maps_COORDS_DM' , 'dm' ); +define( 'Maps_COORDS_DD' , 'dd' ); + +require_once __DIR__ . '/Maps_Settings.php'; // Include the composer autoloader if it is present. if ( is_readable( __DIR__ . '/vendor/autoload.php' ) ) { include_once( __DIR__ . '/vendor/autoload.php' ); } -// Only initialize the extension when all dependencies are present. -if ( !defined( 'Validator_VERSION' ) ) { - throw new Exception( 'You need to have Validator installed in order to use Maps' ); -} +// Internationalization +$GLOBALS['wgMessagesDirs']['Maps'] = __DIR__ . '/i18n'; +$GLOBALS['wgExtensionMessagesFiles']['MapsMagic'] = __DIR__ . '/Maps.i18n.magic.php'; +$GLOBALS['wgExtensionMessagesFiles']['MapsAlias'] = __DIR__ . '/Maps.i18n.alias.php'; -if ( version_compare( $GLOBALS['wgVersion'], '1.18c' , '<' ) ) { - throw new Exception( 'This version of Maps requires MediaWiki 1.18 or above; use Maps 1.0.x for MediaWiki 1.17 and Maps 0.7.x for older versions.' ); -} -call_user_func( function() { - $GLOBALS['wgExtensionCredits']['parserhook'][] = array( +$GLOBALS['wgExtensionFunctions'][] = function () { + if ( $GLOBALS['egMapsDisableExtension'] ) { + return true; + } + + if ( defined( 'Maps_VERSION' ) ) { + // Do not initialize more than once. + return true; + } + + // Only initialize the extension when all dependencies are present. + if ( !defined( 'Validator_VERSION' ) ) { + throw new Exception( 'You need to have Validator installed in order to use Maps' ); + } + + if ( version_compare( $GLOBALS['wgVersion'], '1.27c' , '<' ) ) { + throw new Exception( + 'This version of Maps requires MediaWiki 1.27 or above; use Maps 4.2.x for older versions.' + . ' More information at https://github.com/JeroenDeDauw/Maps/blob/master/INSTALL.md' + ); + } + + define( 'Maps_VERSION' , '4.3' ); + define( 'SM_VERSION', Maps_VERSION ); + + if ( $GLOBALS['egMapsGMaps3Language'] === '' ) { + $GLOBALS['egMapsGMaps3Language'] = $GLOBALS['wgLang']; + } + + if ( in_array( 'googlemaps3', $GLOBALS['egMapsAvailableServices'] ) ) { + $GLOBALS['wgSpecialPages']['MapEditor'] = 'SpecialMapEditor'; + $GLOBALS['wgSpecialPageGroups']['MapEditor'] = 'maps'; + } + + $GLOBALS['wgExtensionCredits']['parserhook'][] = [ 'path' => __FILE__ , 'name' => 'Maps' , 'version' => Maps_VERSION , - 'author' => array( + 'author' => [ '[https://www.mediawiki.org/wiki/User:Jeroen_De_Dauw Jeroen De Dauw]', '...' - ) , + ] , 'url' => 'https://github.com/JeroenDeDauw/Maps/blob/master/README.md#maps' , 'descriptionmsg' => 'maps-desc', 'license-name' => 'GPL-2.0+' - ); - - // The different coordinate notations. - define( 'Maps_COORDS_FLOAT' , 'float' ); - define( 'Maps_COORDS_DMS' , 'dms' ); - define( 'Maps_COORDS_DM' , 'dm' ); - define( 'Maps_COORDS_DD' , 'dd' ); - - $mapsDir = __DIR__ . '/'; + ]; $GLOBALS['egMapsStyleVersion'] = $GLOBALS['wgStyleVersion'] . '-' . Maps_VERSION; - $GLOBALS['wgMessagesDirs']['Maps'] = __DIR__ . '/i18n'; - $GLOBALS['wgExtensionMessagesFiles']['Maps'] = __DIR__ . '/Maps.i18n.php'; - $GLOBALS['wgExtensionMessagesFiles']['MapsMagic'] = __DIR__ . '/Maps.i18n.magic.php'; - $GLOBALS['wgExtensionMessagesFiles']['MapsNamespaces'] = __DIR__ . '/Maps.i18n.namespaces.php'; - $GLOBALS['wgExtensionMessagesFiles']['MapsAlias'] = __DIR__ . '/Maps.i18n.alias.php'; - $GLOBALS['wgResourceModules'] = array_merge( $GLOBALS['wgResourceModules'], include 'Maps.resources.php' ); $GLOBALS['wgAPIModules']['geocode'] = 'Maps\Api\Geocode'; - // Register the initialization function of Maps. - $GLOBALS['wgExtensionFunctions'][] = function () { - - if ( $GLOBALS['egMapsGMaps3Language'] === '' ) { - $GLOBALS['egMapsGMaps3Language'] = $GLOBALS['wgLang']; - } - Hooks::run( 'MappingServiceLoad' ); - Hooks::run( 'MappingFeatureLoad' ); - - if ( in_array( 'googlemaps3', $GLOBALS['egMapsAvailableServices'] ) ) { - $GLOBALS['wgSpecialPages']['MapEditor'] = 'SpecialMapEditor'; - $GLOBALS['wgSpecialPageGroups']['MapEditor'] = 'maps'; - } - - return true; - }; $GLOBALS['wgHooks']['AdminLinks'][] = 'MapsHooks::addToAdminLinks'; - $GLOBALS['wgHooks']['ArticleFromTitle'][] = 'MapsHooks::onArticleFromTitle'; $GLOBALS['wgHooks']['MakeGlobalVariablesScript'][] = 'MapsHooks::onMakeGlobalVariablesScript'; - $GLOBALS['wgHooks']['CanonicalNamespaces'][] = 'MapsHooks::onCanonicalNamespaces'; $GLOBALS['wgHooks']['LoadExtensionSchemaUpdates'][] = 'MapsHooks::onLoadExtensionSchemaUpdates'; - $GLOBALS['wgHooks']['ArticlePurge'][] = 'MapsHooks::onArticlePurge'; - $GLOBALS['wgHooks']['LinksUpdateConstructed'][] = 'MapsHooks::onLinksUpdateConstructed'; - $GLOBALS['wgHooks']['ParserAfterTidy'][] = 'MapsHooks::onParserAfterTidy'; - $GLOBALS['wgHooks']['ParserClearState'][] = 'MapsHooks::onParserClearState'; // Parser hooks @@ -134,11 +144,6 @@ return $instance->init( $parser ); }; - $GLOBALS['wgHooks']['ParserFirstCallInit'][] = function( Parser $parser ) { - $instance = new MapsLayerDefinition(); - return $instance->init( $parser ); - }; - // Geocoders // Registration of the GeoNames service geocoder. @@ -150,71 +155,93 @@ // Registration of the geocoder.us service geocoder. $GLOBALS['wgHooks']['GeocoderFirstCallInit'][] = 'MapsGeocoderusGeocoder::register'; - // Layers - - // Registration of the image layer type. - $GLOBALS['wgHooks']['MappingLayersInitialization'][] = 'MapsImageLayer::register'; + // Registration of the OSM Nominatim service geocoder. + $GLOBALS['wgHooks']['GeocoderFirstCallInit'][] = function() { + \Maps\Geocoders::registerGeocoder( + 'nominatim', + new \Maps\Geocoders\NominatimGeocoder( new SimpleFileFetcher() ) + ); + return true; + }; - // Mapping services - // Include the mapping services that should be loaded into Maps. - // Commenting or removing a mapping service will make Maps completely ignore it, and so improve performance. // Google Maps API v3 - // TODO: improve loading mechanism - include_once $mapsDir . 'includes/services/GoogleMaps3/GoogleMaps3.php'; + if ( $GLOBALS['egMapsGMaps3ApiKey'] === '' && array_key_exists( 'egGoogleJsApiKey', $GLOBALS ) ) { + $GLOBALS['egMapsGMaps3ApiKey'] = $GLOBALS['egGoogleJsApiKey']; + } + + include_once __DIR__ . '/includes/services/GoogleMaps3/GoogleMaps3.php'; + + MapsMappingServices::registerService( 'googlemaps3', MapsGoogleMaps3::class ); + + $googleMaps = MapsMappingServices::getServiceInstance( 'googlemaps3' ); + $googleMaps->addFeature( 'display_map', MapsDisplayMapRenderer::class ); + + // OpenLayers API - // TODO: improve loading mechanism - include_once $mapsDir . 'includes/services/OpenLayers/OpenLayers.php'; + include_once __DIR__ . '/includes/services/OpenLayers/OpenLayers.php'; + + MapsMappingServices::registerService( + 'openlayers', + MapsOpenLayers::class, + [ 'display_map' => MapsDisplayMapRenderer::class ] + ); + + // Leaflet API - // TODO: improve loading mechanism - include_once $mapsDir . 'includes/services/Leaflet/Leaflet.php'; + include_once __DIR__ . '/includes/services/Leaflet/Leaflet.php'; + MapsMappingServices::registerService( 'leaflet', MapsLeaflet::class ); + $leafletMaps = MapsMappingServices::getServiceInstance( 'leaflet' ); + $leafletMaps->addFeature( 'display_map', MapsDisplayMapRenderer::class ); - require_once __DIR__ . '/Maps_Settings.php'; + $GLOBALS['wgParamDefinitions']['coordinate'] = [ + 'string-parser' => GeoCoordinateParser::class, + ]; - define( 'Maps_NS_LAYER' , $GLOBALS['egMapsNamespaceIndex'] + 0 ); - define( 'Maps_NS_LAYER_TALK' , $GLOBALS['egMapsNamespaceIndex'] + 1 ); + $GLOBALS['wgParamDefinitions']['mappingservice'] = [ + 'definition'=> ServiceParam::class, + ]; - $GLOBALS['wgParamDefinitions']['coordinate'] = array( - 'string-parser' => 'DataValues\Geo\Parsers\GeoCoordinateParser', - ); + $GLOBALS['wgParamDefinitions']['mapslocation'] = [ + 'string-parser' => LocationParser::class, + ]; - $GLOBALS['wgParamDefinitions']['mappingservice'] = array( - 'definition'=> 'Maps\ServiceParam', - ); + $GLOBALS['wgParamDefinitions']['mapsline'] = [ + 'string-parser' => LineParser::class, + ]; - $GLOBALS['wgParamDefinitions']['mapslocation'] = array( - 'string-parser' => 'Maps\LocationParser', - ); + $GLOBALS['wgParamDefinitions']['mapscircle'] = [ + 'string-parser' => CircleParser::class, + ]; - $GLOBALS['wgParamDefinitions']['mapsline'] = array( - 'string-parser' => 'Maps\LineParser', - ); + $GLOBALS['wgParamDefinitions']['mapsrectangle'] = [ + 'string-parser' => RectangleParser::class, + ]; - $GLOBALS['wgParamDefinitions']['mapscircle'] = array( - 'string-parser' => 'Maps\CircleParser', - ); + $GLOBALS['wgParamDefinitions']['mapspolygon'] = [ + 'string-parser' => PolygonParser::class, + ]; - $GLOBALS['wgParamDefinitions']['mapsrectangle'] = array( - 'string-parser' => 'Maps\RectangleParser', - ); + $GLOBALS['wgParamDefinitions']['distance'] = [ + 'string-parser' => DistanceParser::class, + ]; - $GLOBALS['wgParamDefinitions']['mapspolygon'] = array( - 'string-parser' => 'Maps\PolygonParser', - ); + $GLOBALS['wgParamDefinitions']['wmsoverlay'] = [ + 'string-parser' => WmsOverlayParser::class, + ]; - $GLOBALS['wgParamDefinitions']['distance'] = array( - 'string-parser' => 'Maps\DistanceParser', - ); + $GLOBALS['wgParamDefinitions']['mapsimageoverlay'] = [ + 'string-parser' => ImageOverlayParser::class, + ]; - $GLOBALS['wgParamDefinitions']['wmsoverlay'] = array( - 'string-parser' => 'Maps\WmsOverlayParser', - ); + if ( !$GLOBALS['egMapsDisableSmwIntegration'] && defined( 'SMW_VERSION' ) ) { + SemanticMaps::newFromMediaWikiGlobals( $GLOBALS )->initExtension(); + } + + return true; +}; - $GLOBALS['wgParamDefinitions']['mapsimageoverlay'] = array( - 'string-parser' => 'Maps\ImageOverlayParser', - ); -} ); diff --git a/Maps.resources.php b/Maps.resources.php index 13f052299..fcf05c347 100644 --- a/Maps.resources.php +++ b/Maps.resources.php @@ -15,60 +15,54 @@ $pathParts = ( explode( DIRECTORY_SEPARATOR . 'extensions' . DIRECTORY_SEPARATOR, __DIR__, 2 ) ); - $moduleTemplate = array( + $moduleTemplate = [ 'position' => 'top', 'localBasePath' => __DIR__ . '/includes', 'remoteExtPath' => end( $pathParts ) . '/includes', 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ) - ); + ] + ]; - return array( - 'ext.maps.common' => $moduleTemplate + array( - 'messages' => array( + return [ + 'ext.maps.common' => $moduleTemplate + [ + 'messages' => [ 'maps-load-failed', - ) , - 'scripts' => array( + ] , + 'scripts' => [ 'ext.maps.common.js', - ), - ), + ], + ], - 'ext.maps.layers' => $moduleTemplate + array( - 'styles' => array( - 'ext.maps.layers.css' - ) - ), - - 'ext.maps.coord' => $moduleTemplate + array( - 'messages' => array( + 'ext.maps.coord' => $moduleTemplate + [ + 'messages' => [ 'maps-abb-north', 'maps-abb-east', 'maps-abb-south', 'maps-abb-west', - ), - 'scripts' => array( + ], + 'scripts' => [ 'ext.maps.coord.js' - ), - ), + ], + ], - 'ext.maps.resizable' => $moduleTemplate + array( + 'ext.maps.resizable' => $moduleTemplate + [ 'dependencies' => 'jquery.ui.resizable', - ), + ], - 'mapeditor' => $moduleTemplate + array( - 'scripts' => array( + 'mapeditor' => $moduleTemplate + [ + 'scripts' => [ 'editor/js/jquery.miniColors.js', 'editor/js/mapeditor.iefixes.js', 'editor/js/mapeditor.js', - ), - 'styles' => array( + ], + 'styles' => [ 'editor/css/jquery.miniColors.css', 'editor/css/mapeditor.css', - ), - 'messages' => array( + ], + 'messages' => [ 'mapeditor-parser-error', 'mapeditor-none-text', 'mapeditor-done-button', @@ -80,27 +74,26 @@ 'mapeditor-mapparam-button', 'mapeditor-clear-button', 'mapeditor-imageoverlay-button', - ), - 'dependencies' => array( + ], + 'dependencies' => [ 'ext.maps.common', 'jquery.ui.autocomplete', 'jquery.ui.slider', 'jquery.ui.dialog', - ), - ), + ], + ], - 'ext.maps.services' => $moduleTemplate + array( + 'ext.maps.services' => $moduleTemplate + [ 'group' => 'ext.maps', - 'scripts' => array( + 'scripts' => [ 'ext.maps.services.js', - ), - 'dependencies' => array( + ], + 'dependencies' => [ 'ext.maps.common', - 'ext.maps.layers', 'ext.maps.coord' - ) - ) - ); + ] + ] + ]; } ); // @codeCoverageIgnoreEnd diff --git a/Maps_Settings.php b/Maps_Settings.php index c8de195a3..3af5b1d58 100644 --- a/Maps_Settings.php +++ b/Maps_Settings.php @@ -10,33 +10,44 @@ * @author Jeroen De Dauw */ -if ( !defined( 'MEDIAWIKI' ) ) { - die( 'Not an entry point.' ); -} - // Mapping services configuration // Array of String. Array containing all the mapping services that will be made available to the user. - $GLOBALS['egMapsAvailableServices'] = array( + $GLOBALS['egMapsAvailableServices'] = [ 'googlemaps3', 'openlayers', 'leaflet', - ); + ]; // String. The default mapping service, which will be used when no default // service is present in the $GLOBALS['egMapsDefaultServices'] array for a certain feature. // A service that supports all features is recommended. This service needs to be // enabled, if not, the first one from the available services will be taken. - $GLOBALS['egMapsDefaultService'] = 'googlemaps3'; + $GLOBALS['egMapsDefaultService'] = 'leaflet'; // Array of String. The default mapping service for each feature, which will be // used when no valid service is provided by the user. Each service needs to be // enabled, if not, the first one from the available services will be taken. // Note: The default service needs to be available for the feature you set it // for, since it's used as a fallback mechanism. - $GLOBALS['egMapsDefaultServices'] = array( - 'display_map' => $GLOBALS['egMapsDefaultService'], - ); + $GLOBALS['egMapsDefaultServices'] = []; + $GLOBALS['egMapsDefaultServices']['display_map'] = $GLOBALS['egMapsDefaultService']; + $GLOBALS['egMapsDefaultServices']['qp'] = $GLOBALS['egMapsDefaultService']; + + +// Enable/disable parts of the extension + + // Allows disabling the extension even when it is installed. + // + // CAUTION: this setting is intended for wiki farms. On single wiki installations, + // the recommended way to disable maps is to uninstall it via Composer. Disabling + // Maps via this setting undermines package management safety: extensions that depend + // on Maps will likely either break of disable themselves. + $GLOBALS['egMapsDisableExtension'] = false; + + // Allows disabling the Semantic MediaWiki integration. + $GLOBALS['egMapsDisableSmwIntegration'] = false; + // Geocoding @@ -47,11 +58,12 @@ // at http://www.geonames.org/login and set the username to $GLOBALS['egMapsGeoNamesUser'] below. // Not doing this will result into a legacy service being used, which might be // disabled at some future point. - $GLOBALS['egMapsAvailableGeoServices'] = array( + $GLOBALS['egMapsAvailableGeoServices'] = [ 'geonames', 'google', 'geocoderus', - ); + 'nominatim', + ]; // String. The default geocoding service, which will be used when no service is // is provided by the user. This service needs to be enabled, if not, the first @@ -77,21 +89,29 @@ // Coordinate configuration // The coordinate notations that should be available. - $GLOBALS['egMapsAvailableCoordNotations'] = array( + $GLOBALS['egMapsAvailableCoordNotations'] = [ Maps_COORDS_FLOAT, Maps_COORDS_DMS, Maps_COORDS_DM, Maps_COORDS_DD - ); + ]; // Enum. The default output format of coordinates. // Possible values: Maps_COORDS_FLOAT, Maps_COORDS_DMS, Maps_COORDS_DM, Maps_COORDS_DD $GLOBALS['egMapsCoordinateNotation'] = Maps_COORDS_DMS; + # Enum. The default output format of coordinates when displayed by Semantic MediaWiki. + # Possible values: Maps_COORDS_FLOAT, Maps_COORDS_DMS, Maps_COORDS_DM, Maps_COORDS_DD + $GLOBALS['smgQPCoodFormat'] = $GLOBALS['egMapsCoordinateNotation']; + // Boolean. Indicates if coordinates should be outputted in directional notation by default. // Recommended to be true for Maps_COORDS_DMS and false for Maps_COORDS_FLOAT. $GLOBALS['egMapsCoordinateDirectional'] = true; + # Boolean. Indicates if coordinates should be outputted in directional notation by default when + # displayed by Semantic MediaWiki. + $GLOBALS['smgQPCoodDirectional'] = $GLOBALS['egMapsCoordinateDirectional']; + // Boolean. Sets if direction labels should be translated to their equivalent in the wiki language or not. $GLOBALS['egMapsInternatDirectionLabels'] = true; @@ -101,7 +121,7 @@ // Array. A list of units (keys) and how many meters they represent (value). // No spaces! If the unit consists out of multiple words, just write them together. - $GLOBALS['egMapsDistanceUnits'] = array( + $GLOBALS['egMapsDistanceUnits'] = [ 'm' => 1, 'meter' => 1, 'meters' => 1, @@ -114,7 +134,7 @@ 'nm' => 1852, 'nauticalmile' => 1852, 'nauticalmiles' => 1852, - ); + ]; // String. The default unit for distances. $GLOBALS['egMapsDistanceUnit'] = 'm'; @@ -134,10 +154,10 @@ // max for absolute values, then min and max for percentage values. When the // height or width exceed their limits, they will be changed to the closest // allowed value. - $GLOBALS['egMapsSizeRestrictions'] = array( - 'width' => array( 50, 1020, 1, 100 ), - 'height' => array( 50, 1000, 1, 100 ), - ); + $GLOBALS['egMapsSizeRestrictions'] = [ + 'width' => [ 50, 1020, 1, 100 ], + 'height' => [ 50, 1000, 1, 100 ], + ]; // String. The default centre for maps. Can be either a set of coordinates or an address. $GLOBALS['egMapsDefaultMapCentre'] = '0, 0'; @@ -152,24 +172,42 @@ $GLOBALS['egMapsRezoomForKML'] = false; +# Semantic MediaWiki queries + + # Boolean. The default value for the showtitle parameter. Will hide the title in the marker pop-ups when set to true. + # This value will only be used when the user does not provide one. + $GLOBALS['smgQPShowTitle'] = true; + + # Boolean. The default value for the hidenamespace parameter. Will hide the namespace in the marker pop-ups when set to true. + # This value will only be used when the user does not provide one. + $GLOBALS['smgQPHideNamespace'] = false; + + # String or false. Allows you to define the content and it's layout of marker pop-ups via a template. + # This value will only be used when the user does not provide one. + $GLOBALS['smgQPTemplate'] = false; + + // Other general configuration + // Boolean. Sets if pages with maps should be put in special category + $GLOBALS['egMapsEnableCategory'] = false; + // When true, debugging messages will be logged using mw.log(). Do not use on production wikis. $GLOBALS['egMapsDebugJS'] = false; // Namespace index start of the mapping namespaces. $GLOBALS['egMapsNamespaceIndex'] = 420; - // Boolean. Controls if you can specify images using a full path in layers. - $GLOBALS['egMapsAllowExternalImages'] = true; - // Boolean. Sets if pages with maps should be put in special category - $GLOBALS['egMapsEnableCategory'] = true; +// Mapping service specific configuration + // Google Maps v3 -// Specific mapping service configuration + // String. Google Maps v3 API Key + $GLOBALS['egMapsGMaps3ApiKey'] = ''; - // Google Maps v3 + // String. Google Maps v3 API version number + $GLOBALS['egMapsGMaps3ApiVersion'] = ''; // Integer. The default zoom of a map. This value will only be used when the // user does not provide one. @@ -177,25 +215,25 @@ // Array of String. The Google Maps v3 default map types. This value will only // be used when the user does not provide one. - $GLOBALS['egMapsGMaps3Types'] = array( + $GLOBALS['egMapsGMaps3Types'] = [ 'roadmap', 'satellite', 'hybrid', 'terrain' - ); + ]; // String. The default map type. This value will only be used when the user // does not provide one. $GLOBALS['egMapsGMaps3Type'] = 'roadmap'; // Array. List of controls to display onto maps by default. - $GLOBALS['egMapsGMaps3Controls'] = array( + $GLOBALS['egMapsGMaps3Controls'] = [ 'pan', 'zoom', 'type', 'scale', 'streetview' - ); + ]; // String. The default style for the type control. // horizontal, vertical or default @@ -210,7 +248,7 @@ // Array. Layers to load by default. // traffic and bicycling - $GLOBALS['egMapsGMaps3Layers'] = array(); + $GLOBALS['egMapsGMaps3Layers'] = []; // Integer. Default tilt when using Google Maps. $GLOBALS['egMapsGMaps3DefaultTilt'] = 0; @@ -231,71 +269,132 @@ // be used when the user does not provide one. // Available values: layerswitcher, mouseposition, autopanzoom, panzoom, // panzoombar, scaleline, navigation, keyboarddefaults, overviewmap, permalink - $GLOBALS['egMapsOLControls'] = array( + $GLOBALS['egMapsOLControls'] = [ 'layerswitcher', 'mouseposition', 'autopanzoom', 'scaleline', 'navigation' - ); + ]; // Array of String. The default layers for Open Layers. This value will only be // used when the user does not provide one. - $GLOBALS['egMapsOLLayers'] = array( + $GLOBALS['egMapsOLLayers'] = [ 'osm-mapnik', 'osm-cyclemap' - ); + ]; - // The difinitions for the layers that should be available for the user. - $GLOBALS['egMapsOLAvailableLayers'] = array( + // The definitions for the layers that should be available for the user. + $GLOBALS['egMapsOLAvailableLayers'] = [ //'google' => array( 'OpenLayers.Layer.Google("Google Streets")' ), - 'bing-normal' => array( 'OpenLayers.Layer.VirtualEarth( "Bing Streets", {type: VEMapStyle.Shaded, "sphericalMercator":true} )', 'bing' ), - 'bing-satellite' => array( 'OpenLayers.Layer.VirtualEarth( "Bing Satellite", {type: VEMapStyle.Aerial, "sphericalMercator":true} )', 'bing' ), - 'bing-hybrid' => array( 'OpenLayers.Layer.VirtualEarth( "Bing Hybrid", {type: VEMapStyle.Hybrid, "sphericalMercator":true} )', 'bing' ), + 'bing-normal' => [ 'OpenLayers.Layer.VirtualEarth( "Bing Streets", {type: VEMapStyle.Shaded, "sphericalMercator":true} )', 'bing' ], + 'bing-satellite' => [ 'OpenLayers.Layer.VirtualEarth( "Bing Satellite", {type: VEMapStyle.Aerial, "sphericalMercator":true} )', 'bing' ], + 'bing-hybrid' => [ 'OpenLayers.Layer.VirtualEarth( "Bing Hybrid", {type: VEMapStyle.Hybrid, "sphericalMercator":true} )', 'bing' ], - 'yahoo-normal' => array( 'OpenLayers.Layer.Yahoo( "Yahoo! Streets", {"sphericalMercator":true} )', 'yahoo' ), - 'yahoo-hybrid' => array( 'OpenLayers.Layer.Yahoo( "Yahoo! Hybrid", {"type": YAHOO_MAP_HYB, "sphericalMercator":true} )', 'yahoo' ), - 'yahoo-satellite' => array( 'OpenLayers.Layer.Yahoo( "Yahoo! Satellite", {"type": YAHOO_MAP_SAT, "sphericalMercator":true} )', 'yahoo' ), + 'yahoo-normal' => [ 'OpenLayers.Layer.Yahoo( "Yahoo! Streets", {"sphericalMercator":true} )', 'yahoo' ], + 'yahoo-hybrid' => [ 'OpenLayers.Layer.Yahoo( "Yahoo! Hybrid", {"type": YAHOO_MAP_HYB, "sphericalMercator":true} )', 'yahoo' ], + 'yahoo-satellite' => [ 'OpenLayers.Layer.Yahoo( "Yahoo! Satellite", {"type": YAHOO_MAP_SAT, "sphericalMercator":true} )', 'yahoo' ], - 'osm-mapnik' => array( 'OpenLayers.Layer.OSM.Mapnik("OSM Mapnik")', 'osm' ), - 'osm-cyclemap' => array( 'OpenLayers.Layer.OSM.CycleMap("OSM Cycle Map")', 'osm' ), - 'osm-mapquest' => array( 'OpenLayers.Layer.OSM.Mapquest("Mapquest OSM")', 'osm' ), + 'osm-mapnik' => [ 'OpenLayers.Layer.OSM.Mapnik("OSM Mapnik")', 'osm' ], + 'osm-cyclemap' => [ 'OpenLayers.Layer.OSM.CycleMap("OSM Cycle Map")', 'osm' ], + 'osm-mapquest' => [ 'OpenLayers.Layer.OSM.Mapquest("Mapquest OSM")', 'osm' ], - 'google-normal' => array( 'OpenLayers.Layer.Google("Google Streets", {type: google.maps.MapTypeId.STREETS, numZoomLevels: 20})', 'google' ), - 'google-satellite' => array( 'OpenLayers.Layer.Google("Google Satellite", {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22})', 'google' ), - 'google-hybrid' => array( 'OpenLayers.Layer.Google("Google Hybrid", {type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20})', 'google' ), - 'google-terrain' => array( 'OpenLayers.Layer.Google("Google Terrain", {type: google.maps.MapTypeId.TERRAIN, numZoomLevels: 22})', 'google' ), + 'google-normal' => [ 'OpenLayers.Layer.Google("Google Streets", {type: google.maps.MapTypeId.STREETS, numZoomLevels: 20})', 'google' ], + 'google-satellite' => [ 'OpenLayers.Layer.Google("Google Satellite", {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22})', 'google' ], + 'google-hybrid' => [ 'OpenLayers.Layer.Google("Google Hybrid", {type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20})', 'google' ], + 'google-terrain' => [ 'OpenLayers.Layer.Google("Google Terrain", {type: google.maps.MapTypeId.TERRAIN, numZoomLevels: 22})', 'google' ], 'nasa' => 'OpenLayers.Layer.WMS("NASA Global Mosaic", "http://t1.hypercube.telascience.org/cgi-bin/landsat7", {layers: "landsat7", "sphericalMercator":true} )', - ); + ]; // Layer group definitions. Group names must be different from layer names, and // must only contain layers that are present in $GLOBALS['egMapsOLAvailableLayers']. - $GLOBALS['egMapsOLLayerGroups'] = array( - 'yahoo' => array( 'yahoo-normal', 'yahoo-satellite', 'yahoo-hybrid' ), - 'bing' => array( 'bing-normal', 'bing-satellite', 'bing-hybrid' ), - 'google' => array( 'google-normal', 'google-satellite', 'google-terrain', 'google-hybrid' ), - 'osm' => array( 'osm-mapnik', 'osm-cyclemap' ), - ); + $GLOBALS['egMapsOLLayerGroups'] = [ + 'yahoo' => [ 'yahoo-normal', 'yahoo-satellite', 'yahoo-hybrid' ], + 'bing' => [ 'bing-normal', 'bing-satellite', 'bing-hybrid' ], + 'google' => [ 'google-normal', 'google-satellite', 'google-terrain', 'google-hybrid' ], + 'osm' => [ 'osm-mapnik', 'osm-cyclemap' ], + ]; global $wgJsMimeType; // Layer dependencies - $GLOBALS['egMapsOLLayerDependencies'] = array( + $GLOBALS['egMapsOLLayerDependencies'] = [ 'yahoo' => "", 'bing' => "", 'ol-wms' => "", - 'google' => "", - ); + 'google' => "", + ]; - // Leaflet + // Leaflet // Integer. The default zoom of a map. This value will only be used when the // user does not provide one. $GLOBALS['egMapsLeafletZoom'] = 14; + // String. The default layer for Leaflet. This value will only be + // used when the user does not provide one. + $GLOBALS['egMapsLeafletLayer'] = 'OpenStreetMap'; + + $GLOBALS['egMapsLeafletOverlayLayers'] = [ + + ]; + + // The definitions for the layers that should be available for the user. + $GLOBALS['egMapsLeafletAvailableLayers'] = [ + 'OpenStreetMap' => true, + 'OpenStreetMap.DE' => true, + 'OpenStreetMap.BlackAndWhite' => true, + 'OpenStreetMap.HOT' => true, + 'Thunderforest.OpenCycleMap' => true, + 'Thunderforest.Transport' => true, + 'Thunderforest.Landscape' => true, + 'Hydda.Full' => true, + //'MapBox' => false, // todo: implement setting api key + 'Stamen.Toner' => true, + 'Stamen.Terrain' => true, + 'Stamen.Watercolor' => true, + 'Esri.WorldStreetMap' => true, + 'Esri.DeLorme' => true, + 'Esri.WorldTopoMap' => true, + 'Esri.WorldImagery' => true, + 'Esri.WorldTerrain' => true, + 'Esri.WorldShadedRelief' => true, + 'Esri.WorldPhysical' => true, + 'Esri.OceanBasemap' => true, + 'Esri.NatGeoWorldMap' => true, + 'Esri.WorldGrayCanvas' => true, + 'MapQuestOpen' => true, + ]; + + $GLOBALS['egMapsLeafletAvailableOverlayLayers'] = [ + 'OpenSeaMap' => true, + 'OpenWeatherMap.Clouds' => true, + 'OpenWeatherMap.CloudsClassic' => true, + 'OpenWeatherMap.Precipitation' => true, + 'OpenWeatherMap.PrecipitationClassic' => true, + 'OpenWeatherMap.Rain' => true, + 'OpenWeatherMap.RainClassic' => true, + 'OpenWeatherMap.Pressure' => true, + 'OpenWeatherMap.PressureContour' => true, + 'OpenWeatherMap.Wind' => true, + 'OpenWeatherMap.Temperature' => true, + 'OpenWeatherMap.Snow' => true, + ]; + + $GLOBALS['egMapsLeafletLayersApiKeys'] = [ + 'MapBox' => '', + 'MapQuestOpen' => '', + ]; + + // Layer dependencies + $GLOBALS['egMapsLeafletLayerDependencies'] = [ + 'MapQuestOpen' => 'https://open.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=', + ]; + + + $GLOBALS['egMapsGlobalJSVars'] = []; -$GLOBALS['egMapsGlobalJSVars'] = array(); diff --git a/README.md b/README.md index a17175a88..7af63a75d 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,43 @@ # Maps -Maps is a [MediaWiki](https://www.mediawiki.org) extension to work with and visualise geographical +Maps is a [MediaWiki](https://www.mediawiki.org) extension to work with and visualize geographical information. Features: * Powerful `#display_map` parser hook for embedding highly customizable dynamic maps into wiki pages. -* Support for multiple mapping services: Google Maps, [OpenLayers](http://www.openlayers.org/), -[OpenStreetMap](www.openstreetmap.org/) and [Leaflet](http://leafletjs.com/). +* Support for multiple mapping services: [Leaflet](http://leafletjs.com/), Google Maps, [OpenLayers](http://www.openlayers.org/) and [OpenStreetMap](www.openstreetmap.org/). +* Integration with [Semantic MediaWiki](https://www.semantic-mediawiki.org) via a [coordinate datatype](https://www.semantic-mediawiki.org/wiki/Help:Type_Geographic_coordinate) + * Query your stored coordinates and visualize them on dynamic maps, as tables or as lists + * Export your coordinates as KML or RDF + * Combine coordinates with other structured data stored in your wiki * Coordinate formatting and format conversion via the `#coordinates` parser function. * Geocoding via several supported services with the `#geocode` parser function. * Geospatial operations * Calculating the distance between two points with `#geodistance` * Finding a destination given a starting point, bearing and distance with `#finddestination` * Distance formatting and format conversion via the `#distance` parser function. -* Visual map editor (Special:MapEditor) to edit `#display_map` wikitext. -* Structured data support provided by the [Semantic Maps extension] -(https://www.mediawiki.org/wiki/Extension:Semantic_Maps). +* Visual map editor (Special:MapEditor) to edit `#display_map` wikitext (requires Google Maps). -View the [release notes](RELEASE-NOTES.md) for recent changes to Maps. +## User manual -### User manual +### For administrators * [Installation and configuration](INSTALL.md) -* [Usage instructions and examples](https://www.semantic-mediawiki.org/wiki/Maps) +* [Release notes](RELEASE-NOTES.md) - detailed list of changes per release +* [Platform compatibility](INSTALL.md#platform-compatibility-and-release-status) - overview of PHP and MediaWiki support per release + +### For wiki users + +* [Usage instructions](https://www.semantic-mediawiki.org/wiki/Maps) +* [Usage examples](https://www.semantic-mediawiki.org/wiki/Category:Maps_examples) +* [Semantic usage examples](https://www.semantic-mediawiki.org/wiki/Semantic_Maps_examples) + +### Getting support + +* Ask a question on [the mailing list](https://semantic-mediawiki.org/wiki/Mailing_list) +* Ask a question on the #mediawiki IRC channel on Freenode. +* File an issue on [our issue tracker](https://github.com/JeroenDeDauw/Maps/issues) (technical issues only) ## Project status @@ -41,47 +55,27 @@ On [Packagist](https://packagist.org/packages/mediawiki/maps): ## Contributing -Feel free to fork the [code on GitHub](https://github.com/JeroenDeDauw/Maps) and to submit pull -requests. - -You can run the PHPUnit tests by changing into the `tests/phpunit` directory of your MediaWiki -install and running - - php phpunit.php -c ../../extensions/Maps/ - -## Credits to other projects - -### jQuery - -This extension uses code from the jQuery library. -jQuery is dual licensed under the -[MIT](http://www.opensource.org/licenses/mit-license.php) -and -[GPL](http://www.opensource.org/licenses/gpl-license.php) -licenses. - -### OpenLayers +* [File an issue](https://github.com/JeroenDeDauw/Maps/issues) +* [Submit a pull request](https://github.com/JeroenDeDauw/Maps/pulls) ([tasks for newcomers](https://github.com/JeroenDeDauw/Maps/issues?q=is%3Aissue+is%3Aopen+label%3Anewcomer)) -This extension includes code from the OpenLayers application. -OpenLayers is an open-source product released under a -[BSD-style license](http://svn.openlayers.org/trunk/openlayers/license.txt). +### Running the tests -### geoxml3 +As setup, run `composer install` inside of the Maps root directory. -This extension includes a copy of the geoxml3 KML processor. -geoxml3 is released under the -[Apache License 2.0 license](http://www.apache.org/licenses/LICENSE-2.0). +You can run the MediaWiki independent tests by changing into the Maps root directory and running -### google-maps-utility-library-v3 + phpunit + +This is possible without having a MediaWiki installation or webserver. A clone of the Maps code suffices. -This extension includes code from the google-maps-utility-library-v3 (googleearth.js). -It is released under the -[Apache License 2.0 license](http://www.apache.org/licenses/LICENSE-2.0). +To run the tests with MediaWiki, change into `tests/phpunit` of your MediaWiki installation and run -### OpenStreetMap.js + php phpunit.php --wiki wiki -c ../../extensions/Maps/phpunit.xml.dist + +Where you either update `wiki` to match your wikis name, or drop the parameter. The above command +works without modification if you are using the [MediaWiki Vagrant](https://www.mediawiki.org/wiki/MediaWiki-Vagrant). -This extension includes the OpenStreetMap.js file which can be found -[here](http://www.openstreetmap.org/openlayers/OpenStreetMap.js). +Beware that due to severe technical debt, some tests access the network. ## Links diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 768c446ee..5a3c137ce 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,6 +1,158 @@ -These are the release notes for the [Maps extension](../README.md). +These are the release notes for the [Maps extension](README.md). For an overview of the different releases and which versions of PHP and MediaWiki they support, see the [platform compatibility tables](INSTALL.md#platform-compatibility-and-release-status). +## Maps 4.3.0 + +Released on June 10th, 2017. + +* Dropped support for MediaWiki older than 1.27 +* Dropped support for PHP older than 5.6 +* Fixed compatibility conflict with the GitHub MediaWiki extension + +## Maps 4.2.1 + +Released on May 20th, 2017. + +* Fixed issue occurring when using the `template` parameter in the Google Maps result format more than once on a page + +## Maps 4.2.0 + +Released on May 15th, 2017. + +* Fixed bug in Nomatim geocoder that caused page loading to fail when Nomatim is down +* Fixed bug in Nomatim geocoder that caused page loading to fail when Nomatim returned an invalid response +* Updated Leaflet from 1.0.0-rc to 1.0.3 + +## Maps 4.1.0 + +Released on April 14th, 2017. + +* Fixed rendering of area query values (they now work properly in SMW "further result" links) +* Fixed type warning in `SMMapPrinter::getMapHTML` +* Added missing geographical polygon type i18n messages + +## Maps 4.0.5 + +Released on March 5th, 2017. + +* Fixed i18n issue in the `mapsdoc` parser hook + +## Maps 4.0.4 + +Released on January 9th, 2017. + +* Fixed encoding of special characters in the Google geocoder (by somescout) +* Improved PHP 7 compatibility (by Andre Klapper) + +## Maps 4.0.3 + +Released on December 6th, 2016. + +* Fixed regression introduced in 4.0.2 that caused the JavaScript to not be loaded in some cases +* The `display_map` parser hook now correctly uses its `geoservice` parameter +* The `center` parameter for the map result format now takes into account the `geoservice` parameter + +## Maps 4.0.2 + +Released on December 4th, 2016. + +* Fixed fatal error caused by double loading of initialization code on some platforms + +## Maps 4.0.1 + +Released on November 19th, 2016. + +* The `geocode` parser hook now correctly uses its `geoservice` and `allowcoordinates` parameters + +## Maps 4.0 + +Released on November 16th, 2016. Also see the [Maps 4.0 blog post](https://www.entropywins.wtf/blog/2016/11/09/maps-4-0-0-rc1-released/) + +### Highlight: Integrated Semantic MediaWiki support + +Merged in most of the features of the Semantic Maps extension. These are enabled automatically when SMW is installed. + +* Added a [coordinate datatype](https://www.semantic-mediawiki.org/wiki/Help:Type_Geographic_coordinate) +* Added a [result format](https://www.semantic-mediawiki.org/wiki/Help:Result_formats) for each mapping service +* Added a KML result format +* Added [distance query](https://www.semantic-mediawiki.org/wiki/Semantic_Maps_examples/Distance_query) support + +Semantic Maps is discontinued as the features will now be maintained in Maps. The Semantic Maps form input +has been moved into the [Page Forms](https://www.mediawiki.org/wiki/Extension:Page_Forms) extension. + +### Breaking changes + +* The default mapping service was changed from Google Maps to Leaflet (can be changed via the `egMapsDefaultService` setting) +* The Maps tracking category is now disabled by default (can be enabled using the `egMapsEnableCategory` setting) + +### Other changes + +* Added `egMapsDisableExtension` setting that allows disabling the extension even when it is installed +* The `egGoogleJsApiKey` setting from Maps 2.x will now be used as Google API key when `egMapsGMaps3ApiKey` is not set +* Various missing messages where added + +## Maps 3.8.2 + +Released on September 22nd, 2016. + +* Fixed incorrect centering of OpenLayers maps (by Peter Grassberger) + +## Maps 3.8.1 + +Released on September 7th, 2016. + +* Fixed bug that caused clustering to always be enabled for Leaflet (by Peter Grassberger) + +## Maps 3.8 + +Released on August 24rd, 2016. + +Due to changes to Google Maps, an API key now needs to be set. See the +[installation configuration instructions](https://github.com/JeroenDeDauw/Maps/blob/master/INSTALL.md#configuration). + +* Added Google Maps API key `egMapsGMaps3ApiKey` setting (by Peter Grassberger) +* Added Google Maps API version number `egMapsGMaps3ApiVersion` setting (by Peter Grassberger) +* Added [Leaflet marker clustering](https://www.semantic-mediawiki.org/wiki/Maps_examples/Leaflet_marker_clustering) (by Peter Grassberger) + * `markercluster`: Enables clustering, multiple markers are merged into one marker. + * `clustermaxzoom`: The maximum zoom level where clusters may exist. + * `clusterzoomonclick`: Whether clicking on a cluster zooms into it. + * `clustermaxradius`: The maximum radius that a cluster will cover. + * `clusterspiderfy`: At the lowest zoom level markers are separated so you can see them all. +* Added [Leaflet fullscreen control](https://www.semantic-mediawiki.org/wiki/Maps_examples/Leaflet_fullscreen_control) (by Peter Grassberger) +* Added [OSM Nominatim Geocoder](https://www.semantic-mediawiki.org/wiki/Maps_examples/Geocode) (by Peter Grassberger) +* Upgraded Leaflet library to its latest version (1.0.0-r3) (by Peter Grassberger) +* Made removal of marker clusters more robust (by Peter Grassberger) +* Unified system messages for several services (by Karsten Hoffmeyer) + +## Maps 3.7 + +Released on June 21st, 2016. + +* Added [rotate control support](https://www.semantic-mediawiki.org/wiki/Maps_examples/Google_Maps_with_rotate_control) for Google Maps (by Peter Grassberger) +* Changed coordinate display on OpenLayers maps from long-lat to lat-long (by Peter Grassberger) +* Upgraded google marker cluster library to its latest version (2.1.2) (by Peter Grassberger) +* Upgraded Leaflet library to its latest version (0.7.7) (by Peter Grassberger) +* Added missing system messages (by Karsten Hoffmeyer) +* Internal code enhancements (by Peter Grassberger) +* Removed broken custom map layer functionality. You no longer need to run update.php for full installation. + +## Maps 3.6 + +Released on May 26th, 2016. + +* Dropped support for MediaWiki older than 1.23 +* Dropped support for PHP older than 5.5 +* Added cluster properties for Google Maps (by Peter Grassberger) + * `clustergridsize`: The grid size of a cluster in pixels + * `clustermaxzoom`: The maximum zoom level that a marker can be part of a cluster + * `clusterzoomonclick`: Whether the default behaviour of clicking on a cluster is to zoom into it. + * `clusteraveragecenter`: Whether the center of each cluster should be the average of all markers in the cluster. + * `clusterminsize`: The minimum number of markers required to form a cluster. +* Fixed missing marker cluster images for Google Maps (by Peter Grassberger) +* Fixed duplicate markers in OpenLayers maps (by Peter Grassberger) +* Fixed URL support in the icon parameter (by Peter Grassberger) +* Various minor MediaWiki compatibility enhancements (by Karsten Hoffmeyer, Siebrand Mazeland and FlorianSW) + ## Maps 3.5 Released on April 2nd, 2016. @@ -60,7 +212,7 @@ Released on January 19th, 2015. Released on January 13th, 2015. * Fixed `geocode` right -* Fixed coordinate precision issue after breaking changes in DataValues Geo +* Fixed coordinate precision issue after breaking changes in DataValues Geo ## Maps 3.2 @@ -289,11 +441,11 @@ MediaWiki unit testing support. #### New features #### * Tag support for these parser hooks (which previously only had parser function support): -** Coordinates -** Distance -** Finddestination -** Geocode -** Geodistance + * Coordinates + * Distance + * Finddestination + * Geocode + * Geodistance * Thumbs and photos parameters for the OSM service. #### Bug fixes #### @@ -348,7 +500,7 @@ with all the globals previously needed for this. * Moved marker JavaScript creation for display_points to the mapping service class for all features. * Moved default zoom level access method to the mapping service class for all features. * Improved the way marker data is turned into JavaScript variables. -* Improved coordinate recognition regexes. +* Improved coordinate recognition regexes. #### Bug fixes #### @@ -579,8 +731,8 @@ for the current version. Changes in 0.4.2 discussed on the authors blog: -* [Maps and Semantic Maps 0.4.2 released](http://www.bn2vs.com/blog/2009/11/16/maps-and-semantic-maps-0-4-2/) -* [New in Maps 0.4.2](http://www.bn2vs.com/blog/2009/11/12/new-in-maps-0-4-2/) +* [Maps and Semantic Maps 0.4.2 released](https://www.entropywins.wtf/blog/2009/11/16/maps-and-semantic-maps-0-4-2/) +* [New in Maps 0.4.2](https://www.entropywins.wtf/blog/2009/11/12/new-in-maps-0-4-2/) #### New features #### @@ -622,7 +774,7 @@ where not separated by a comma. Changes in 0.4 discussed on the authors blog: -* [Finally! Maps and Semantic Maps 0.4!](http://www.bn2vs.com/blog/2009/11/03/finally-maps-and-semantic-maps-0-4/) +* [Finally! Maps and Semantic Maps 0.4!](https://www.entropywins.wtf/blog/2009/11/03/finally-maps-and-semantic-maps-0-4/) #### New features #### @@ -661,7 +813,7 @@ for large contents. Changes in 0.3.4 discussed on the authors blog: -* [Maps and Semantic Maps 0.3.4 released](http://www.bn2vs.com/blog/2009/09/12/maps-and-semantic-maps-0-3-4-released/) +* [Maps and Semantic Maps 0.3.4 released](https://www.entropywins.wtf/blog/2009/09/12/maps-and-semantic-maps-0-3-4-released/) ####New features#### @@ -691,7 +843,7 @@ any value (ie |coordinates=|) Changes in 0.3.3 discussed on the authors blog: -* [Maps and Semantic Maps 0.3.3](http://www.bn2vs.com/blog/2009/08/25/maps-and-semantic-maps-0-3-3/) +* [Maps and Semantic Maps 0.3.3](https://www.entropywins.wtf/blog/2009/08/25/maps-and-semantic-maps-0-3-3/) ####New features#### @@ -741,10 +893,10 @@ since adding the path is impossible in the declaration. Changes in 0.3 discussed on the authors blog: -* [Final changes for Maps and SM 0.3](http://www.bn2vs.com/blog/2009/08/13/final-changes-for-maps-and-sm-0-3/) -* [New features in Maps and SM 0.3](http://www.bn2vs.com/blog/2009/08/07/new-features-in-maps-and-sm-0-3/) -* [Structural changes for Maps and SM 0.3](http://www.bn2vs.com/blog/2009/08/05/structural-changes-for-maps-and-sm-0-3/) - +* [Final changes for Maps and SM 0.3](https://www.entropywins.wtf/blog/2009/08/13/final-changes-for-maps-and-sm-0-3/) +* [New features in Maps and SM 0.3](https://www.entropywins.wtf/blog/2009/08/07/new-features-in-maps-and-sm-0-3/) +* [Structural changes for Maps and SM 0.3](https://www.entropywins.wtf/blog/2009/08/05/structural-changes-for-maps-and-sm-0-3/) + ####New features#### * Multi location parser functions. Two completely new parser functions have been added that diff --git a/SemanticMaps/SemanticMaps.hooks.php b/SemanticMaps/SemanticMaps.hooks.php new file mode 100644 index 000000000..9da8a89bd --- /dev/null +++ b/SemanticMaps/SemanticMaps.hooks.php @@ -0,0 +1,113 @@ + + */ +final class SemanticMapsHooks { + + /** + * Adds a link to Admin Links page. + * + * @since 0.7 + * + * @param ALTree $admin_links_tree + * + * @return boolean + */ + public static function addToAdminLinks( ALTree &$admin_links_tree ) { + $displaying_data_section = $admin_links_tree->getSection( wfMessage( 'smw_adminlinks_displayingdata' )->text() ); + + // Escape if SMW hasn't added links. + if ( is_null( $displaying_data_section ) ) { + return true; + } + + $smw_docu_row = $displaying_data_section->getRow( 'smw' ); + + $sm_docu_label = wfMessage( 'adminlinks_documentation', 'Semantic Maps' )->text(); + $smw_docu_row->addItem( AlItem::newFromExternalLink( 'http://mapping.referata.com/wiki/Semantic_Maps', $sm_docu_label ) ); + + return true; + } + + /** + * Adds support for the geographical coordinates and shapes data type to Semantic MediaWiki. + * + * @since 2.0 + * + * @return boolean + */ + public static function initGeoDataTypes() { + DataTypeRegistry::getInstance()->registerDatatype( + '_geo', + CoordinateValue::class, + SMWDataItem::TYPE_GEO + ); + + DataTypeRegistry::getInstance()->registerDatatype( + '_gpo', + GeoPolygonValue::class, + SMWDataItem::TYPE_BLOB + ); + + return true; + } + + /** + * Set the default format to 'map' when the requested properties are + * of type geographic coordinates. + * + * TODO: have a setting to turn this off and have it off by default for #show + * + * @since 1.0 + * + * @param $format Mixed: The format (string), or false when not set yet + * @param array $printRequests The print requests made + * @param array $params The parameters for the query printer + * + * @return boolean + */ + public static function addGeoCoordsDefaultFormat( &$format, array $printRequests, array $params ) { + // Only set the format when not set yet. This allows other extensions to override the Semantic Maps behavior. + if ( $format === false ) { + // Only apply when there is more then one print request. + // This way requests comming from #show are ignored. + if ( count( $printRequests ) > 1 ) { + $allValid = true; + $hasCoords = false; + + // Loop through the print requests to determine their types. + foreach( $printRequests as /* SMWPrintRequest */ $printRequest ) { + // Skip the first request, as it's the object. + if ( $printRequest->getMode() == SMWPrintRequest::PRINT_THIS ) { + continue; + } + + $typeId = $printRequest->getTypeID(); + + if ( $typeId == '_geo' ) { + $hasCoords = true; + } + else { + $allValid = false; + break; + } + } + + // If they are all coordinates, set the result format to 'map'. + if ( $allValid && $hasCoords ) { + $format = 'map'; + } + } + + } + + return true; + } + +} diff --git a/SemanticMaps/src/SM_PolygonHandler.php b/SemanticMaps/src/SM_PolygonHandler.php new file mode 100644 index 000000000..3aeffc3e1 --- /dev/null +++ b/SemanticMaps/src/SM_PolygonHandler.php @@ -0,0 +1,118 @@ + 'LocationValidator', + 'lines' => 'LineValidator', + 'polygons' => 'PolygonValidator', + 'circles' => 'CircleValidator', + 'rectangles' => 'RectangleValidator' + ]; + + /** + * Array of classes of different Geographic shapes. + * + * @var array + */ + private $geoClasses = [ + 'locations' => 'MapsLocation', + 'lines' => 'MapsLine', + 'polygons' => 'MapsPolygon', + 'circles' => 'MapsCircle', + 'rectangles' => 'MapsRectanlge' + ]; + + /** + * NOTE: These need to be changed as Manipulations are deprecated. + * Array of classes for param handling of different Geographic shapes. + * + * @var array + */ + private $paramClasses = [ + 'locations' => 'MapsParamLocation', + 'lines' => 'MapsParamLine', + 'polygons' => 'MapsParamPolygon', + 'circles' => 'MapsParamCircle', + 'rectangles' => 'MapsParamRectangle' + ]; + + /** + * @param string $text + */ + public function __construct( $text ) { + $this->text = $text; + } + + public function getGeoType() { + $parts = explode( '=', $this->text ); + return current( $parts ); + } + + public function getValidationErrors() { + $this->validateText(); + return $this->errors; + } + + private function validateText() { + $parts = explode( '=', $this->text ); + if( array_key_exists( $parts[0], $this->validatorClasses ) ) { + $validatorClass = new $this->validatorClasses[ $parts[0] ]( '~' ); + if ( !$validatorClass->doValidation( $parts[1] ) ) + $this->errors[] = wfMessage( 'semanticmaps-shapes-improperformat', $this->text )->escaped(); + } else { + $this->errors[] = wfMessage( 'semanticmaps-shapes-missingshape', $parts[0] )->escaped(); + } + } + + /** + * Gets an object of the model class the string represents. + * + * @since 2.1 + */ + public function shapeFromText() { + $parts = explode( '~' , $this->text ); + $shape = explode( '=', array_shift( $parts ) ); + if( array_key_exists( $shape[0] , $this->geoClasses ) ) { + $geoClass = new $this->geoClasses[ $shape[0] ]( explode( ':' , $shape[1] ) ); + + return $geoClass; + } else { + return false; + } + } +} diff --git a/SemanticMaps/src/ext.sm.common.js b/SemanticMaps/src/ext.sm.common.js new file mode 100644 index 000000000..19148c562 --- /dev/null +++ b/SemanticMaps/src/ext.sm.common.js @@ -0,0 +1,76 @@ +/** + * JavaScript the Semantic Maps extension. + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Maps + * + * @licence GNU GPL v2++ + * @author Peter Grassberger < petertheone@gmail.com > + */ +window.sm = new ( function( $, mw ) { + + this.buildQueryString = function( query, ajaxcoordproperty, top, right, bottom, left ) { + var isCompoundQuery = query.indexOf('|') > -1; + var query = query.split('|'); + $.each( query, function ( index ) { + query[index] += ' [[' + ajaxcoordproperty + '::+]] '; + query[index] += '[[' + ajaxcoordproperty + '::>' + bottom + '°, ' + left + '°]] '; + query[index] += '[[' + ajaxcoordproperty + '::<' + top + '°, ' + right + '°]]'; + if (!isCompoundQuery) { + query[index] += '|?' + ajaxcoordproperty; + } else { + query[index] += ';?' + ajaxcoordproperty; + } + } ); + return query.join(' | '); + }; + + /** + * Detects semicolons `;` not in square brackets `[]`. + * + * @param string + * @returns {boolean} + */ + this.hasCompoundQuerySemicolon = function( string ) { + return /;(?![^[]*])/g.test( string ); + }; + + this.sendQuery = function( query ) { + var action = this.hasCompoundQuerySemicolon( query ) ? 'compoundquery' : 'ask'; + return $.ajax( { + method: 'GET', + url: mw.util.wikiScript( 'api' ), + data: { + 'action': action, + 'query': query, + 'format': 'json' + }, + dataType: 'json' + } ); + }; + + this.ajaxUpdateMarker = function( map, query, icon ) { + return this.sendQuery(query).done( function( data ) { + if ( !data.hasOwnProperty( 'query' ) || + !data.query.hasOwnProperty( 'results' )) { + return; + } + // todo: don't remove and recreate all markers.. + // only add new ones. + map.removeMarkers(); + for ( var property in data.query.results ) { + if ( data.query.results.hasOwnProperty( property ) ) { + var location = data.query.results[property]; + var coordinates = location.printouts[map.options.ajaxcoordproperty][0]; + var markerOptions = { + lat: coordinates.lat, + lon: coordinates.lon, + title: location.fulltext, + text: '' + location.fulltext + '', + icon: icon + }; + map.addMarker( markerOptions ); + } + } + } ); + }; + +} )( jQuery, mediaWiki ); diff --git a/SemanticMaps/src/queryprinters/SM_KMLPrinter.php b/SemanticMaps/src/queryprinters/SM_KMLPrinter.php new file mode 100644 index 000000000..f47271e4c --- /dev/null +++ b/SemanticMaps/src/queryprinters/SM_KMLPrinter.php @@ -0,0 +1,174 @@ + + */ +class SMKMLPrinter extends FileExportPrinter { + + /** + * Handler of the print request. + * + * @param SMWQueryResult $res + * @param $outputmode + * + * @return array + */ + public function getResultText( SMWQueryResult $res, $outputmode ) { + if ( $outputmode == SMW_OUTPUT_FILE ) { + return $this->getKML( $res, $outputmode ); + } + else { + return $this->getKMLLink( $res, $outputmode ); + } + } + + /** + * @see SMWResultPrinter::handleParameters + * + * @param array $params + * @param $outputmode + */ + protected function handleParameters( array $params, $outputmode ) { + $this->params = $params; + } + + /** + * @see SMWResultPrinter::getParamDefinitions + * + * @param ParamDefinition[] $definitions + * + * @return array of ParamDefinition|array + */ + public function getParamDefinitions( array $definitions ) { + global $egMapsDefaultLabel, $egMapsDefaultTitle; + + $params = parent::getParamDefinitions( $definitions ); + + $params['text'] = [ + 'message' => 'semanticmaps-kml-text', + 'default' => $egMapsDefaultLabel, + ]; + + $params['title'] = [ + 'message' => 'semanticmaps-kml-title', + 'default' => $egMapsDefaultTitle, + ]; + + $params['linkabsolute'] = [ + 'message' => 'semanticmaps-kml-linkabsolute', + 'type' => 'boolean', + 'default' => true, + ]; + + $params['pagelinktext'] = [ + 'message' => 'semanticmaps-kml-pagelinktext', + 'default' => wfMessage( 'semanticmaps-default-kml-pagelink' )->text(), + ]; + + return $params; + } + + /** + * Returns the KML for the query result. + * + * @param SMWQueryResult $res + * @param integer $outputmode + * + * @return string + */ + private function getKML( SMWQueryResult $res, $outputmode ) { + $queryHandler = new SMQueryHandler( $res, $outputmode, $this->params['linkabsolute'] ); + $queryHandler->setText( $this->params['text'] ); + $queryHandler->setTitle( $this->params['title'] ); + $queryHandler->setSubjectSeparator( '' ); + $queryHandler->setPageLinkText( $this->params['pagelinktext'] ); + + $formatter = new MapsKMLFormatter( $this->params ); + + $shapes = $queryHandler->getShapes(); + $formatter->addPlacemarks( $shapes['locations'] ); + + return $formatter->getKML(); + } + + /** + * Returns a link (HTML) pointing to a query that returns the actual KML file. + * + * @param SMWQueryResult $res + * @param integer $outputmode + * + * @return string + */ + private function getKMLLink( SMWQueryResult $res, $outputmode ) { + $searchLabel = $this->getSearchLabel( $outputmode ); + $link = $res->getQueryLink( $searchLabel ? $searchLabel : wfMessage( 'semanticmaps-kml-link' )->inContentLanguage()->text() ); + $link->setParameter( 'kml', 'format' ); + $link->setParameter( $this->params['linkabsolute'] ? 'yes' : 'no', 'linkabsolute' ); + $link->setParameter( $this->params['pagelinktext'], 'pagelinktext' ); + + if ( $this->params['title'] !== '' ) { + $link->setParameter( $this->params['title'], 'title' ); + } + + if ( $this->params['text'] !== '' ) { + $link->setParameter( $this->params['text'], 'text' ); + } + + // Fix for offset-error in getQueryLink() + // (getQueryLink by default sets offset to point to the next + // result set, fix by setting it to 0 if now explicitly set) + if ( array_key_exists( 'offset', $this->params ) ) { + $link->setParameter( $this->params['offset'], 'offset' ); + } else { + $link->setParameter( 0, 'offset' ); + } + + if ( array_key_exists( 'limit', $this->params ) ) { + $link->setParameter( $this->params['limit'], 'limit' ); + } else { // Use a reasonable default limit. + $link->setParameter( 20, 'limit' ); + } + + $this->isHTML = ( $outputmode == SMW_OUTPUT_HTML ); + + return $link->getText( $outputmode, $this->mLinker ); + } + + /** + * @see SMWIExportPrinter::getMimeType + * + * @param SMWQueryResult $queryResult + * + * @return string + */ + public function getMimeType( SMWQueryResult $queryResult ) { + return 'application/vnd.google-earth.kml+xml'; + } + + /** + * @see SMWIExportPrinter::getFileName + * + * @param SMWQueryResult $queryResult + * + * @return string|boolean + */ + public function getFileName( SMWQueryResult $queryResult ) { + return 'kml.kml'; + } + + /** + * @see SMWResultPrinter::getName() + */ + public final function getName() { + return wfMessage( 'semanticmaps-kml' )->text(); + } +} diff --git a/SemanticMaps/src/queryprinters/SM_MapPrinter.php b/SemanticMaps/src/queryprinters/SM_MapPrinter.php new file mode 100644 index 000000000..a32a61c12 --- /dev/null +++ b/SemanticMaps/src/queryprinters/SM_MapPrinter.php @@ -0,0 +1,415 @@ + + * @author Peter Grassberger < petertheone@gmail.com > + */ +class SMMapPrinter extends SMW\ResultPrinter { + + private static $services = []; + + /** + * @var LocationParser + */ + private $locationParser; + + /** + * @since 3.4 + * FIXME: this is a temporary hack that should be replaced when SMW allows for dependency + * injection in query printers. + * + * @param MapsMappingService $service + */ + public static function registerService( MapsMappingService $service ) { + self::$services[$service->getName()] = $service; + } + + public static function registerDefaultService( $serviceName ) { + self::$services['map'] = self::$services[$serviceName]; + } + + /** + * @var MapsMappingService + */ + private $service; + + /** + * @var string|boolean + */ + private $fatalErrorMsg = false; + + /** + * @param string $format + * @param bool $inline + */ + public function __construct( $format, $inline = true ) { + $this->service = self::$services[$format]; + + parent::__construct( $format, $inline ); + } + + /** + * Returns an array containing the parameter info. + * + * @return array + */ + private function getParameterInfo() { + global $smgQPShowTitle, $smgQPTemplate, $smgQPHideNamespace; + + $params = ParamDefinition::getCleanDefinitions( MapsMapper::getCommonParameters() ); + + $this->service->addParameterInfo( $params ); + + $params['staticlocations'] = [ + 'type' => 'mapslocation', // FIXME: geoservice is not used + 'aliases' => [ 'locations', 'points' ], + 'default' => [], + 'islist' => true, + 'delimiter' => ';', + 'message' => 'semanticmaps-par-staticlocations', + ]; + + $params['showtitle'] = [ + 'type' => 'boolean', + 'aliases' => 'show title', + 'default' => $smgQPShowTitle, + ]; + + $params['hidenamespace'] = [ + 'type' => 'boolean', + 'aliases' => 'hide namespace', + 'default' => $smgQPHideNamespace, + ]; + + $params['template'] = [ + 'default' => $smgQPTemplate, + ]; + + $params['userparam'] = [ + 'default' => '', + ]; + + $params['activeicon'] = [ + 'type' => 'string', + 'default' => '', + ]; + + $params['pagelabel'] = [ + 'type' => 'boolean', + 'default' => false, + ]; + + $params['ajaxcoordproperty'] = [ + 'default' => '', + ]; + + $params['ajaxquery'] = [ + 'default' => '', + 'type' => 'string' + ]; + + // Messages: + // semanticmaps-par-staticlocations, semanticmaps-par-showtitle, semanticmaps-par-hidenamespace, + // semanticmaps-par-template, semanticmaps-par-userparam, semanticmaps-par-activeicon, + // semanticmaps-par-pagelabel, semanticmaps-par-ajaxcoordproperty semanticmaps-par-ajaxquery + foreach ( $params as $name => &$data ) { + if ( is_array( $data ) && !array_key_exists( 'message', $data ) ) { + $data['message'] = 'semanticmaps-par-' . $name; + } + } + + return $params; + } + + /** + * Builds up and returns the HTML for the map, with the queried coordinate data on it. + * + * @param SMWQueryResult $res + * @param $outputmode + * + * @return string + */ + public final function getResultText( SMWQueryResult $res, $outputmode ) { + if ( $this->fatalErrorMsg !== false ) { + return $this->fatalErrorMsg; + } + + $this->addTrackingCategoryIfNeeded(); + + $params = $this->params; + + $this->initializeLocationParser( $params ); + + $queryHandler = new SMQueryHandler( $res, $outputmode ); + $queryHandler->setLinkStyle( $params['link'] ); + $queryHandler->setHeaderStyle($params['headers']); + $queryHandler->setShowSubject( $params['showtitle'] ); + $queryHandler->setTemplate( $params['template'] ); + $queryHandler->setUserParam( $params['userparam'] ); + $queryHandler->setHideNamespace( $params['hidenamespace'] ); + $queryHandler->setActiveIcon( $params['activeicon'] ); + + $this->handleMarkerData( $params, $queryHandler ); + + $params['ajaxquery'] = urlencode( $params['ajaxquery'] ); + + $locationAmount = count( $params['locations'] ); + + if ( $locationAmount > 0 ) { + // We can only take care of the zoom defaulting here, + // as not all locations are available in whats passed to Validator. + if ( $this->fullParams['zoom']->wasSetToDefault() && $locationAmount > 1 ) { + $params['zoom'] = false; + } + + $mapName = $this->service->getMapId(); + + SMWOutputs::requireHeadItem( + $mapName, + $this->service->getDependencyHtml() . + $configVars = Skin::makeVariablesScript( $this->service->getConfigVariables() ) + ); + + foreach ( $this->service->getResourceModules() as $resourceModule ) { + SMWOutputs::requireResource( $resourceModule ); + } + + if ( array_key_exists( 'source', $params ) ) { + unset( $params['source'] ); + } + + return $this->getMapHTML( $params, $mapName ); + } + else { + return $params['default']; + } + } + + private function addTrackingCategoryIfNeeded() { + /** + * @var Parser $wgParser + */ + global $wgParser; + + if ( $GLOBALS['egMapsEnableCategory'] && $wgParser->getOutput() !== null ) { + $wgParser->addTrackingCategory( 'maps-tracking-category' ); + } + } + + private function initializeLocationParser( array $params ) { + $this->locationParser = new LocationParser( new ValueParserOptions( [ + 'geoService' => $params['geoservice'] + ] ) ); + } + + /** + * Converts the data in the coordinates parameter to JSON-ready objects. + * These get stored in the locations parameter, and the coordinates on gets deleted. + * + * @param array &$params + * @param SMQueryHandler $queryHandler + */ + private function handleMarkerData( array &$params, SMQueryHandler $queryHandler ) { + $params['centre'] = $this->getCenter( $params['centre'] ); + + $iconUrl = MapsMapper::getFileUrl( $params['icon'] ); + $visitedIconUrl = MapsMapper::getFileUrl( $params['visitedicon'] ); + + $params['locations'] = $this->getJsonForStaticLocations( + $params['staticlocations'], + $params, + $iconUrl, + $visitedIconUrl + ); + + unset( $params['staticlocations'] ); + + $this->addShapeData( $queryHandler->getShapes(), $params, $iconUrl, $visitedIconUrl ); + + if ( $params['format'] === 'openlayers' ) { + $params['layers'] = MapsDisplayMapRenderer::evilOpenLayersHack( $params['layers'] ); + } + } + + private function getCenter( $coordinatesOrAddress ) { + if ( $coordinatesOrAddress === false ) { + return false; + } + + try { + // FIXME: a Location makes no sense here, since the non-coordinate data is not used + $location = $this->locationParser->stringParse( $coordinatesOrAddress ); + } + catch ( \Exception $ex ) { + // TODO: somehow report this to the user + return false; + } + + return $location->getJSONObject(); + } + + /** + * Returns the HTML to display the map. + * + * @param array $params + * @param string $mapName + * + * @return string + */ + private function getMapHTML( array $params, $mapName ) { + return Html::rawElement( + 'div', + [ + 'id' => $mapName, + 'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;", + 'class' => 'maps-map maps-' . $this->service->getName() + ], + wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() . + Html::element( + 'div', + [ 'style' => 'display:none', 'class' => 'mapdata' ], + FormatJson::encode( $params ) + ) + ); + } + + private function getJsonForStaticLocations( array $staticLocations, array $params, $iconUrl, $visitedIconUrl ) { + /** + * @var Parser $wgParser + */ + global $wgParser; + + $parser = version_compare( $GLOBALS['wgVersion'], '1.18', '<' ) ? $wgParser : clone $wgParser; + + $locationsJson = []; + + foreach ( $staticLocations as $location ) { + $locationsJson[] = $this->getJsonForStaticLocation( + $location, + $params, + $iconUrl, + $visitedIconUrl, + $parser + ); + } + + return $locationsJson; + } + + private function getJsonForStaticLocation( Location $location, array $params, $iconUrl, $visitedIconUrl, Parser $parser ) { + $jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl ); + + $jsonObj['title'] = $parser->parse( $jsonObj['title'], $parser->getTitle(), new ParserOptions() )->getText(); + $jsonObj['text'] = $parser->parse( $jsonObj['text'], $parser->getTitle(), new ParserOptions() )->getText(); + + $hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== ''; + $jsonObj['text'] = ( $hasTitleAndtext ? '' . $jsonObj['title'] . '
' : $jsonObj['title'] ) . $jsonObj['text']; + $jsonObj['title'] = strip_tags( $jsonObj['title'] ); + + if ( $params['pagelabel'] ) { + $jsonObj['inlineLabel'] = Linker::link( Title::newFromText( $jsonObj['title'] ) ); + } + + return $jsonObj; + } + + /** + * @param Element[] $queryShapes + * @param array $params + * @param string $iconUrl + * @param string $visitedIconUrl + */ + private function addShapeData( array $queryShapes, array &$params, $iconUrl, $visitedIconUrl ) { + $params['locations'] = array_merge( + $params['locations'], + $this->getJsonForLocations( + $queryShapes['locations'], + $params, + $iconUrl, + $visitedIconUrl + ) + ); + + $params['lines'] = $this->getElementJsonArray( $queryShapes['lines'], $params ); + $params['polygons'] = $this->getElementJsonArray( $queryShapes['polygons'], $params ); + } + + /** + * @param Location[] $locations + * @param array $params + * @param string $iconUrl + * @param string $visitedIconUrl + * + * @return array + */ + private function getJsonForLocations( array $locations, array $params, $iconUrl, $visitedIconUrl ) { + $locationsJson = []; + + foreach ( $locations as $location ) { + $jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl ); + + $jsonObj['title'] = strip_tags( $jsonObj['title'] ); + + $locationsJson[] = $jsonObj; + } + + return $locationsJson; + } + + /** + * @param BaseElement[] $elements + * @param array $params + * + * @return array + */ + private function getElementJsonArray( array $elements, array $params ) { + $elementsJson = []; + + foreach ( $elements as $element ) { + $jsonObj = $element->getJSONObject( $params['title'], $params['label'] ); + $elementsJson[] = $jsonObj; + } + + return $elementsJson; + } + + /** + * Returns the internationalized name of the mapping service. + * + * @return string + */ + public final function getName() { + return wfMessage( 'maps_' . $this->service->getName() )->text(); + } + + /** + * Returns a list of parameter information, for usage by Special:Ask and others. + * + * @return array + */ + public function getParameters() { + $params = parent::getParameters(); + $paramInfo = $this->getParameterInfo(); + + // Do not display this as an option, as the format already determines it + // TODO: this can probably be done cleaner with some changes in Maps + unset( $paramInfo['mappingservice'] ); + + $params = array_merge( $params, $paramInfo ); + + return $params; + } +} diff --git a/SemanticMaps/src/queryprinters/SM_QueryHandler.php b/SemanticMaps/src/queryprinters/SM_QueryHandler.php new file mode 100644 index 000000000..eedba15fe --- /dev/null +++ b/SemanticMaps/src/queryprinters/SM_QueryHandler.php @@ -0,0 +1,594 @@ + + */ +class SMQueryHandler { + + private $queryResult; + private $outputMode; + + /** + * @var array + */ + private $geoShapes = [ + 'lines' => [], + 'locations' => [], + 'polygons' => [] + ]; + + /** + * The template to use for the text, or false if there is none. + * + * @var string|boolean false + */ + private $template = false; + + /** + * The global icon. + * + * @var string + */ + public $icon = ''; + + /** + * The global text. + * + * @var string + */ + public $text = ''; + + /** + * The global title. + * + * @var string + */ + public $title = ''; + + /** + * Make a separate link to the title or not? + * + * @var boolean + */ + public $titleLinkSeparate = false; + + /** + * Should link targets be made absolute (instead of relative)? + * + * @var boolean + */ + private $linkAbsolute; + + /** + * The text used for the link to the page (if it's created). $1 will be replaced by the page name. + * + * @var string + */ + private $pageLinkText = '$1'; + + /** + * A separator to use between the subject and properties in the text field. + * + * @var string + */ + private $subjectSeparator = '
'; + + /** + * Make the subject in the text bold or not? + * + * @var boolean + */ + private $boldSubject = true; + + /** + * Show the subject in the text or not? + * + * @var boolean + */ + private $showSubject = true; + + /** + * Hide the namespace or not. + * + * @var boolean + */ + private $hideNamespace = false; + + + /** + * Defines which article names in the result are hyperlinked, all normally is the default + * none, subject, all + */ + private $linkStyle = 'all'; + + /* + * Show headers (with links), show headers (just text) or hide them. show is default + * show, plain, hide + */ + private $headerStyle = 'show'; + + /** + * Marker icon to show when marker equals active page + * + * @var string|null + */ + private $activeIcon = null; + + /** + * @var string + */ + private $userParam = ''; + + /** + * @param SMWQueryResult $queryResult + * @param integer $outputMode + * @param boolean $linkAbsolute + */ + public function __construct( SMWQueryResult $queryResult, $outputMode, $linkAbsolute = false ) { + $this->queryResult = $queryResult; + $this->outputMode = $outputMode; + $this->linkAbsolute = $linkAbsolute; + } + + /** + * Sets the template. + * + * @param string $template + */ + public function setTemplate( $template ) { + $this->template = $template === '' ? false : $template; + } + + /** + * @param string $userParam + */ + public function setUserParam( $userParam ) { + $this->userParam = $userParam; + } + + /** + * Sets the global icon. + * + * @param string $icon + */ + public function setIcon( $icon ) { + $this->icon = $icon; + } + + /** + * Sets the global title. + * + * @param string $title + */ + public function setTitle( $title ) { + $this->title = $title; + } + + /** + * Sets the global text. + * + * @param string $text + */ + public function setText( $text ) { + $this->text = $text; + } + + /** + * Sets the subject separator. + * + * @param string $subjectSeparator + */ + public function setSubjectSeparator( $subjectSeparator ) { + $this->subjectSeparator = $subjectSeparator; + } + + /** + * Sets if the subject should be made bold in the text. + * + * @param string $boldSubject + */ + public function setBoldSubject( $boldSubject ) { + $this->boldSubject = $boldSubject; + } + + /** + * Sets if the subject should shown in the text. + * + * @param string $showSubject + */ + public function setShowSubject( $showSubject ) { + $this->showSubject = $showSubject; + } + + /** + * Sets the text for the link to the page when separate from the title. + * + * @param string $text + */ + public function setPageLinkText( $text ) { + $this->pageLinkText = $text; + } + + /** + * + * @param boolean $link + */ + public function setLinkStyle ( $link ) { + $this->linkStyle = $link; + } + + /** + * + * @param boolean $headers + */ + public function setHeaderStyle ( $headers ) { + $this->headerStyle = $headers; + } + + /** + * @return array + */ + public function getShapes() { + $this->findShapes(); + return $this->geoShapes; + } + + /** + * @since 2.0 + */ + private function findShapes() { + while ( ( $row = $this->queryResult->getNext() ) !== false ) { + $this->handleResultRow( $row ); + } + } + + /** + * Returns the locations found in the provided result row. + * + * @param SMWResultArray[] $row + */ + private function handleResultRow( array $row ) { + $locations = []; + $properties = []; + + $title = ''; + $text = ''; + + // Loop through all fields of the record. + foreach ( $row as $i => $resultArray ) { + $printRequest = $resultArray->getPrintRequest(); + + // Loop through all the parts of the field value. + while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) { + if ( $dataValue->getTypeID() == '_wpg' && $i == 0 ) { + list( $title, $text ) = $this->handleResultSubject( $dataValue ); + } + else if ( $dataValue->getTypeID() == '_str' && $i == 0 ) { + $title = $dataValue->getLongText( $this->outputMode, null ); + $text = $dataValue->getLongText( $this->outputMode, smwfGetLinker() ); + } + else if ( $dataValue->getTypeID() == '_gpo' ) { + $dataItem = $dataValue->getDataItem(); + $polyHandler = new PolygonHandler ( $dataItem->getString() ); + $this->geoShapes[ $polyHandler->getGeoType() ][] = $polyHandler->shapeFromText(); + } else if ( strpos( $dataValue->getTypeID(), '_rec' ) !== false ) { + foreach ( $dataValue->getDataItems() as $dataItem ) { + if ( $dataItem instanceof \SMWDIGeoCoord ) { + $location = Location::newFromLatLon( $dataItem->getLatitude(), $dataItem->getLongitude() ); + $locations[] = $location; + } + } + } + else if ( $dataValue->getTypeID() != '_geo' && $i != 0 && !$this->isHeadersHide() ) { + $properties[] = $this->handleResultProperty( $dataValue, $printRequest ); + } + else if ( $printRequest->getMode() == SMWPrintRequest::PRINT_PROP && $printRequest->getTypeID() == '_geo' || $dataValue->getTypeID() == '_geo' ) { + $dataItem = $dataValue->getDataItem(); + + $location = Location::newFromLatLon( $dataItem->getLatitude(), $dataItem->getLongitude() ); + + $locations[] = $location; + } + } + } + + if ( $properties !== [] && $text !== '' ) { + $text .= $this->subjectSeparator; + } + + $icon = $this->getLocationIcon( $row ); + + $this->geoShapes['locations'] = array_merge( + $this->geoShapes['locations'], + $this->buildLocationsList( + $locations, + $text, + $icon, + $properties, + Title::newFromText( $title ) + ) + ); + } + + /** + * Handles a SMWWikiPageValue subject value. + * Gets the plain text title and creates the HTML text with headers and the like. + * + * @param SMWWikiPageValue $object + * + * @return array with title and text + */ + private function handleResultSubject( SMWWikiPageValue $object ) { + $title = $object->getLongText( $this->outputMode, null ); + $text = ''; + + if ( $this->showSubject ) { + if( !$this->showArticleLink()){ + $text = $this->hideNamespace ? $object->getText() : $object->getTitle()->getFullText(); + }else if ( !$this->titleLinkSeparate && $this->linkAbsolute ) { + $text = Html::element( + 'a', + [ 'href' => $object->getTitle()->getFullUrl() ], + $this->hideNamespace ? $object->getText() : $object->getTitle()->getFullText() + ); + } + else { + if($this->hideNamespace){ + $text = $object->getShortHTMLText(smwfGetLinker()); + }else{ + $text = $object->getLongHTMLText( smwfGetLinker() ); + } + } + + if ( $this->boldSubject ) { + $text = '' . $text . ''; + } + + if ( $this->titleLinkSeparate ) { + $txt = $object->getTitle()->getText(); + + if ( $this->pageLinkText !== '' ) { + $txt = str_replace( '$1', $txt, $this->pageLinkText ); + } + $text .= Html::element( + 'a', + [ 'href' => $object->getTitle()->getFullUrl() ], + $txt + ); + } + } + + return [ $title, $text ]; + } + + private function showArticleLink() { + return $this->linkStyle !== 'none'; + } + + private function hasTemplate() { + return is_string( $this->template ); + } + + /** + * Handles a single property (SMWPrintRequest) to be displayed for a record (SMWDataValue). + * + * @param SMWDataValue $object + * @param SMWPrintRequest $printRequest + * + * @return string + */ + private function handleResultProperty( SMWDataValue $object, SMWPrintRequest $printRequest ) { + if ( $this->hasTemplate() ) { + if ( $object instanceof SMWWikiPageValue ) { + return $object->getTitle()->getPrefixedText(); + } + + return $object->getLongText( SMW_OUTPUT_WIKI, null ); + } + + if ( $this->linkAbsolute ) { + $titleText = $printRequest->getText( null ); + $t = Title::newFromText($titleText , SMW_NS_PROPERTY ); + + if ($this->isHeadersShow() && $t instanceof Title && $t->exists() ) { + $propertyName = $propertyName = Html::element( + 'a', + [ 'href' => $t->getFullUrl() ], + $printRequest->getHTMLText( null ) + ); + } + else { + $propertyName = $titleText; + } + } + else { + if($this->isHeadersShow()){ + $propertyName = $printRequest->getHTMLText( smwfGetLinker() ); + }else if($this->isHeadersPlain()){ + $propertyName = $printRequest->getText(null); + } + } + + if ( $this->linkAbsolute ) { + $hasPage = $object->getTypeID() == '_wpg'; + + if ( $hasPage ) { + $t = Title::newFromText( $object->getLongText( $this->outputMode, null ), NS_MAIN ); + $hasPage = $t !== null && $t->exists(); + } + + if ( $hasPage ) { + $propertyValue = Html::element( + 'a', + [ 'href' => $t->getFullUrl() ], + $object->getLongText( $this->outputMode, null ) + ); + } + else { + $propertyValue = $object->getLongText( $this->outputMode, null ); + } + } + else { + $propertyValue = $object->getLongText( $this->outputMode, smwfGetLinker() ); + } + + return $propertyName . ( $propertyName === '' ? '' : ': ' ) . $propertyValue; + } + + + private function isHeadersShow() { + return $this->headerStyle === 'show'; + } + + private function isHeadersHide() { + return $this->headerStyle === 'hide'; + } + + private function isHeadersPlain() { + return $this->headerStyle === 'plain'; + } + + /** + * Builds a set of locations with the provided title, text and icon. + * + * @param Location[] $locations + * @param string $text + * @param string $icon + * @param array $properties + * @param Title|null $title + * + * @return Location[] + */ + private function buildLocationsList( array $locations, $text, $icon, array $properties, Title $title = null ) { + if ( !$this->hasTemplate() ) { + $text .= implode( '
', $properties ); + } + + $titleOutput = $this->getTitleOutput( $title ); + + foreach ( $locations as &$location ) { + if ( $this->hasTemplate() ) { + $segments = array_merge( + [ + $this->template, + 'title=' . $titleOutput, + 'latitude=' . $location->getCoordinates()->getLatitude(), + 'longitude=' . $location->getCoordinates()->getLongitude(), + 'userparam=' . $this->userParam + ], + $properties + ); + + $text .= $this->getParser()->recursiveTagParse( + '{{' . implode( '|', $segments ) . '}}' + ); + } + + $location->setTitle( $titleOutput ); + $location->setText( $text ); + $location->setIcon( $icon ); + } + + return $locations; + } + + /** + * @return \Parser + */ + private function getParser() { + return $GLOBALS['wgParser']; + } + + private function getTitleOutput( Title $title = null ) { + if ( $title === null ) { + return ''; + } + + return $this->hideNamespace ? $title->getText() : $title->getFullText(); + } + + /** + * Get the icon for a row. + * + * @param array $row + * + * @return string + */ + private function getLocationIcon( array $row ) { + $icon = ''; + $legendLabels = []; + + //Check for activeicon parameter + + if ( $this->shouldGetActiveIconUrlFor( $row[0]->getResultSubject()->getTitle() ) ){ + $icon = MapsMapper::getFileUrl( $this->activeIcon ); + } + + // Look for display_options field, which can be set by Semantic Compound Queries + // the location of this field changed in SMW 1.5 + $display_location = method_exists( $row[0], 'getResultSubject' ) ? $row[0]->getResultSubject() : $row[0]; + + if ( property_exists( $display_location, 'display_options' ) && is_array( $display_location->display_options ) ) { + $display_options = $display_location->display_options; + if ( array_key_exists( 'icon', $display_options ) ) { + $icon = $display_options['icon']; + + // This is somewhat of a hack - if a legend label has been set, we're getting it for every point, instead of just once per icon + if ( array_key_exists( 'legend label', $display_options ) ) { + + $legend_label = $display_options['legend label']; + + if ( ! array_key_exists( $icon, $legendLabels ) ) { + $legendLabels[$icon] = $legend_label; + } + } + } + } // Icon can be set even for regular, non-compound queries If it is, though, we have to translate the name into a URL here + elseif ( $this->icon !== '' ) { + $icon = MapsMapper::getFileUrl( $this->icon ); + } + + return $icon; + } + + private function shouldGetActiveIconUrlFor( Title $title ) { + global $wgTitle; + + return isset( $this->activeIcon ) && is_object( $wgTitle ) + && $wgTitle->equals( $title ); + } + + /** + * @param boolean $hideNamespace + */ + public function setHideNamespace( $hideNamespace ) { + $this->hideNamespace = $hideNamespace; + } + + /** + * @return boolean + */ + public function getHideNamespace() { + return $this->hideNamespace; + } + + /** + * @param string $activeIcon + */ + public function setActiveIcon( $activeIcon ) { + $this->activeIcon = $activeIcon; + } + + /** + * @return string + */ + public function getActiveIcon() { + return $this->activeIcon; + } + +} diff --git a/SemanticMaps/src/services/GoogleMaps3/ext.sm.googlemaps3ajax.js b/SemanticMaps/src/services/GoogleMaps3/ext.sm.googlemaps3ajax.js new file mode 100644 index 000000000..aa568abd2 --- /dev/null +++ b/SemanticMaps/src/services/GoogleMaps3/ext.sm.googlemaps3ajax.js @@ -0,0 +1,48 @@ +/** + * JavaScript for Google Maps v3 maps in the Semantic Maps extension. + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Maps + * + * @licence GNU GPL v2+ + * @author Peter Grassberger < petertheone@gmail.com > + */ + + +(function( $, sm ) { + var ajaxRequest = null; + var mapEvents = ['dragend', 'zoom_changed']; + + $( document ).ready( function() { + // todo: find a way to remove setTimeout. + setTimeout(function() { + if ( typeof google === 'undefined' ) { + return; + } + $( window.maps.googlemapsList ).each( function( index, map ) { + if (!map.options.ajaxquery || !map.options.ajaxcoordproperty) { + return; + } + $( mapEvents ).each( function( index, event ) { + google.maps.event.addListener( map.map, event, function () { + var bounds = map.map.getBounds(); + var query = sm.buildQueryString( + decodeURIComponent(map.options.ajaxquery.replace(/\+/g, ' ')), + map.options.ajaxcoordproperty, + bounds.getNorthEast().lat(), + bounds.getNorthEast().lng(), + bounds.getSouthWest().lat(), + bounds.getSouthWest().lng() + ); + + if ( ajaxRequest !== null ) { + ajaxRequest.abort(); + } + ajaxRequest = sm.ajaxUpdateMarker( map, query, map.options.icon ).done( function () { + map.createMarkerCluster(); + ajaxRequest = null; + } ); + } ); + } ); + } ); + }, 500 ); + } ); +})( window.jQuery, window.sm ); diff --git a/SemanticMaps/src/services/Leaflet/ext.sm.leafletajax.js b/SemanticMaps/src/services/Leaflet/ext.sm.leafletajax.js new file mode 100644 index 000000000..ebb671b9a --- /dev/null +++ b/SemanticMaps/src/services/Leaflet/ext.sm.leafletajax.js @@ -0,0 +1,44 @@ +/** + * JavaScript for Leaflet in the Semantic Maps extension. + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Maps + * + * @licence GNU GPL v2+ + * @author Peter Grassberger < petertheone@gmail.com > + */ + + +(function( $, sm ) { + var ajaxRequest = null; + + var mapEvents = ['dragend', 'zoomend']; + + $( document ).ready( function() { + // todo: find a way to remove setTimeout. + setTimeout(function() { + $( window.maps.leafletList ).each( function( index, map ) { + if (!map.options.ajaxquery || !map.options.ajaxcoordproperty) { + return; + } + map.map.on( mapEvents.join( ' ' ), function() { + var bounds = map.map.getBounds(); + var query = sm.buildQueryString( + decodeURIComponent(map.options.ajaxquery.replace(/\+/g, ' ')), + map.options.ajaxcoordproperty, + bounds.getNorthEast().lat, + bounds.getNorthEast().lng, + bounds.getSouthWest().lat, + bounds.getSouthWest().lng + ); + + if ( ajaxRequest !== null ) { + ajaxRequest.abort(); + } + ajaxRequest = sm.ajaxUpdateMarker( map, query, map.options.icon ).done( function () { + map.createMarkerCluster(); + ajaxRequest = null; + } ); + } ); + } ); + }, 1000 ); + } ); +})( window.jQuery, window.sm ); diff --git a/SemanticMaps/src/services/OpenLayers/ext.sm.openlayersajax.js b/SemanticMaps/src/services/OpenLayers/ext.sm.openlayersajax.js new file mode 100644 index 000000000..f4813af3e --- /dev/null +++ b/SemanticMaps/src/services/OpenLayers/ext.sm.openlayersajax.js @@ -0,0 +1,41 @@ +/** + * JavaScript for OpenLayers maps in the Semantic Maps extension. + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Maps + * + * @licence GNU GPL v2+ + * @author Peter Grassberger < petertheone@gmail.com > + */ + + +(function( $, sm ) { + var ajaxRequest = null; + + $( document ).ready( function() { + // todo: find a way to remove setTimeout. + setTimeout(function() { + $( window.maps.openlayersList ).each( function( index, map ) { + if (!map.options.ajaxquery || !map.options.ajaxcoordproperty) { + return; + } + map.map.events.register( 'moveend', map.map, function () { + var bounds = map.map.getExtent().transform(map.map.projection, map.map.displayProjection); + var query = sm.buildQueryString( + decodeURIComponent(map.options.ajaxquery.replace(/\+/g, ' ')), + map.options.ajaxcoordproperty, + bounds.top, + bounds.right, + bounds.bottom, + bounds.left + ); + + if ( ajaxRequest !== null ) { + ajaxRequest.abort(); + } + ajaxRequest = sm.ajaxUpdateMarker( map, query, map.options.icon ).done( function () { + ajaxRequest = null; + } ); + } ); + } ); + }, 500 ); + } ); +})( window.jQuery, window.sm ); diff --git a/build/travis/after_success.sh b/build/travis/after_success.sh deleted file mode 100644 index 62e3bd6c9..000000000 --- a/build/travis/after_success.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/bash - -set -x - -originalDirectory=$(pwd) - -if [ "$TYPE" == "coverage" ] -then - wget https://scrutinizer-ci.com/ocular.phar - du -hs $originalDirectory/build/coverage.clover - ls -lap $originalDirectory - ls -lap $originalDirectory/build - php ocular.phar code-coverage:upload --format=php-clover $originalDirectory/build/coverage.clover -fi \ No newline at end of file diff --git a/build/travis/script.sh b/build/travis/script.sh deleted file mode 100644 index 67f3b4bca..000000000 --- a/build/travis/script.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/bash - -set -x - -originalDirectory=$(pwd) - -cd ../phase3/tests/phpunit - -if [ "$TYPE" == "coverage" ] -then - php phpunit.php --group Maps -c ../../extensions/Maps/phpunit.xml.dist --coverage-clover $originalDirectory/build/coverage.clover -else - php phpunit.php --group Maps -c ../../extensions/Maps/phpunit.xml.dist -fi \ No newline at end of file diff --git a/composer.json b/composer.json index 084b8ea40..8226c7615 100644 --- a/composer.json +++ b/composer.json @@ -6,9 +6,13 @@ "MediaWiki", "Semantic MediaWiki", "Maps", + "Semantic Maps", "Google Maps", "OpenLayers", "OSM", + "Leaflet", + "Geocode", + "Geocoding", "OpenStreetMap" ], "homepage": "https://github.com/JeroenDeDauw/Maps", @@ -27,32 +31,55 @@ "source": "https://github.com/JeroenDeDauw/Maps" }, "require": { - "php": ">=5.3.2", + "php": ">=5.6", "composer/installers": "^1.0.1", - "mediawiki/validator": "^2.0.2", - "data-values/geo": "~1.0" + "mediawiki/validator": "~2.2", + "data-values/geo": "~2.0", + "jeroen/file-fetcher": "~3.1|~4.0", + "jeroen/simple-cache": "~2.0" + }, + "require-dev": { + "data-values/common": "~0.3.1", + "phpunit/phpunit": "~3.7" }, "autoload": { "files" : [ "Maps.php" ], "psr-4": { - "Maps\\": "src/Maps/" + "Maps\\": "src/" }, "classmap": [ "includes/", - "Maps.hooks.php" + "Maps.hooks.php", + "SemanticMaps/src/", + "SemanticMaps/SemanticMaps.hooks.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Maps\\Tests\\TestDoubles\\": "tests/TestDoubles/" + }, + "classmap": [ + "tests/Unit/Elements/", + "tests/Integration/parserhooks/ParserHookTest.php" ] }, "extra": { "branch-alias": { - "dev-master": "3.5.x-dev" + "dev-master": "4.3.x-dev" } }, + "replace": { + "mediawiki/semantic-maps": "*" + }, + "suggest": { + "mediawiki/semantic-media-wiki": "Add, edit, aggregate and visualize structured coordinate data stored with Semantic MediaWiki" + }, "config": { "process-timeout": 0 }, "scripts":{ - "phpunit": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist" + "ci": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist" } } diff --git a/i18n/ast.json b/i18n/ast.json index 184f0ee12..b58792fe8 100644 --- a/i18n/ast.json +++ b/i18n/ast.json @@ -39,7 +39,6 @@ "maps-layer-type-supported-by": "Esta triba de capa pue emplegase {{PLURAL:$2|namái col serviciu de mapes $1|con estos servicios de mapes: $1}}.", "maps-coordinates-description": "Asociador del analizador pa dar formatu a les coordenaes, dende y a cualesquiera de los formatos sofitaos.", "maps-displaymap-description": "Amosar mapes xeográficos ensin dengún marcador definíu na wiki nellos.", - "maps-displaypoint-description": "Amosar mapes xeográficos con unu o más marcadores definíos na wiki nellos.", "maps-distance-description": "Convertir una distancia usando cierta unidá sofitada al equivalente utilizando otra unidá.", "maps-finddestination-description": "Alcontrar un destín dende un puntu de partida (que pue tar en cualesquiera de los formatos compatibles), una orientación inicial y una distancia.", "maps-geocode-description": "Activa la xeocodificación de direiciones; n'otres pallabres, tresformar llugares lleíbles por humanos en conxuntos de coordenaes. Hai sofitu pa dellos servicios de xeocodificación, que nun tienen de confundise con servicios de mapes.", @@ -93,7 +92,6 @@ "maps-displaymap-par-wmsoverlay": "Usar una superposición WMS", "maps-fullscreen-button": "Conmutar pantalla completa", "maps-fullscreen-button-tooltip": "Ver el mapa como pantalla completa o incrustáu.", - "maps-googlemaps3-par-enable-fullscreen": "Activar el botón de pantalla completa", "validation-error-invalid-location": "El parámetru $1 tien de ser un llugar válidu.", "validation-error-invalid-locations": "El parámetru $1 tien de ser un o más llugares válidos.", "validation-error-invalid-width": "El parámetru $1 tien de ser un anchor válidu.", @@ -119,6 +117,11 @@ "maps_map_cannot_be_displayed": "Nun se pue amosar el mapa.", "maps-geocoder-not-available": "La carauterística de xeocodificación de mapes nun ta disponible. Nun se pue xeocodificar la to situación.", "maps_leaflet": "Leaflet", + "maps-leaflet-par-defzoom": "Permite configurar el nivel predetermináu d'ampliación del mapa.", + "maps-leaflet-par-layer": "La capa que va apaecer cuando se cargue'l mapa.", + "maps-leaflet-par-overlaylayers": "Les capas sobrepuestes qu'apaecerán cuando se cargue'l mapa.", + "maps-leaflet-par-maxclusterradius": "El radiu máximu que cubrirá un grupu dende'l marcador central (en pixels).", + "maps-leaflet-par-clusterspiderfy": "Cuando faes click nun grupu al mínimu d'ampliación, espardémoslu pa que puedan vese los marcadores.", "maps_click_to_activate": "Calca p'activar el mapa", "maps_centred_on": "Mapa centráu en $1, $2.", "maps-par-mappingservice": "Permite configurar el serviciu de mapes que s'usará pa xenerar el mapa.", @@ -129,9 +132,11 @@ "maps-par-width": "Permite configurar l'anchor del mapa. De mou predetermináu s'asume el pixel como unidá, pero se pue conseñar esplícitamente una d'estes unidaes: px, ex, em, %.", "maps-par-height": "Permite configurar l'altor del mapa. De mou predetermináu s'asume el pixel como unidá, pero se pue conseñar esplícitamente una d'estes unidaes: px, ex, em, %.", "maps-par-centre": "El llugar nel que se tien de centrar el mapa", + "maps-par-enable-fullscreen": "Activar el botón de pantalla completa", + "maps-par-kml": "Ficheros KML a cargar nel mapa.", + "maps-par-markercluster": "Permite fusionar múltiples marcadores cercanos nun solu marcador", "maps-googlemaps3-incompatbrowser": "El to navegador nun ye compatible con Google Maps v3.", "maps-googlemaps3-par-imageoverlays": "Permite amestar una imaxe p'amosala nel llugar especificáu del mapa.", - "maps-googlemaps3-par-markercluster": "Permite fusionar múltiples marcadores cercanos nun solu marcador", "maps-googlemaps3-par-type": "El tipu de mapa a amosar inicialmente.", "maps-googlemaps3-par-types": "Los tipos de mapa que tarán disponibles al traviés del control de tipu.", "maps-googlemaps3-par-layers": "Capes especiales a cargar nel mapa.", @@ -139,17 +144,20 @@ "maps-googlemaps3-par-zoomstyle": "El estilu del control de zoom.", "maps-googlemaps3-par-typestyle": "El estilo del control de tipu.", "maps-googlemaps3-par-autoinfowindows": "Abrir automáticamente toles ventanes d'información dempués de que se cargue la páxina.", - "maps-googlemaps3-par-kml": "Ficheros KML a cargar nel mapa.", "maps-googlemaps3-par-gkml": "Ficheros KML agospiaos por Google a cargar nel mapa.", "maps-googlemaps3-par-fusiontables": "IDs de les tables de Google Fusion que tienen de cargase nel mapa.", "maps-googlemaps3-par-tilt": "Inclinación del mapa al usar Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Axustar el nivel de zoom dempués de que carguen les capes KML.", "maps-googlemaps3-par-poi": "Amosar puntos d'interés.", + "maps-googlemaps3-par-clustergridsize": "La midida de rexa d'un grupu en píxeles.", + "maps-par-clustermaxzoom": "El nivel máximu d'ampliación nel que pueden esistir grupos.", + "maps-par-clusterzoomonclick": "Si'l comportamientu predetermináu al facer click nun grupu ye amplialu.", + "maps-par-maxclusterradius": "El radiu máximu que cubrirá un cluster.", + "maps-googlemaps3-par-clusteraveragecenter": "Si'l centru de cada grupu tien de ser la media de tolos marcadores del grupu.", + "maps-googlemaps3-par-clusterminsize": "El númberu mínimu de marcadores que tán nun grupu primero que se despinten los marcadores y s'amuese un recuentu.", "maps-openlayers-par-controls": "Controles a poner nel mapa.", "maps-openlayers-par-layers": "Les capes que tarán disponibles nel selector de capes. La primera capa s'amosará al cargar el mapa.", "maps-openlayers-par-overlays": "Capes superpuestes que tarán disponibles nel selector de capes. Eses capes veránse enriba d'una capa normal, de mou asemeyáu a un marcador.", - "maps-osm-par-thumbs": "Amosar miniatures", - "maps-osm-par-photos": "Amosar les fotos", "mapeditor": "Editor de mapes", "specialpages-group-maps": "Mapes", "mapeditor-parser-error": "Hebo un error al analizar los metadatos. Inorando la entrada d'usuariu.", @@ -185,5 +193,42 @@ "mapeditor-imageoverlay-button": "Amestar superposición d'imaxe", "mapeditor-form-field-image": "Imaxe", "mapeditor-imageoverlay-title": "Detalles de superposición d'imaxe", - "mapeditor-form-field-visitedicon": "Iconu visitáu" + "mapeditor-form-field-visitedicon": "Iconu visitáu", + "semanticmaps-unrecognizeddistance": "El valor $1 nun ye una distancia válida.", + "semanticmaps-kml-link": "Ver el ficheru KML", + "semanticmaps-default-kml-pagelink": "Ver la páxina \"$1\"", + "semanticmaps-latitude": "Llatitú: $1", + "semanticmaps-longitude": "Llonxitú: $1", + "semanticmaps-altitude": "Altitú: $1", + "semanticmaps-forminput-locations": "Llugares", + "semanticmaps-par-staticlocations": "Llista de llugares p'amestar al mapa xunto colos datos consultaos. Como con display_points, pues amestar un títulu, una descripción y un iconu pa cada llugar usando'l signu \"~\" como separador.", + "semanticmaps-par-showtitle": "Amosar o non un títulu na ventana d'información del marcador. De vezu, desactivalo ye útil cuando s'utiliza una plantía pa dar formatu al conteníu de la ventana d'información.", + "semanticmaps-par-hidenamespace": "Amosar el títulu del espaciu de nomes na ventana d'información del marcador.", + "semanticmaps-par-centre": "El centru del mapa. Cuando nun se proporciona, el mapa escoyerá automáticamente'l meyor centru p'amosar tolos marcadores del mapa.", + "semanticmaps-par-template": "Una plantía que s'utiliza pa dar formatu al conteníu de la ventana d'información.", + "semanticmaps-par-geocodecontrol": "Amosar el control de xeocodificación.", + "semanticmaps-par-activeicon": "Iconu a amosar en llugar del marcador predetermináu, cuando la páxina activa ye igual al resultáu de la consulta", + "semanticmaps-par-pagelabel": "Cuando se pon a \"si\", tolos marcadores tendrán una \"inlineLabel\" con un enllaz a la páxina que contien les coordenaes del marcador", + "semanticmaps-par-ajaxcoordproperty": "Nome de la propiedá de coordenaes que s'usa pa construir la consulta ajax.", + "semanticmaps-par-ajaxquery": "Una segunda consulta que s'unvia con ajax para recuperar otres coordenaes más.", + "semanticmaps-par-userparam": "Un valor pasáu en cada llamada de plantía,si s'usa una plantía", + "semanticmaps-kml-text": "El testu asociáu con cada páxina. Sustituyíu poles otres propiedaes consultaes, si esisten.", + "semanticmaps-kml-title": "El títulu predetermináu pa los resultaos", + "semanticmaps-kml-linkabsolute": "Si los títulos tienen de ser absolutos (lo contrario de relativos)", + "semanticmaps-kml-pagelinktext": "El testu a usar pa los enllaces a la páxina, onde \"$1\" se sustituye pol títulu de la páxina", + "semanticmaps-shapes-improperformat": "Formatu incorreutu de $1. Por favor, consulta la documentación sobre formatos", + "semanticmaps-shapes-missingshape": "Nun s'alcontraron formes pa $1. Por favor, consulta la documentación de les formes disponibles", + "validator-type-mapscircle": "Círculu xeográficu", + "validator-type-mapscircle-list": "Llista de círculos", + "validator-type-mapsimageoverlay": "Superposición d'imaxen", + "validator-type-mapsimageoverlay-list": "Lista de superposiciones d'imaxen", + "validator-type-mapsline": "Llinia xeográfica", + "validator-type-mapsline-list": "Llista de llinies", + "validator-type-mapslocation": "Allugamientu xeográficu", + "validator-type-mapslocation-list": "Llista d'allugamientos", + "validator-type-mapsrectangle": "Rectángulu xeográficu", + "validator-type-mapsrectangle-list": "Llista de rectángulos", + "validator-type-mapspolygon": "Polígonu xeográficu", + "validator-type-mapspolygon-list": "Llista de polígonos xeográficos", + "validator-type-wmsoverlay": "Superposición de Serviciu de Mapes web" } diff --git a/i18n/be-tarask.json b/i18n/be-tarask.json index 3da66ff08..60eb49c56 100644 --- a/i18n/be-tarask.json +++ b/i18n/be-tarask.json @@ -5,7 +5,8 @@ "Jim-by", "Wizardist", "Red Winged Duck", - "Macofe" + "Macofe", + "Renessaince" ] }, "maps-desc": "Забясьпечвае магчымасьць убудаваньня дынамічных мапаў у вікі-старонкі, геаграфічнага кадаваньня адрасоў і іншыя геаграфічныя апэрацыі", @@ -30,7 +31,6 @@ "maps-layer-type-supported-by": "Гэты тып слою можа быць выкарыстаны толькі з {{PLURAL:$2|1=сэрвісам мапаў $1|сэрвісамі мапаў: $1}}.", "maps-coordinates-description": "Перахопнік парсэру для фарматаваньня каардынатаў, з і ў любыя фарматы, якія падтрымліваюцца.", "maps-displaymap-description": "Паказвае геаграфічныя мапы без аніякіх вікі-пазнакаў на іх.", - "maps-displaypoint-description": "Паказвае геаграфічныя мапы з адной ці болей вікі-пазнакамі на іх.", "maps-distance-description": "Канвэртуе адлегласьць выкарыстоўваючы адзінкі, якія падтрымліваюцца, ў іх эквівалент, выкарыстоўваючы іншыя адзінкі.", "maps-finddestination-description": "Знаходзіць пункт прызначэньня з пададзенага пачатковага пункту (можа быць у любым фармаце, якія падтрымліваюцца), пачатковага напрамку і адлегласьці.", "maps-geocode-description": "Уключае геаграфічную кадыроўку адрасу, іншымі словамі, пераўтварае чытальнае для чалавека знаходжаньне ў набор каардынатаў. Тут ёсьць падтрымка для некалькіх сэрвісаў геаграфічнай кадыроўкі, якія не павінны быць блытаныя з сэрвісамі мапаў.", @@ -102,6 +102,7 @@ "maps-par-zoom": "Маштаб мапы. Для мапаў з пазначэньнямі маштаб будзе такім, пры якім яшчэ будуць паказвацца ўсе пазначэньні.", "maps-par-width": "Дазваляе наладжваць шырыню мапы. Па змоўчваньні піксэлі выкарыстоўваюцца як адзінкі вымярэньня, але Вы можаце непасрэдна вызначыць адну з гэтых адзінак вымярэньня: px, ex, em, %.", "maps-par-height": "Дазваляе наладжваць вышыню мапы. Па змоўчваньні піксэлі выкарыстоўваюцца як адзінкі вымярэньня, але Вы можаце непасрэдна вызначыць адну з гэтых адзінак вымярэньня: px, ex, em, %.", + "maps-par-kml": "KML-файлы для загрузкі ў мапу.", "maps-googlemaps3-incompatbrowser": "Ваш браўзэр не сумяшчальны з Google Maps v3.", "maps-googlemaps3-par-type": "Тып мапы, які будзе паказвацца ў пачатку.", "maps-googlemaps3-par-types": "Тыпы мапаў, якія будуць даступныя праз элемэнт кіраваньня тыпамі.", @@ -110,7 +111,6 @@ "maps-googlemaps3-par-zoomstyle": "Стыль элемэнта кіраваньня маштабам.", "maps-googlemaps3-par-typestyle": "Стыль элемэнта кіраваньня тыпамі.", "maps-googlemaps3-par-autoinfowindows": "Аўтаматычна адкрываць ўсе інфармацыйныя вокны, пасьля таго, як старонка была загружаная.", - "maps-googlemaps3-par-kml": "KML-файлы для загрузкі ў мапу.", "maps-googlemaps3-par-gkml": "Файлы KML разьмешчаныя на Google для загрузкі на мапу.", "maps-googlemaps3-par-fusiontables": "Ідэнтыфікатары табліцаў Google Fusion, якія павінны быць загружаныя ў мапу.", "maps-googlemaps3-par-tilt": "Вугал нахілу мапы, падчас выкарыстаньня Google Maps.", @@ -118,8 +118,6 @@ "maps-googlemaps3-par-poi": "Паказаць выбітныя мясьціны.", "maps-openlayers-par-controls": "Элемэнты кіраваньня, якія будуць разьмешчаныя на мапе.", "maps-openlayers-par-layers": "Слаі, якія будуць даступныя падчас выбару слаёў. Першы слой будзе паказаны пасьля загрузкі мапы.", - "maps-osm-par-thumbs": "Паказваць мініятуры", - "maps-osm-par-photos": "Паказваць выявы", "mapeditor": "Рэдактар мап", "specialpages-group-maps": "Мапы", "mapeditor-parser-error": "У час разбору мэтазьвестак адбылася памылка. Ігнаруем уведзеныя зьвесткі.", @@ -155,5 +153,14 @@ "mapeditor-imageoverlay-button": "Накласьці выяву", "mapeditor-form-field-image": "Выява", "mapeditor-imageoverlay-title": "Накладаньне выявы", - "mapeditor-form-field-visitedicon": "Значак для наведанага" + "mapeditor-form-field-visitedicon": "Значак для наведанага", + "semanticmaps-unrecognizeddistance": "Значэньне $1 — няслушная адлегласьць.", + "semanticmaps-kml-link": "Паказаць KML-файл", + "semanticmaps-default-kml-pagelink": "Паказаць старонку $1", + "semanticmaps-forminput-locations": "Месцы", + "semanticmaps-par-staticlocations": "Сьпіс месцазнаходжаньняў для даданьня на мапу разам з запытанымі зьвесткамі. Напрыклад, разам з «display_points», Вы можаце дадаць назву, апісаньне і мініятуру для месцазнаходжаньня з дапамогай сымбаля «~» у якасьці разьдзяляльніка.", + "semanticmaps-par-showtitle": "Паказваць назву ў акне інфармацыі пра маркер ці не. Адключэньне гэтай функцыі часта карыснае падчас выкарыстаньня шаблёну для фарматаваньня зьместу акна інфармацыі.", + "semanticmaps-par-centre": "Цэнтар мапы. Калі ён не пададзены, мапа будзе аўтаматычна выбіраць аптымальны цэнтар для паказу ўсіх маркераў.", + "semanticmaps-par-template": "Шаблён для фарматаваньня зьместу акна інфармацыі.", + "semanticmaps-par-geocodecontrol": "Паказаць элемэнты кіраваньня геаграфічным кадаваньнем." } diff --git a/i18n/bn.json b/i18n/bn.json index 32c2b6697..793e43228 100644 --- a/i18n/bn.json +++ b/i18n/bn.json @@ -2,29 +2,110 @@ "@metadata": { "authors": [ "Tauhid16", - "Wikitanvir" + "Wikitanvir", + "Aftabuzzaman", + "আজিজ" ] }, + "right-geocode": "জিওকোড", + "action-geocode": "এই উইকিতে জিওকোডিং করুন", "maps_map": "মানচিত্র", "maps-loading-map": "মানচিত্র লোড করা হচ্ছে...", "maps-load-failed": "মানচিত্র লোড করা সম্ভব হয়নি!", + "maps-markers": "চিহ্নিতকারী", + "maps-copycoords-prompt": "CTRL+C, ENTER", + "maps-searchmarkers-text": "ছাকনি চিহ্নিতকারী", "maps-others": "অন্যান্য", - "maps-ns-layer": "পর্ব", - "maps-ns-layer-talk": "পর্ব আলোচনা", + "maps-kml-parsing-failed": "একটি অথবা আরও বেশি KML ফাইল পদান্বয় ব্যর্থ। সাধারণত এটি আহরণ ব্যর্থতা বা ত্রুটিপূর্ণ XML-এর কারণে ঘটে।", + "maps-ns-layer": "স্তর", + "maps-ns-layer-talk": "স্তর আলোচনা", "maps-layer-property": "সম্পত্তি", "maps-layer-value": "মান", "maps-layer-errors": "ত্রুটি", + "maps-layerdef-invalid": "অবৈধ {{PLURAL:$1|সংজ্ঞা}}", + "maps-layerdef-invalid-fatal": "ধ্বংসাত্মক অবৈধ সংজ্ঞা", + "maps-layerdef-wrong-namespace": "স্তর সজ্ঞা শুধুমাত্র \"$1\" নামস্থান পাতাসমূহে বৈধ", + "maps-layerdef-equal-layer-name": "স্তরের নামসমূহ একই স্তর পৃষ্ঠার মধ্যে অনন্য হওয়া আবশ্যক। \"$1\" ইতিমধ্যে আরেকটি স্তর দ্বারা ব্যবহৃত হয়েছে।", + "maps-layerpage-usage": "\"$1\" স্তর ব্যবহৃত মানচিত্র সহ পৃষ্ঠাসমূহ", + "maps-layerpage-nousage": "এই মুহূর্তে কোন পৃষ্ঠায় এই স্তরটি ব্যবহার হয়নি।", + "maps-error-invalid-layertype": "সেখানে \"$1\" ধরনের কোন স্তর নেই। শুধু {{PLURAL:$3|এই ধরনের}} স্তর সমর্থিত হবে: $2", + "maps-error-no-layertype": "আপনাকে স্তরের ধরন নির্দিষ্ট করতে হবে। শুধু {{PLURAL:$2|এই ধরনের}} স্তর সমর্থিত: $1", + "validation-error-invalid-layer": "\"$1\" পরামিতি অবশ্যই বৈধ স্তর হতে হবে।", + "validation-error-invalid-layers": "\"$1\" পরামিতি অবশ্যই এক বা একাধিক বৈধ স্তর হতে হবে।", + "validation-error-no-non-numeric": "\"$1\" পরামিতি অবশ্যই অ-সাংখ্যিক স্ট্রিং হতে হবে।", + "validation-error-no-non-numerics": "\"$1\" পরামিতি অবশ্যই এক বা একাধিক অ-সাংখ্যিক স্ট্রিং হতে হবে।", "maps-layer-of-type": "\"$1\" ধরণের লেয়ার", + "maps-layer-of-type-and-name": "\"$2\" স্তরটি \"$1\" ধরণের", + "maps-finddestination-par-location": "প্রারম্ভিক অবস্থান", + "maps-finddestination-par-distance": "ভ্রমণ করার ব্যবধান", "validation-error-invalid-location": "স্থিতিমাপ \"$1\" একটি বৈধ অবস্থান হতে হবে।", + "validation-error-invalid-locations": "\"$1\" পরামিতি অবশ্যই এক বা একাধিক বৈধ অবস্থান হতে হবে।", + "validation-error-invalid-width": "\"$1\" পরামিতি অবশ্যই বৈধ প্রস্থ বিশিষ্ঠ হতে হবে।", + "validation-error-invalid-height": "\"$1\" পরামিতি অবশ্যই বৈধ উচ্চতা বিশিষ্ঠ হতে হবে।", + "validation-error-invalid-distance": "\"$1\" পরামিতি অবশ্যই বৈধ দূরত্ব বিশিষ্ঠ হতে হবে।", + "validation-error-invalid-distances": "\"$1\" পরামিতি অবশ্যই এক বা একাধিক বৈধ দূরত্ব বিশিষ্ঠ হতে হবে।", + "validation-error-invalid-image": "\"$1\" পরামিতি অবশ্যই বৈধ চিত্র যুক্ত হতে হবে।", + "validation-error-invalid-images": "\"$1\" পরামিতি অবশ্যই এক বা একাধিক বৈধ চিত্র যুক্ত হতে হবে।", + "validation-error-invalid-goverlay": "\"$1\" পরামিতি অবশ্যই বৈধ আচ্ছদন হতে হবে।", + "validation-error-invalid-goverlays": "\"$1\" পরামিতি অবশ্যই এক বা একাধিক বৈধ আচ্ছদন হতে হবে।", "maps-abb-north": "উ", "maps-abb-east": "পূ", "maps-abb-south": "দ", "maps-abb-west": "প", "maps-latitude": "অক্ষাংশ:", "maps-longitude": "দ্রাঘিমাংশ:", + "maps_coordinates_missing": "মানচিত্রের জন্য স্থানাঙ্ক প্রদান করা হয়নি।", "maps_map_cannot_be_displayed": "এই মানচিত্রটি প্রদর্শন করা সম্ভব নয়।", + "maps-geocoder-not-available": "মানচিত্রে জিওকোডিং বৈশিষ্টটি উপলব্ধ নয়। আপনার অবস্থান জিওকোডেড করা যাবে না।", + "maps_leaflet": "প্রচারপত্র", "maps_click_to_activate": "মানচিত্র চালু করতে ক্লিক করুন", "maps_centred_on": "মানচিত্র $1, $2-এ কেন্দ্রীভূত।", - "maps-osm-par-thumbs": "থাম্ব দেখাও", - "maps-osm-par-photos": "ছবি দেখাও" + "maps-googlemaps3-par-poi": "আগ্রহের বিষয়সমূহ দেখাও।", + "mapeditor": "মানচিত্র সম্পাদক", + "specialpages-group-maps": "মানচিত্র", + "mapeditor-parser-error": "মেটাডেটা বিশ্লেষণ করার সময় একটি ত্রুটি ঘটেছে। ব্যবহারকারীর ইনপুট উপেক্ষা করা হয়েছে।", + "mapeditor-none-text": "কিছু নয়", + "mapeditor-done-button": "সম্পন্ন", + "mapeditor-remove-button": "সরান", + "mapeditor-import-button2": "আমদানি", + "mapeditor-export-button": "উইকি কোডে রপ্তানি করুন", + "mapeditor-import-button": "উইকি কোড থেকে আমদানি করুন", + "mapeditor-select-button": "এই বহুভুজ নির্বাচন করুন", + "mapeditor-mapparam-button": "মানচিত্রের পরামিতিগুলো সম্পাদনা করুন", + "mapeditor-clear-button": "মানচিত্র সাফ করুন", + "mapeditor-code-title": "উইকি কোড", + "mapeditor-import-title": "উইকি কোড আমদানি করুন", + "mapeditor-form-title": "তথ্য সংশোধন করুন", + "mapeditor-link-title-switcher-link-text": "সংযোগ", + "mapeditor-form-field-title": "শিরোনাম", + "mapeditor-form-field-text": "লেখা", + "mapeditor-form-field-link": "সংযোগ", + "mapeditor-form-field-icon": "আইকন", + "mapeditor-form-field-group": "দল", + "mapeditor-form-field-strokecolor": "রেখার রং", + "mapeditor-form-field-strokeopacity": "রেখার অস্পষ্টতা", + "mapeditor-form-field-strokeweight": "রেখার প্রস্থ", + "mapeditor-mapparam-title": "মানচিত্রের পরামিতিগুলো সম্পাদনা করুন", + "mapeditor-mapparam-defoption": "-পরামিতি বাছাই করুন-", + "mapeditor-imageoverlay-button": "চিত্র আচ্ছাদন যোগ করুন", + "mapeditor-form-field-image": "চিত্র", + "mapeditor-imageoverlay-title": "চিত্র আচ্ছদনের খুঁটিনাটি", + "semanticmaps-kml-link": "কেএমএল ফাইল দেখাও", + "semanticmaps-default-kml-pagelink": "$1 পাতা প্রদর্শন করো", + "semanticmaps-latitude": "অক্ষাংশ: $1", + "semanticmaps-longitude": "দ্রাঘিমাংশ: $1", + "semanticmaps-altitude": "উচ্চতা: $1", + "semanticmaps-forminput-locations": "অবস্থান", + "validator-type-mapscircle": "ভৌগলিক বৃত্ত", + "validator-type-mapscircle-list": "বৃত্তের তালিকা", + "validator-type-mapsimageoverlay": "চিত্র প্রতিস্থাপক", + "validator-type-mapsimageoverlay-list": "চিত্র প্রতিস্থাপকের তালিকা", + "validator-type-mapsline": "ভৌগলিক রেখা", + "validator-type-mapsline-list": "রেখার তালিকা", + "validator-type-mapslocation": "ভৌগলিক অবস্থান", + "validator-type-mapslocation-list": "অবস্থানগুলির তালিকা", + "validator-type-mapsrectangle": "ভৌগলিক আয়তক্ষেত্র", + "validator-type-mapsrectangle-list": "আয়তক্ষেত্রের তালিকা", + "validator-type-mapspolygon": "ভৌগলিক বহুভুজ", + "validator-type-mapspolygon-list": "ভৌগলিক বহুভুজের তালিকা" } diff --git a/i18n/br.json b/i18n/br.json index accde547a..3035ad900 100644 --- a/i18n/br.json +++ b/i18n/br.json @@ -47,7 +47,6 @@ "maps-displaymap-par-rectangles": "Hirgarrezennoù da ziskwel", "maps-displaymap-par-static": "Lakaat ar gartenn da vezañ statek", "maps-fullscreen-button": "Gweredekaat ar skramm leun", - "maps-googlemaps3-par-enable-fullscreen": "Gweredekaat ar bouton skramm leun", "validation-error-invalid-location": "Rankout a ra an arventenn $1 bezañ evit ul lec'hiadur reizh.", "validation-error-invalid-locations": "Rankout a ra an arventenn $1 bezañ evit ul lec'hiadur reizh, da nebeutañ.", "validation-error-invalid-width": "Rankout a ra an arventenn $1 bezañ evit ul ledander reizh.", @@ -72,8 +71,11 @@ "maps_unrecognized_coords_for": "N'eo ket bet anavezet an {{PLURAL:$2|daveenn|daveennoù}} da-heul ha {{PLURAL:$2|n'eo|n'int}} ket bet lakaet war ar gartenn :\n$1", "maps_map_cannot_be_displayed": "N'hall ket ar gartenn bezañ diskwelet.", "maps-geocoder-not-available": "N'haller ket ober gant arc'hwel geokodañ ar c'hartennoù. N'haller ket geokodañ ho lec'hiadur.", + "maps_leaflet": "Plegfollenn", "maps_click_to_activate": "Klikañ evit gweredekaat ar gartenn", "maps_centred_on": "Kartenn kreizet war $1, $2.", + "maps-par-enable-fullscreen": "Gweredekaat ar bouton skramm leun", + "maps-par-kml": "Restroù KML da gargañ war ar gartenn.", "maps-googlemaps3-incompatbrowser": "N'eo ket kenglotus ho merdeer gant Google Maps v3.", "maps-googlemaps3-par-type": "Ar seurt kartenn da ziskouez da gentañ.", "maps-googlemaps3-par-layers": "Gwiskadoù arbennik da gargañ war ar gartenn.", @@ -81,11 +83,8 @@ "maps-googlemaps3-par-zoomstyle": "Stil kontroll ar zoum.", "maps-googlemaps3-par-typestyle": "Stil kontroll ar seurt.", "maps-googlemaps3-par-autoinfowindows": "Digeriñ an holl brenestroù diouzhtu goude bezañ karget ar bajenn.", - "maps-googlemaps3-par-kml": "Restroù KML da gargañ war ar gartenn.", "maps-googlemaps3-par-poi": "Diskouez al lec'hioù dudius.", "maps-openlayers-par-controls": "Ar c'hontrolloù da lakaat war ar gartenn.", - "maps-osm-par-thumbs": "Diskouez ar munudoù", - "maps-osm-par-photos": "Diskouez ar skeudennoù", "mapeditor": "Aozer kartennoù", "specialpages-group-maps": "Kartennoù", "mapeditor-none-text": "Hini ebet", @@ -109,5 +108,22 @@ "mapeditor-mapparam-title": "Kemmañ arventennoù ar gartenn", "mapeditor-mapparam-defoption": "-Diuzañ un arventenn-", "mapeditor-form-field-image": "Skeudenn", - "mapeditor-form-field-visitedicon": "Arlun gweladennet" + "mapeditor-form-field-visitedicon": "Arlun gweladennet", + "semanticmaps-unrecognizeddistance": "An talvoud $1 n'eo ket un hed reizh anezhañ.", + "semanticmaps-kml-link": "Gwelet ar restr KML", + "semanticmaps-default-kml-pagelink": "Gwelet ar pennad $1", + "semanticmaps-latitude": "Ledred : $1", + "semanticmaps-longitude": "Hedred : $1", + "semanticmaps-altitude": "Uhelder : $1", + "semanticmaps-forminput-locations": "Lec'hiadurioù", + "semanticmaps-par-template": "Ur patrom d'ober gantañ da furmadiñ boued ar prenestr titouriñ.", + "semanticmaps-kml-title": "Titl dre ziouer evit an disoc'hoù", + "validator-type-mapscircle": "Kelc'h douaroniel", + "validator-type-mapscircle-list": "Roll kelc'hioù", + "validator-type-mapsline": "Linenn zouaroniel", + "validator-type-mapsline-list": "Roll linennoù", + "validator-type-mapslocation": "Lec'hiadur douaroniel", + "validator-type-mapslocation-list": "Roll lec'hiadurioù", + "validator-type-mapsrectangle": "Higarrezenn zouaroniel", + "validator-type-mapsrectangle-list": "Roll hirgarrezennoù" } diff --git a/i18n/cs.json b/i18n/cs.json index 861dc705e..29bc084ea 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -2,7 +2,9 @@ "@metadata": { "authors": [ "Mormegil", - "Vks" + "Vks", + "Utar", + "XenoPheX" ] }, "right-geocode": "Geokódování", @@ -40,8 +42,6 @@ "maps_map_cannot_be_displayed": "Nelze zobrazit mapu.", "maps_click_to_activate": "Mapu aktivujete kliknutím", "maps-googlemaps3-par-poi": "Zobrazit body zájmu.", - "maps-osm-par-thumbs": "Zobrazit náhledy", - "maps-osm-par-photos": "Zobrazit fotografie", "mapeditor": "Editor map", "specialpages-group-maps": "Mapy", "mapeditor-none-text": "Nic", @@ -69,5 +69,28 @@ "mapeditor-form-field-fillopcaity": "Krytí výplně", "mapeditor-form-field-showonhover": "Zobrazit pouze pod myší", "mapeditor-form-field-image": "Obrázek", - "mapeditor-form-field-visitedicon": "Navštívená ikona" + "mapeditor-form-field-visitedicon": "Navštívená ikona", + "semanticmaps-desc": "Poskytuje možnost zobrazit a upravovat data souřadnic uložená rozšířením Semantic MediaWiki ([https://mapping.referata.com/wiki/Examples demos]).", + "semanticmaps-unrecognizeddistance": "Hodnota $1 není platná vzdálenost.", + "semanticmaps-kml-link": "Zobrazit soubor KML", + "semanticmaps-default-kml-pagelink": "Zobrazit stránku $1", + "semanticmaps-loading-forminput": "Načítání mapy ze vstupu…", + "semanticmaps_lookupcoordinates": "Vyhledat souřadnice", + "semanticmaps_enteraddresshere": "Sem zadejte adresu", + "semanticmaps-updatemap": "Aktualizovat mapu", + "semanticmaps-forminput-remove": "Odebrat", + "semanticmaps-forminput-add": "Přidat", + "semanticmaps-latitude": "Z. šířka: $1", + "semanticmaps-longitude": "Z. délka: $1", + "semanticmaps-altitude": "Nadm. výška: $1", + "semanticmaps-forminput-locations": "Místa", + "semanticmaps-par-staticlocations": "Seznam míst, která se přidají do mapy spolu s dotazovanými daty. Podobně jako u display_points můžete každé místo doplnit o titulek, popis a ikonu, za použití tildy „~“ jako oddělovače.", + "semanticmaps-par-showtitle": "Zobrazovat název v info okně značky či ne. Vypnutí je často užitečné, pokud je obsah informačního okna formátován pomocí šablony.", + "semanticmaps-par-centre": "Střed mapy. Není-li specifikován, mapa automaticky vybere optimální střed tak, aby byly zobrazeny všechny značky na ní.", + "semanticmaps-par-template": "Šablona formátování obsahu informačního okna", + "semanticmaps-par-geocodecontrol": "Zobrazit ovladač geocodingu.", + "semanticmaps-kml-text": "Text je přidružený ke každé stránce. Je přepsán dodatečnými dotazovanými vlastnostmi, jsou-li nějaké.", + "semanticmaps-kml-title": "Výchozí titulek pro výsledky", + "semanticmaps-kml-linkabsolute": "Mají být odkazy absolutní či ne (tj. relativní)", + "semanticmaps-kml-pagelinktext": "Text, který bude použit pro odkazy na stránku, ve kterém bude $1 nahrazeno názvem stránky" } diff --git a/i18n/de.json b/i18n/de.json index 1c044e55a..4ba987932 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -7,12 +7,13 @@ "Kghbln", "Metalhead64", "Purodha", - "The Evil IP address" + "The Evil IP address", + "Umherirrender" ] }, "maps-desc": "Ermöglicht das Einbinden dynamischer Karten, die Georeferenzierung von Adressen und andere geographische Operationen", "right-geocode": "Georeferenzieren", - "action-geocode": "Geocoding auf diesem Wiki auszuführen", + "action-geocode": "Georeferenzierungen auf diesem Wiki auszuführen", "maps_map": "Karte", "maps-tracking-category": "Seiten mit einer von der Maps-Erweiterung gerenderten Karte", "maps-loading-map": "Die Karte wird geladen …", @@ -21,22 +22,22 @@ "maps-copycoords-prompt": "STRG+C, ENTER", "maps-searchmarkers-text": "Markierungen filtern", "maps-others": "andere", - "maps-kml-parsing-failed": "Das Parsen einer oder mehrerer KML-Dateien ist fehlgeschlagen, normalerweise aufgrund eines Abfragefehlers oder aufgrund von fehlerhaftem XML.", + "maps-kml-parsing-failed": "Das Parsen einer oder mehrerer KML-Dateien ist fehlgeschlagen. Dies geschieht normalerweise aufgrund eines Abfragefehlers oder aufgrund von fehlerhaftem XML.", "maps-ns-layer": "Ebene", "maps-ns-layer-talk": "Ebene Diskussion", "maps-layer-property": "Attribut", "maps-layer-value": "Wert", "maps-layer-errors": "Fehler", "maps-layerdef-invalid": "Ungültige {{PLURAL:$1|Definition|Definitionen}}", - "maps-layerdef-invalid-fatal": "Schwerwiegende ungültige Definition", - "maps-layerdef-wrong-namespace": "Ebenendefinitionen sind nur gültig auf Seiten des Namensraums „$1“", - "maps-layerdef-equal-layer-name": "Ebenennamen müssen innerhalb der gleichen Ebenenseite einmalig sein. „$1“ wird bereits von einer anderen Ebene verwendet.", - "maps-layerpage-usage": "Wikiseiten mit Karten die die Ebene „$1“ verwenden", - "maps-layerpage-nousage": "Keine Seite verwendet diese Ebene momentan.", + "maps-layerdef-invalid-fatal": "Die Definition ist ungültig und führt zu einem schwerwiegenden Fehler.", + "maps-layerdef-wrong-namespace": "Ebenendefinitionen sind nur auf Seiten des Namensraums „$1“ gültig", + "maps-layerdef-equal-layer-name": "Ebenennamen müssen auf der gleichen Ebenenseite einmalig sein. „$1“ wird bereits von einer anderen Ebene verwendet.", + "maps-layerpage-usage": "Seiten mit Karten, die die Ebene „$1“ verwenden", + "maps-layerpage-nousage": "Keine Seite verwendet momentan diese Ebene.", "maps-error-invalid-layertype": "Es gibt keine Ebenen des Typs „$1“. Nur {{PLURAL:$3|dieser Typ wird|diese Typen werden}} unterstützt: $2", "maps-error-no-layertype": "Der Ebenentyp muss angegeben werden. Nur {{PLURAL:$2|dieser Typ wird|diese Typen werden}} unterstützt: $1", - "validation-error-invalid-layer": "Parameter „$1“ muss einer gültigen Ebene entsprechen.", - "validation-error-invalid-layers": "Parameter „$1“ muss einer oder mehreren gültigen Ebenen entsprechen.", + "validation-error-invalid-layer": "Der Parameter „$1“ muss einer gültigen Ebene entsprechen.", + "validation-error-invalid-layers": "Der Parameter „$1“ muss einer oder mehreren gültigen Ebenen entsprechen.", "validation-error-no-non-numeric": "Der Parameter „$1“ muss eine nicht-numerische Zeichenfolge sein.", "validation-error-no-non-numerics": "Der Parameter „$1“ muss eine oder mehrere nicht-numerische Zeichenfolgen sein.", "maps-layer-of-type": "Ebene des Typs „$1“", @@ -44,7 +45,6 @@ "maps-layer-type-supported-by": "Dieser Ebenentyp kann {{PLURAL:$2|nur mit dem Kartografiedienst $1 genutzt werden|mit diesen Kartografiediensten genutzt werden: $1}}.", "maps-coordinates-description": "Parserhook zur Koordinatenformatierung aus und in alle unterstützte Formate.", "maps-displaymap-description": "Geographische Karten ohne jegliche im Wiki definierte Markierungen anzeigen.", - "maps-displaypoint-description": "Geographische Karten zusammen mit einer oder mehreren im Wiki definierter Markierungen anzeigen.", "maps-distance-description": "Konvertiere die Entfernung unter Verwendung einer der unterstützten Einheiten in ihr Äquivalent einer anderen unterstützen Einheit.", "maps-finddestination-description": "Ein Ziel unter Angabe des Ausgangspunkts (kann in jedwedem unterstützten Format angegeben sein), der Peilung sowie der Entfernung ermitteln.", "maps-geocode-description": "Aktiviert das Georeferenzieren von Adressen, also deren Umwandlung in Koordinaten. Mehrere Georeferenzierungsdienste werden unterstützt, was allerdings nicht mit den Kartografiediensten zu verwechseln ist.", @@ -78,7 +78,7 @@ "maps-geodistance-par-unit": "Die Ausgabeeinheit für die Entfernung.", "maps-geodistance-par-decimals": "Die bei der Ergebnisausgabe zu verwendende Höchstzahl an Nachkommastellen.", "maps-geodistance-par-mappingservice": "Der Kartografiedienst der für alle Adressen genutzt werden soll.", - "maps-geodistance-par-geoservice": "Der Kartografiedienst mit dem diese Parserfunktion genutzt wird.\nDies kann Auswirkungen auf die Standardwerte des Georeferenzierungsdiensts haben.", + "maps-geodistance-par-geoservice": "Der Kartografiedienst, der von dieser Parserfunktion genutzt wird.\nDies kann Auswirkungen auf die Standardeinstellungswerte des Georeferenzierungsdiensts haben", "maps-displaymap-par-mappingservice": "Der Kartografiedienst, der zur Generierung der Karte genutzt werden soll", "maps-displaymap-par-coordinates": "Die Postion auf welche die Karte zunächst zentriert werden soll", "maps-displaymap-par-visitedicon": "Der Dateiname des Symbols, das anstelle der ursprünglichen Markierung angezeigt werden soll, sobald die Originalmarkierungen angeklickt wurden", @@ -94,11 +94,10 @@ "maps-displaymap-par-minzoom": "Die minimale Anzeigestufe", "maps-displaymap-par-polygons": "Anzuzeigende Vielecke", "maps-displaymap-par-rectangles": "Anzuzeigende Rechtecke", - "maps-displaymap-par-static": "Macht die Karte statisch", - "maps-displaymap-par-wmsoverlay": "Eine WMS-Überlagerung verwenden", + "maps-displaymap-par-static": "Die Karte statisch machen", + "maps-displaymap-par-wmsoverlay": "Eine Web-Map-Service-Ebene verwenden", "maps-fullscreen-button": "Auf Vollbild umschalten", "maps-fullscreen-button-tooltip": "Die Karte als Vollbild oder eingebettet darstellen.", - "maps-googlemaps3-par-enable-fullscreen": "Vollbildbutton aktivieren", "validation-error-invalid-location": "Parameter $1 muss einem gültigen Standort entsprechen.", "validation-error-invalid-locations": "Parameter $1 muss einem oder mehreren gültigen Standorten entsprechen.", "validation-error-invalid-width": "Parameter $1 muss einer gültigen Breite entsprechen.", @@ -125,23 +124,27 @@ "maps-geocoder-not-available": "Die Funktion zum Georeferenzierung von Karten ist nicht verfügbar. Der Standort kann nicht georeferenziert werden.", "maps_googlemaps3": "Karte (Google Maps v3)", "maps_leaflet": "Karte (Leaflet)", - "maps-leaflet-par-zoom": "Erlaubt das Festlegen der Vergrößerungsstufe der Karte.", - "maps-leaflet-par-defzoom": "Erlaubt das Festlegen der Standardvergrößerungsstufe der Karte.", - "maps-leaflet-par-resizable": "Erlaubt die Anpassung der Kartengröße durch das Ziehen an der rechten unteren Ecke.", + "maps-leaflet-par-defzoom": "Erlaubt das Festlegen der Standardvergrößerungsstufe der Karte", + "maps-leaflet-par-layer": "Die Ebene, die angezeigt wird, wenn die Karte lädt.", + "maps-leaflet-par-overlaylayers": "Die Überlagerungsebenen, die angezeigt werden, wenn die Karte lädt.", + "maps-leaflet-par-maxclusterradius": "Der maximale Radius, den ein Cluster ab der Mittelmarkierung abdeckt (in Pixeln).", + "maps-leaflet-par-clusterspiderfy": "Bei Klicken auf einen Cluster in einer niedrigen Vergrößerungsstufe wird dieser netzförmig expandiert, so dass alle enthaltenen Markierungen eingesehen werden können.", "maps_openlayers": "Karte (OpenLayers)", "maps_click_to_activate": "Klicken, um die Karte zu aktivieren.", "maps_centred_on": "Karte ist auf $1, $2 zentriert.", "maps-par-mappingservice": "Ermöglicht das Festlegen des Kartografiedienstes, der zum Erstellen der Karte verwendet werden soll", "maps-par-resizable": "Die Karte durch Ziehen von der unteren rechten Ecke größenveränderbar machen können", - "maps-par-searchmarkers": "Erlaubt die Suche nach speziellen Markierungen über ein in die Karte eingebettetes Feld.", + "maps-par-searchmarkers": "Erlaubt die Suche nach speziellen Markierungen über ein in die Karte eingebettetes Feld", "maps-par-geoservice": "Der für Umwandlung von Adressen in Koordinaten zu verwendende Georeferenzierungsdienst.", "maps-par-zoom": "Die Zoomstufe für die Karte. Karten mit Kennzeichnungen werden standardmäßig auf die Stufe gezoomt in der diese noch alle gemeinsam angezeigt werden können.", "maps-par-width": "Die Kartenbreite, die genutzt werden soll. Standardmäßig wird Pixel (px) als Einheit angenommen. Jedoch kann auch eine der folgenden Einheiten angegeben werden: ex, em und %", "maps-par-height": "Die Kartenhöhe, die genutzt werden soll. Standardmäßig wird Pixel (px) als Einheit angenommen. Jedoch kann auch eine der folgenden Einheiten angegeben werden: ex, em und %", - "maps-par-centre": "Der Standort, an dem die Karte zentriert werden soll", + "maps-par-centre": "Die Koordinaten des Standorts (bpsw. 50.0093,8.2564), an dem die Karte zentriert werden soll", + "maps-par-enable-fullscreen": "Vollbildschaltfläche aktivieren", + "maps-par-kml": "Die auf die Karte zu ladenden KML-Dateien.", + "maps-par-markercluster": "Erlaubt das Zusammenführen mehrerer benachbarter Markierungen zu einer Markierung", "maps-googlemaps3-incompatbrowser": "Der Browser ist nicht mit Google Maps v3 kompatibel.", - "maps-googlemaps3-par-imageoverlays": "Erlaubt das Hinzufügen eines Bildes, das auf dem angegebenen Ort auf der Karte angezeigt wird.", - "maps-googlemaps3-par-markercluster": "Erlaubt das Zusammenführen mehrerer benachbarter Markierungen in eine Markierung", + "maps-googlemaps3-par-imageoverlays": "Erlaubt das Hinzufügen eines Bildes, das am angegebenen Ort auf der Karte angezeigt wird", "maps-googlemaps3-par-type": "Die zunächst anzuzeigende Kartenart.", "maps-googlemaps3-par-types": "Die Kartenarten, die über die Steuerung zu den Kartenarten verfügbar gemacht werden sollen.", "maps-googlemaps3-par-layers": "Die auf die Karte zu ladenden Sonderebenen.", @@ -149,17 +152,20 @@ "maps-googlemaps3-par-zoomstyle": "Der Stil der Zoomsteuerung.", "maps-googlemaps3-par-typestyle": "Der Stil der Steuerung zu den Kartenarten.", "maps-googlemaps3-par-autoinfowindows": "Die Informationsfenster nach dem Laden der Seite automatisch öffnen oder nicht", - "maps-googlemaps3-par-kml": "Die auf die Karte zu ladenden KML-Dateien.", "maps-googlemaps3-par-gkml": "Die von Google gehosteten KML-Dateien, die auf die Karte geladen werden sollen", "maps-googlemaps3-par-fusiontables": "Die Kennungen der Google Fusion Tables, die auf die Karte geladen werden sollen", "maps-googlemaps3-par-tilt": "Die Neigung der Karte bei der Nutzung von Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Die Karte erneut zoomen, nachdem die KML-Ebenen geladen wurden.", "maps-googlemaps3-par-poi": "Die Sehenswürdigkeiten anzeigen", + "maps-googlemaps3-par-clustergridsize": "Die Rastergröße eines Clusters in Pixeln", + "maps-par-clustermaxzoom": "Die maximale Vergrößerungsstufe, in der Cluster vorhanden sein können.", + "maps-par-clusterzoomonclick": "Ob das Standardverhalten beim Klicken auf einen Cluster dessen Vergrößerung ist.", + "maps-par-maxclusterradius": "Der maximale Radius, den ein Cluster abdeckt.", + "maps-googlemaps3-par-clusteraveragecenter": "Ob die Mitte jedes Clusters der Durchschnitt aller Markierungen des Clusters sein soll", + "maps-googlemaps3-par-clusterminsize": "Die Mindestzahl der Markierungen, die ein Cluster enthalten soll, bevor die Markierungen versteckt werden und ein Zähler angezeigt wird", "maps-openlayers-par-controls": "Die auf der Karte anzuzeigenden Steuerelemente.", "maps-openlayers-par-layers": "Die Ebenen, die über die Ebenenauswahl verfügbar sein sollen. Die erste Ebene wird während des Ladens der Karten angezeigt.", - "maps-openlayers-par-overlays": "Überlagerungsebenen, die in der Ebenenauswahl zur Verfügung stehen. Diese Ebenen werden bei einer normalen Ebene oben angezeigt, in der Art einer Markierung.", - "maps-osm-par-thumbs": "Miniaturansichten anzeigen", - "maps-osm-par-photos": "Fotografien anzeigen", + "maps-openlayers-par-overlays": "Die Überlagerungsebenen, die in der Ebenenauswahl zur Verfügung stehen. Sie werden auf einer normalen Ebene nach Art einer Markierung angezeigt", "mapeditor": "Karteneditor", "specialpages-group-maps": "Karten", "mapeditor-parser-error": "Ein Fehler ist beim Parsen der Metadaten aufgetreten. Ignoriere Benutzereingaben.", @@ -195,5 +201,43 @@ "mapeditor-imageoverlay-button": "Bildeinblendung hinzufügen", "mapeditor-form-field-image": "Bild", "mapeditor-imageoverlay-title": "Einzelheiten zur Bildeinblendung", - "mapeditor-form-field-visitedicon": "Symbol sofern besucht" + "mapeditor-form-field-visitedicon": "Symbol sofern besucht", + "semanticmaps-unrecognizeddistance": "Der Wert $1 ist keine gültige Distanz.", + "semanticmaps-kml-link": "KML-Datei ansehen", + "semanticmaps-kml": "Export (KML)", + "semanticmaps-default-kml-pagelink": "Artikel $1 ansehen", + "semanticmaps-latitude": "Breitengrad: $1", + "semanticmaps-longitude": "Längengrad: $1", + "semanticmaps-altitude": "Höhe: $1", + "semanticmaps-forminput-locations": "Standort", + "semanticmaps-par-staticlocations": "Die Listen von Standorten, die zusammen mit den abgefragten Daten, der Karte hinzugefügt werden sollen. Analog zu den Anzeigepunkten können je Standort Titel, Beschreibung und Symbol, unter Verwendung einer Tilde „~“ als Trennzeichen, hinzugefügt werden.", + "semanticmaps-par-showtitle": "Den Titel im Informationsfenster der Kennzeichnung anzeigen oder nicht. Diese Option zu deaktivieren ist oftmals dann nützlich, sofern eine Vorlage zur Formatierung des Informationsfensterinhalts verwendet wird.", + "semanticmaps-par-hidenamespace": "Den Namen des Namensraums im Informationsfenster der Kennzeichnung anzeigen", + "semanticmaps-par-centre": "Das Zentrum der Karte. Sofern nicht angegeben wird automatisch das optimale Zentrum zur Darstellung aller Kennzeichnungen auf der Karte gewählt.", + "semanticmaps-par-template": "Die zur Formatierung des Informationsfensterinhalts zu verwendende Vorlage.", + "semanticmaps-par-geocodecontrol": "Die Steuerungsseite zum Geokodieren anzeigen.", + "semanticmaps-par-activeicon": "Das Symbol, das anstelle der Standardmarkierung angezeigt wird, sofern die aktive Seite dem Abfrageergebnis entspricht.", + "semanticmaps-par-pagelabel": "Sofern mit „yes“ (ja) festgelegt, verfügen alle Markierungen über eine eingebettete Anzeige mit einem Link zur entsprechenden Seite sowie den entsprechenden Koordinaten.", + "semanticmaps-par-ajaxcoordproperty": "Name des Koordinatenattributs, das zur Erstellung der Ajax-Abfrage verwendet wird.", + "semanticmaps-par-ajaxquery": "Eine zweite Abfrage, die über Ajax gesendet wird, um zusätzliche Koordinaten abzurufen.", + "semanticmaps-par-userparam": "Ein in jedem Vorlagenaufruf zu übergebender Wert, falls eine Vorlage verwendet wird.", + "semanticmaps-kml-text": "Der Text, der zu jeder Seite angezeigt wird. Wird im Fall zusätzlich abgefragter Attribute ersetzt.", + "semanticmaps-kml-title": "Der Standardtitel für die Ergebnisse", + "semanticmaps-kml-linkabsolute": "Die Links sollen absolut sein (anstatt relativ)", + "semanticmaps-kml-pagelinktext": "Der Text, der für die Links zur Seite genutzt werden soll. $1 wird dabei durch den Namen der Seite ersetzt.", + "semanticmaps-shapes-improperformat": "$1 ist falsch formatiert. Siehe hierzu die Dokumentation bezüglich Formatierungen.", + "semanticmaps-shapes-missingshape": "Für $1 wurden keine Formen gefunden. Siehe hierzu die Dokumentation bezüglich verfügbarer Formen.", + "validator-type-mapscircle": "Geografischer Kreis", + "validator-type-mapscircle-list": "Liste der Kreise", + "validator-type-mapsimageoverlay": "Bildüberlagerung", + "validator-type-mapsimageoverlay-list": "Liste der Bildüberlagerungen", + "validator-type-mapsline": "Geografische Linie", + "validator-type-mapsline-list": "Liste der Linien", + "validator-type-mapslocation": "Geografischer Standort", + "validator-type-mapslocation-list": "Liste der Standorte", + "validator-type-mapsrectangle": "Geografisches Rechteck", + "validator-type-mapsrectangle-list": "Liste der Rechtecke", + "validator-type-mapspolygon": "Geografisches Vieleck", + "validator-type-mapspolygon-list": "Liste geografischer Vielecke", + "validator-type-wmsoverlay": "Web-Map-Service-Überlagerung" } diff --git a/i18n/el.json b/i18n/el.json index 9aba2d1a8..6fb0a06ee 100644 --- a/i18n/el.json +++ b/i18n/el.json @@ -33,7 +33,6 @@ "maps-layer-of-type-and-name": "Στρώση «$2» τύπου «$1»", "maps-layer-type-supported-by": "Αυτός ο τύπος στρώσης μπορεί να χρησιμοποιηθεί {{PLURAL:$2|μόνο με την υπηρεσία|με αυτές τις υπηρεσίες}} χαρτογράφησης: $1.", "maps-displaymap-description": "Προβολή γεωγραφικών χαρτών χωρίς σημάδια ορισμένα μέσω wiki.", - "maps-displaypoint-description": "Προβολή γεωγραφικών χαρτών με ένα ή περισσότερα σημάδια ορισμένα μέσω wiki.", "maps-coordinates-par-location": "Οι συντεταγμένες που θέλετε να μορφοποιήσετε.", "maps-coordinates-par-format": "Η μορφή προορισμού για τις συντεταγμένες.", "maps-coordinates-par-directional": "Δηλώνει εάν οι συντεταγμένες πρέπει να εκφραστούν κατευθυντικά ή όχι.", @@ -65,7 +64,6 @@ "maps-displaymap-par-wmsoverlay": "Χρήση μιας υπέρθεσης WMS", "maps-fullscreen-button": "Εναλλαγή πλήρους οθόνης", "maps-fullscreen-button-tooltip": "Προβολή του χάρτη σε πλήρη οθόνη ή ενσωματωμένου.", - "maps-googlemaps3-par-enable-fullscreen": "Ενεργοποίηση κουμπιού πλήρους οθόνης", "validation-error-invalid-location": "Η παράμετρος «$1» πρέπει να είναι μια έγκυρη τοποθεσία.", "validation-error-invalid-locations": "Η παράμετρος «$1» πρέπει να είναι μία ή περισσότερες έγκυρες τοποθεσίες.", "validation-error-invalid-width": "Η παράμετρος «$1» πρέπει να είναι ένα έγκυρο πλάτος.", @@ -96,9 +94,11 @@ "maps-par-searchmarkers": "Επιτρέπει την αναζήτηση για συγκεκριμένα σημάδια μέσω πεδίου ενσωματωμένου στο χάρτη.", "maps-par-geoservice": "Η υπηρεσία γεωκωδικοποίησης που να χρησιμοποιείται για να μεταφράζει μεταξύ διευθύνσεων και συντεταγμένων.", "maps-par-centre": "Η τοποθεσία στην οποία ο χάρτης θα πρέπει να είναι κεντραρισμένος", + "maps-par-enable-fullscreen": "Ενεργοποίηση κουμπιού πλήρους οθόνης", + "maps-par-kml": "Αρχεία KML για φόρτωση στο χάρτη.", + "maps-par-markercluster": "Επιτρέπει τη συγχώνευση πολλαπλών κοντινών σημαδιών σε ένα σημάδι", "maps-googlemaps3-incompatbrowser": "Το πρόγραμμα περιήγησης δεν είναι συμβατό με την έκδοση 3 των Χαρτών Google.", "maps-googlemaps3-par-imageoverlays": "Επιτρέπει την προσθήκη μιας εικόνας προς εμφάνιση στην καθοριζόμενη θέση στο χάρτη.", - "maps-googlemaps3-par-markercluster": "Επιτρέπει τη συγχώνευση πολλαπλών κοντινών σημαδιών σε ένα σημάδι", "maps-googlemaps3-par-type": "Τύπος χάρτη που να εμφανίζεται αρχικά.", "maps-googlemaps3-par-types": "Τύποι χάρτη που θα είναι διαθέσιμοι μέσω της ρύθμισης τύπου.", "maps-googlemaps3-par-layers": "Ειδικές στρώσεις για φόρτωση επάνω στο χάρτη.", @@ -106,13 +106,10 @@ "maps-googlemaps3-par-zoomstyle": "Στυλ του στοιχείου ελέγχου του ζουμ.", "maps-googlemaps3-par-typestyle": "Στυλ του στοιχείου ελέγχου του τύπου.", "maps-googlemaps3-par-autoinfowindows": "Αυτόματο άνοιγμα όλων των παραθύρων πληροφοριών μετά τη φόρτωση της σελίδας.", - "maps-googlemaps3-par-kml": "Αρχεία KML για φόρτωση στο χάρτη.", "maps-googlemaps3-par-gkml": "Αρχεία KML που φιλοξενούνται στη Google για φόρτωση στο χάρτη.", "maps-googlemaps3-par-poi": "Εμφάνιση σημείων ενδιαφέροντος.", "maps-openlayers-par-controls": "Στοιχεία ελέγχου προς τοποθέτηση στο χάρτη.", "maps-openlayers-par-layers": "Οι στρώσεις που θα είναι διαθέσιμες στον επιλογέα στρώσεων. Η πρώτη στρώση θα εμφανίζεται κατά τη φόρτωση του χάρτη.", - "maps-osm-par-thumbs": "Εμφάνιση μικρογραφιών", - "maps-osm-par-photos": "Εμφάνιση φωτογραφιών", "mapeditor": "Πρόγραμμα επεξεργασίας χαρτών", "specialpages-group-maps": "Χάρτες", "mapeditor-none-text": "Κανένα", @@ -146,5 +143,25 @@ "mapeditor-imageoverlay-button": "Προσθήκη υπέρθεσης εικόνας", "mapeditor-form-field-image": "Εικόνα", "mapeditor-imageoverlay-title": "Λεπτομέρειες υπέρθεσης εικόνας", - "mapeditor-form-field-visitedicon": "Επισκεφθέν εικονίδιο" + "mapeditor-form-field-visitedicon": "Επισκεφθέν εικονίδιο", + "semanticmaps-unrecognizeddistance": "Η τιμή $1 δεν είναι έγκυρη απόσταση.", + "semanticmaps-kml-link": "Προβολή του αρχείου KML", + "semanticmaps-default-kml-pagelink": "Προβολή σελίδας $1", + "semanticmaps-latitude": "Γεωγραφικό πλάτος: $1", + "semanticmaps-longitude": "Γεωγραφικό μήκος: $1", + "semanticmaps-altitude": "Υψόμετρο: $1", + "semanticmaps-forminput-locations": "Τοποθεσίες", + "semanticmaps-par-staticlocations": "Μια λίστα με τοποθεσίες για προσθήκη στο χάρτη μαζί με τα ερωτηθέντα δεδομένα. Όπως και με τα display_points, μπορείτε να προσθέσετε τίτλο, περιγραφή και εικονίδιο ανά τοποθεσία χρησιμοποιώντας την περισπωμένη «~» ως διαχωριστικό.", + "semanticmaps-par-showtitle": "Εμφάνιση ή μη του τίτλου στο παράθυρο πληροφοριών δείκτη. Η απενεργοποίησή του είναι συχνά χρήσιμη όταν χρησιμοποιείται πρότυπο για τη μορφοποίηση του περιεχομένου του παραθύρου πληροφοριών.", + "semanticmaps-par-hidenamespace": "Εμφάνιση τίτλου ονοματοχώρου στο παράθυρο πληροφοριών δείκτη", + "semanticmaps-par-centre": "Το κέντρο του χάρτη. Όταν δεν παρέχεται, ο χάρτης θα επιλέξει αυτόματα το βέλτιστο κέντρο για την προβολή όλων των δεικτών επάνω στο χάρτη.", + "semanticmaps-par-template": "Πρότυπο για να το χρησιμοποιήσετε για τη μορφοποίηση των περιεχομένων του παραθύρου πληροφοριών.", + "semanticmaps-par-geocodecontrol": "Εμφάνιση στοιχείου ελέγχου γεωκωδικοποίησης.", + "semanticmaps-par-activeicon": "Εικονίδιο που θα εμφανίζεται αντί του προεπιλεγμένου δείκτη, όταν η ενεργή σελίδα ισούται με το αποτέλεσμα του ερωτήματος", + "semanticmaps-kml-text": "Το κείμενο που σχετίζεται με κάθε σελίδα. Παρακάμπτεται από τις πρόσθετες ερωτηθέντες ιδιότητες αν υπάρχουν.", + "semanticmaps-kml-title": "Προεπιλεγμένος τίτλος για αποτελέσματα", + "semanticmaps-kml-linkabsolute": "Να είναι οι σύνδεσμοι απόλυτοι (ως αντιπαράθεση με τους σχετικούς)", + "semanticmaps-kml-pagelinktext": "Το κείμενο που θα χρησιμοποιείται για τους συνδέσμους προς τη σελίδα, στο οποίο το $1 θα αντικαθίσταται από τον τίτλο της σελίδας", + "semanticmaps-shapes-improperformat": "Εσφαλμένη μορφοποίηση του $1, ανατρέξτε στην τεκμηρίωση περί μορφοποίησης", + "semanticmaps-shapes-missingshape": "Δεν βρέθηκαν σχήματα για το $1, ανατρέξτε στην τεκμηρίωση για διαθέσιμα σχήματα" } diff --git a/i18n/en.json b/i18n/en.json index 0e6669db3..4e54c6553 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -39,7 +39,6 @@ "maps-layer-type-supported-by": "This layer type can {{PLURAL:$2|only be used with the $1 mapping service|be used with these mapping services: $1}}.", "maps-coordinates-description": "Parser hook to format coordinates, from and to any of the supported formats.", "maps-displaymap-description": "Display geographical maps without any wiki-defined markers on them.", - "maps-displaypoint-description": "Display geographical maps with one or more wiki-defined markers on them.", "maps-distance-description": "Convert a distance using a certain supported unit to its equivalent using another unit.", "maps-finddestination-description": "Find a destination given a starting point (that can be in any of the supported formats), an initial bearing and a distance.", "maps-geocode-description": "Enables the geocoding of addresses, in other words, turning human readable locations into sets of coordinates. There is support for several geocoding services, which should not be confused with mapping services.", @@ -93,7 +92,6 @@ "maps-displaymap-par-wmsoverlay": "Use a WMS overlay", "maps-fullscreen-button": "Toggle fullscreen", "maps-fullscreen-button-tooltip": "View the map as fullscreen or embedded.", - "maps-googlemaps3-par-enable-fullscreen": "Enable fullscreen button", "validation-error-invalid-location": "Parameter \"$1\" must be a valid location.", "validation-error-invalid-locations": "Parameter \"$1\" must be one or more valid locations.", "validation-error-invalid-width": "Parameter \"$1\" must be a valid width.", @@ -120,11 +118,12 @@ "maps-geocoder-not-available": "The geocoding feature of Maps is not available. Your location cannot be geocoded.", "maps_googlemaps3": "Google Maps v3", "maps_leaflet": "Leaflet", - "maps-leaflet-par-zoom": "Allows setting the zoom level of the map.", "maps-leaflet-par-defzoom": "Allows setting the default zoom level of the map.", - "maps-leaflet-par-resizable": "Allows making the map resizable by dragging at its lower right corner.", + "maps-leaflet-par-layer": "The layer that will be shown when the map loads.", + "maps-leaflet-par-overlaylayers": "The overlay layers that will be shown when the map loads.", + "maps-leaflet-par-maxclusterradius": "The maximum radius that a cluster will cover from the central marker (in pixels).", + "maps-leaflet-par-clusterspiderfy": "When you click a cluster at the bottom zoom level we spiderfy it so you can see all of its markers.", "maps_openlayers": "OpenLayers", - "maps_osm": "OpenStreetMap", "maps_click_to_activate": "Click to activate map", "maps_centred_on": "Map centered on $1, $2.", "maps-par-mappingservice": "Allows setting the mapping service that will be used to generate the map.", @@ -135,9 +134,11 @@ "maps-par-width": "Allows setting the width of the map. By default pixels will be assumed as unit, but you can explicitly specify one of these units: px, ex, em, %.", "maps-par-height": "Allows setting the height of the map. By default pixels will be assumed as unit, but you can explicitly specify one of these units: px, ex, em, %.", "maps-par-centre": "The location on which the map should be centered", + "maps-par-enable-fullscreen": "Enable fullscreen button", + "maps-par-kml": "KML files to load onto the map.", + "maps-par-markercluster": "Allows merging of multiple nearby markers into one marker", "maps-googlemaps3-incompatbrowser": "Your browser is not compatible with Google Maps v3.", "maps-googlemaps3-par-imageoverlays": "Allows adding an image to be shown on the specified location on the map.", - "maps-googlemaps3-par-markercluster": "Allows merging of multiple nearby markers into one marker", "maps-googlemaps3-par-type": "The map type to initially show.", "maps-googlemaps3-par-types": "The map types that will be available via the type control.", "maps-googlemaps3-par-layers": "Special layers to load onto the map.", @@ -145,17 +146,20 @@ "maps-googlemaps3-par-zoomstyle": "The style of the zoom control.", "maps-googlemaps3-par-typestyle": "The style of the type control.", "maps-googlemaps3-par-autoinfowindows": "Automatically open all info windows after the page has loaded.", - "maps-googlemaps3-par-kml": "KML files to load onto the map.", "maps-googlemaps3-par-gkml": "KML files hosted by Google to load onto the map.", "maps-googlemaps3-par-fusiontables": "IDs of Google Fusion Tables which should be loaded onto the map.", "maps-googlemaps3-par-tilt": "Tilt for the Map when using Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Rezoom the map after the KML layers have been loaded.", "maps-googlemaps3-par-poi": "Show points of interest.", + "maps-googlemaps3-par-clustergridsize": "The grid size of a cluster in pixels.", + "maps-par-clustermaxzoom": "The maximum zoom level where clusters may exist.", + "maps-par-clusterzoomonclick": "Whether the default behaviour of clicking on a cluster is to zoom into it.", + "maps-par-maxclusterradius": "The maximum radius that a cluster will cover.", + "maps-googlemaps3-par-clusteraveragecenter": "Whether the center of each cluster should be the average of all markers in the cluster.", + "maps-googlemaps3-par-clusterminsize": "The minimum number of markers to be in a cluster before the markers are hidden and a count is shown.", "maps-openlayers-par-controls": "The controls to place on the map.", "maps-openlayers-par-layers": "The layers that will be available in the layer selector. The first layer will be shown when the map loads.", "maps-openlayers-par-overlays": "Overlay layers that will be available in the layer selector. These layers will be displayed on top of a normal layer, kind of like a marker.", - "maps-osm-par-thumbs": "Show thumbs", - "maps-osm-par-photos": "Show photos", "mapeditor": "Map editor", "specialpages-group-maps": "Maps", "mapeditor-parser-error": "An error occurred when parsing metadata. Ignoring user input.", @@ -191,5 +195,43 @@ "mapeditor-imageoverlay-button": "Add image overlay", "mapeditor-form-field-image": "Image", "mapeditor-imageoverlay-title": "Image overlay details", - "mapeditor-form-field-visitedicon": "Visited icon" + "mapeditor-form-field-visitedicon": "Visited icon", + "semanticmaps-unrecognizeddistance": "The value $1 is not a valid distance.", + "semanticmaps-kml-link": "View the KML file", + "semanticmaps-kml": "KML", + "semanticmaps-default-kml-pagelink": "View page $1", + "semanticmaps-latitude": "Latitude: $1", + "semanticmaps-longitude": "Longitude: $1", + "semanticmaps-altitude": "Altitude: $1", + "semanticmaps-forminput-locations": "Locations", + "semanticmaps-par-staticlocations": "A list of locations to add to the map together with the queried data. Like with display_points, you can add a title, description and icon per location using the tilde \"~\" as separator.", + "semanticmaps-par-showtitle": "Show a title in the marker info window or not. Disabling this is often useful when using a template to format the info window content.", + "semanticmaps-par-hidenamespace": "Show the namespace title in the marker info window", + "semanticmaps-par-centre": "The center of the map. When not provided, the map will automatically pick the optimal center to display all markers on the map.", + "semanticmaps-par-template": "A template to use to format the info window contents.", + "semanticmaps-par-geocodecontrol": "Show the geocoding control.", + "semanticmaps-par-activeicon": "Icon to be displayed instead of default marker, when active page is equal to query result", + "semanticmaps-par-pagelabel": "When set to \"yes\", all markers will have an \"inlineLabel\" with a link to the page containing the coordinates for the marker", + "semanticmaps-par-ajaxcoordproperty": "Name of the coordinate property which is used to build the ajax query.", + "semanticmaps-par-ajaxquery": "A second query that is sent via ajax to fetch additional coordinates.", + "semanticmaps-par-userparam": "A value passed into each template call, if a template is used", + "semanticmaps-kml-text": "The text associated with each page. Overridden by the additional queried properties if any.", + "semanticmaps-kml-title": "The default title for results", + "semanticmaps-kml-linkabsolute": "Should links be absolute (as opposed to relative)", + "semanticmaps-kml-pagelinktext": "The text to use for the links to the page, in which $1 will be replaced by the page title", + "semanticmaps-shapes-improperformat": "Improper formatting of $1. Please see documentation for formatting", + "semanticmaps-shapes-missingshape": "No shapes found for $1. Please see documentation for available shapes", + "validator-type-mapscircle": "Geographical circle", + "validator-type-mapscircle-list": "List of circles", + "validator-type-mapsimageoverlay": "Image overlay", + "validator-type-mapsimageoverlay-list": "List of image overlays", + "validator-type-mapsline": "Geographical line", + "validator-type-mapsline-list": "List of lines", + "validator-type-mapslocation": "Geographical location", + "validator-type-mapslocation-list": "List of locations", + "validator-type-mapsrectangle": "Geographical rectangle", + "validator-type-mapsrectangle-list": "List of rectangles", + "validator-type-mapspolygon": "Geographical polygon", + "validator-type-mapspolygon-list": "List of geographical polygons", + "validator-type-wmsoverlay": "Web Map Service overlay" } diff --git a/i18n/es.json b/i18n/es.json index 69eafc693..1fe791ed8 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -19,7 +19,12 @@ "Macofe", "Themasterriot", "Mor", - "Rafael.minuesa" + "Rafael.minuesa", + "Indiralena", + "Lemondoge", + "Rubentl134", + "AlvaroMolina", + "Dgstranz" ] }, "maps-desc": "Habilita la inserción de mapas dinámicos en páginas wikis, la geocodificación de direcciones y otras operaciones geográficas", @@ -33,6 +38,7 @@ "maps-copycoords-prompt": "Ctrl+C, Intro", "maps-searchmarkers-text": "Marcadores de filtro", "maps-others": "otros", + "maps-kml-parsing-failed": "Falló el análisis de uno o más archivos KML. Por lo general, esto se debe a fallos de recuperación o a XML con formato incorrecto.", "maps-ns-layer": "Capa", "maps-ns-layer-talk": "Discusión de capa", "maps-layer-property": "Propiedad", @@ -41,6 +47,7 @@ "maps-layerdef-invalid": "{{PLURAL:$1|Definición no válida|Definiciones no válidas}}", "maps-layerdef-invalid-fatal": "Definición no válida fatal", "maps-layerdef-wrong-namespace": "Las definiciones de capas solo son válidas en el espacio de nombres «$1».", + "maps-layerdef-equal-layer-name": "Los nombres de las capas deben ser únicos dentro de la misma página de capas. Otra capa ya está utilizando «$1».", "maps-layerpage-usage": "Páginas con mapas que usan la capa «$1»", "maps-layerpage-nousage": "No hay páginas que usen esta capa en este momento.", "maps-error-invalid-layertype": "No hay capas de tipo \"$1\". Sólo {{PLURAL:$3|este tipo es compatible|estos tipos son compatibles}} :$2", @@ -54,7 +61,6 @@ "maps-layer-type-supported-by": "Este tipo de capa solo puede ser utilizado con {{PLURAL:$2|el servicio de mapas $1|estos servicios de mapas: $1 }}.", "maps-coordinates-description": "Marcador del analizador para formatear las coordenadas, desde y hacia cualquiera de los formatos compatibles.", "maps-displaymap-description": "Mostrar mapas geográficos sin ningún marcador definido por el wiki sobre ellos.", - "maps-displaypoint-description": "Mostrar mapas geográficos con uno o más marcadores wiki en ellos.", "maps-distance-description": "Convertir una distancia usando un cierta unidad soportada a su equivalente utilizando otra unidad.", "maps-finddestination-description": "Encontrar un destino dado un punto de partida (que puede estar en cualquiera de los formatos compatibles), un orientación inicial y una distancia.", "maps-geocode-description": "Permite la geocodificación de direcciones, en otras palabras, transformando las ubicaciones legibles por humanos en conjuntos de coordenadas. No hay soporte para varios servicios de geocodificación, que no deben confundirse con servicios de mapas.", @@ -108,7 +114,6 @@ "maps-displaymap-par-wmsoverlay": "Utilizar una superposición WMS", "maps-fullscreen-button": "Activar o desactivar pantalla completa", "maps-fullscreen-button-tooltip": "Ver el mapa en toda la pantalla o incrustado.", - "maps-googlemaps3-par-enable-fullscreen": "Activar el botón «Pantalla completa»", "validation-error-invalid-location": "El parámetro \"$1\" deber ser una ubicación válida.", "validation-error-invalid-locations": "El parámetro \"$1\" debe ser una o más ubicaciones válidas.", "validation-error-invalid-width": "El parámetro \"$1\" debe ser un ancho válido.", @@ -133,19 +138,23 @@ "maps_unrecognized_coords_for": "{{PLURAL:$2|La coordenada siguiente no se reconoce y se ha|Las coordenadas siguientes no se reconocen y se han}} omitido del mapa:\n$1", "maps_map_cannot_be_displayed": "No se puede mostrar el mapa.", "maps-geocoder-not-available": "La funcionalidad de geocodificación de Maps no está disponible. Su ubicación no puede ser geocodificada.", + "maps-leaflet-par-defzoom": "Permite establecer el nivel de ampliación predeterminado del mapa.", + "maps-leaflet-par-layer": "La capa que aparecerá cuando se cargue el mapa.", "maps_click_to_activate": "Haz clic para activar el mapa", "maps_centred_on": "Mapa centrado en $1, $2.", "maps-par-mappingservice": "Permite configurar el servicio de cartografía que se utilizará para generar el mapa.", - "maps-par-resizable": "Hace que se puedan alteras las dimensiones del mapa arrastrando su esquina inferior derecha.", + "maps-par-resizable": "Hace que se puedan alterar las dimensiones del mapa arrastrando su esquina inferior derecha.", "maps-par-searchmarkers": "Permite buscar marcadores específicos a través de un campo incrustado en el mapa.", "maps-par-geoservice": "El servicio de geocodificación a utilizar para realizar traducciones entre las direcciones y las coordenadas.", "maps-par-zoom": "El nivel de ampliación del mapa. Para mapas con marcadores el valor predeterminado será el máximo que aun muestre todos los marcadores.", "maps-par-width": "Permite establecer la anchura del mapa. De forma predeterminada se emplearán los pixeles como unidad, pero puede especificar explícitamente una de estas unidades: px, ex, em, %.", "maps-par-height": "Permite establecer la altura del mapa. De forma predeterminada se usarán los pixeles como unidad, pero puede especificar explícitamente una de estas unidades: px, ex, em, %.", "maps-par-centre": "La ubicación en la que el mapa debe quedar centrado", + "maps-par-enable-fullscreen": "Activar el botón «Pantalla completa»", + "maps-par-kml": "Archivos KML para cargar en el mapa.", + "maps-par-markercluster": "Permite fusionar múltiples marcadores cercanos en un marcador", "maps-googlemaps3-incompatbrowser": "Su navegador no es compatible con Google Maps v2.", "maps-googlemaps3-par-imageoverlays": "Permite añadir una imagen que mostrar en la ubicación especificada en el mapa.", - "maps-googlemaps3-par-markercluster": "Permite fusionar múltiples marcadores cercanos en un marcador", "maps-googlemaps3-par-type": "El tipo de mapa que mostrar inicialmente.", "maps-googlemaps3-par-types": "Los tipos de mapa que estarán disponibles a través del control de tipo.", "maps-googlemaps3-par-layers": "Capas especiales para cargar en el mapa.", @@ -153,17 +162,16 @@ "maps-googlemaps3-par-zoomstyle": "El estilo del control de zoom.", "maps-googlemaps3-par-typestyle": "El estilo del control de tipo.", "maps-googlemaps3-par-autoinfowindows": "Abrir automáticamente todas las ventanas de información después de que la página se haya cargado.", - "maps-googlemaps3-par-kml": "Archivos KML para cargar en el mapa.", "maps-googlemaps3-par-gkml": "Archivos KML alojados por Google para cargar en el mapa.", "maps-googlemaps3-par-fusiontables": "Identificadores de las tablas de Google Fusion que se deben cargar en el mapa.", "maps-googlemaps3-par-tilt": "Inclinación del mapa al utilizar Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Ajustar el nivel de zoom del mapa después de que se hayan cargado las capas KML.", "maps-googlemaps3-par-poi": "Mostrar puntos de interés.", + "maps-googlemaps3-par-clustergridsize": "La medida de verja de un grupo en píxeles.", + "maps-googlemaps3-par-clusterminsize": "El número mínimo de marcadores que están en un grupo antes de que los marcadores se oculten y un recuento se muestre", "maps-openlayers-par-controls": "Los controles a colocar en el mapa.", "maps-openlayers-par-layers": "Las capas que estarán disponibles en el selector de capas. La primera capa se mostrará cuando se cargue el mapa.", "maps-openlayers-par-overlays": "Capas superposicionadas que estarán disponibles en el selector de capas. Estas capas serán mostradas sobre la parte superior de una capa normal, como si fuera una especie de marcador.", - "maps-osm-par-thumbs": "Mostrar las miniaturas", - "maps-osm-par-photos": "Mostrar las fotos", "mapeditor": "Editor de mapas", "specialpages-group-maps": "Mapas", "mapeditor-parser-error": "Se ha producido un error al analizar los metadatos. Ignorando la entrada del usuario.", @@ -199,5 +207,34 @@ "mapeditor-imageoverlay-button": "Agregar imagen superpuesta", "mapeditor-form-field-image": "Imagen", "mapeditor-imageoverlay-title": "Detalles de la imagen superpuesta", - "mapeditor-form-field-visitedicon": "Icono visitado" + "mapeditor-form-field-visitedicon": "Icono visitado", + "semanticmaps-unrecognizeddistance": "El valor $1 no es una distancia válida.", + "semanticmaps-kml-link": "Ver el archivo KML", + "semanticmaps-default-kml-pagelink": "Ver página $1", + "semanticmaps-latitude": "Latitud: $1", + "semanticmaps-longitude": "Longitud: $1", + "semanticmaps-altitude": "Altitud: $1", + "semanticmaps-forminput-locations": "Ubicaciones", + "semanticmaps-par-staticlocations": "Una lista de localizaciones para añadir al mapa junto a los datos consultados. De forma similar a display_points, puede añadir un título, una descripción o un icono por localización usando el signo \"~\" como separador.", + "semanticmaps-par-showtitle": "Mostrar o no mostrar un título en la ventana de información del marcador. La desactivación de esto es frecuentemente útil al utilizar una plantilla para dar formato al contenido de la ventana de información.", + "semanticmaps-par-hidenamespace": "Mostrar el título del espacio de nombres en la ventana de información del marcador.", + "semanticmaps-par-centre": "El centro del mapa. Cuando no se proporciona, el mapa escogerá automáticamente el mejor centro para mostrar todos los marcadores en el mapa.", + "semanticmaps-par-template": "Una plantilla a usar para dar formato al contenido de la ventana de información.", + "semanticmaps-par-geocodecontrol": "Mostrar el control de geocodificación.", + "semanticmaps-par-ajaxquery": "Una segunda consulta que se envía mediante AJAX para obtener coordenadas adicionales.", + "semanticmaps-par-userparam": "Un valor pasado en cada llamada de plantilla,si una plantilla es usada", + "semanticmaps-kml-text": "El texto asociado a cada página. Es substituído por las propiedades recuperadas adicionales, si existen.", + "semanticmaps-kml-title": "El título predeterminado de los resultados", + "semanticmaps-kml-linkabsolute": "Los enlaces deberían ser absolutos (lo opuesto de relativos)", + "semanticmaps-kml-pagelinktext": "El texto a usar para los enlaces a la página, en las que $1 será substituído por el título de la página", + "semanticmaps-shapes-improperformat": "Formateo incorrecto de $1, por favor consulta la documentación sobre formateo", + "semanticmaps-shapes-missingshape": "No se ha encontrado ninguna forma para $1, por favor consulta la documentación sobre formas disponibles", + "validator-type-mapscircle": "Círculo geográfico", + "validator-type-mapscircle-list": "Lista de círculos", + "validator-type-mapsline": "Línea geográfica", + "validator-type-mapsline-list": "Lista de líneas", + "validator-type-mapslocation": "Ubicación geográfica", + "validator-type-mapslocation-list": "Lista de ubicaciones", + "validator-type-mapsrectangle": "Rectángulo geográfico", + "validator-type-mapsrectangle-list": "Lista de rectángulos" } diff --git a/i18n/fa.json b/i18n/fa.json index 6cacaed6a..77c79b73e 100644 --- a/i18n/fa.json +++ b/i18n/fa.json @@ -42,7 +42,6 @@ "maps-layer-type-supported-by": "این نوع لایه می‌تواند {{PLURAL:$2|فقط با سرویس نقشه‌برداری $1 استفاده شود|با این سرویس‌های نقشه‌برداری استفاده شود: $1}}.", "maps-coordinates-description": "قلاب تجزیه کننده برای فرمت مختصات، از و به هر فرمت پشتیبانی شده.", "maps-displaymap-description": "نمایش نقشه‌های جغرافیایی بدون هر نشانگر تعریف شده‌ٔ ویکی بر روی آنها.", - "maps-displaypoint-description": "نمایش نقشه‌های جغرافیایی بدون هر نشانگر تعریف شده‌ٔ ویکی بر روی آنها.", "maps-distance-description": "تبدیل یک فاصله با استفاده از یک واحد مشخص پشتیبانی شده برابر با استفاده از واحد دیگری.", "maps-finddestination-description": "پیدا کردن یک مقصد که یک نقطهٔ شروع داده (که می‌تواند در هر فرمت پشتیبانی شده‌ای باشد)، وضع اولیه و یک فاصله.", "maps-geocode-description": "فعل کردن آدرس‌های جئوکدینگ، به عبارت دیگر تبدیل مکان‌های انسانی قابل خواندن به مجموعهٔ مختصات. پشتیبانی برای چندین سرویس های جئوکدینگ، که نباید با سرویس‌های نقشه برداری اشتباه شود، وجود دارد.", @@ -96,7 +95,6 @@ "maps-displaymap-par-wmsoverlay": "استفاده از یک پوشش وی‌ام‌اس", "maps-fullscreen-button": "ضامن تمام صفحه", "maps-fullscreen-button-tooltip": "مشاهدهٔ‌ نقشه به عنوان تمام صفحه یا تعبیه شده.", - "maps-googlemaps3-par-enable-fullscreen": "فعا کردن دکمهٔ تمام صفحه", "validation-error-invalid-location": "پارامتر $1 باید یک مکان معتبر باشد.", "validation-error-invalid-locations": "پارامتر $1 باید یک مکان یا مکان‌های بیشتر معتبری باشد.", "validation-error-invalid-width": "پارامتر $1 باید یک عرض معتبر باشد.", @@ -130,6 +128,8 @@ "maps-par-width": "اجازهٔ تنظیم عرض نقشه. با پیکسل‌های پیش‌فرض، به عنوان واحد فرض خواهد شد، اما شما می‌توانید یکی از این واحدها را به طور واضح مشخص کنید: پی‌ایکس، ای‌ایکس، ای‌ام، ٪.", "maps-par-height": "اجازهٔ تنظیم ارتفاع نقشه. با پیکسل‌های پیش‌فرض، به عنوان واحد فرض خواهد شد، اما شما می‌توانید یکی از این واحدها را به طور واضح مشخص کنید: پی‌ایکس، ای‌ایکس، ای‌ام، ٪.", "maps-par-centre": "مکانی که در نقشه باید مرکز باشد", + "maps-par-enable-fullscreen": "فعا کردن دکمهٔ تمام صفحه", + "maps-par-kml": "پوشه‌های کا‌ام‌ال برای بارگذاری بر روی نقشه.", "maps-googlemaps3-incompatbrowser": "مرورگر شما با نقشه‌های گوگل وی۳ سازگار نیست.", "maps-googlemaps3-par-type": "نوع نقشه برای ابتدا نشان دادن.", "maps-googlemaps3-par-types": "انواع نقشه‌ای که از طریق کنترل نوع در دسترس خواهد بود.", @@ -138,7 +138,6 @@ "maps-googlemaps3-par-zoomstyle": "سبک کنترل زوم.", "maps-googlemaps3-par-typestyle": "سبک کنترل نوع.", "maps-googlemaps3-par-autoinfowindows": "به طور خودکار باز شدن همهٔ صفحات اطلاعات، پس از بارگذاری صفحات.", - "maps-googlemaps3-par-kml": "پوشه‌های کا‌ام‌ال برای بارگذاری بر روی نقشه.", "maps-googlemaps3-par-gkml": "پوشه‌های کا‌ام‌ال توسط گوگل برای بارگذاری بر روی نقشه میزبانی شده‌.", "maps-googlemaps3-par-fusiontables": "شناسه‌های جداول گوگل فوژن که باید بر روی نقشه بارگذاری شود.", "maps-googlemaps3-par-tilt": "نوسان برای نقشه هنگامی که استفاده از نقشه‌های گوگل.", @@ -147,8 +146,6 @@ "maps-openlayers-par-controls": "کنترل‌ها برای قرار دادن بر روی نقشه.", "maps-openlayers-par-layers": "لایه‌هایی که در انتخاب کننده‌ٔ لایه در دسترس خواهند بود. اولین لایه هنگامی نمایش داده خواهد شد که نقشه بازگداری می‌شود.", "maps-openlayers-par-overlays": "لایه‌های پوششی در انتخاب کنندهٔ لایه در دسترس خواهد بود. این لایه‌ها در بالای یک لایهٔ عادی، نمایش داده خواهد شد، نوعی مانند یک علامت.", - "maps-osm-par-thumbs": "نشان دادن جای شست", - "maps-osm-par-photos": "نمایش عکس‌ها", "mapeditor": "تدوین‌گر نقشه", "specialpages-group-maps": "نقشه‌ها", "mapeditor-parser-error": "خطاای هنگام تجزیه‌ٔ فراداده اتفاق افتاد. نادیده گرفتن ورودی کاربر.", @@ -184,5 +181,26 @@ "mapeditor-imageoverlay-button": "افزودن روی هم قرار دادن عکس", "mapeditor-form-field-image": "تصویر", "mapeditor-imageoverlay-title": "جزئیات روی هم قرار دادن عکس", - "mapeditor-form-field-visitedicon": "نمادهای بازدید شده" + "mapeditor-form-field-visitedicon": "نمادهای بازدید شده", + "semanticmaps-unrecognizeddistance": "مقدار $1 یک فاصلهٔ معتبر نیست.", + "semanticmaps-kml-link": "مشاهدهٔ پوشهٔ کا‌ام‌ال", + "semanticmaps-default-kml-pagelink": "مشاهده صفحهٔ $1", + "semanticmaps-latitude": "عرض جغرافیایی: $1", + "semanticmaps-longitude": "طول جغرافیایی: $1", + "semanticmaps-altitude": "ارتفاع: $1", + "semanticmaps-forminput-locations": "مکان‌ها", + "semanticmaps-par-staticlocations": "فهرست مکان‌های برای افزودن به نقشه با اطلاعات سوال شده. مانند با display_points، شما می توانید یک عنوان، توصیف و نماد در هر مکان با استفاده از عنوان جدا کننده \"~\".", + "semanticmaps-par-showtitle": "نمایش یک عنوان در پنجره اطلاعات نشانگر یا نمایش ندادن آن.غیرفعال کردن این اغلب مفید است هنگام استفاده از الگو برای فرمت کردن محتوای پنجره اطلاعات.", + "semanticmaps-par-hidenamespace": "نمایش عنوان فضای نام در پنجره اطلاعات نشانگر", + "semanticmaps-par-centre": "مرکز نقشه. هنگامی که ارائه نشد،نقشه به طور خودکار مرکز مطلوب را برای نمایش همه نشانگرها در نقشه انتخاب می‌کند.", + "semanticmaps-par-template": "الگو برای استفاده از فرمت محتویات پنجره اطلاعات.", + "semanticmaps-par-geocodecontrol": "نشان دادن کنترل جئوکدینگ.", + "semanticmaps-par-activeicon": "نماد به جای نشانگر پیش‌فرض نمایش داده می‌شود هنگامی که صفحه فعال برابر با نتیجه پرس‌و‌جوی است", + "semanticmaps-par-pagelabel": "هنگامی که به «بله» تنظیم می‌شود، همه نشانگرها، یک «inlineLabel» با یک پیوند به صفحه دارند که شامل مختصات برای نشانگر است", + "semanticmaps-kml-text": "متن با هر صفحه مرتبط است. اگر هر خواص پرس‌وجو اضافی وجود داشته باشد، به‌وسیله آن خذف لغو شده.", + "semanticmaps-kml-title": "عنوان پیش‌زمینه برای نتایج", + "semanticmaps-kml-linkabsolute": "پیوندها باید (به عنوان مخالف به نسبی) مطلق باشند", + "semanticmaps-kml-pagelinktext": "متن برای استفاده پیوندها به صفحه، که در آن توسط عنوان صفحه $1 جایگزین خواهد شد", + "semanticmaps-shapes-improperformat": "شکل‌بندی نادرست $1. لطفاً مستندات را برای شکل‌بندی مشاهده کنید", + "semanticmaps-shapes-missingshape": "هیچ شکلی برای$1 پیدا نشد. لطفاً مستندات را برای شکل‌های دردسترس مشاهده کنید" } diff --git a/i18n/fi.json b/i18n/fi.json index 6d6e5a009..1298307b3 100644 --- a/i18n/fi.json +++ b/i18n/fi.json @@ -71,7 +71,6 @@ "maps-displaymap-par-static": "Onko kartan on oltava staattinen", "maps-fullscreen-button": "Koko näytön tila", "maps-fullscreen-button-tooltip": "Näytä kartta koko näytön tilassa tai upotettuna.", - "maps-googlemaps3-par-enable-fullscreen": "Koko näytön tila -painike", "validation-error-invalid-location": "Parametrin $1 on oltava sallittu sijainti.", "validation-error-invalid-locations": "Parametrin $1 on oltava yksi tai useampi sallittu sijainti.", "validation-error-invalid-width": "Parametrin $1 on oltava sallittu leveys.", @@ -102,6 +101,8 @@ "maps-par-width": "Mahdollistaa kartan leveyden asettamisen. Oletusyksikkönä on pikseli, mutta voit erikseen määrittää jonkin seuraavista yksiköistä: px, ex, em, %.", "maps-par-height": "Mahdollistaa kartan korkeuden asettamisen. Oletusyksikkönä on pikseli, mutta voit erikseen määrittää jonkin seuraavista yksiköistä: px, ex, em, %.", "maps-par-centre": "Sijainti, johon kartta keskitetään", + "maps-par-enable-fullscreen": "Koko näytön tila -painike", + "maps-par-kml": "Kartalle ladattavat KML-tiedostot.", "maps-googlemaps3-incompatbrowser": "Selaimesi ei ole yhteensopiva Google Maps v3:n kanssa.", "maps-googlemaps3-par-type": "Ensimmäiseksi näytettävä karttatyyppi.", "maps-googlemaps3-par-types": "Karttatasovalitsimen käyttämät karttatyypit.", @@ -110,14 +111,11 @@ "maps-googlemaps3-par-zoomstyle": "Loitonnusohjaimen tyyli.", "maps-googlemaps3-par-typestyle": "Karttatasovalitsimen tyyli.", "maps-googlemaps3-par-autoinfowindows": "Avaa automaattisesti kaikki tietoikkunat sen jälkeen, kun sivu on ladattu.", - "maps-googlemaps3-par-kml": "Kartalle ladattavat KML-tiedostot.", "maps-googlemaps3-par-fusiontables": "Google Fusion Tables -tunnukset, joka ladataan karttaan.", "maps-googlemaps3-par-tilt": "Kartan kallistus, kun käytössä on Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Valitse paras loitonnustaso uudelleen sen jälkeen, kun KML-tasot on ladattu.", "maps-openlayers-par-controls": "Kartalle sijoitettavat ohjaimet.", "maps-openlayers-par-layers": "Tasot, jotka näytetään karttatasojen valinnassa. Kartan oletustaso on listan ensimmäinen taso.", - "maps-osm-par-thumbs": "Näytä pienoiskuvat", - "maps-osm-par-photos": "Näytä valokuvat", "mapeditor": "Kartan muokkausohjelma", "specialpages-group-maps": "Kartat", "mapeditor-parser-error": "Metadatan jäsennys epäonnistui. Käyttäjän antamat tiedot ohitetaan.", @@ -145,5 +143,24 @@ "mapeditor-form-field-showonhover": "Näytä työkaluvihjeenä", "mapeditor-mapparam-title": "Kartan parametrien muokkaus", "mapeditor-mapparam-defoption": "-Valitse parametri-", - "mapeditor-form-field-image": "Kuva" + "mapeditor-form-field-image": "Kuva", + "semanticmaps-unrecognizeddistance": "Arvoa $1 ei ole sallittu etäisyys.", + "semanticmaps-kml-link": "Näytä KLM-tiedosto", + "semanticmaps-default-kml-pagelink": "Näytä sivu $1", + "semanticmaps-latitude": "Leveyspiiri: $1", + "semanticmaps-longitude": "Pituuspiiri: $1", + "semanticmaps-altitude": "Korkeus: $1", + "semanticmaps-forminput-locations": "Sijainnit", + "semanticmaps-par-staticlocations": "Sijaintien luettelo voidaan lisätä karttaan kyselydatan lisäksi. Kuten display_points-parametrissa voit lisätä sijaintikohtaisen otsikon, kuvauksen ja kuvakkeen; erottimena on \"~\".", + "semanticmaps-par-showtitle": "Näyttää kohdemerkin tietoikkunan otsikon tai ei. Käytöstä poisto on usein hyödyllistä, jos tietoikkunan sisältö muotoillaan mallineella.", + "semanticmaps-par-hidenamespace": "Näytä nimiavaruuden otsikko kohdemerkin tietoikkunassa", + "semanticmaps-par-centre": "Kartan keskus. Jos sitä ei määritetä, kartta laskee automaattisesti optimaalisen keskuksen kartalla olevien kohdemerkkien perusteella.", + "semanticmaps-par-template": "Tietoikkunan sisällön muotoilussa käytettävä malline.", + "semanticmaps-par-geocodecontrol": "Näytä geokoodausohjaimet.", + "semanticmaps-kml-text": "Kuhunkin sivuun liittyvä teksti. Jos kyselyllä on lisäominaisuuksia, ne syrjäyttävät tämän.", + "semanticmaps-kml-title": "Tulossivun oletusotsikko", + "semanticmaps-kml-linkabsolute": "Ovatko linkit absoluuttisia (eivätkä suhteellisia)", + "semanticmaps-kml-pagelinktext": "Sivulinkeissä käytettävä teksti, jossa $1 korvataan sivun otsikolla", + "semanticmaps-shapes-improperformat": "$1 on muotoiltu väärin. Katso muotoilun dokumentaatiota.", + "semanticmaps-shapes-missingshape": "$1: muotoja ei löytynyt. Dokumentaatiossa kerrotaan sallituista muodoista." } diff --git a/i18n/fr.json b/i18n/fr.json index 0d3c90072..ed434b056 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -17,7 +17,12 @@ "Wyz", "Weft", "Jonathan1", - "Lbayle" + "Lbayle", + "Yasten", + "Trial", + "Wladek92", + "Urhixidur", + "Grondin" ] }, "maps-desc": "Permet d’afficher des cartes dynamiques dans les pages du wiki, des adresses géo-codées et d'autres opérations géographiques.", @@ -52,11 +57,10 @@ "maps-layer-of-type": "Couche de type $1", "maps-layer-of-type-and-name": "Couche « $2 » de type « $1 »", "maps-layer-type-supported-by": "Ce type de couche peut {{PLURAL:$2|être utilisé uniquement avec le service de cartographie $1|être utilisé avec ces services de cartographie : $1}}.", - "maps-coordinates-description": "Crochet de l'analyseur pour formater les coordonnées, depuis et vers n'importe quel format supporté.", + "maps-coordinates-description": "Crochet de l’analyseur syntaxique pour formater les coordonnées, depuis et vers n’importe quel format pris en charge.", "maps-displaymap-description": "Affiche les cartes géographiques sans aucun marqueur wiki sur eux.", - "maps-displaypoint-description": "Affiche les cartes géographiques avec un ou plusieurs marqueurs wiki sur eux.", "maps-distance-description": "Convertit une distance d'une certaine unité prise en charge à son équivalent en utilisant une autre unité.", - "maps-finddestination-description": "Trouver une destination avec un point de départ donné (qui peuvent être dans n'importe lequel des formats supportés), une orientation initiale et une distance.", + "maps-finddestination-description": "Trouver une destination avec un point de départ donné (qui peut être dans n’importe lequel des formats pris en charge), une orientation initiale et une distance.", "maps-geocode-description": "Permet le géocodage d'adresses, en d'autres termes, la transformation des positions humainement lisible en ensembles de coordonnées. Plusieurs services de géocodage sont pris en charge, qui ne doivent pas être confondu avec les services de cartographie.", "maps-geodistance-description": "Calculer la distance géographique entre deux points, depuis et vers n'importe quel format pris en charge.", "maps-mapsdoc-description": "Affiche une table avec les paramètres pour un service de cartographie spécifié, avec leurs valeurs par défaut et leur description.", @@ -108,7 +112,6 @@ "maps-displaymap-par-wmsoverlay": "Utiliser une superposition WMS", "maps-fullscreen-button": "Basculer en plein écran", "maps-fullscreen-button-tooltip": "Visualiser la carte en plein écran ou incorporé.", - "maps-googlemaps3-par-enable-fullscreen": "Activer le bouton plein écran", "validation-error-invalid-location": "Le paramètre $1 doit être un emplacement valide.", "validation-error-invalid-locations": "Le paramètre $1 doit être un ou plusieurs emplacement(s) valide(s).", "validation-error-invalid-width": "Le paramètre $1 doit être une largeur valide.", @@ -134,9 +137,11 @@ "maps_map_cannot_be_displayed": "La carte ne peut pas être affichée.", "maps-geocoder-not-available": "La fonctionnalité géocodage des cartes n'est pas disponible. Votre emplacement ne peut être géocodé.", "maps_leaflet": "Dépliant", - "maps-leaflet-par-zoom": "Permet de définir le niveau de zoom de la carte.", "maps-leaflet-par-defzoom": "Permet de définir le niveau de zoom par défaut de la carte.", - "maps-leaflet-par-resizable": "Permet de rendre la carte redimensionnable en tirant sur son coin inférieur droit.", + "maps-leaflet-par-layer": "La couche qui sera affichée pendant que la carte se charge.", + "maps-leaflet-par-overlaylayers": "Les surcouches qui seront affichées pendant que la carte se charge.", + "maps-leaflet-par-maxclusterradius": "Rayon maximal qu'un agrégat peut couvrir en partant du marqueur central (en pixels).", + "maps-leaflet-par-clusterspiderfy": "Lorsque vous cliquez sur un cluster à bas niveau de zoom nous l'explicitons afin que vous puissiez voir l'ensemble de ses marqueurs.", "maps_click_to_activate": "Cliquer pour activer la carte", "maps_centred_on": "Carte centrée sur $1, $2.", "maps-par-mappingservice": "Permet de régler le service de cartographie qui sera utilisé pour générer la carte.", @@ -147,9 +152,11 @@ "maps-par-width": "Permet de définir la largeur de la carte. Par défaut les pixels seront considérés comme unité, mais vous pouvez spécifier explicitement une de ces unités : px, ex, em, %.", "maps-par-height": "Permet de définir la hauteur de la carte. Par défaut les pixels seront considérés comme unité, mais vous pouvez spécifier explicitement une de ces unités : px, ex, em, %.", "maps-par-centre": "Le lieu sur lequel la carte devra être centrée", + "maps-par-enable-fullscreen": "Activer le bouton plein écran", + "maps-par-kml": "Fichiers KML à charger sur la carte.", + "maps-par-markercluster": "Autoriser la fusion de plusieurs repères à proximité en un seul repère", "maps-googlemaps3-incompatbrowser": "Votre navigateur n'est pas compatible avec Google Maps v3.", "maps-googlemaps3-par-imageoverlays": "Permet d'ajouter une image à l'emplacement indiqué sur la carte.", - "maps-googlemaps3-par-markercluster": "Autoriser la fusion de plusieurs repères à proximité en un seul repère", "maps-googlemaps3-par-type": "Le type de carte à afficher initialement.", "maps-googlemaps3-par-types": "Les types de carte qui seront disponibles via le contrôle de type.", "maps-googlemaps3-par-layers": "Couches spéciales à charger sur la carte.", @@ -157,17 +164,20 @@ "maps-googlemaps3-par-zoomstyle": "Style du contrôle de zoom.", "maps-googlemaps3-par-typestyle": "Style du contrôle de type.", "maps-googlemaps3-par-autoinfowindows": "Ouvrir automatiquement toutes les fenêtres d'information après le chargement de la page.", - "maps-googlemaps3-par-kml": "Fichiers KML à charger sur la carte.", "maps-googlemaps3-par-gkml": "Les fichiers KML hébergés par Google à charger sur la carte.", "maps-googlemaps3-par-fusiontables": "ID des tables de Google Fusion qui devrait être chargées sur la carte.", "maps-googlemaps3-par-tilt": "Inclinaison de la carte lors de l'utilisation de Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Zoomer de nouveau la carte une fois que les couches KML ont été chargées", "maps-googlemaps3-par-poi": "Afficher les points d’intérêt", + "maps-googlemaps3-par-clustergridsize": "La taille de la grille (en pixels) d'un agrégat.", + "maps-par-clustermaxzoom": "Niveau maximal de zoom pour lequel des agrégats peuvent exister.", + "maps-par-clusterzoomonclick": "Si le comportement par défaut de cliquer sur un agrégat est de zoomer.", + "maps-par-maxclusterradius": "Le rayon maximal que ce groupe couvrira.", + "maps-googlemaps3-par-clusteraveragecenter": "Si le centre de chaque groupe est le barycentre des marqueurs de l'agrégat.", + "maps-googlemaps3-par-clusterminsize": "Le nombre minimum de marqueurs dans un agrégat avant que les marqueurs ne soient cachés et qu'un compteur ne les remplace.", "maps-openlayers-par-controls": "Les contrôles à placer sur la carte.", "maps-openlayers-par-layers": "Les couches qui seront disponibles dans le sélecteur de couche. La première couche sera affichée lors du chargement de la carte.", "maps-openlayers-par-overlays": "Superposer les couches qui seront disponibles dans le sélecteur de couches. Ces couches seront affichées par dessus la couche normale, comme une sorte de marqueur.", - "maps-osm-par-thumbs": "Afficher des miniatures", - "maps-osm-par-photos": "Afficher des photos", "mapeditor": "Éditeur de carte", "specialpages-group-maps": "Cartes", "mapeditor-parser-error": "Une erreur s'est produite lors de l'analyse des métadonnées. Entrées de l'utilisateur ignorées.", @@ -203,5 +213,42 @@ "mapeditor-imageoverlay-button": "Ajouter la couverture d'image", "mapeditor-form-field-image": "Image", "mapeditor-imageoverlay-title": "Détails de la couverture d'image", - "mapeditor-form-field-visitedicon": "Icône visité" + "mapeditor-form-field-visitedicon": "Icône visité", + "semanticmaps-unrecognizeddistance": "La valeur $1 n'est pas une distance valide", + "semanticmaps-kml-link": "Voir le fichier KML", + "semanticmaps-default-kml-pagelink": "Voir l’article $1", + "semanticmaps-latitude": "Latitude : $1", + "semanticmaps-longitude": "Longitude : $1", + "semanticmaps-altitude": "Altitude : $1", + "semanticmaps-forminput-locations": "Emplacements", + "semanticmaps-par-staticlocations": "Une liste des endroits à ajouter à la carte avec les données demandées. Comme avec display_points, vous pouvez ajouter un titre, une description et une icône par emplacement en utilisant le tilde « ~ » comme séparateur.", + "semanticmaps-par-showtitle": "Afficher un titre dans la fenêtre d'informations des marqueurs ou non. La désactivation de ceci est souvent utile lorsque vous utilisez un modèle pour formater le contenu de la fenêtre d'informations.", + "semanticmaps-par-hidenamespace": "Afficher le titre de l’espace de noms dans la fenêtre d’information du marqueur.", + "semanticmaps-par-centre": "Le centre de la carte. Lorsqu'il n'est pas fourni, la carte va choisir automatiquement le centre optimal pour afficher tous les marqueurs sur la carte.", + "semanticmaps-par-template": "Un modèle à utiliser pour mettre en forme le contenu de la fenêtre d'informations.", + "semanticmaps-par-geocodecontrol": "Afficher le contrôle de géocodage.", + "semanticmaps-par-activeicon": "Icône à afficher à la place du marqueur par défaut, quand la page active est égale au résultat de la recherche", + "semanticmaps-par-pagelabel": "Quand il vaut « oui », tous les marqueurs auront un « inlineLabel » avec un lien vers la page contenant les coordonnées du marqueur", + "semanticmaps-par-ajaxcoordproperty": "Nom de la propriété de coordonnées utilisée pour construire la requête Ajax.", + "semanticmaps-par-ajaxquery": "Une seconde requête qui est envoyée via Ajax pour récupérer les coordonnées supplémentaires.", + "semanticmaps-par-userparam": "Une valeur passée dans chaque appel de modèle, si un modèle est utilisé", + "semanticmaps-kml-text": "Le texte associé avec chaque page. Remplacé par des propriétés récupérées supplémentaires s'il y en a.", + "semanticmaps-kml-title": "Le titre par défaut pour les résultats", + "semanticmaps-kml-linkabsolute": "Si les titres doivent être absolus (au contraire de relatifs)", + "semanticmaps-kml-pagelinktext": "Le texte à utiliser pour les liens vers la page, dans lesquels $1 sera remplacé par le titre de la page", + "semanticmaps-shapes-improperformat": "Format de $1 incorrect, veuillez vous reporter à la documentation pour le format attendu", + "semanticmaps-shapes-missingshape": "Aucune forme trouvée pour $1; veuillez voir dans la documentation les formes disponibles", + "validator-type-mapscircle": "Cercle géographique", + "validator-type-mapscircle-list": "Liste des cercles", + "validator-type-mapsimageoverlay": "Superposition d’image", + "validator-type-mapsimageoverlay-list": "Liste des superpositions d’image", + "validator-type-mapsline": "Ligne géographique", + "validator-type-mapsline-list": "Liste des lignes", + "validator-type-mapslocation": "Emplacement géographique", + "validator-type-mapslocation-list": "Liste des emplacements", + "validator-type-mapsrectangle": "Rectangle géographique", + "validator-type-mapsrectangle-list": "Liste des rectangles", + "validator-type-mapspolygon": "Polygone géographique", + "validator-type-mapspolygon-list": "Liste des polygones géographiques", + "validator-type-wmsoverlay": "Surcouche de Service de Carte web" } diff --git a/i18n/frp.json b/i18n/frp.json index 4332dd3d3..18efd662f 100644 --- a/i18n/frp.json +++ b/i18n/frp.json @@ -41,8 +41,6 @@ "maps_centred_on": "Mapa centrâ dessus $1, $2.", "maps-googlemaps3-par-poi": "Montrar los pouents d’entèrèt.", "maps-openlayers-par-controls": "Los contrôlos a placiér sur la mapa.", - "maps-osm-par-thumbs": "Fâre vêre des figures", - "maps-osm-par-photos": "Fâre vêre des fotôs", "mapeditor": "Changior de mapa", "specialpages-group-maps": "Mapes", "mapeditor-none-text": "Nion", @@ -76,5 +74,18 @@ "mapeditor-imageoverlay-button": "Apondre la cuvèrta d’émâge", "mapeditor-form-field-image": "Émâge", "mapeditor-imageoverlay-title": "Dètalys de la cuvèrta d’émâge", - "mapeditor-form-field-visitedicon": "Icôna visitâ" + "mapeditor-form-field-visitedicon": "Icôna visitâ", + "semanticmaps-unrecognizeddistance": "La valor $1 est pas una distance valida.", + "semanticmaps-kml-link": "Vêre lo fichiér KML", + "semanticmaps-default-kml-pagelink": "Vêre la pâge $1", + "semanticmaps-loading-forminput": "Chargement du formulèro d’entrâ de la mapa...", + "semanticmaps_lookupcoordinates": "Èstimar les coordonâs", + "semanticmaps_enteraddresshere": "Buchiéd l’adrèce ique", + "semanticmaps-updatemap": "Misa a jorn de la mapa", + "semanticmaps-forminput-remove": "Enlevar", + "semanticmaps-forminput-add": "Apondre", + "semanticmaps-latitude": "Latituda : $1", + "semanticmaps-longitude": "Longituda : $1", + "semanticmaps-altitude": "Hôtior : $1", + "semanticmaps-forminput-locations": "Emplacements" } diff --git a/i18n/fy.json b/i18n/fy.json index c98005bea..0ac2a2c79 100644 --- a/i18n/fy.json +++ b/i18n/fy.json @@ -1,7 +1,8 @@ { "@metadata": { "authors": [ - "Robin0van0der0vliet" + "Robin0van0der0vliet", + "Robin van der Vliet" ] }, "maps-layer-property": "Eigenskip", diff --git a/i18n/gl.json b/i18n/gl.json index d91f8c3b0..b7ed21b2e 100644 --- a/i18n/gl.json +++ b/i18n/gl.json @@ -8,8 +8,8 @@ ] }, "maps-desc": "Permite incorporar mapas dinámicos, enderezos xeocodificados e outras operacións xeográficas nas páxinas do wiki", - "right-geocode": "Xeocódigo", - "action-geocode": "Xeocodificar nesta wiki", + "right-geocode": "Xeocodificar", + "action-geocode": "xeocodificar neste wiki", "maps_map": "Mapa", "maps-tracking-category": "Páxinas cun mapa renderizado coa extensión Maps", "maps-loading-map": "Cargando o mapa...", @@ -41,7 +41,6 @@ "maps-layer-type-supported-by": "Este tipo de capa só se pode empregar {{PLURAL:$2|co servizo de mapas $1|con estes servizos de mapas: $1}}.", "maps-coordinates-description": "Asociador do analizador para dar formato ás coordenadas, desde e cara a calquera formato soportado.", "maps-displaymap-description": "Mostrar os mapas xeográficos sen marcadores wiki sobre eles.", - "maps-displaypoint-description": "Mostrar os mapas xeográficos con, polo menos, un ou máis marcadores wiki sobre eles.", "maps-distance-description": "Converter unha distancia nunha certa unidade soportada na súa equivalente noutra unidade.", "maps-finddestination-description": "Atopar un destino a partir dun punto de partida (que pode ser en calquera dos formatos soportados), unha orientación inicial e unha distancia.", "maps-geocode-description": "Permite a xeocodificación de enderezos; noutras palabras, transformar as localizacións lexibles por humanos en conxuntos de coordenadas. Hai soporte para diversos servizos de xeocodificación, que non se deben confundir cos servizos de cartografía.", @@ -95,7 +94,6 @@ "maps-displaymap-par-wmsoverlay": "Utilizar unha sobreposición WMS", "maps-fullscreen-button": "Activar ou desactivar a pantalla completa", "maps-fullscreen-button-tooltip": "Mostrar o mapa en pantalla completa ou incrustado.", - "maps-googlemaps3-par-enable-fullscreen": "Activar o botón de pantalla completa", "validation-error-invalid-location": "O parámetro \"$1\" debe ser unha localización válida.", "validation-error-invalid-locations": "O parámetro \"$1\" debe ser unha ou máis localizacións válidas.", "validation-error-invalid-width": "O parámetro \"$1\" debe ser un largo válido.", @@ -121,9 +119,9 @@ "maps_map_cannot_be_displayed": "O mapa non se pode mostrar.", "maps-geocoder-not-available": "A funcionalidade de xeocodificación de mapas non está dispoñible; non se pode xeocodificar a súa situación.", "maps_leaflet": "Folleto", - "maps-leaflet-par-zoom": "Permite definir o nivel de zoom do mapa.", "maps-leaflet-par-defzoom": "Permite definir o nivel de zoom por defecto do mapa.", - "maps-leaflet-par-resizable": "Permite que o mapa sexa redimensionable tirando da súa esquina inferior dereita.", + "maps-leaflet-par-layer": "A capa que se mostrará cando se cargue o mapa.", + "maps-leaflet-par-overlaylayers": "As capas de transparencia que se mostrarán cando se cargue o mapa.", "maps_click_to_activate": "Prema para activar o mapa", "maps_centred_on": "Mapa centrado en $1, $2.", "maps-par-mappingservice": "Permite configurar o servizo de mapas que se empregará para xerar o mapa.", @@ -134,9 +132,11 @@ "maps-par-width": "Permite definir o largo do mapa. Por defecto, os píxeles asúmense como unidade, pero tamén pode especificar unha destas unidades: px, ex, em, %.", "maps-par-height": "Permite definir a altura do mapa. Por defecto, os píxeles asúmense como unidade, pero tamén pode especificar unha destas unidades: px, ex, em, %.", "maps-par-centre": "O lugar no que se debe centrar o mapa", + "maps-par-enable-fullscreen": "Activar o botón de pantalla completa", + "maps-par-kml": "Ficheiros KML que cargar no mapa.", + "maps-par-markercluster": "Permite fusionar múltiples marcadores cercanos nun só marcador", "maps-googlemaps3-incompatbrowser": "O seu navegador é compatible co Google Maps v3.", "maps-googlemaps3-par-imageoverlays": "Permite engadir unha imaxe a mostrar na situación especificada no mapa.", - "maps-googlemaps3-par-markercluster": "Permite fusionar múltiples marcadores cercanos nun só marcador", "maps-googlemaps3-par-type": "O tipo de mapa que mostrar inicialmente.", "maps-googlemaps3-par-types": "Os tipos de mapas que estarán dispoñibles a través do control de tipos.", "maps-googlemaps3-par-layers": "As capas especiais que cargar no mapa.", @@ -144,17 +144,15 @@ "maps-googlemaps3-par-zoomstyle": "O estilo do control do zoom.", "maps-googlemaps3-par-typestyle": "O estilo do control do tipo.", "maps-googlemaps3-par-autoinfowindows": "Abrir automaticamente todas as ventás de información tras a carga da páxina.", - "maps-googlemaps3-par-kml": "Ficheiros KML que cargar no mapa.", "maps-googlemaps3-par-gkml": "Ficheiros KML aloxados polo Google que cargar no mapa.", "maps-googlemaps3-par-fusiontables": "Identificadores das táboas do Google Fusion que se deben cargar no mapa.", "maps-googlemaps3-par-tilt": "Inclinación do mapa ao empregar o Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Axustar o nivel de zoom despois da carga das capas KML.", "maps-googlemaps3-par-poi": "Mostrar os puntos de interese.", + "maps-googlemaps3-par-clustergridsize": "A medida da reixa dun grupo de píxeles.", "maps-openlayers-par-controls": "Os controis que incluír no mapa.", "maps-openlayers-par-layers": "As capas que estarán dispoñibles no selector de capas. A primeira capa aparecerá cando o mapa acabe de cargar.", "maps-openlayers-par-overlays": "As capas de sobreposición que estarán dispoñibles no selector de capas. Estas capas han mostrarse por riba da capa normal, como un marcador.", - "maps-osm-par-thumbs": "Mostrar as miniaturas", - "maps-osm-par-photos": "Mostrar as fotos", "mapeditor": "Editor de mapa", "specialpages-group-maps": "Mapas", "mapeditor-parser-error": "Houbo un erro ao analizar os metadatos. Ignórase a entrada do usuario.", @@ -190,5 +188,42 @@ "mapeditor-imageoverlay-button": "Engadir a sobreposición da imaxe", "mapeditor-form-field-image": "Imaxe", "mapeditor-imageoverlay-title": "Detalles da sobreposición da imaxe", - "mapeditor-form-field-visitedicon": "Icona visitada" + "mapeditor-form-field-visitedicon": "Icona visitada", + "semanticmaps-unrecognizeddistance": "O valor $1 non é unha distancia válida.", + "semanticmaps-kml-link": "Ollar o ficheiro KML", + "semanticmaps-default-kml-pagelink": "Ver a páxina \"$1\"", + "semanticmaps-latitude": "Latitude: $1", + "semanticmaps-longitude": "Lonxitude: $1", + "semanticmaps-altitude": "Altitude: $1", + "semanticmaps-forminput-locations": "Localizacións", + "semanticmaps-par-staticlocations": "Unha lista de localizacións para engadir ao mapa xunto aos datos consultados. Como con display_points, pode engadir un título, unha descrición e mais unha icona por localización mediante o signo \"~\" como separador.", + "semanticmaps-par-showtitle": "Mostrar ou non un título na ventá de información do marcador. Frecuentemente, desactivar isto é útil ao utilizar un modelo para dar formato ao contido da ventá de información.", + "semanticmaps-par-hidenamespace": "Mostrar o título do espazo de nomes na ventá de información do marcador", + "semanticmaps-par-centre": "O centro do mapa. Cando non se proporciona, o mapa ha escoller automaticamente o mellor centro para mostrar todos os marcadores no mapa.", + "semanticmaps-par-template": "Un modelo a empregar para dar formato ao contido da ventá de información.", + "semanticmaps-par-geocodecontrol": "Mostrar o control de xeocodificación.", + "semanticmaps-par-activeicon": "Icona a mostrar no canto do marcador predeterminado, cando a páxina é igual ao resultado da pescuda", + "semanticmaps-par-pagelabel": "Ao definirse en \"si\", todos os macadores terán un \"inlineLabel\" cunha ligazón cara á páxina que conten as coordenadas do marcador", + "semanticmaps-par-ajaxcoordproperty": "Nome da propiedade de coordenadas usada para construír a consulta Ajax.", + "semanticmaps-par-ajaxquery": "Unha segunda consulta que é enviada vía Ajax para recuperar as coordenadas adicionais.", + "semanticmaps-par-userparam": "O valor pasado en cada chamada de modelo, se se empregase algún modelo", + "semanticmaps-kml-text": "O texto asociado a cada páxina. Substituído polas propiedades pescudadas adicionais, se existen.", + "semanticmaps-kml-title": "O título por defecto para os resultados", + "semanticmaps-kml-linkabsolute": "Se as ligazóns deberían ser absolutas (contrario a relativas)", + "semanticmaps-kml-pagelinktext": "O texto a usar para as ligazóns cara á páxina, nas que \"$1\" será substituído polo título da páxina", + "semanticmaps-shapes-improperformat": "Formato incorrecto de \"$1\"; consulte a documentación sobre os formatos", + "semanticmaps-shapes-missingshape": "Non se atopou forma ningunha para \"$1\"; consulte a documentación sobre as formas dispoñibles", + "validator-type-mapscircle": "Círculo xeográfico", + "validator-type-mapscircle-list": "Lista de círculos", + "validator-type-mapsimageoverlay": "Superposición de imaxe", + "validator-type-mapsimageoverlay-list": "Lista de superposicións de imaxe", + "validator-type-mapsline": "Liña xeográfica", + "validator-type-mapsline-list": "Lista de liñas", + "validator-type-mapslocation": "Localización xeográfica", + "validator-type-mapslocation-list": "Lista de localizacións", + "validator-type-mapsrectangle": "Rectángulo xeográfico", + "validator-type-mapsrectangle-list": "Lista de rectángulos", + "validator-type-mapspolygon": "Polígono xeográfico", + "validator-type-mapspolygon-list": "Lista dos polígonos xeográficos", + "validator-type-wmsoverlay": "Transparencia de Servizo de Mapa web" } diff --git a/i18n/he.json b/i18n/he.json index 5c07b8635..8a4eba0d5 100644 --- a/i18n/he.json +++ b/i18n/he.json @@ -10,12 +10,14 @@ "ערן", "תומר ט", "Inkbug", - "Macofe" + "Macofe", + "Guycn2", + "המקיסט" ] }, "maps-desc": "הוספת האפשרות להטמעת מפות דינמיות אל תוך דפי ויקי, קידוד גאוגרפי של כתובות ופעולות גאוגרפיות אחרות", - "right-geocode": "לעשות קידוד גאוגרפי", - "action-geocode": "לעשות קידוד גאוגרפי בוויקי הזה", + "right-geocode": "ביצוע קידודים גאוגרפיים", + "action-geocode": "לבצע קידודים גאוגרפיים באתר הוויקי הזה", "maps_map": "מפה", "maps-tracking-category": "דפים עם מפה שהוכנה באמצעות הרחבת המפות", "maps-loading-map": "המפה נטענת...", @@ -47,7 +49,6 @@ "maps-layer-type-supported-by": "השכבה הזאת יכולה לעבוד רק עם {{PLURAL:$2|שירות המפות הבא|שירותי המפות הבאים}}: $1.", "maps-coordinates-description": "מילת הפעלה לעיצוב נקודות ציון, מכל תסדיר נתמך לכל תסדיר נתמך.", "maps-displaymap-description": "להציג מפות גאוגרפיות ללא שום סמנים מוגדרים בוויקי עליהן.", - "maps-displaypoint-description": "להציג מפות גאוגרפיות עם סמן מוגדר בוויקי אחד או יותר עליהן.", "maps-distance-description": "להמיר את המרחק ביחידות נתמכות מסוימות לערך מתאים ביחידות אחרות.", "maps-finddestination-description": "למצוא את היעד בהינתן נקודת התחלה (שיכולה להיות בכל פורמט), הכיוון הראשוני והמרחק.", "maps-geocode-description": "מפעיל קידוד גאוגרפי של כתובות, במילים אחרות, הופך מיקומים עם שמות שאנשים יכולים לקרוא לערכות של נקודות ציון. יש תמיכה במספר שירותי קידוד גאוגרפי, ואין להתבלבל בינם לבין שירותי מיפוי.", @@ -101,7 +102,6 @@ "maps-displaymap-par-wmsoverlay": "להשתמש בשכבת כיסוי WMS", "maps-fullscreen-button": "להפעיל מסך מלא", "maps-fullscreen-button-tooltip": "להציג את המפה במסך מלא או מוטבעת", - "maps-googlemaps3-par-enable-fullscreen": "להפעיל כתפור מסך מלא", "validation-error-invalid-location": "הערך $1 צריך להיות מיקום תקין.", "validation-error-invalid-locations": "הערך $1 צריך להיות מיקום תקין אחד או יותר.", "validation-error-invalid-width": "הערך $1 צריך להיות רוחב תקין.", @@ -126,6 +126,8 @@ "maps_unrecognized_coords_for": "{{PLURAL:$2|נקודת הציון הבאה לא זוהתה והושמטה|נקודות הציון הבאות לא זוהו והושמטו}} מהמפה: $1", "maps_map_cannot_be_displayed": "לא ניתן להציג את המפה.", "maps-geocoder-not-available": "הקידוד הגאוגרפי של מפות אינו זמין. לא ניתן לקודד את המיקום שנבחר.", + "maps_leaflet": "עלון", + "maps-leaflet-par-defzoom": "מאפשר להגדיר את רמת המרחק ההתחלתית במפה.", "maps_click_to_activate": "יש ללחוץ כדי להפעיל את המפה", "maps_centred_on": "המפה ממורכזת סביב $1,$2", "maps-par-mappingservice": "מאפשר הגדרת שירות המיפוי שישמש לחילול המפה.", @@ -136,9 +138,11 @@ "maps-par-width": "לאפשר הגדרת רוחב המפה. ברירת המחדל היא שהיחידה תהיה פיקסל, אבל אפשר להגדיר במפורש אחת מהיחידות הבאות: px, ex, em, %.", "maps-par-height": "לאפשר הגדרת גובה המפה. ברירת המחדל היא שהיחידה תהיה פיקסל, אבל אפשר להגדיר במפורש אחת מהיחידות הבאות: px, ex, em, %.", "maps-par-centre": "המיקום שבו המפה צריכה להיות ממורכזת", + "maps-par-enable-fullscreen": "להפעיל כתפור מסך מלא", + "maps-par-kml": "קבצי KML שייטענו אל המפה.", + "maps-par-markercluster": "מאפשר מיזוג מספר סמנים קרובים לסמן אחד", "maps-googlemaps3-incompatbrowser": "הדפדפן שלך לא תומך בגוגל מפות גרסה 3.", "maps-googlemaps3-par-imageoverlays": "מאפשר הוספת תמונה שתוצג במיקום מסוים על המפה.", - "maps-googlemaps3-par-markercluster": "מאפשר מיזוג מספר סמנים קרובים לסמן אחד", "maps-googlemaps3-par-type": "סוג המפה שיוצג תחילה.", "maps-googlemaps3-par-types": "סוגי המפה שיהיו זמינים דרך בקר הסוג.", "maps-googlemaps3-par-layers": "שכבות מיוחדות שייטענו אל המפה.", @@ -146,17 +150,18 @@ "maps-googlemaps3-par-zoomstyle": "סגנון בקר התקריב.", "maps-googlemaps3-par-typestyle": "סגנון בקר הסוג.", "maps-googlemaps3-par-autoinfowindows": "לפתוח את כל חלונות המידע אחרי שהדף נטען.", - "maps-googlemaps3-par-kml": "קבצי KML שייטענו אל המפה.", "maps-googlemaps3-par-gkml": "קבצי KML שמתארחים בגוגל וייטענו אל המפה.", "maps-googlemaps3-par-fusiontables": "מזהים של Google Fusion Tables שייטענו אל המפה.", "maps-googlemaps3-par-tilt": "רכינה עבור המפה כאשר נעשה שימוש במפות גוגל.", "maps-googlemaps3-par-kmlrezoom": "לקרב מחדש את המפה אחרי ששכבות KML נטענו.", "maps-googlemaps3-par-poi": "הצגת נקודות עניין.", + "maps-googlemaps3-par-clustergridsize": "גודל הרשת של האשכול בפיקסלים.", + "maps-par-clusterzoomonclick": "האם ההתנהגות הראשונית ללחיצה על אשכולית היא להתקרב לתוכו.", + "maps-googlemaps3-par-clusteraveragecenter": "האם המרכז של כל אשכול אמור להיות הממוצע של כל הסמנים באשכול.", + "maps-googlemaps3-par-clusterminsize": "המספר המזערי של הסמנים שאמורים להיות באשכול לפני שהסמנים מוסתרים ומוצג מונה.", "maps-openlayers-par-controls": "אילו בקרים להציב על המפה.", "maps-openlayers-par-layers": "אילו שכבות יהיו זמינות בבוחר השכבות. השכבה הראשונה תוצג כאשר המפה נטענת.", "maps-openlayers-par-overlays": "שכבות כיסוי שיהיו זמינות בבורר השכבות. השכבות האלו תוצגנה בראש שכבה רגילה, כמו סמן.", - "maps-osm-par-thumbs": "להציג תמונות ממוזערות.", - "maps-osm-par-photos": "להציג צילומים", "mapeditor": "עורך מפות", "specialpages-group-maps": "מפות", "mapeditor-parser-error": "אירעה שגיאה בעת עיבוד מטא־נתונים. קלט ממשתמשים לא יעובד.", @@ -192,5 +197,30 @@ "mapeditor-imageoverlay-button": "הוספת שכבת תמונה", "mapeditor-form-field-image": "תמונה", "mapeditor-imageoverlay-title": "פרטי שכבת תמונה", - "mapeditor-form-field-visitedicon": "סמל לסימון מקומות שביקרת בהם" + "mapeditor-form-field-visitedicon": "סמל לסימון מקומות שביקרת בהם", + "semanticmaps-unrecognizeddistance": "הערך $1 אינו מרחק תקין.", + "semanticmaps-kml-link": "הצגת קובץ KML", + "semanticmaps-default-kml-pagelink": "הצגת הדף $1", + "semanticmaps-latitude": "קו־רוחב: $1", + "semanticmaps-longitude": "קו־אורך: $1", + "semanticmaps-altitude": "גובה: $1", + "semanticmaps-forminput-locations": "מיקומים", + "semanticmaps-par-staticlocations": "רשימת מיקומים להוסיף למפה יחד עם הנתונים המבוקשים בשאילתה. כמו עם display_points, אפשר להוסיף כאן כותרת, תיאור וסמל לכל מיקום עם טילדה (~) בתור תו מפריד.", + "semanticmaps-par-showtitle": "להציג את הכותרת בחלון המידע על הסמן או לא. הכיבוי של זה שימושי לעתים קרובות כאשר נעשה שימוש בתבנית לעיצוב חלון המידע.", + "semanticmaps-par-hidenamespace": "האם להציג את שם המרחב בחלון המידע על סמן.", + "semanticmaps-par-centre": "מרכז המפה. אם לא ניתן, המפה תבחר בעצמה את המרכז המיטבי להצגת כל הסמנים על המפה.", + "semanticmaps-par-template": "תבנית לעיצוב תוכן חלון המידע.", + "semanticmaps-par-geocodecontrol": "הצגת בקר קידוד גאוגרפי.", + "semanticmaps-par-activeicon": "סמל שיוצג במקום הסמן הרגיל כאשר הדף הפעיל זהה לתוצאת השאילתה", + "semanticmaps-par-pagelabel": "כשזה מכון ל־\"yes\", לכל הסמנים יהיה \"inlineLabel\" עם קישור לדף שמכיל את נקודות הציון עבור הסמן", + "semanticmaps-par-ajaxcoordproperty": "שם המאפיין של נקודות הציון שמשמש לבניית שאילתת ה־ajax.", + "semanticmaps-par-ajaxquery": "שאילתה שנייה שנשלחת ב־ajax כדי לאחזר נקודות ציון נוספות.", + "semanticmaps-par-userparam": "ערך שמועבר לכל קריאה לתבנית, אם משמשת תבנית", + "semanticmaps-kml-text": "הטקסט משויך לכל עמוד ועמוד. נדרס במאפיינים אחרים שנעשית עליהם שאילתה, אם יש כאלה.", + "semanticmaps-kml-title": "כותרת לתוצאות לפי בררת המחדל.", + "semanticmaps-kml-linkabsolute": "האם הקישורים צריכים להיות מוחלטים (או יחסיים)", + "semanticmaps-kml-pagelinktext": "הטקסט שישמש לקישורים לדף, כאשר $1 יוחלף בכותרת הדף", + "semanticmaps-shapes-improperformat": "עיצוב לא מתאים עבור $1. נא לראות את התיעוד על עיצוב", + "semanticmaps-shapes-missingshape": "לא נמצאו צורות עבור $1. נא לראות את התיעוד עבור צורות", + "validator-type-mapscircle-list": "רשימת מעגלים" } diff --git a/i18n/hsb.json b/i18n/hsb.json index 183977ada..6777092eb 100644 --- a/i18n/hsb.json +++ b/i18n/hsb.json @@ -36,7 +36,6 @@ "maps-layer-type-supported-by": "Tutón typ runiny móže so {{PLURAL:$2|jenož z kartografiskej słužbu $1|z tutej kartografiskimaj słužbomaj: $1|z tutymi kartografiskimi słužbami: $1|z tutymi kartografiskimi słužbami: $1}}.wužiwać.", "maps-coordinates-description": "Parserowa hóčka za formatowanje koordinatow z a do podpěranych formatow.", "maps-displaymap-description": "Geografiske karty bjez we wikiju definowanych markow na nich zwobraznić.", - "maps-displaypoint-description": "Geografiske karty z jednym we wikiju definowanej marku abo wjace markow na nich zwobraznić.", "maps-distance-description": "Konwertuj distancu z pomocu wěsteje podpěraneje jednotki do jeje ekwiwalenta z pomocu druheje jednotki.", "maps-finddestination-description": "Cil z pomocu podateho startoweho dypka (kotryž móže w někajkim z podpěranych formatow być), spočatneho nasměrjenja a zdalenosće pytać.", "maps-geocode-description": "Zmóžnja geokodowanje adresow, hinak prajene, přetworja wot čłowjeka čitajomne městna do sadźbow koordinatow. Je podpěra za wjacore geokodowanske słužby, kotrež njeměli so z kartowymi słužbami zaměnić.", @@ -80,7 +79,6 @@ "maps-displaymap-par-wmsoverlay": "WMS-naworštowanje wužiwać", "maps-fullscreen-button": "Połnu wobrazowku přepinać", "maps-fullscreen-button-tooltip": "Kartu jako połnu wobrazowku abo zasadźenu pokazać", - "maps-googlemaps3-par-enable-fullscreen": "Tłóčatko połneje wobrazowki zmóžnić", "validation-error-invalid-location": "Parameter $1 dyrbi płaćiwe městno być.", "validation-error-invalid-locations": "Parameter $1 dyrbi jedne městno abo wjacore městna być.", "validation-error-invalid-width": "Parameter $1 dyrbi płaćiwa šěrokosć być.", @@ -110,6 +108,8 @@ "maps-par-mappingservice": "Zmóžnja nastajenje kartografiskeje słužby, kotraž ma so za wutworjenje karty wužiwać,", "maps-par-geoservice": "Geokodowanska słužba, kotraž ma so za konwertowanje adresow do koordinatow wužiwać.", "maps-par-centre": "Městno, hdźež karta ma so centrować", + "maps-par-enable-fullscreen": "Tłóčatko połneje wobrazowki zmóžnić", + "maps-par-kml": "KML-dataje, kotrež maja so na kartu začitać.", "maps-googlemaps3-incompatbrowser": "Twój wobhladowak njeje kompatibelny z Google Maps v3.", "maps-googlemaps3-par-type": "Kartowy typ, kotryž ma so na spočatku pokazać.", "maps-googlemaps3-par-layers": "Wosebite runiny, kotrež maja so na kartu začitać.", @@ -117,12 +117,9 @@ "maps-googlemaps3-par-zoomstyle": "Stil skalowanskeho wodźenja.", "maps-googlemaps3-par-typestyle": "Stil wodźenja za kartowe typy.", "maps-googlemaps3-par-autoinfowindows": "Wšě informaciske wokna awtomatisce wočinić, po tym zo strona je so začitała.", - "maps-googlemaps3-par-kml": "KML-dataje, kotrež maja so na kartu začitać.", "maps-googlemaps3-par-tilt": "Schilenje za kartu, hdyž so Google Maps wužiwa.", "maps-googlemaps3-par-poi": "Zajimawosće pokazać.", "maps-openlayers-par-controls": "Wodźenske elementy, kotrež maja so na karće zwobraznić.", - "maps-osm-par-thumbs": "Miniaturne wobrazki pokazać", - "maps-osm-par-photos": "Fotografije pokazać", "mapeditor": "Kartowy editor", "specialpages-group-maps": "Karty", "mapeditor-parser-error": "Při parsowanju metadatow je so zmylk wustupił. Zapodaća wužiwarja so ignoruja.", @@ -157,5 +154,26 @@ "mapeditor-imageoverlay-button": "Wobrazowe zablendowanje přidać", "mapeditor-form-field-image": "Wobraz", "mapeditor-imageoverlay-title": "Podrobnosće wo wobrazowym zablendowanju", - "mapeditor-form-field-visitedicon": "Symbol za wopytany" + "mapeditor-form-field-visitedicon": "Symbol za wopytany", + "semanticmaps-unrecognizeddistance": "Hódnota $1 płaćiwa distanca njeje.", + "semanticmaps-kml-link": "KML-dataju sej wobhladać", + "semanticmaps-default-kml-pagelink": "Nastawk $1 sej wobhladać", + "semanticmaps-latitude": "Šěrokostnik: $1", + "semanticmaps-longitude": "Dołhostnik: $1", + "semanticmaps-altitude": "Wysokosć: $1", + "semanticmaps-forminput-locations": "Městna", + "semanticmaps-par-staticlocations": "Lisćina městnow, kotrež maja so zhromadnje z naprašowanymi datami karće přidać. Kaž pola zwobraznjenskich dypkow móžeš titul. wopisanje a symbol na městno z pomocu tildy \"~\" jako dźělatko přidać.", + "semanticmaps-par-showtitle": "Titul w informaciskim woknje woznamjenjenja pokazać abo nic. Je husto wužitne, tutu opciju znjemóžnić, hdyž so předłoha wužiwa, zo by so wobsah informaciskeho wokna formatował.", + "semanticmaps-par-hidenamespace": "Mjeno mjenoweho ruma w informaciskim woknje woznamjenjenja pokazać.", + "semanticmaps-par-centre": "Srjedźišćo karty. Jeli je njepodate, budźe so karta awtomatisce optimalne srjedźišćo wuběrać, zo bychu so wšě woznamjenjenja na karće pokazali.", + "semanticmaps-par-template": "Předłoha, kotraž ma so za formatowanje wobsaha infowokna wužiwać,", + "semanticmaps-par-geocodecontrol": "Geokodowanske wodźenje pokazać", + "semanticmaps-par-activeicon": "Symbol, kotryž ma so město standardneho woznamjenjenja zwobraznić, hdyž aktiwna strona naprašowanskemu wuslědkej wotpowěduje.", + "semanticmaps-par-pagelabel": "Jeli na \"haj\" stajene, změju wšě marki \"inlineLabel\" z wotkazom k stronje, kotraž koordinaty marki wobsahuje.", + "semanticmaps-kml-text": "Tekst, kotryž je z kóždej stronu zwjazany. Naruna so přez přidatne naprašowane kajkosće, jeli tajke su.", + "semanticmaps-kml-title": "Standardny titul za wuslědki", + "semanticmaps-kml-linkabsolute": "Wotkazy měli absolutne być (nic relatiwne)", + "semanticmaps-kml-pagelinktext": "Tekst, kotryž ma so za wotkazy k tej stronje wužiwać, w kotrejž $1 so přez titul strony naruna", + "semanticmaps-shapes-improperformat": "$1 je so wopak formatował. Prošu hlej dokumentaciju za formatowanje", + "semanticmaps-shapes-missingshape": "Formy za $1 njejsu so namakali. Prošu hlej dokumentaciju za k dispoziciji stejace formy." } diff --git a/i18n/hu.json b/i18n/hu.json index 22c5c6219..46edba6f7 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -6,7 +6,8 @@ "Glanthor Reviol", "Misibacsi", "Máté", - "Macofe" + "Macofe", + "TK-999" ] }, "maps-desc": "Lehetővé teszi a dinamikus térképek beágyazását a wiki lapokba, címek geográfiai kódolását és más geográfiai műveleteket", @@ -51,12 +52,10 @@ "maps-geocoder-not-available": "A térképek kiterjesztés geokódoló funkciója nem elérhető. A tartózkodási helyed nem geokódolható.", "maps_click_to_activate": "Kattints a térkép aktiválásához", "maps_centred_on": "Térkép középre igazítva a következő koordináták alapján: $1, $2.", + "maps-par-kml": "Betöltendő KML fájlok.", "maps-googlemaps3-incompatbrowser": "A böngésződ nem kompatibilis a Google Maps v3-mal.", "maps-googlemaps3-par-type": "Elsőre megjelenítendő térkép típusa.", "maps-googlemaps3-par-zoomstyle": "A nagyítás irányításának stílusa.", - "maps-googlemaps3-par-kml": "Betöltendő KML fájlok.", - "maps-osm-par-thumbs": "Bélyegképek megjelenítése", - "maps-osm-par-photos": "Fényképek megjelenítése", "mapeditor": "Térkép szerkesztő", "specialpages-group-maps": "Térképek", "mapeditor-none-text": "Nincs", @@ -77,5 +76,21 @@ "mapeditor-form-field-icon": "Ikon", "mapeditor-form-field-group": "Csoport", "mapeditor-form-field-inlinelabel": "Beágyazott címke", - "mapeditor-form-field-image": "Kép" + "mapeditor-form-field-image": "Kép", + "semanticmaps-desc": "Lehetővé teszi a szemantikus MediaWiki kiterjesztéssel tárolt koordinátaadatok megtekintését és szerkesztését ([https://mapping.referata.com/wiki/Examples bemutató]).", + "semanticmaps-unrecognizeddistance": "A(z) $1 érték nem egy érvényes távolság.", + "semanticmaps-kml-link": "KML fájl megtekintése", + "semanticmaps-default-kml-pagelink": "A(z) $1 lap megtekintése", + "semanticmaps-loading-forminput": "Térkép űrlapjának betöltése…", + "semanticmaps_lookupcoordinates": "Koordináták felkeresése", + "semanticmaps_enteraddresshere": "Add meg a címet itt", + "semanticmaps-updatemap": "Térkép frissítése", + "semanticmaps-forminput-remove": "Eltávolítás", + "semanticmaps-forminput-add": "Hozzáadás", + "semanticmaps-latitude": "Szélesség: $1", + "semanticmaps-longitude": "Hosszúság: $1", + "semanticmaps-altitude": "Tengerszint feletti magasság: $1", + "semanticmaps-forminput-locations": "Helyszínek", + "semanticmaps-par-staticlocations": "A térképre a lekérdezett adatok mellett felveendő helyek listája. Akárcsak a megjelenítési pontokkal, minden helyhez megadhatsz címet, leírást és ikont hullámvonal (\"~\") elválasztóval.", + "semanticmaps-par-showtitle": "Megjelenítse a címet a jelző információs ablakában, vagy ne? Ennek kikapcsolás hasznos lehet, ha sablonnal formázod az információs ablak tartalmát." } diff --git a/i18n/ia.json b/i18n/ia.json index c56c0934f..0906445a7 100644 --- a/i18n/ia.json +++ b/i18n/ia.json @@ -21,13 +21,12 @@ "maps-layer-errors": "Errores", "maps-error-invalid-layertype": "Il non ha stratos del typo \"$1\". Solmente iste {{PLURAL:$3|typo|typos}} es supportate: $2", "maps-error-no-layertype": "Tu debe specificar le typo de strato. {{PLURAL:$2|Solmente iste typo|Iste typos}} es supportate: $1", - "validation-error-invalid-layer": "Le parametro $1 debe esser un strato valide.", - "validation-error-invalid-layers": "Le parametro $1 debe esser un o plus stratos valide.", + "validation-error-invalid-layer": "Le parametro \"$1\" debe esser un strato valide.", + "validation-error-invalid-layers": "Le parametro \"$1\" debe esser un o plus stratos valide.", "maps-layer-of-type": "Strato del typo $1", "maps-layer-type-supported-by": "Iste typo de strato pote {{PLURAL:$2|solmente esser usate con le servicio cartographic|esser usate con le sequente servicios cartographic:}} $1.", "maps-coordinates-description": "Uncino analysator pro formatar coordinatas, ex e in tote le formatos supportate.", "maps-displaymap-description": "Monstra cartas geographic sin marcatores definite in wiki.", - "maps-displaypoint-description": "Monstra cartas geographic con un o plus marcatores definite in wiki.", "maps-distance-description": "Converte un distantia in un del unitates supportate a su equivalente in un altere unitate.", "maps-finddestination-description": "Cercar un destination, date un puncto de initio (que pote esser in omne formato supportate), un direction initial e un distantia.", "maps-geocode-description": "Permitte le geocodification de adresses, in altere parolas, converte adresses conventional de locos in gruppos de coordinatas. Existe supporto pro plure servicios de geocodification, le quales non debe esser confundite con servicios cartographic.", @@ -60,7 +59,7 @@ "maps-geodistance-par-unit": "Le unitate in le qual presentar le distantia.", "maps-geodistance-par-decimals": "Le numero maxime de digitos fractional a usar in le valor resultante.", "maps-geodistance-par-mappingservice": "Le servicio de geocodification a usar pro geocodificar adresses.", - "maps-geodistance-par-geoservice": "Le servicio cartographic con le qual isto es usate.\nIsto pote influentiar le valor predefinite de servicio de geocodification.", + "maps-geodistance-par-geoservice": "Le servicio cartographic con le qual iste function del analysator es usate.\nIsto pote influentiar le valor predefinite del servicio de geocodification.", "maps-displaymap-par-mappingservice": "Permitte definir le servicio cartographic a usar pro generar le carta.", "maps-displaymap-par-coordinates": "Le loco in le qual le carta essera initialmente centrate.", "maps-displaymap-par-zoom": "Permitte definir le nivello de zoom del carta.\nSi isto non es fornite, e multiple marcatores es presente in le cata, le zoom que los arrangia melio essera prendite, non le predefinition configurabile.", @@ -99,6 +98,7 @@ "maps-par-zoom": "Le nivello de zoom pro le carta. Pro cartas con marcatores isto es predefinite como le nivello de zoom le plus alte que ancora monstra tote le marcatores.", "maps-par-width": "Permitte fixar le latitude del carta. Le unitate assumite es pixels, ma tu pote specificar un de iste unitates: px, ex, em, %.", "maps-par-height": "Permitte fixar le altitude del carta. Le unitate assumite es pixels, ma tu pote specificar un de iste unitates: px, ex, em, %.", + "maps-par-kml": "Files KML pro cargar in le carta.", "maps-googlemaps3-incompatbrowser": "Tu navigator de web non es compatibile con Google Maps version 3.", "maps-googlemaps3-par-type": "Le typo de carta a monstrar initialmente.", "maps-googlemaps3-par-types": "Le typos de carta que essera disponibile via le controlo de typo.", @@ -107,7 +107,6 @@ "maps-googlemaps3-par-zoomstyle": "Le stilo del controlo de zoom.", "maps-googlemaps3-par-typestyle": "Le stilo del controlo de typo.", "maps-googlemaps3-par-autoinfowindows": "Aperir automaticamente tote le fenestras informative post le cargamento del pagina.", - "maps-googlemaps3-par-kml": "Files KML pro cargar in le carta.", "maps-googlemaps3-par-gkml": "KML files albergate per Google a cargar sur le carta.", "maps-googlemaps3-par-fusiontables": "IDs de tabellas de Google Fusion que debe esser cargate in le carta.", "maps-googlemaps3-par-tilt": "Inclination del carta durante le uso de Google Maps.", @@ -115,8 +114,6 @@ "maps-googlemaps3-par-poi": "Monstrar punctos de interesse.", "maps-openlayers-par-controls": "Le controlos a placiar super le carta.", "maps-openlayers-par-layers": "Le stratos que essera disponibile in le selector de stratos. Le prime strato essera monstrate durante le cargamento del carta.", - "maps-osm-par-thumbs": "Monstrar miniaturas", - "maps-osm-par-photos": "Monstrar photos", "mapeditor": "Editor cartographic", "specialpages-group-maps": "Cartas", "mapeditor-parser-error": "Un error occurreva durante le processamento del metadatos. Le entrata del usator es ignorate.", @@ -151,5 +148,22 @@ "mapeditor-imageoverlay-button": "Adder un imagine superponite", "mapeditor-form-field-image": "Imagine", "mapeditor-imageoverlay-title": "Detalios del imagine superponite", - "mapeditor-form-field-visitedicon": "Icone visitate" + "mapeditor-form-field-visitedicon": "Icone visitate", + "semanticmaps-unrecognizeddistance": "Le valor $1 non es un distantia valide.", + "semanticmaps-kml-link": "Vider le file KML", + "semanticmaps-default-kml-pagelink": "Vider articulo $1", + "semanticmaps-latitude": "Latitude: $1", + "semanticmaps-longitude": "Longitude: $1", + "semanticmaps-altitude": "Altitude: $1", + "semanticmaps-forminput-locations": "Locos", + "semanticmaps-par-staticlocations": "Un lista de locos a adder al carta con le datos resultante del consulta. Como con display_points, tu pote adder un titulo, description e icone per loco usante le tilde \"~\" como separator.", + "semanticmaps-par-showtitle": "Monstrar un titulo in le fenestra de information de marcator o non. Disactivar isto es sovente utile si un patrono es usate pro formatar le contento del fenestra de information.", + "semanticmaps-par-hidenamespace": "Monstrar le titulo del spatio de nomines in le fenestra de information del marcator.", + "semanticmaps-par-centre": "Le centro del carta. Si non specificate, le systema selige automaticamente le centro optimal pro monstrar tote le marcatores in le carta.", + "semanticmaps-par-template": "Un patrono a usar pro formatar le contento del fenestra de information.", + "semanticmaps-par-geocodecontrol": "Monstrar le controlo de geocodification.", + "semanticmaps-kml-text": "Le texto associate con cata pagina. Es supplantate per le additional proprietates consultate, si existe.", + "semanticmaps-kml-title": "Le titulo predefinite pro resultatos", + "semanticmaps-kml-linkabsolute": "Debe ligamines esser absolute (in vice de relative)", + "semanticmaps-kml-pagelinktext": "Le texto a usar pro le ligamines al pagina, in le quales $1 essera reimplaciate per le titulo de pagina" } diff --git a/i18n/id.json b/i18n/id.json index dc5692315..12173e1bc 100644 --- a/i18n/id.json +++ b/i18n/id.json @@ -6,7 +6,8 @@ "Irwangatot", "IvanLanin", "පසිඳු කාවින්ද", - "Macofe" + "Macofe", + "C5st4wr6ch" ] }, "maps-desc": "Mengaktifkan penyertaan peta dinamis dalam halaman wiki, pembuatan geokode alamat, dan operasi geografi lain", @@ -29,7 +30,6 @@ "maps-layer-type-supported-by": "Lapisan ini hanya dapat digunakan oleh layanan pemetaan {{PLURAL:$2|$1|$1}}.", "maps-coordinates-description": "Pengait parser untuk memformat koordinat, dari dan ke salah satu format yang didukung.", "maps-displaymap-description": "Menampilkan peta geografis tanpa mencantumkan penanda wiki terdefinisi.", - "maps-displaypoint-description": "Menampilkan peta geografis dengan satu atau lebih penanda wiki terdefinisi.", "maps-distance-description": "Mengubah jarak dengan menggunakan unit terdukung tertentu menjadi setaranya dengan menggunakan unit lain.", "maps-finddestination-description": "Menemukan tujuan dari suatu titik awal (dalam salah satu format yang didukung), arah, dan jarak.", "maps-geocode-description": "Memberikan geokode alamat, atau dengan kata lain, mengubah lokasi yang dapat dibaca manusia ke set koordinat. Tersedia dukungan untuk beberapa layanan geokode, yang berbeda dengan layanan pemetaan.", @@ -98,6 +98,7 @@ "maps-par-zoom": "Tingkat pembesaran peta. Secara bawaan, peta bertanda akan mengambil tingkat pembesaran yang masih menunjukkan semua tanda.", "maps-par-width": "Memungkinkan pengaturan lebar peta. Secara bawaan, piksel akan dianggap sebagai unit, tetapi Anda dapat menentukan secara eksplisit salah satu unit berikut: px, ex, em, %.", "maps-par-height": "Memungkinkan pengaturan tinggi peta. Secara bawaan, piksel akan dianggap sebagai unit, tetapi Anda dapat menentukan secara eksplisit salah satu unit berikut: px, ex, em, %.", + "maps-par-kml": "Berkas KML yang akan dimuat ke dalam peta.", "maps-googlemaps3-incompatbrowser": "Peramban Anda tidak kompatibel dengan Google Maps v3.", "maps-googlemaps3-par-type": "Jenis peta yang ditampilkan saat awal.", "maps-googlemaps3-par-types": "Jenis peta yang akan tersedia melalui kontrol jenis.", @@ -106,12 +107,9 @@ "maps-googlemaps3-par-zoomstyle": "Gaya kontrol pembesaran.", "maps-googlemaps3-par-typestyle": "Gaya jenis kontrol.", "maps-googlemaps3-par-autoinfowindows": "Otomatis membuka semua jendela info setelah halaman dimuat.", - "maps-googlemaps3-par-kml": "Berkas KML yang akan dimuat ke dalam peta.", "maps-googlemaps3-par-fusiontables": "ID Google Fusion Tables yang harus dimuat ke dalam peta.", "maps-openlayers-par-controls": "Kontrol yang akan ditempatkan pada peta.", "maps-openlayers-par-layers": "Lapisan yang akan tersedia pada pemilih lapisan. Lapisan pertama akan ditampilkan ketika peta dimuat.", - "maps-osm-par-thumbs": "Tampilkan gambar mini", - "maps-osm-par-photos": "Tampilkan foto", "mapeditor": "Penyunting peta", "specialpages-group-maps": "Peta", "mapeditor-none-text": "Tidak ada", @@ -139,5 +137,15 @@ "mapeditor-form-field-fillopcaity": "Transparansi isi", "mapeditor-mapparam-title": "Sunting parameter peta", "mapeditor-mapparam-defoption": "-Pilih parameter-", - "mapeditor-form-field-image": "Gambar" + "mapeditor-form-field-image": "Gambar", + "semanticmaps-unrecognizeddistance": "Nilai $1 bukan jarak yang sah.", + "semanticmaps-kml-link": "Lihat berkas KML", + "semanticmaps-default-kml-pagelink": "Lihat halaman $1", + "semanticmaps-forminput-locations": "Lokasi", + "semanticmaps-par-staticlocations": "Daftar lokasi yang akan ditambahkan ke dalam peta, berikut data kueri. Seperti halnya display_points, Anda dapat menambahkan judul, deskripsi, dan ikon per lokasi dengan menggunakan tanda tilde \"~\" sebagai pemisah.", + "semanticmaps-par-showtitle": "Tampilkan judul di jendela info penanda. Penonaktifan judul sering berguna ketika menggunakan templat untuk memformat isi jendela info.", + "semanticmaps-par-centre": "Pusat peta. Jika tidak disediakan, peta secara otomatis akan memilih pusat optimal untuk menampilkan semua penanda di peta.", + "semanticmaps-par-template": "Ttemplat yang digunakan untuk memformat isi jendela info.", + "semanticmaps-kml-linkabsolute": "Pranala sebaiknya adalah mutlak (lawan dari relatif)", + "semanticmaps-shapes-improperformat": "Format yang kurang tepat untuk $1. Silakan lihat dokumentasi untuk format." } diff --git a/i18n/it.json b/i18n/it.json index f78b36bc5..58a734f93 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -8,7 +8,9 @@ "Gianfranco", "HalphaZ", "Rosh", - "Viscontino" + "Viscontino", + "Matteocng", + "Kaspo" ] }, "maps-desc": "Consente di includere mappe dinamiche nelle pagine wiki, la geocodifica degli indirizzi ed altre operazioni geografiche", @@ -71,22 +73,25 @@ "maps_map_cannot_be_displayed": "La mappa non può essere visualizzata.", "maps-geocoder-not-available": "La funzionalità di geocodifica dell'estensione Maps non è disponibile. La tua posizione non può essere geocodificata.", "maps_leaflet": "Volantino", - "maps-leaflet-par-zoom": "Permette di impostare il livello di zoom della mappa.", "maps-leaflet-par-defzoom": "Permette l'impostazione del livello di zoom predefinito della mappa.", - "maps-leaflet-par-resizable": "Permette di realizzare una mappa di ridimensionabile trascinando al suo angolo in basso a destra.", "maps_click_to_activate": "Clicca per attivare la mappa.", "maps_centred_on": "Mappa centrata su $1, $2.", + "maps-par-enable-fullscreen": "Attiva bottone a tutto schermo", + "maps-par-kml": "File KML da caricare sulla mappa.", "maps-googlemaps3-incompatbrowser": "Si sta utilizzando un browser non compatibile con Google Maps v3.", "maps-googlemaps3-par-type": "Il tipo di mappa da mostrare inizialmente.", "maps-googlemaps3-par-layers": "Livelli speciali da caricare sulla mappa.", "maps-googlemaps3-par-controls": "I controlli da posizionare sulla mappa.", "maps-googlemaps3-par-zoomstyle": "Lo stile del controllo dello zoom.", - "maps-googlemaps3-par-kml": "File KML da caricare sulla mappa.", "maps-googlemaps3-par-gkml": "File KML ospitati da Google da caricare sulla mappa.", "maps-googlemaps3-par-poi": "Mostra punti di interesse.", + "maps-googlemaps3-par-clustergridsize": "La dimensione della griglia di un cluster in pixels.", + "maps-par-clustermaxzoom": "Il massimo livello di zoom in cui i cluster possono esistere.", + "maps-par-clusterzoomonclick": "Se il comportamento predefinito quando si clicca su un cluster è di fare lo zoom su di esso.", + "maps-par-maxclusterradius": "Il raggio massimo coperto da un cluster.", + "maps-googlemaps3-par-clusteraveragecenter": "Se il centro di ogni cluster dovrebbe essere la media di tutti i marcatori del cluster.", + "maps-googlemaps3-par-clusterminsize": "Il numero minimo di marcatori presenti in un cluster dopo il quale tutti i marcatori saranno nascosti e sarà mostrato il loro numero.", "maps-openlayers-par-controls": "I controlli da posizionare sulla mappa.", - "maps-osm-par-thumbs": "Visualizza miniature", - "maps-osm-par-photos": "Mostra foto", "mapeditor": "Editor della mappa", "specialpages-group-maps": "Mappe", "mapeditor-parser-error": "Si verificato un errore durante l'analisi dei metadati. Ignorato l'input dell'utente.", @@ -118,5 +123,39 @@ "mapeditor-mapparam-defoption": "-Selezionare parametro-", "mapeditor-form-field-image": "Immagine", "mapeditor-imageoverlay-title": "Dettagli di sovrapposizione di immagini", - "mapeditor-form-field-visitedicon": "Icona visitato" + "mapeditor-form-field-visitedicon": "Icona visitato", + "semanticmaps-unrecognizeddistance": "Il valore $1 non è una distanza valida.", + "semanticmaps-kml-link": "Visualizza il file KML", + "semanticmaps-default-kml-pagelink": "Visualizza la pagina $1", + "semanticmaps-latitude": "Latitudine: $1", + "semanticmaps-longitude": "Longitudine: $1", + "semanticmaps-altitude": "Altitudine: $1", + "semanticmaps-forminput-locations": "Luoghi", + "semanticmaps-par-staticlocations": "Un elenco di luoghi da aggiungere alla mappa unitamente ai dati interrogati. Come con display_points, si può aggiungere un titolo, la descrizione e l'icona per ogni posizione utilizzando la tilde \"~\" come separatore.", + "semanticmaps-par-showtitle": "Mostrare oppure no un titolo nella finestra informazioni per l'indicatore. Disattivarlo è spesso utile quando si utilizza un template per la formattazione del contenuto della finestra informazioni.", + "semanticmaps-par-hidenamespace": "Mostrare il namespace del titolo nella finestra informazioni per l'indicatore", + "semanticmaps-par-centre": "Il centro della mappa. Quando non indicato, la mappa sceglierà automaticamente il centro ottimale per visualizzare tutti gli indicatori sulla mappa.", + "semanticmaps-par-template": "Un template da utilizzare per formattare il contenuto della finestra informazioni.", + "semanticmaps-par-geocodecontrol": "Mostra il controllo per geocodifica.", + "semanticmaps-par-activeicon": "Icona da mostrare al posto dell'indicatore predefinito, quando la pagina attiva è uguale al risultato dell'interrogazione", + "semanticmaps-par-pagelabel": "Quando impostato su \"yes\", tutti gli indicatori avranno un \"inlineLabel\" con un collegamento alla pagina che contiene le coordinate per l'indicatore", + "semanticmaps-par-userparam": "Un valore passato in ogni chiamata a template, se un template è utilizzato", + "semanticmaps-kml-text": "Il testo associato per ogni pagina. Sovrascritto dall'eventuale proprietà dell'interrogazione aggiuntiva.", + "semanticmaps-kml-title": "Il titolo predefinito per i risultati", + "semanticmaps-kml-linkabsolute": "I collegamenti dovranno essere assoluti (anziché relativi)", + "semanticmaps-kml-pagelinktext": "Il testo da utilizzare per i collegamenti alla pagina, in cui $1 verrà sostituito dal titolo della pagina", + "semanticmaps-shapes-improperformat": "Formattazione impropria di $1. Per favore controlla la documentazione sulla formattazione", + "semanticmaps-shapes-missingshape": "Nessuna forma trovata per $1. Per favore controlla la documentazione sulle forme disponibili", + "validator-type-mapscircle": "Cerchio geografico", + "validator-type-mapscircle-list": "Elenco di cerchi", + "validator-type-mapsimageoverlay": "Sovrapposizione di immagini", + "validator-type-mapsimageoverlay-list": "Elenco delle sovrapposizioni di immagini", + "validator-type-mapsline": "Linea geografica", + "validator-type-mapsline-list": "Elenco di linee", + "validator-type-mapslocation": "Posizione geografica", + "validator-type-mapslocation-list": "Elenco delle località", + "validator-type-mapsrectangle": "Rettangolo geografico", + "validator-type-mapsrectangle-list": "Elenco di rettangoli", + "validator-type-mapspolygon": "Poligono geografico", + "validator-type-mapspolygon-list": "Elenco dei poligoni geografici" } diff --git a/i18n/ja.json b/i18n/ja.json index 44d22fb3f..be0e1a9da 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -5,7 +5,8 @@ "Fryed-peach", "Shirayuki", "Yanajin66", - "青子守歌" + "青子守歌", + "Schu" ] }, "maps-desc": "ウィキページへの動的な地図の埋め込み、住所の座標データへの変換、その他の地図関連の操作ができるようにする。", @@ -46,7 +47,6 @@ "maps-displaymap-par-wmsoverlay": "WMS オーバーレイを使用", "maps-fullscreen-button": "全画面表示を切り替え", "maps-fullscreen-button-tooltip": "地図の表示を全画面または埋め込みに切り替えます。", - "maps-googlemaps3-par-enable-fullscreen": "全画面表示のボタンを有効にする", "validation-error-invalid-location": "引数「$1」には有効な場所を指定してください。", "validation-error-invalid-locations": "引数「$1」には有効な場所を 1 つ以上指定してください。", "validation-error-invalid-width": "引数「$1」には有効な幅を指定してください。", @@ -76,6 +76,8 @@ "maps_click_to_activate": "クリックして地図をアクティブに", "maps_centred_on": "地図の中心は $1、$2。", "maps-par-centre": "地図の中心にしたい場所", + "maps-par-enable-fullscreen": "全画面表示のボタンを有効にする", + "maps-par-kml": "地図に読み込む KML ファイルです。", "maps-googlemaps3-incompatbrowser": "あなたのブラウザーは Google マップ v3 と互換性がありません。", "maps-googlemaps3-par-type": "最初に表示する地図の種類です。", "maps-googlemaps3-par-types": "種類コントロールで利用できる、地図の種類です。", @@ -83,9 +85,6 @@ "maps-googlemaps3-par-controls": "地図上に配置するコントロールです。", "maps-googlemaps3-par-zoomstyle": "ズーム コントロールのスタイルです。", "maps-googlemaps3-par-typestyle": "種類コントロールのスタイルです。", - "maps-googlemaps3-par-kml": "地図に読み込む KML ファイルです。", - "maps-osm-par-thumbs": "縮小版を表示", - "maps-osm-par-photos": "写真を表示", "mapeditor": "地図の編集", "specialpages-group-maps": "地図", "mapeditor-parser-error": "メタデータの構文解析でエラーが発生しました。利用者の入力を無視しています。", @@ -120,5 +119,26 @@ "mapeditor-imageoverlay-button": "画像オーバーレイを追加", "mapeditor-form-field-image": "画像", "mapeditor-imageoverlay-title": "画像オーバーレイの詳細", - "mapeditor-form-field-visitedicon": "訪問済みアイコン" + "mapeditor-form-field-visitedicon": "訪問済みアイコン", + "semanticmaps-unrecognizeddistance": "値$1は有効な距離ではありません。", + "semanticmaps-kml-link": "KMLファイルを閲覧", + "semanticmaps-default-kml-pagelink": "ページ$1を表示", + "semanticmaps-latitude": "緯度: $1", + "semanticmaps-longitude": "経度: $1", + "semanticmaps-altitude": "高度: $1", + "semanticmaps-forminput-locations": "場所", + "semanticmaps-par-staticlocations": "問い合わせたデータと共に地図に追加する場所の列挙です。display_points と同様に、区切り文字としてチルダ「~」を使用して、場所ごとにタイトル、説明、アイコンを追加できます。", + "semanticmaps-par-showtitle": "マーカーの情報ウィンドウのタイトルを表示するかどうか。情報ウィンドウのコンテンツをフォーマットするためにテンプレートを使用するとき、これを無効にすると便利です。", + "semanticmaps-par-hidenamespace": "マーカー情報ウィンドウに名前空間名を表示する", + "semanticmaps-par-centre": "地図の中心。提供されていないときは、自動的に地図上のすべてのマーカーを表示するための最適な中心が選択されます。", + "semanticmaps-par-template": "情報ウィンドウのコンテンツの整形に使用するテンプレートです。", + "semanticmaps-par-geocodecontrol": "ジオコーディングコントロールを表示します。", + "semanticmaps-par-activeicon": "アクティブなページがクエリ結果と等しい場合に、デフォルトのアイコンの代わりに表示されるアイコン", + "semanticmaps-par-pagelabel": "「はい」に設定すると、マーカーの緯度経度を含むページにリンクされた「インライン ラベル」がすべてのマーカーに付きます。", + "semanticmaps-kml-text": "各ページに関連付けられたテキストです。クエリに追加的なプロパティがある場合は上書きされます。", + "semanticmaps-kml-title": "結果の既定のタイトル", + "semanticmaps-kml-linkabsolute": "リンクは絶対表記 (= 相対表記の対義語) にしてください。", + "semanticmaps-kml-pagelinktext": "ページへのリンクに使用するテキスト ($1 はページ名に置換される)", + "semanticmaps-shapes-improperformat": "$1 を不適切な形式に整形しようとしました。整形の説明文書を参照してください。", + "semanticmaps-shapes-missingshape": "$1 の図形が見つかりません。利用できる図形について説明文書を参照してください。" } diff --git a/i18n/ko.json b/i18n/ko.json index 28cab5eaf..9855076b0 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -6,10 +6,11 @@ "Priviet", "아라", "Revi", - "Macofe" + "Macofe", + "Ykhwong" ] }, - "maps-desc": "위키 문서에 동적 지도를 포함하고, 주소의 좌표화와 다른 지리적 작업을 할 수 있습니다", + "maps-desc": "위키 문서에 동적 지도를 넣고, 주소의 좌표화와 다른 지리적 작업을 할 수 있습니다", "right-geocode": "좌표화", "maps_map": "지도", "maps-tracking-category": "지도를 지도 확장 기능으로 표시하는 문서", @@ -41,16 +42,15 @@ "maps-layer-of-type-and-name": "\"$1\" 형식의 \"$2\" 레이어", "maps-layer-type-supported-by": "이 레이어 유형은 {{PLURAL:$2|$1 매핑 서비스에서만 사용할 수 있습니다.|다음 매핑 서비스에서 사용할 수 있습니다: $1}}", "maps-coordinates-description": "지원되는 좌표 형식간에 서로 변환하는 파서 훅입니다.", - "maps-displaymap-description": "지도에 위키 정의한 표시 없이 지리적 지도를 보여줍니다.", - "maps-displaypoint-description": "지도에 하나 이상의 표시가 있는 지리적 지도를 보여줍니다.", + "maps-displaymap-description": "지도에 위키 정의한 표시 없이 지리적 지도를 표시합니다.", "maps-distance-description": "다른 단위를 사용하여 해당하는 특정 지원되는 단위를 사용하여 거리를 변환합니다.", "maps-finddestination-description": "주어진 시작점과 (지원되는 형식을 사용할 수 있습니다) 초기 방위, 거리로 목적지를 찾습니다.", "maps-geocode-description": "주소, 즉 좌표 집합으로 인간이 읽을 수 있는 위치를 전환하는 좌표화를 활성화합니다. 매핑 서비스와 혼동하지 않아야 하는 여러 좌표화 서비스에 대한 지원이 있습니다.", "maps-geodistance-description": "지원하는 형식으로 두 점 사이의 지리적 거리를 계산합니다.", - "maps-mapsdoc-description": "기본 값과 설명과 함께 지정된 좌표화 서비스에 대한 변수로 테이블을 보여줍니다.", + "maps-mapsdoc-description": "기본 값과 설명과 함께 지정된 좌표화 서비스에 대한 변수로 테이블을 표시합니다.", "maps-layerdefinition-description": "지도기능으로 표시할 수 있는 사용자 정의 레이어를 설명하세요.", - "maps-mapsdoc-par-service": "변수 설명문을 보여줄 좌표화 서비스입니다.", - "maps-mapsdoc-par-language": "설명문을 보여줄 언어입니다. 변역을 사용할 수 없으면 영어가 대신 사용됩니다.", + "maps-mapsdoc-par-service": "변수 설명문서를 표시할 좌표화 서비스입니다.", + "maps-mapsdoc-par-language": "설명문을 표시할 언어입니다. 이러한 번역을 사용할 수 없으면 영어가 대신 사용됩니다.", "maps-coordinates-par-location": "형식을 지정할 좌표입니다.", "maps-coordinates-par-format": "죄표에 대한 대상 형식입니다.", "maps-coordinates-par-directional": "좌표가 방향이 출력되어야 할 것인지를 나타냅니다.", @@ -71,32 +71,31 @@ "maps-geocode-par-allowcoordinates": "이 기능에서 좌표에 대한 지원을 비활성화할 수 있습니다. 예나 아니오여야 합니다. 아니오일 때, 모든 값은 올바른 좌표조차 좌표화됩니다.", "maps-geocode-par-format": "결과 좌표에 대한 형식입니다.", "maps-geocode-par-directional": "좌표가 방향이 출력되어야 할 것인지를 나타냅니다.", - "maps-geodistance-par-location1": "집합에서 사이의 거리를 계산하는 첫번째 지점입니다.", - "maps-geodistance-par-location2": "집합에서 사이의 거리를 계산하는 두번째 지점입니다.", + "maps-geodistance-par-location1": "집합에서 사이의 거리를 계산하는 첫 번째 지점입니다.", + "maps-geodistance-par-location2": "집합에서 사이의 거리를 계산하는 두 번째 지점입니다.", "maps-geodistance-par-unit": "거리를 출력할 단위입니다.", "maps-geodistance-par-decimals": "결과 값에 사용할 최대 소수 자릿수입니다.", "maps-geodistance-par-mappingservice": "주소를 좌표화로 사용할 좌표화 서비스입니다.", "maps-geodistance-par-geoservice": "함께 사용될 매핑 서비스입니다.\n기본 좌표화 서비스 값에 영향을 줄 수 있습니다.", "maps-displaymap-par-mappingservice": "지도를 생성하는데 사용될 매핑 서비스를 설정할 수 있습니다.", - "maps-displaymap-par-coordinates": "지도에 보여줄 하나 이상의 위치입니다. 표시로 표시됩니다.", + "maps-displaymap-par-coordinates": "지도에 표시할 하나 이상의 위치입니다. 표시로 표시됩니다.", "maps-displaymap-par-visitedicon": "원래의 마커가 클릭된 후 마커 아이콘에 사용된 이미지 파일 이름이 클릭되었습니다", "maps-displaymap-par-zoom": "지도의 확대 수준을 설정할 수 있습니다.\n제공하지 않고 여러 표시가 지도에 존재하지 않으면 설정한 기본값이 아닌 최고의 맞춤 확대로 설정됩니다.", "maps-displaymap-par-centre": "display_point에 대한 지도의 중심 좌표를 설정할 수 있습니다.\n주소와 좌표를 모두 사용할 수 있습니다.\n이 속성이 제공되어 있지 않은 경우 지도는 제공한 표시에 대한 자체 중심에 있거나 제공한 표시 사이에 있습니다.", "maps-displaymap-par-title": "특정 제목이 없는 모든 표시의 팝업에 보여줄 텍스트를 설정할 수 있습니다.\n레이블과 함께 사용하면 제목은 굵고 밑줄이 그어집니다.", "maps-displaymap-par-label": "특정 레이블이 없는 마든 표시의 팝업에 보여줄 텍스트를 설정할 수 있습니다.", - "maps-displaymap-par-icon": "모든 표시에 사용하는 아이콘을 설정할 수 있습니다.", - "maps-displaymap-par-circles": "보여줄 동그라미", - "maps-displaymap-par-copycoords": "무언가를 클릭할 때 대화 상자에 위키의 좌표를 보여줄 때", - "maps-displaymap-par-lines": "보여줄 선", + "maps-displaymap-par-icon": "모든 표시에 사용하는 아이콘을 설정할 수 있게 합니다.", + "maps-displaymap-par-circles": "표시할 동그라미", + "maps-displaymap-par-copycoords": "좌표를 복사한 위치를 클릭할 때 대화상자를 표시합니다.", + "maps-displaymap-par-lines": "표시할 선", "maps-displaymap-par-maxzoom": "최대 확대 수준", "maps-displaymap-par-minzoom": "최소 확대 수준", - "maps-displaymap-par-polygons": "보여줄 다각형", - "maps-displaymap-par-rectangles": "보려줄 네모", - "maps-displaymap-par-static": "지도는 정적이어야 할 때", + "maps-displaymap-par-polygons": "표시할 다각형", + "maps-displaymap-par-rectangles": "표시할 직사각형", + "maps-displaymap-par-static": "지도를 정적으로 만듭니다.", "maps-displaymap-par-wmsoverlay": "WMS 오버레이 사용", "maps-fullscreen-button": "전체화면으로 전환", "maps-fullscreen-button-tooltip": "지도를 전체 화면 또는 삽입된 형태로 보기", - "maps-googlemaps3-par-enable-fullscreen": "전체 화면 버튼 활성화", "validation-error-invalid-location": "$1 변수는 올바른 위치여야 합니다.", "validation-error-invalid-locations": "$1 변수는 하나 이상의 올바른 위치여야 합니다.", "validation-error-invalid-width": "$1 변수는 올바른 너비여야 합니다.", @@ -131,6 +130,8 @@ "maps-par-width": "지도의 너비을 설정할 수 있습니다. 기본적으로 픽셀은 단위로 간주되지만, 명시적으로 이러한 단위 중 하나를 지정할 수 있습니다: px, ex, em, %.", "maps-par-height": "지도의 높이를 설정할 수 있습니다. 기본적으로 픽셀은 단위로 간주되지만, 명시적으로 이러한 단위 중 하나를 지정할 수 있습니다: px, ex, em, %.", "maps-par-centre": "지도의 중심으로 할 위치", + "maps-par-enable-fullscreen": "전체 화면 버튼 활성화", + "maps-par-kml": "지도에 불러올 KML 파일입니다.", "maps-googlemaps3-incompatbrowser": "브라우저는 Google 지도 v3와 호환되지 않습니다.", "maps-googlemaps3-par-type": "처음 보여줄 지도 종류입니다.", "maps-googlemaps3-par-types": "종류 컨트롤을 통해 사용할 수 있는 지도 종류입니다.", @@ -139,7 +140,6 @@ "maps-googlemaps3-par-zoomstyle": "줌 컨트롤의 스타일입니다.", "maps-googlemaps3-par-typestyle": "종류 컨트롤의 스타일입니다.", "maps-googlemaps3-par-autoinfowindows": "문서를 불러오고 나서 모든 정보 창을 자동으로 엽니다.", - "maps-googlemaps3-par-kml": "지도에 불러올 KML 파일입니다.", "maps-googlemaps3-par-gkml": "지도에 불러올 Google이 호스트하는 KML 파일입니다.", "maps-googlemaps3-par-fusiontables": "지도에 불러와야 할 Google 퓨전 테이블의 ID입니다.", "maps-googlemaps3-par-tilt": "Google 지도를 사용할 때의 기울기입니다.", @@ -148,8 +148,6 @@ "maps-openlayers-par-controls": "지도에 놓을 컨트롤입니다.", "maps-openlayers-par-layers": "레이서 선택기에서 사용할 수 있는 레이어입니다. 첫 레이어는 지도를 불러올 때 보여줍니다.", "maps-openlayers-par-overlays": "레이어 선택기에서 사용 가능하게 될 오버레이 레이어. 이 레이어는 정상 레이어의 맨 위에 일종의 마커처럼 표시될 것입니다.", - "maps-osm-par-thumbs": "섬네일 보기", - "maps-osm-par-photos": "사진 보기", "mapeditor": "지도 편집기", "specialpages-group-maps": "지도", "mapeditor-parser-error": "메타데이터를 구문 분석하는 동안 오류가 발생했습니다. 사용자 입력을 무시합니다.", @@ -185,5 +183,29 @@ "mapeditor-imageoverlay-button": "그림 배치 추가", "mapeditor-form-field-image": "그림", "mapeditor-imageoverlay-title": "그림 배치 자세한 사항", - "mapeditor-form-field-visitedicon": "방문한 아이콘" + "mapeditor-form-field-visitedicon": "방문한 아이콘", + "semanticmaps-unrecognizeddistance": "$1 값은 올바른 거리가 아닙니다.", + "semanticmaps-kml-link": "KML 파일 보기", + "semanticmaps-default-kml-pagelink": "$1 문서 보기", + "semanticmaps-latitude": "위도: $1", + "semanticmaps-longitude": "경도: $1", + "semanticmaps-altitude": "고도: $1", + "semanticmaps-forminput-locations": "위치", + "semanticmaps-par-staticlocations": "쿼리된 데이터와 함께 지도를 추가하는 위치의 목록입니다. display_points와 같이, 구분자로 물결표 \"~\"를 사용하여 위치마다 제목과 설명, 아이콘을 추가할 수 있습니다.", + "semanticmaps-par-showtitle": "표시 정보 창에서 제목에 보여주거나 보여주지 않습니다. 정보 창 내용의 형식에 틀을 사용할 때 이를 비활성화하면 편리합니다.", + "semanticmaps-par-hidenamespace": "표시 정보 창의 이름공간 제목 보이기", + "semanticmaps-par-centre": "지도의 가운데입니다. 제공하지 않으면, 지도는 자동으로 지도에서 모든 표시를 표시할 최적의 가운데를 선택합니다.", + "semanticmaps-par-template": "정보 창 내용을 형식에 사용하는 틀입니다.", + "semanticmaps-par-geocodecontrol": "좌표화 컨트롤을 보여줍니다.", + "semanticmaps-par-activeicon": "활성화된 문서는 쿼리 결과와 같을 때 아이콘이 기본값 표시기 대신에 표시해야 합니다", + "semanticmaps-par-pagelabel": "\"yes\"로 설정하면, 모든 마커가 마커의 좌표를 포함하는 문서로 연결된 링크와 \"inlineLabel\"을 가집니다.", + "semanticmaps-kml-text": "각 문서와 연관된 텍스트입니다. 추가적인 쿼리된 속성이 있으면 덮어씁니다.", + "semanticmaps-kml-title": "결과에 대한 기본 제목", + "semanticmaps-kml-linkabsolute": "링크는 (상대적와 반대인) 절대적이어야 합니다", + "semanticmaps-kml-pagelinktext": "$1 문서는 문서 제목으로 바뀔 문서의 링크에 사용하는 텍스트", + "semanticmaps-shapes-improperformat": "$1의 부적절한 형식입니다. 형식에 대해서는 설명서를 참조하세요.", + "semanticmaps-shapes-missingshape": "$1에 대한 모양을 찾을 수 없습니다. 사용할 수 있는 모양에 대해서는 설명서를 참조하세요", + "validator-type-mapsimageoverlay": "이미지 오버레이", + "validator-type-mapsimageoverlay-list": "이미지 오버레이의 목록", + "validator-type-mapslocation": "지리적 위치" } diff --git a/i18n/ksh.json b/i18n/ksh.json index a5a90823c..b0994cc6e 100644 --- a/i18n/ksh.json +++ b/i18n/ksh.json @@ -48,6 +48,6 @@ "maps_click_to_activate": "Donn klecke, öm op di Kaat ze jonn", "maps_centred_on": "De Kaat met $1, $2 en de Medde.", "maps-googlemaps3-par-imageoverlays": "Määd et müjjelesch, e Beld obb em aanjejovve Plaz op dä Kaat aanzeije ze lohße.", - "maps-googlemaps3-par-markercluster": "Määd et müjjelesch, benaachbaate Makehronge zesamme ze faße.", + "maps-par-markercluster": "Määd et müjjelesch, benaachbaate Makehronge zesamme ze faße.", "maps-googlemaps3-par-kmlrezoom": "Donn di Kaat norr_ens zoome, nohdäm de layers vum KLM jelaade sin." } diff --git a/i18n/lb.json b/i18n/lb.json index 0a800b90f..f61bf4e93 100644 --- a/i18n/lb.json +++ b/i18n/lb.json @@ -16,7 +16,7 @@ "maps-copycoords-prompt": "CTRL+C, ENTER", "maps-searchmarkers-text": "Markéierunge fir Filteren", "maps-others": "anerer", - "maps-layer-property": "Eegeschaft", + "maps-layer-property": "Eegenschaft", "maps-layer-value": "Wäert", "maps-layer-errors": "Feeler", "maps-layerdef-invalid": "Net valabel {{PLURAL:$1|Definitioun|Definitiounen}}", @@ -44,7 +44,6 @@ "maps-displaymap-par-polygons": "Polygonen fir ze weisen", "maps-displaymap-par-rectangles": "Rechtecker fir ze weisen", "maps-displaymap-par-static": "D'Kaart statesch maachen", - "maps-googlemaps3-par-enable-fullscreen": "'Fullscreen'-Knäppchen aschalten", "validation-error-invalid-location": "Parameter $1 muss eng valabel Plaz sinn.", "validation-error-invalid-locations": "Parameter $1 muss eng oder méi valabel Plaze sinn.", "validation-error-invalid-width": "Parameter $1 muss eng valabel Breet sinn.", @@ -68,15 +67,15 @@ "maps_map_cannot_be_displayed": "D'Kaart kann net gewise ginn.", "maps-geocoder-not-available": "D'Funktioun vun der Geocodéierung vu Kaarten ass net disponibel. Äre Standuert konnt net geocodéiert ginn.", "maps_leaflet": "Depliant", + "maps-leaflet-par-layer": "De Layer dee gewise gëtt wann d'Kaart geluede gëtt.", "maps_click_to_activate": "Klickt fir d'kaart z'aktivéieren", "maps_centred_on": "D'Kaart ass zentréiert op $1, $2", + "maps-par-enable-fullscreen": "'Fullscreen'-Knäppchen aschalten", + "maps-par-kml": "KML-Fichieren déi op d'Kaart musse geluede ginn.", "maps-googlemaps3-incompatbrowser": "Äre Browser ass net mat Google Maps v3 kompatibel.", "maps-googlemaps3-par-type": "Den Typ vu Kaart den am Ufank gewise gëtt.", "maps-googlemaps3-par-autoinfowindows": "Automatesch all Fënstere mat Informatiounen opmaachen nodeem d'Säit geluede gouf.", - "maps-googlemaps3-par-kml": "KML-Fichieren déi op d'Kaart musse geluede ginn.", "maps-googlemaps3-par-poi": "Kuckeswäertes weisen", - "maps-osm-par-thumbs": "Miniaturbiller weisen", - "maps-osm-par-photos": "Fotoe weisen", "specialpages-group-maps": "Kaarten", "mapeditor-none-text": "Keen", "mapeditor-done-button": "Fäerdeg", @@ -98,5 +97,26 @@ "mapeditor-form-field-showonhover": "Nëmme weise wann een driwwer fiert", "mapeditor-mapparam-title": "Parametere vun der Kaart änneren", "mapeditor-mapparam-defoption": "-Parameter eraussichen-", - "mapeditor-form-field-image": "Bild" + "mapeditor-form-field-image": "Bild", + "semanticmaps-unrecognizeddistance": "De Wäert $1 ass keng valabel Distanz.", + "semanticmaps-kml-link": "KML-Fichier weisen", + "semanticmaps-default-kml-pagelink": "Säit $1 weisen", + "semanticmaps-latitude": "Breedegrad: $1", + "semanticmaps-longitude": "Längtegrad: $1", + "semanticmaps-altitude": "Héicht: $1", + "semanticmaps-forminput-locations": "Plazen", + "semanticmaps-kml-title": "De Standard-Titel fir Resultater", + "semanticmaps-kml-linkabsolute": "Solle Linken absolut sinn (am Géigesaz zu relativ)", + "validator-type-mapscircle": "Geographesche Krees", + "validator-type-mapscircle-list": "Lëscht vun de Kreesser", + "validator-type-mapsimageoverlay": "Bildiwwerlagerung", + "validator-type-mapsimageoverlay-list": "Lëscht vun de Bildiwwerlagerungen", + "validator-type-mapsline": "Geographesch Linn", + "validator-type-mapsline-list": "Lëscht vu Linnen", + "validator-type-mapslocation": "Geographesch Plaz", + "validator-type-mapslocation-list": "Lëscht vu Plazen", + "validator-type-mapsrectangle": "Geographesche Rechteck", + "validator-type-mapsrectangle-list": "Lëscht vun de Rechtecken", + "validator-type-mapspolygon": "Geographesche Polygon", + "validator-type-mapspolygon-list": "Lëscht vun de geographesche Polygonen" } diff --git a/i18n/lt.json b/i18n/lt.json index b4cc5ac20..1356ce082 100644 --- a/i18n/lt.json +++ b/i18n/lt.json @@ -11,22 +11,108 @@ "action-geocode": " šioje wiki atlikite geokodavimą", "maps_map": "Žemėlapis", "maps-loading-map": "Kraunamas žemėlapis ...", + "maps-load-failed": "Nepavyko įkelti žemėlapio!", + "maps-markers": "Žymekliai", + "maps-copycoords-prompt": "CTRL+C, ENTER", "maps-others": "kita", + "maps-ns-layer": "Sluoksnis", + "maps-ns-layer-talk": "Sluoksnio aptarimas", + "maps-layer-property": "Savybė", + "maps-layer-value": "Vertė", + "maps-layer-errors": "Klaidos", + "maps-layerdef-invalid": "{{PLURAL:$1|Negalimas apibrėžimas|Negalimi apibrėžimai}}", + "maps-layerdef-invalid-fatal": "Galutinis negalimas apibrėžimas", + "maps-layerpage-usage": "Puslapiai su žemėlapiais, naudojantys sluoksnį „$1“", + "maps-layerpage-nousage": "Šiuo metu nėra puslapių, naudojančiu šį sluoksnį", + "maps-error-invalid-layertype": "Nėra „$1“ tipo sluoksnių. Tik {{PLURAL:$3|šis tipas|šie tipai}} yra palaikomi: $2", + "maps-error-no-layertype": "Turite nurodyti sluoksnio tipą. {{PLURAL:$2|Tik šis tipas|Tik šie tipai}} yra palaikomi: $1", + "validation-error-invalid-layer": "Parametras „$1“ turi būti galimas sluoksnis.", + "validation-error-invalid-layers": "Parametras „$1“ turi būti vienas ar daugiau galimų sluoksnių.", + "maps-layer-of-type": "„$1“ tipo sluoksnis", + "maps-layer-of-type-and-name": "„$1“ tipo sluoksnis „$2“", + "maps-coordinates-par-location": "Koordinatės, kurias norite formatuoti.", + "maps-finddestination-par-location": "Pradinė vieta.", + "maps-finddestination-par-distance": "Kelionės atstumas.", + "maps-displaymap-par-circles": "Rodomi apskritimai", + "maps-displaymap-par-lines": "Rodomos linijos", + "maps-displaymap-par-maxzoom": "Didžiausias priartinimo lygis", + "maps-displaymap-par-minzoom": "Mažiausias priartinimo lygis", + "maps-displaymap-par-polygons": "Rodomi daugiakampiai", + "maps-displaymap-par-rectangles": "Rodomi stačiakampiai", + "maps-displaymap-par-static": "Padaryti žemėlapį statinį", + "maps-displaymap-par-wmsoverlay": "Naudoti WMS perdangą", + "maps-fullscreen-button": "Perjungti į visą ekraną", + "maps-fullscreen-button-tooltip": "Peržiūrėti žemėlapį visame ekrane arba kaip integruotą", + "validation-error-invalid-location": "Parametras „$1“ turi būti galima vieta.", + "validation-error-invalid-locations": "Parametras „$1“ turi būti viena ar kelios galimos vietos.", + "validation-error-invalid-width": "Parametras „$1“ turi būti galimas plotis.", + "validation-error-invalid-height": "Parametras „$1“ turi būti galimas aukštis.", + "validation-error-invalid-distance": "Parametras „$1“ turi būti galimas atstumas.", + "validation-error-invalid-distances": "Parametras „$1“ turi būti vienas ar keli galimi atstumai.", + "validation-error-invalid-image": "Parametras „$1“ turi būti galimas paveikslėlis.", + "validation-error-invalid-images": "Parametras „$1“ turi būti vienas ar keli galimi paveikslėliai.", "maps-abb-north": "Š", "maps-abb-east": "R", "maps-abb-south": "P", "maps-abb-west": "V", "maps-latitude": "Platuma:", "maps-longitude": "Ilguma:", - "maps-invalid-coordinates": "Vertė $ 1 nepripažįstama kaip galiojanti koordinatė.", + "maps-invalid-coordinates": "Vertė $1 nepripažįstama kaip galiojančios koordinatės.", "maps_coordinates_missing": "Nesudarytos koordinatės žemėlapiui.", "maps_geocoding_failed": "{{PLURAL:$2|Šis adresas|Šie adresai}} negali būti kartografuoti: $1.", "maps_unrecognized_coords": "{{PLURAL:$2|Ši koordinatė|Šios koordinatės}} nebuvo atpažintos: $1.", "maps_map_cannot_be_displayed": "Žemėlapis negal būti parodytas.", "maps_leaflet": "Lankstinukas", + "maps-leaflet-par-defzoom": "Leidžia nustatyti numatytąjį žemėlapio priartinimo lygį.", + "maps-leaflet-par-layer": "Sluoksnis, kuris bus rodomas kai žemėlapis bus įkeltas.", "maps_click_to_activate": "Spustelėkite, norėdami įjungti žemėlapį", "maps_centred_on": "Žemėlapis centruotas link $1, $2.", + "maps-par-enable-fullscreen": "Įgalinti viso ekrano mygtuką", + "maps-par-markercluster": "Leidžia sujungti kelius netoliese esančius žymeklius į vieną žymeklį", + "maps-googlemaps3-incompatbrowser": "Jūsų naršyklė nėra suderinama su Google Maps v3.", + "maps-googlemaps3-par-type": "Pradinis žemėlapio tipas.", "mapeditor": "Žemėlapio redaktorius", "specialpages-group-maps": "Žemėlapiai", - "mapeditor-done-button": "Atlikta" + "mapeditor-none-text": "Nėra", + "mapeditor-done-button": "Atlikta", + "mapeditor-remove-button": "Pašalinti", + "mapeditor-import-button2": "Importuoti", + "mapeditor-export-button": "Eksportuoti į viki kodą", + "mapeditor-import-button": "Importuoti iš viki kodo", + "mapeditor-select-button": "Pasirinkti šį daugiakampį", + "mapeditor-mapparam-button": "Redaguoti žemėlapio parametrus", + "mapeditor-clear-button": "Valyti žemėlapį", + "mapeditor-code-title": "Viki kodas", + "mapeditor-import-title": "Importuoti vikį kodą", + "mapeditor-form-title": "Redaguoti informaciją", + "mapeditor-link-title-switcher-popup-text": "Iššokantis langas su tekstu", + "mapeditor-link-title-switcher-link-text": "Nuoroda", + "mapeditor-form-field-title": "Pavadinimas", + "mapeditor-form-field-text": "Tekstas", + "mapeditor-form-field-link": "Nuoroda", + "mapeditor-form-field-icon": "Ikona", + "mapeditor-form-field-group": "Grupė", + "mapeditor-form-field-strokecolor": "Potėpio spalva", + "mapeditor-form-field-strokeopacity": "Potėpio matomumas", + "mapeditor-form-field-strokeweight": "Potėpio svoris", + "mapeditor-form-field-fillcolor": "Užpildo spalva", + "mapeditor-form-field-fillopcaity": "Užpildo matomumas", + "mapeditor-form-field-showonhover": "Rodyti tik užvedus pelytę", + "mapeditor-mapparam-title": "Redaguoti žemėlapio parametrus", + "mapeditor-mapparam-defoption": "-Pasirinkti parametrą-", + "mapeditor-form-field-image": "Paveikslėlis", + "semanticmaps-kml-link": "Žiūrėti KML failą", + "semanticmaps-default-kml-pagelink": "Žiūrėti puslapį $1", + "semanticmaps-latitude": "Platuma: $1", + "semanticmaps-longitude": "Ilguma: $1", + "semanticmaps-altitude": "Aukštis: $1", + "semanticmaps-forminput-locations": "Vietovės", + "validator-type-mapscircle": "Geografinis apskritimas", + "validator-type-mapscircle-list": "Apskritimų sąrašas", + "validator-type-mapsline": "Geografinė linija", + "validator-type-mapsline-list": "Linijų sąrašas", + "validator-type-mapslocation": "Geografinė vieta", + "validator-type-mapslocation-list": "Vietų sąrašas", + "validator-type-mapsrectangle": "Geografinis stačiakampis", + "validator-type-mapsrectangle-list": "Stačiakampių sąrašas" } diff --git a/i18n/mk.json b/i18n/mk.json index 4fad1ddf4..87f62a491 100644 --- a/i18n/mk.json +++ b/i18n/mk.json @@ -6,7 +6,7 @@ "Macofe" ] }, - "maps-desc": "Дава можност за вметнување на динамички карти во викистраници, геокодирање на адреси и други географски операции", + "maps-desc": "Дава можност за вметнување на динамички карти во викистраници, геокодирање на адреси и други географски постапки", "right-geocode": "Геокод", "action-geocode": "вршење на геокодирање на ова вики", "maps_map": "Карта", @@ -38,9 +38,8 @@ "maps-layer-of-type": "Слој од типот $1", "maps-layer-of-type-and-name": "Слој „$2“ од типот „$1“", "maps-layer-type-supported-by": "Овој тип на слој може да се користи {{PLURAL:$2|само со картографската служба $1|само со следниве картографски служби: $1}}.", - "maps-coordinates-description": "Расчленувачка кука за форматирање на координати. Ги претвора сите поддржани формати.", + "maps-coordinates-description": "Расчленувачкиот пресретник за форматирање на координати. Ги претвора сите поддржани формати.", "maps-displaymap-description": "Приказ на географски карти без никакви обележувачи на нив определени од викито.", - "maps-displaypoint-description": "Приказ на географски карти со една или повеќе обележувачи на нив определени од викито.", "maps-distance-description": "Претворање на растојание од една во друга поддржана единица.", "maps-finddestination-description": "Пронаоѓање на одредница со зададена почетна точка (која може да биде во било кој поддржан формат), првична насока и растојание", "maps-geocode-description": "Овозможува геокодирање на адреси, што значи дека претвора места во координати. Има поддршка за неколку служби за геокодирање (не е исто што и картографски служби).", @@ -53,7 +52,7 @@ "maps-coordinates-par-format": "Целниот формат за координатите.", "maps-coordinates-par-directional": "Покажува дали координатите треба да се испишат со или без насока.", "maps-distance-par-distance": "Растојанието во кое претворате е истоветно со единицата што се укажува.", - "maps-distance-par-decimals": "Максимален број на децимални места што ќе се користат во изводната вредност.", + "maps-distance-par-decimals": "Највеќе децимални места што ќе се користат во изводната вредност.", "maps-distance-par-unit": "Единица на испишаното растојание во изводот.", "maps-finddestination-par-location": "Првичната местоположба.", "maps-finddestination-par-bearing": "Првичната насока.", @@ -72,7 +71,7 @@ "maps-geodistance-par-location1": "Првата точка во пресметката на растојанието.", "maps-geodistance-par-location2": "Втората точка во пресметката на растојанието.", "maps-geodistance-par-unit": "Во која единица да се испише растојанието.", - "maps-geodistance-par-decimals": "Максималниот број на децимални места за добиената вредност.", + "maps-geodistance-par-decimals": "Допуштениот број на децимални места за добиената вредност.", "maps-geodistance-par-mappingservice": "Службата за геокодирање што се користи за геокодирање на било која адреса.", "maps-geodistance-par-geoservice": "Со која картографска служба ќе ја користите оваа расчленувачка функција.\nОва може да влијае на основната вредност за служба за геокодирање.", "maps-displaymap-par-mappingservice": "Овозможува задавање на картографска служба што ќе се користи за создавање на картата.", @@ -86,15 +85,14 @@ "maps-displaymap-par-circles": "Кругови за приказ", "maps-displaymap-par-copycoords": "Прикажувај прозорче со координатите на местото при стискање на место од кајшто можат да се прекопираат.", "maps-displaymap-par-lines": "Линии за приказ", - "maps-displaymap-par-maxzoom": "Максимална приближеност", - "maps-displaymap-par-minzoom": "Минимална приближеност", + "maps-displaymap-par-maxzoom": "Најголема приближеност", + "maps-displaymap-par-minzoom": "Најмала приближеност", "maps-displaymap-par-polygons": "Многуаголници за приказ", "maps-displaymap-par-rectangles": "Правоаголници за приказ", "maps-displaymap-par-static": "Напарви ја картата неподвижна", "maps-displaymap-par-wmsoverlay": "Користи WMS-облога", "maps-fullscreen-button": "Префрли на широк екран", "maps-fullscreen-button-tooltip": "Поглед на картата на цел екран или вгнездено.", - "maps-googlemaps3-par-enable-fullscreen": "Овозможи копче за цел екран", "validation-error-invalid-location": "Параметарот $1 мора да претставува важечка местоположба.", "validation-error-invalid-locations": "Параметарот $1 мора да претставува една или повеќе важечки местоположби.", "validation-error-invalid-width": "Параметарот $1 мора да претставува важечка ширина.", @@ -121,6 +119,11 @@ "maps-geocoder-not-available": "Функцијата за геокодирање на Карти е недостапна. Вашата местоположба не може да се геокодира.", "maps_googlemaps3": "Google Карти вер. 2", "maps_leaflet": "Леток", + "maps-leaflet-par-defzoom": "Овозможува задавање на основен степен на приближеност на картата.", + "maps-leaflet-par-layer": "Слојот што ќе се покажува кога се вчитува картата.", + "maps-leaflet-par-overlaylayers": "Слоеви на облогата што ќе се покажуваат кога се вчитува картата.", + "maps-leaflet-par-maxclusterradius": "Најголемиот полупречник што може да го покрие еден грозд од средишниот обележувач (во пиксели).", + "maps-leaflet-par-clusterspiderfy": "Кога ќе стиснете на грозд при најслаба приближеност, истиот ќе се разграни за да можете да ги видите сите негови обележувачи.", "maps_click_to_activate": "Стиснете за активирање на картата", "maps_centred_on": "Средиште на картата во $1, $2.", "maps-par-mappingservice": "Овозможува назначување на картографска служба што ќе се користи за создавање на картата.", @@ -131,9 +134,11 @@ "maps-par-width": "Овозможува задавање на ширина на картата во пиксели по основно, но по желба можете да изберете една од следниве единици: px, ex, em, %.", "maps-par-height": "Овозможува задавање на висина на картата во пиксели по основно, но по желба можете да изберете една од следниве единици: px, ex, em, %.", "maps-par-centre": "На која местоположба да се сосредоточи картата", + "maps-par-enable-fullscreen": "Овозможи копче за цел екран", + "maps-par-kml": "KML-податотеки за вчитување во картата.", + "maps-par-markercluster": "Овозможува спојување на повеќе соседни бележници во еден", "maps-googlemaps3-incompatbrowser": "Вашиот прелистувач не е погоден за Google Карти вер. 3.", "maps-googlemaps3-par-imageoverlays": "Овозможува додавање на слика што ќе се прикажува на укажаното место на картата.", - "maps-googlemaps3-par-markercluster": "Овозможува спојување на повеќе соседни бележници во еден", "maps-googlemaps3-par-type": "Типот на карта за првичниот приказ.", "maps-googlemaps3-par-types": "Типовите на карти што ќе бидат достапни преку контролата за тип.", "maps-googlemaps3-par-layers": "Посебни слоеви за вчитување во картата.", @@ -141,17 +146,20 @@ "maps-googlemaps3-par-zoomstyle": "Стил на контролата за приближување.", "maps-googlemaps3-par-typestyle": "Стилот на контролата за тип.", "maps-googlemaps3-par-autoinfowindows": "Автоматски отворај ги сите инфопрозорци откако ќе се вчита страницата.", - "maps-googlemaps3-par-kml": "KML-податотеки за вчитување во картата.", "maps-googlemaps3-par-gkml": "KML-податотеки вдомени од Google за вчитување на карта.", "maps-googlemaps3-par-fusiontables": "Назнаки (ID) на табели од Google Fusion Tables што треба да се вчитаат во картата.", "maps-googlemaps3-par-tilt": "Наклон на картата кога користите Google Карти.", "maps-googlemaps3-par-kmlrezoom": "Приближи ја картата повторно откако ќе се вчитаат KML-слоевите.", "maps-googlemaps3-par-poi": "Прикажи точки од интерес.", + "maps-googlemaps3-par-clustergridsize": "Решеткаста големина на грозд во пиксели.", + "maps-par-clustermaxzoom": "Најголемиот степен на приближеност при кој можат да постојат гроздови.", + "maps-par-clusterzoomonclick": "Дали, по основно, стискањето на грозд ќе го приближи истиот.", + "maps-par-maxclusterradius": "Најголемиот полупречник што може да го покрие еден грозд.", + "maps-googlemaps3-par-clusteraveragecenter": "Дали средиштето на секој гроз треба да биде просек од сите обележувачи во гроздот.", + "maps-googlemaps3-par-clusterminsize": "Најмалиот број на обележувачи што ќе бидат во грозд пред истите да бидат скриени и да се прикаже нивната бројка.", "maps-openlayers-par-controls": "Контролите што сакате да стојат на картата.", "maps-openlayers-par-layers": "Слоевите што ќе бидат достапни во бирачот на слоеви. Кога ќе се вчита картата ќе се прикаже првиот слој.", "maps-openlayers-par-overlays": "Слоеви за облоги што ќе бидат на располагање во одделот за слоеви. Ќе се прикажуваат врз обичните слоеви, налик на обележувачи.", - "maps-osm-par-thumbs": "Прикажи минијатури", - "maps-osm-par-photos": "Прикажи слики", "mapeditor": "Уредник на карти", "specialpages-group-maps": "Карти", "mapeditor-parser-error": "Се појави грешка при расчленувањето на метаподатоците. Го занемарувам уделот на корисникот.", @@ -187,5 +195,42 @@ "mapeditor-imageoverlay-button": "Додај облога од слика", "mapeditor-form-field-image": "Слика", "mapeditor-imageoverlay-title": "Поединости за облога од слика", - "mapeditor-form-field-visitedicon": "Икона за посетено" + "mapeditor-form-field-visitedicon": "Икона за посетено", + "semanticmaps-unrecognizeddistance": "Вредноста $1 не претставува важечко растојание.", + "semanticmaps-kml-link": "Преглед на KML-податотеката", + "semanticmaps-default-kml-pagelink": "Преглед на статијата $1", + "semanticmaps-latitude": "Геог. ширина: $1", + "semanticmaps-longitude": "Геог. должина: $1", + "semanticmaps-altitude": "Надм. вис: $1", + "semanticmaps-forminput-locations": "Места", + "semanticmaps-par-staticlocations": "Список на места за додавање во картатата заедно со побараните податоци. Како и со „display_points“, тука можете да додадете наслов, опис и икона за секое место, користејќи тилда (~) како одделувач.", + "semanticmaps-par-showtitle": "Дали да се прикажува насловот на инфопрозорецот на ознаката. Оневозможете го кога користите шаблон за форматирање на содржината на инфопрозорецот.", + "semanticmaps-par-hidenamespace": "Дали да се прикажува називот на именскиот простор во инфопрозорецот за ознаката.", + "semanticmaps-par-centre": "Средиштето на картата. Ако не е укажано, картата автоматски ќе го одбере средиштето кајшто оптимално ќе се прикажат сите одбележувачи на картата.", + "semanticmaps-par-template": "Шаблон за форматирање на содржината на инфопрозорецот.", + "semanticmaps-par-geocodecontrol": "Прикажи геокодни котроли.", + "semanticmaps-par-activeicon": "Икона за приказ наместо стандардниот бележник, кога активна страница се совпаѓа со бараното", + "semanticmaps-par-pagelabel": "Ако му е зададено „да“, сите обележувачи ќе имаат „inlineLabel“ со врска до страницата што ги содржат координатите за обележувачот", + "semanticmaps-par-ajaxcoordproperty": "Назив на координатното својство со кое ќе се срочи барање со Ajax.", + "semanticmaps-par-ajaxquery": "Второ барање што се праша преку Ajax за добивање на дополнителни координати.", + "semanticmaps-par-userparam": "Вредност која се дава при секое повикување на шаблон, ако се користи", + "semanticmaps-kml-text": "Текстот на секоја страница. Се презапишува ако има дополнителни барани својства.", + "semanticmaps-kml-title": "Стандарден наслов за исходот", + "semanticmaps-kml-linkabsolute": "Дали врските да бидат апсолутни (наспроти релативни)", + "semanticmaps-kml-pagelinktext": "Текстот на врските на страницата, каде $1 ќе се замени со насловот на страницата", + "semanticmaps-shapes-improperformat": "Несоодветно форматирање на $1. Погледајте во документацијата како треба да се форматира.", + "semanticmaps-shapes-missingshape": "Не пронајдов облици за $1. Погледајте во документацијата кои облици ви се на располагање.", + "validator-type-mapscircle": "Географски круг", + "validator-type-mapscircle-list": "Список на кругови", + "validator-type-mapsimageoverlay": "Обложна слика", + "validator-type-mapsimageoverlay-list": "Список на обложни слики", + "validator-type-mapsline": "Географска линија", + "validator-type-mapsline-list": "Список на линии", + "validator-type-mapslocation": "Географска месност", + "validator-type-mapslocation-list": "Список на месности", + "validator-type-mapsrectangle": "Географски правоаголник", + "validator-type-mapsrectangle-list": "Список на правоаголници", + "validator-type-mapspolygon": "Географски многуаголник", + "validator-type-mapspolygon-list": "Список на географски многуаголници", + "validator-type-wmsoverlay": "Облога Web Map Service" } diff --git a/i18n/ms.json b/i18n/ms.json index eafc3ba9d..aebd8ce61 100644 --- a/i18n/ms.json +++ b/i18n/ms.json @@ -31,7 +31,6 @@ "maps-layer-type-supported-by": "Jenis lapisan ini {{PLURAL:$2|hanya boleh digunakan dengan perkhidmatan pemetaan $1|boleh digunakan dengan perkhidmatan-perkhidmatan pemetaan yang berikut: $1}}.", "maps-coordinates-description": "Cangkuk penghurai untuk memformatkan koordinat daripada/kepada sebarang format yang disokong.", "maps-displaymap-description": "Memaparkan peta geografi tanpa sebarang penanda tentuan wiki padanya.", - "maps-displaypoint-description": "Memaparkan peta geografi dengan sekurang-kurangnya satu penanda tentuan wiki padanya.", "maps-distance-description": "Menukar nilai jarak yang menggunakan unit disokong yang tertentu kepada setaraannya yang menggunakan unit yang lain.", "maps-finddestination-description": "Mencari tujuan dari satu titik permulaan (yang boleh dinyatakan dalam sebarang format yang disokong), bearing permulaan dan jarak.", "maps-geocode-description": "Membolehkan pembuatan geokod alamat, iaitu menukar lokasi yang boleh dibaca oleh manusia kepada peranggu koordinat. Wujudnya sokongan untuk beberapa perkhidmatan geokod yang tidak boleh disamakan dengan perkhidmatan pemetaan.", @@ -115,6 +114,7 @@ "maps-par-width": "Membolehkan penetapan lebar peta. Pada asali, piksel dianggap sebagai unit, tetapi anda boleh menetapkan mana-mana unit yang berikut: px, ex, em, %.", "maps-par-height": "Membolehkan penetapan tinggi peta. Pada asali, piksel dianggap sebagai unit, tetapi anda boleh menetapkan mana-mana unit yang berikut: px, ex, em, %.", "maps-par-centre": "Lokasi yang hendak dijadikan pusat peta", + "maps-par-kml": "Fail-fail KML untuk dimuatkan kepada peta.", "maps-googlemaps3-incompatbrowser": "Pelayar anda tidak serasi dengan Google Maps v3.", "maps-googlemaps3-par-type": "Jenis peta untuk dipaparkan pada mulanya.", "maps-googlemaps3-par-types": "Jenis-jenis peta yang tersedia melalui kawalan jenis.", @@ -123,7 +123,6 @@ "maps-googlemaps3-par-zoomstyle": "Gaya kawalan zum.", "maps-googlemaps3-par-typestyle": "Gaya kawalan jenis.", "maps-googlemaps3-par-autoinfowindows": "Membuka semua tetingkap maklumat secara automatik selepas laman dimuatkan.", - "maps-googlemaps3-par-kml": "Fail-fail KML untuk dimuatkan kepada peta.", "maps-googlemaps3-par-gkml": "Fail-fail KML yang dihoskan oleh Google untuk dimuatkan pada peta.", "maps-googlemaps3-par-fusiontables": "ID Google Fusion Tables yang patut dimuatkan pada peta.", "maps-googlemaps3-par-tilt": "Ciri menyendengkan Peta ketika menggunakan Google Maps.", @@ -131,8 +130,6 @@ "maps-googlemaps3-par-poi": "Tunjukkan tempat-tempat menarik.", "maps-openlayers-par-controls": "Alat kawalan untuk diletakkan pada peta.", "maps-openlayers-par-layers": "Lapisan-lapisan yang akan tersedia pada pemilih lapisan. Lapisan pertama akan dipaparkan apabila peta dimuatkan.", - "maps-osm-par-thumbs": "Tunjukkan gambar kenit (thumbnail)", - "maps-osm-par-photos": "Tunjukkan gambar", "mapeditor": "Editor peta", "specialpages-group-maps": "Peta", "mapeditor-parser-error": "Timbulnya ralat ketika menghuraikan metadata. Input pengguna diabaikan.", @@ -168,5 +165,6 @@ "mapeditor-imageoverlay-button": "Tambah tindihan imej", "mapeditor-form-field-image": "Imej", "mapeditor-imageoverlay-title": "Butiran tindihan imej", - "mapeditor-form-field-visitedicon": "Ikon dikunjungi" + "mapeditor-form-field-visitedicon": "Ikon dikunjungi", + "semanticmaps-forminput-locations": "Lokasi" } diff --git a/i18n/nb.json b/i18n/nb.json index 477cbee77..a419fa0f0 100644 --- a/i18n/nb.json +++ b/i18n/nb.json @@ -5,35 +5,51 @@ "Kim Eik", "Nghtwlkr", "Danmichaelo", - "Macofe" + "Macofe", + "EvenT", + "Jon Harald Søby" ] }, "maps-desc": "Gir mulighet for å bygge inn dynamiske kart i wikisider, geokoding av adresser og andre geografiske operasjoner", "right-geocode": "Geokode", + "action-geocode": "utføre geokoding på denne wikien", "maps_map": "Kart", + "maps-tracking-category": "Sider med kart som vises med kartutvidelsen", "maps-loading-map": "Laster kart...", "maps-load-failed": "Klarte ikke laste kartet.", "maps-markers": "Markører", + "maps-copycoords-prompt": "Chrl+C, Enter", + "maps-searchmarkers-text": "Filtrer markører", "maps-others": "andre", + "maps-kml-parsing-failed": "Klarte ikke å parse én eller flere KML-filer. Dette skjer vanligvis på grunn av en hentingsfeil eller ugyldig XML.", "maps-ns-layer": "Lag", "maps-ns-layer-talk": "Lagdiskusjon", "maps-layer-property": "Egenskap", "maps-layer-value": "Verdi", "maps-layer-errors": "Feil", + "maps-layerdef-invalid": "{{PLURAL:$1|Ugyldig definisjon|Ugyldige definisjoner}}", + "maps-layerdef-invalid-fatal": "Katastrofalt ugyldig definisjon", + "maps-layerdef-wrong-namespace": "Lagdefinisjoner er kun gyldige på sider i navnerommet «$1»", + "maps-layerdef-equal-layer-name": "Lagnavn må være unike innen samme lagside. «$1» brukes allerede av et annet lag.", + "maps-layerpage-usage": "Sider med kart som bruker laget «$1»", + "maps-layerpage-nousage": "Ingen sider bruker dette laget for tiden.", "maps-error-invalid-layertype": "Det er ingen lag av typen «$1». Bare {{PLURAL:$3|denne typen|disse typene}} er støttet: $2", "maps-error-no-layertype": "Du må angi en lagtype. Bare {{PLURAL:$2|denne typen|disse typene}} er støttet: $1", "validation-error-invalid-layer": "Parameter $1 må været et gyldig lag.", "validation-error-invalid-layers": "Parameter $1 må være et eller flere gyldige lag.", + "validation-error-no-non-numeric": "Parameteren «$1» må være en ikke-numerisk streng.", + "validation-error-no-non-numerics": "Parameteren «$1» må være én eller flere ikke-numeriske strenger.", "maps-layer-of-type": "Lagtype $1", + "maps-layer-of-type-and-name": "Lag «$2» av typen «$1»", "maps-layer-type-supported-by": "Denne lagtypen kan bare brukes med {{PLURAL:$2|karttjenesten $1|disse karttjenestene: $1}}.", "maps-coordinates-description": "Parser-hook for å formatere koordinater, fra og til vilkårlige av de støttede formatene.", "maps-displaymap-description": "Vis geografiske kart uten wiki-spesifiserte markører.", - "maps-displaypoint-description": "Vis geografiske kart med en eller flere wiki-spesifiserte markører.", "maps-distance-description": "Gjør om en distanse basert på en viss støttet enhet til tilsvarende verdi i en annen enhet.", "maps-finddestination-description": "Finn et mål med gitt startpunkt (som kan være i ett av de støttede formatene), en initial retning og distanse.", "maps-geocode-description": "Gjør tilgjengelig geokoding av adresser, dvs. gjør menneskelesbare lokasjoner til koordinatsett. Det finnes støtte for flere geokodingstjenester, som ikke må forveksles med mappingtjenester.", "maps-geodistance-description": "Beregn den geografiske avstanden mellom to punkter, fra og til et vilkårlig av de støttede formatene.", "maps-mapsdoc-description": "Vis en tabell med parametrene for en spesifisert mappingstjeneste sammen med deres standardverdier og beskrivelser.", + "maps-layerdefinition-description": "Beskriver et egendefinert lag som kan vises med andre kartfunksjoner.", "maps-mapsdoc-par-service": "Mappingstjenesten for å vise parameterdokumentasjon.", "maps-mapsdoc-par-language": "Språket for å vise dokumentasjonen. Hvis ingen slik oversettelse er tilgjengelig, blir engelsk brukt.", "maps-coordinates-par-location": "Koordinatene du ønsker å formatere.", @@ -52,6 +68,18 @@ "maps-finddestination-par-mappingservice": "Parameter for å angi mappetjenesten som skal brukes for denne funksjonen.\nDette vil tillate kart å overstyre standardverdien av tjenesteparameteren med den som er optimal for mappetjenesten.\n(Eksempel: For Google Maps vil Google geocoder brukes.)", "maps-geocode-par-location": "Adressen du ønsker å geokode.", "maps-geocode-par-mappingservice": "Geokodetjenesten du ønsker å bruke. Sjekk de tilgjengelige geokodetjenestene.", + "maps-geocode-par-allowcoordinates": "Gjør det mulig å deaktivere støtten for koordinater i denne funksjonen. Må være enten ja eller nei. Om den er nei vil hver verdi geokodes, også gyldige koordinater.", + "maps-geocode-par-format": "Formatet for de resulterende koordinatene.", + "maps-geodistance-par-unit": "Enheten avstanden skal måles i.", + "maps-displaymap-par-circles": "Sirkler å vise", + "maps-displaymap-par-lines": "Linjer å vise", + "maps-displaymap-par-maxzoom": "Maksimalt zoomnivå", + "maps-displaymap-par-minzoom": "Minste zoomnivå", + "maps-displaymap-par-polygons": "Polygoner å vise", + "maps-displaymap-par-rectangles": "Rektangler å vise", + "maps-displaymap-par-static": "Gjør kartet statisk", + "maps-fullscreen-button": "Slå av/på fullskjerm", + "maps-fullscreen-button-tooltip": "Vis kartet som fullskjerm eller innbygd.", "validation-error-invalid-location": "Parameter $1 må være en gyldig lokasjon.", "validation-error-invalid-locations": "Parameter $1 må være en eller flere gyldige lokasjoner.", "validation-error-invalid-width": "Parameter $1 må være en gyldig bredde.", @@ -76,6 +104,7 @@ "maps_unrecognized_coords_for": "Følgende {{PLURAL:$2|koordinat|koordinater}} ble ikke gjenkjent og har blitt utelatt fra kartet:\n$1", "maps_map_cannot_be_displayed": "Kartet kan ikke vises.", "maps-geocoder-not-available": "Geokodingsfunksjonen i Maps er ikke tilgjengelig. Din plassering kan ikke geokodes.", + "maps-leaflet-par-layer": "Laget som vil vises mens kartet laster.", "maps_click_to_activate": "Klikk for å aktivere kartet", "maps_centred_on": "Kart sentrert om $1, $2.", "mapeditor": "Kart tegner", @@ -87,6 +116,7 @@ "mapeditor-import-button2": "Importer", "mapeditor-export-button": "Eksporter til wiki kode", "mapeditor-import-button": "Importer fra wiki kode", + "mapeditor-select-button": "Velg dette polygonet", "mapeditor-mapparam-button": "Rediger kart parametere", "mapeditor-clear-button": "Tøm kart", "mapeditor-code-title": "Wiki kode", @@ -112,5 +142,34 @@ "mapeditor-imageoverlay-button": "Legg til bilde", "mapeditor-form-field-image": "Bilde", "mapeditor-imageoverlay-title": "Bilde lag detaljer", - "mapeditor-form-field-visitedicon": "Besøkt ikon" + "mapeditor-form-field-visitedicon": "Besøkt ikon", + "semanticmaps-unrecognizeddistance": "Verdien $1 er ikke en gyldig avstand.", + "semanticmaps-kml-link": "Vis KML-filen", + "semanticmaps-default-kml-pagelink": "Vis siden $1", + "semanticmaps-latitude": "Breddegrad: $1", + "semanticmaps-longitude": "Lengdegrad: $1", + "semanticmaps-altitude": "Høyde over havet: $1", + "semanticmaps-forminput-locations": "Lokasjoner", + "semanticmaps-par-staticlocations": "En lokasjonsliste til å legge inn i kartet sammen med data fra spørringen. Som med display_points, kan du legge inn en tittel, en beskrivelse og et ikon per lokasjon med tilde \"~\" som skilletegn.", + "semanticmaps-par-showtitle": "Vise tittel i markørinfovinduet eller ikke. Deaktivering er ofte nyttig når en bruker en mal for å formatere innholdet i infovinduet.", + "semanticmaps-par-hidenamespace": "Vis tittelen for navnerommet i markørens informasjonsboks", + "semanticmaps-par-centre": "Kartets sentrum. Hvis dette ikke er angitt, vil kartet automatisk velge det optimale senteret for å vise alle kartmarkørene.", + "semanticmaps-par-template": "Mal som brukes for å formatere innholdet i infovinduet.", + "semanticmaps-par-geocodecontrol": "Vis geokodingsstyringen", + "semanticmaps-par-activeicon": "Ikon som vises istedenfor standardmarkøren, når aktiv side er lik resultatet av spørringen", + "semanticmaps-par-pagelabel": "Når satt til \"ja\", vil alle markører ha en \"inlineLabel\" med en lenke til siden som inneholder markørens koordinater", + "semanticmaps-kml-text": "Teksten knyttes til hver side. Overstyrt av spørringer på ekstra egenskaper, om noen.", + "semanticmaps-kml-title": "Standard resultatoverskrift", + "semanticmaps-kml-linkabsolute": "Skal lenker være absolutte eller ikke (dvs. relative)", + "semanticmaps-kml-pagelinktext": "Teksten som skal brukes for lenker til siden, der $1 erstattes av sidetittelen", + "semanticmaps-shapes-improperformat": "Ulovlig formatering av $1. Vennligst les dokumentasjonen for å korrigere", + "semanticmaps-shapes-missingshape": "Ingen figurer funnet for $1. Vennlig bruk tilgjengelige figurer fra dokumentasjonen", + "validator-type-mapscircle": "Geografisk sirkel", + "validator-type-mapscircle-list": "Liste over sirkler", + "validator-type-mapsline": "Geografisk linje", + "validator-type-mapsline-list": "Liste over linjer", + "validator-type-mapslocation": "Geografisk sted", + "validator-type-mapslocation-list": "Liste over steder", + "validator-type-mapsrectangle": "Geografisk rektangel", + "validator-type-mapsrectangle-list": "Liste over rektangler" } diff --git a/i18n/nl.json b/i18n/nl.json index b1b34b924..dac3f73d2 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -7,12 +7,15 @@ "SPQRobin", "Siebrand", "Sjoerddebruin", - "Esketti" + "Esketti", + "MrLeopold", + "Hex", + "Mainframe98" ] }, "maps-desc": "Maakt het insluiten van dynamische kaarten in de wikipagina's, het geocoderen van adressen en andere geografische activiteiten mogelijk", "right-geocode": "Geocoderen", - "action-geocode": "doen geocoding op deze wiki", + "action-geocode": "doe geocoding op deze wiki", "maps_map": "Kaart", "maps-tracking-category": "Pagina's met een kaart die gerenderd is door de uitbreiding Maps", "maps-loading-map": "Bezig met het laden van de kaart...", @@ -29,28 +32,27 @@ "maps-layer-errors": "Fouten", "maps-layerdef-invalid": "Ongeldige definitie{{PLURAL:$1||s}}", "maps-layerdef-invalid-fatal": "Fatale ongeldige definitie", - "maps-layerdef-wrong-namespace": "Definities zijn alleen geldig op de pagina ' s van de naamruimte \"$1\"", - "maps-layerdef-equal-layer-name": "Laag namen moeten uniek zijn binnen dezelfde laag pagina. \"$1'wordt al gebruikt door een andere laag.", - "maps-layerpage-usage": "Pagina ' s met kaarten met behulp van de laag \"$1\"", - "maps-layerpage-nousage": "Geen pagina ' s zijn met behulp van deze laag op het moment.", + "maps-layerdef-wrong-namespace": "Lagendefinities zijn alleen geldig op pagina's van de naamruimte \"$1\"", + "maps-layerdef-equal-layer-name": "Lagennamen moeten uniek zijn binnen dezelfde lagenpagina. \"$1'wordt al gebruikt door een andere laag.", + "maps-layerpage-usage": "Pagina's met kaarten die laag \"$1\" gebruiken", + "maps-layerpage-nousage": "Er zijn op het moment geen pagina's die deze laag gebruiken.", "maps-error-invalid-layertype": "Er zijn geen lagen van het type \"$1\". Alleen {{PLURAL:$3|dit type wordt|deze typen worden}} ondersteund: $2", "maps-error-no-layertype": "U moet het laagtype opgeven. Alleen {{PLURAL:$2|dit type wordt|deze typen worden}} ondersteund: $1", "validation-error-invalid-layer": "Parameter $1 moet een geldige laag zijn.", "validation-error-invalid-layers": "Parameter $1 moet een of meer geldige lagen zijn.", - "validation-error-no-non-numeric": "Parameter \"$1\" moet een niet-numerieke string.", - "validation-error-no-non-numerics": "Parameter \"$1\" moet een of meer niet-numerieke tekenreeksen.", + "validation-error-no-non-numeric": "Parameter \"$1\" moet een niet-numerieke tekenreeks zijn.", + "validation-error-no-non-numerics": "Parameter \"$1\" moet één of meer niet-numerieke tekenreeksen zijn.", "maps-layer-of-type": "Laag van het type $1", "maps-layer-of-type-and-name": "Laag \"$2\" van het type \"$1\"", "maps-layer-type-supported-by": "Dit laagtype kan {{PLURAL:$2|alleen gebruikt worden met de kaartdienst $1|gebruikt worden met de kaartdiensten $1}}.", "maps-coordinates-description": "Parserhook om coördinaten op te maken, van en naar alle ondersteunde notaties.", "maps-displaymap-description": "Geografische kaarten weergeven zonder in de wiki gedefinieerde markeringen.", - "maps-displaypoint-description": "Geografische kaarten weergeven met een of meer in de wiki gedefinieerde markeringen.", "maps-distance-description": "Converteren naar een afstand met behulp van een bepaalde ondersteunde eenheid naar een equivalent in een andere eenheid.", "maps-finddestination-description": "Een bestemming vinden via een gegeven beginpunt (in elke ondersteunde notatie), een richting en een afstand.", "maps-geocode-description": "Maakt het geocoderen van adressen mogelijk, dat wil zeggen dat leesbare locaties worden omgezet in verzamelingen coördinaten. Er is ondersteuning voor verschillende geocoderingsdiensten die niet verward moeten worden met kaartdiensten.", "maps-geodistance-description": "De geografische afstand tussen twee punten berekenen, van en naar alle ondersteunde notaties.", "maps-mapsdoc-description": "Een tabel met de parameters voor een bepaalde kaartdienst weergeven samen met hun standaardwaarde en beschrijving.", - "maps-layerdefinition-description": "Beschrijft een aangepaste laag, die weergegeven kan worden met een andere Kaart functies.", + "maps-layerdefinition-description": "Beschrijft een aangepaste laag die weergegeven kan worden met andere Kaart-functies.", "maps-mapsdoc-par-service": "De kaartdienst waarvoor parameterdocumentatie weergegeven moet worden.", "maps-mapsdoc-par-language": "De taal waarin de documentatie wordt weergegeven. Indien er geen vertaling beschikbaar is, wordt Engels gebruikt.", "maps-coordinates-par-location": "De op te maken coördinaten.", @@ -81,7 +83,7 @@ "maps-geodistance-par-geoservice": "De mapping service deze parser functie wordt gebruikt in combinatie met.\nDit kan invloed hebben op de standaard geocoding service-waarde.", "maps-displaymap-par-mappingservice": "Maakt het mogelijk om de kaartdienst in te stellen die wordt gebruikt om de kaart te maken.", "maps-displaymap-par-coordinates": "De locatie die zich bij de eerste keer laden in het centrum van de kaart bevindt.", - "maps-displaymap-par-visitedicon": "De bestandsnaam van een afbeelding moet worden gebruikt voor de markering pictogrammen na de oorspronkelijke markeringen zijn geklikt", + "maps-displaymap-par-visitedicon": "De bestandsnaam van een afbeelding voen gebruik als markeringspictogrammen nadat op de oorspronkelijke markeringen is geklikt", "maps-displaymap-par-zoom": "Maakt het mogelijk het schaalniveau van de kaart in te stellen.\nAls deze waarde niet wordt ingesteld en er staan meerdere markers op de kaart, dan wordt het best passende schaalniveau gekozen, niet het instelbare standaardniveau.", "maps-displaymap-par-centre": "Maakt het mogelijk de coördinaten voor het midden van de kaart in te stellen voor display_point(s).\nKan ingesteld worden met adressen en coördinaten.\nAls deze waarde niet wordt ingesteld, wordt de kaart gecentreerd op of tussen de opgegeven marker(s).", "maps-displaymap-par-title": "Maakt het mogelijk om tekst in te stellen die wordt weergegeven in de pop-ups van alle markeringen zonder gespecificeerde naam.\nAls dit samen met een label wordt gebruikt, wordt de titel vetgedrukt en onderstreept weergegeven.", @@ -98,7 +100,6 @@ "maps-displaymap-par-wmsoverlay": "WMS-overlay gebruiken", "maps-fullscreen-button": "Volledig scherm in- of uitschakelen", "maps-fullscreen-button-tooltip": "De kaart als volledig scherm of ingesloten bekijken.", - "maps-googlemaps3-par-enable-fullscreen": "Knop voor volledig scherm inschakelen", "validation-error-invalid-location": "Parameter $1 moet een geldige locatie zijn.", "validation-error-invalid-locations": "Parameter $1 moet een of meer geldige locaties zijn.", "validation-error-invalid-width": "Parameter $1 moet een geldige breedte zijn.", @@ -134,9 +135,11 @@ "maps-par-width": "Maakt het mogelijk om de breedte van de kaart in te stellen. Standaard worden pixels als eenheid gebruikt, maar u kunt expliciet een van deze eenheden opgeven: px, ex, em, %.", "maps-par-height": "Maakt het mogelijk om de hoogte van de kaart in te stellen. Standaard worden pixels als eenheid gebruikt, maar u kunt expliciet een van deze eenheden opgeven: px, ex, em, %.", "maps-par-centre": "De locatie waar de kaart op gecentreerd moet worden", + "maps-par-enable-fullscreen": "Knop voor volledig scherm inschakelen", + "maps-par-kml": "Op de kaart te laden KML-bestanden.", + "maps-par-markercluster": "Laat het samenvoegen van meerdere markers in de buurt in één markering", "maps-googlemaps3-incompatbrowser": "Uw browser kan niet werken met Google Maps v3.", "maps-googlemaps3-par-imageoverlays": "Laat het toevoegen van een afbeelding worden weergegeven op de opgegeven locatie op de kaart.", - "maps-googlemaps3-par-markercluster": "Laat het samenvoegen van meerdere markers in de buurt in één markering", "maps-googlemaps3-par-type": "Het initieel weer te geven kaarttype.", "maps-googlemaps3-par-types": "De kaarttypen die beschikbaar zijn in via het besturingselement type.", "maps-googlemaps3-par-layers": "Op de kaart te laden speciale lagen.", @@ -144,17 +147,15 @@ "maps-googlemaps3-par-zoomstyle": "De stijl van het besturingselement zoom.", "maps-googlemaps3-par-typestyle": "De stijl van het besturingselement type.", "maps-googlemaps3-par-autoinfowindows": "Automatisch alle informatievensters openen na het laden van een pagina.", - "maps-googlemaps3-par-kml": "Op de kaart te laden KML-bestanden.", "maps-googlemaps3-par-gkml": "KML-bestanden die gehost worden door Google om op de kaart te laden.", "maps-googlemaps3-par-fusiontables": "Op de kaart te laden ID's van Google Fusion Tables.", "maps-googlemaps3-par-tilt": "Hoek voor de kaart bij gebruik van Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Het zoomniveau van de kaart opnieuw instellen als de KML-lagen geladen zijn.", "maps-googlemaps3-par-poi": "Interessante plaatsen weergeven.", + "maps-par-clustermaxzoom": "Het maximale zoomniveau waar clusters kunnen bestaan.", "maps-openlayers-par-controls": "De op de kaart te plaatsen besturingselementen.", "maps-openlayers-par-layers": "De lagen die beschikbaar zijn in het selectievak. De eerste laag worden weergegeven als de kaart wordt geladen.", "maps-openlayers-par-overlays": "Overlaylagen die beschikbaar zijn in de lagenselector. Deze lagen worden bovenop een normale laag weergegeven, ongeveer zoals een marker.", - "maps-osm-par-thumbs": "Miniaturen weergeven", - "maps-osm-par-photos": "Afbeeldingen weergeven", "mapeditor": "Kaarteditor", "specialpages-group-maps": "Kaarten", "mapeditor-parser-error": "Er is een fout opgetreden tijdens het verwerken van metagegevens. De gebruikersinvoer wordt genegeerd.", @@ -190,5 +191,27 @@ "mapeditor-imageoverlay-button": "Afbeeldingslaag toevoegen", "mapeditor-form-field-image": "Afbeelding", "mapeditor-imageoverlay-title": "Gegevens over afbeeldingslaag", - "mapeditor-form-field-visitedicon": "Pictogram voor bezocht" + "mapeditor-form-field-visitedicon": "Pictogram voor bezocht", + "semanticmaps-unrecognizeddistance": "De waarde \"$1\" is geen geldige afstand.", + "semanticmaps-kml-link": "KML-bestand bekijken", + "semanticmaps-default-kml-pagelink": "Pagina $1 bekijken", + "semanticmaps-latitude": "Breedtegraad: $1", + "semanticmaps-longitude": "Lengtegraad: $1", + "semanticmaps-altitude": "Hoogte: $1", + "semanticmaps-forminput-locations": "Locaties", + "semanticmaps-par-staticlocations": "Een lijst met aan de kaart toe te voegen locaties samen met de opgegeven gegevens. Zoals bij display_points, kunt u een naam, beschrijving en pictogram per locatie toevoegen door de tilde (\"~\") als scheidingsteken te gebruiken.", + "semanticmaps-par-showtitle": "Een naam weergeven in het gegevensvenster van de markering of niet. Dit uitschakelen is vaak handig als er een sjabloon wordt gebruikt om de inhoud van het gegevensvenster vorm te geven.", + "semanticmaps-par-hidenamespace": "De naamruimtenaam in het informatievenster van de marker weergeven", + "semanticmaps-par-centre": "Het centrum van de kaart. Als deze waarde niet wordt opgegeven, wordt automatisch een keuze gemaakt voor een centrum op basis van alle markeringen op de kaart.", + "semanticmaps-par-template": "Een te gebruiken sjabloon om de inhoud van het gegevensvenster op te maken.", + "semanticmaps-par-geocodecontrol": "Besturingselement voor geocodering weergeven.", + "semanticmaps-par-activeicon": "Pictogram dat wordt weergegeven in plaats van de standaard marker, als de actieve pagina gelijk is aan het zoekresultaat", + "semanticmaps-par-pagelabel": "Wanneer dit is ingesteld op \"yes\", krijgen alle markers een \"inlineLabel\" met een koppeling naar de pagina waarop de coördinaten voor de marker staan", + "semanticmaps-kml-text": "De tekst die gekoppeld is aan iedere pagina. Als er extra opgegeven eigenschappen zijn, wordt deze tekst daardoor overschreven.", + "semanticmaps-kml-title": "De standaard titel voor resultaten", + "semanticmaps-kml-linkabsolute": "Moeten koppelingen absoluut zijn (in tegenstelling tot relatief)", + "semanticmaps-kml-pagelinktext": "De tekst om te gebruiken voor de koppelingen naar de pagina, waarin $1 vervangen wordt door de paginanaam", + "semanticmaps-shapes-improperformat": "Onjuiste opmaak van $1. Raadpleeg de documentatie voor de juiste opmaak", + "semanticmaps-shapes-missingshape": "Geen vormen gevonden voor $1. Raadpleeg de documentatie voor beschikbare vormen", + "validator-type-mapscircle-list": "Lijst van circels" } diff --git a/i18n/pa.json b/i18n/pa.json index ffe93b2d5..cfb243c4e 100644 --- a/i18n/pa.json +++ b/i18n/pa.json @@ -44,7 +44,6 @@ "maps-par-centre": "ਉਹ ਥਾਂ ਜਿਸ ਉੱਤੇ ਨਕਸ਼ਾ ਕੇਂਦਰਤ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ", "maps-googlemaps3-incompatbrowser": "ਤੁਹਾਡਾ ਬਰਾਊਜ਼ਰ Google Maps v3 ਨਾਲ਼ ਕੰਮ ਕਰਨ ਲਈ ਅਨੁਕੂਲ ਨਹੀਂ ਹੈ।", "maps-googlemaps3-par-layers": "ਨਕਸ਼ੇ ਉੱਤੇ ਲੋਡ ਕਰਨ ਲਈ ਖ਼ਾਸ ਪਰਤਾਂ।", - "maps-osm-par-photos": "ਤਸਵੀਰਾਂ ਵਿਖਾਓ", "mapeditor": "ਨਕਸ਼ਾ ਸੰਪਾਦਕ", "specialpages-group-maps": "ਨਕਸ਼ੇ", "mapeditor-none-text": "ਕੋਈ ਨਹੀਂ", diff --git a/i18n/pl.json b/i18n/pl.json index 01fed72cb..5e24b8a69 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -7,7 +7,8 @@ "Ty221", "Yarl", "Alan ffm", - "Macofe" + "Macofe", + "Deejay1" ] }, "maps-desc": "Umożliwia zamieszczanie na stronach wiki map dynamicznych, geokodowanych adresów i innych danych geograficznych", @@ -25,15 +26,16 @@ "maps-layer-value": "Wartość", "maps-layer-errors": "Błędy", "maps-layerdef-invalid": "{{PLURAL:$1|Nieprawidłowa definicja|Nieprawidłowe definicje}}", + "maps-layerpage-nousage": "Nie ma stron, które używają w tej chwili tej warstwy.", "maps-error-invalid-layertype": "Brak warstw typu „$1”. {{PLURAL:$3|Wspierany jest wyłącznie typ|Wspierane są wyłącznie typy:}} $2", "maps-error-no-layertype": "Musisz określić typ warstwy. {{PLURAL:$2|Wspierany jest wyłącznie typ|Wspierane są wyłącznie typy:}} $1", "validation-error-invalid-layer": "Parametr $1 musi określać prawidłową warstwę.", "validation-error-invalid-layers": "Parametr $1 musi wskazywać jedną lub więcej prawidłowych warstw.", "maps-layer-of-type": "Warstwa typu $1", + "maps-layer-of-type-and-name": "Warstwa „$2” typu „$1”", "maps-layer-type-supported-by": "Tego typu warstwa może być używana wyłącznie z {{PLURAL:$2|serwisem map|serwisami map:}} $1.", "maps-coordinates-description": "Przechwycenie analizatora do formatowania współrzędnych z i na dowolny z obsługiwanych formatów.", "maps-displaymap-description": "Wyświetlanie map geograficznych bez żadnych naniesionych na nich znaczników na wiki.", - "maps-displaypoint-description": "Wyświetlanie map geograficznych z naniesionym jednym lub więcej określonych na wiki znaczników.", "maps-distance-description": "Konwertuj odległości za pomocą pewnych obsługiwanych jednostek do ich odpowiedników w innych jednostkach.", "maps-finddestination-description": "Znajdź drogę do celu z podanego punktu początkowego, (który może być w dowolnym z obsługiwanych formatów), początkowy namiar i odległości.", "maps-geocode-description": "Umożliwia geokodowanie adresów, innymi słowy, przekształcenie zapisu miejsca czytelnego dla ludzi w zbiory współrzędnych. Obsługiwane jest kilka usług geokodowania, których nie należy mylić z usługami dostarczania map.", @@ -79,8 +81,12 @@ "maps_unrecognized_coords_for": "{{PLURAL:$2|Następującą współrzędną|Następujące współrzędne}} pominięto, ponieważ nie {{PLURAL:$2|została rozpoznana|zostały rozpoznane}}:\n$1", "maps_map_cannot_be_displayed": "Mapa nie może zostać wyświetlona.", "maps-geocoder-not-available": "Funkcja geokodowania map nie jest dostępna. Lokalizacja nie może zostać zakodowana.", + "maps-leaflet-par-layer": "Warstwa, która będzie wyświetlana podczas ładowania mapy.", + "maps-leaflet-par-overlaylayers": "Nakładane warstwy, które będą wyświetlane podczas ładowania mapy.", "maps_click_to_activate": "Kliknij, aby aktywować mapę", "maps_centred_on": "Środek mapy – $1, $2.", + "maps-par-enable-fullscreen": "Włącz przycisk trybu pełnoekranowego", + "maps-par-kml": "Pliki KML do załadowania na mapie.", "maps-googlemaps3-incompatbrowser": "Twoja przeglądarka nie jest zgodna z Google Maps v3.", "maps-googlemaps3-par-type": "Typ mapy do wyświetlenia na początku.", "maps-googlemaps3-par-types": "Typy map, które będą dostępne za pośrednictwem formantu typu.", @@ -89,22 +95,47 @@ "maps-googlemaps3-par-zoomstyle": "Styl formantu powiększenia.", "maps-googlemaps3-par-typestyle": "Styl formantu typu.", "maps-googlemaps3-par-autoinfowindows": "Automatycznie otwórz wszystkie okna informacyjne po załadowaniu strony.", - "maps-googlemaps3-par-kml": "Pliki KML do załadowania na mapie.", "maps-googlemaps3-par-gkml": "Pliki KML udostępniane przez serwery Google do załadowania na mapie.", + "maps-googlemaps3-par-poi": "Pokaż atrakcje.", + "maps-googlemaps3-par-clustergridsize": "Rozmiar siatki klastra w pikselach.", + "maps-par-clustermaxzoom": "Maksymalny poziom powiększenia, w którym klaster może istnieć.", "maps-openlayers-par-controls": "Formanty do umieszczenia na mapie.", - "maps-osm-par-thumbs": "Pokaż miniatury", - "maps-osm-par-photos": "Pokaż zdjęcia", "mapeditor": "Edytor map", "specialpages-group-maps": "Mapy", + "mapeditor-none-text": "Brak", "mapeditor-done-button": "Gotowe", "mapeditor-remove-button": "Usuń", + "mapeditor-import-button2": "Importuj", + "mapeditor-export-button": "Eksport do kodu wiki", + "mapeditor-import-button": "Import z kodu wiki", + "mapeditor-mapparam-button": "Edytuj parametry mapy", "mapeditor-clear-button": "Wyczyść mapę", "mapeditor-code-title": "Kod wiki", + "mapeditor-import-title": "Import kodu wiki", + "mapeditor-form-title": "Edytuj szczegóły", + "mapeditor-link-title-switcher-link-text": "Link", "mapeditor-form-field-title": "Tytuł", "mapeditor-form-field-text": "Tekst", + "mapeditor-form-field-link": "Link", "mapeditor-form-field-icon": "Ikona", "mapeditor-form-field-group": "Grupa", + "mapeditor-form-field-fillcolor": "Kolor wypełnienia", "mapeditor-form-field-showonhover": "Pokaż tylko po najechaniu", + "mapeditor-mapparam-title": "Edytuj ustawienia mapy", "mapeditor-mapparam-defoption": "-Wybierz parametr-", - "mapeditor-form-field-image": "Grafika" + "mapeditor-form-field-image": "Grafika", + "semanticmaps-unrecognizeddistance": "Wartość $1 nie jest poprawną odległością.", + "semanticmaps-kml-link": "Wyświetla plik KML", + "semanticmaps-default-kml-pagelink": "Pokaż stronę $1", + "semanticmaps-latitude": "Szerokość geograficzna: $1", + "semanticmaps-longitude": "Długość geograficzna: $1", + "semanticmaps-altitude": "Wysokość: $1", + "semanticmaps-forminput-locations": "Miejsca", + "semanticmaps-par-ajaxcoordproperty": "Nazwa właściwości współrzędnych, która jest używana do tworzenia zapytania AJAX.", + "semanticmaps-kml-title": "Domyślny tytuł wyników", + "validator-type-mapsline": "Linia geograficzna", + "validator-type-mapsline-list": "Lista linii", + "validator-type-mapslocation": "Położenie geograficzne", + "validator-type-mapsrectangle": "Prostokąt geograficzny", + "validator-type-mapsrectangle-list": "Lista prostokątów" } diff --git a/i18n/pms.json b/i18n/pms.json index 6b1bae63b..e1657e691 100644 --- a/i18n/pms.json +++ b/i18n/pms.json @@ -30,7 +30,6 @@ "maps-layer-type-supported-by": "Costa sòrt ëd livel a peul {{PLURAL:$2|mach esse dovrà con ël servissi ëd cartografìa $1|esse dovrà con sti servissi ëd cartografìa: $1}}.", "maps-coordinates-description": "Gancio ëd l'analisator për formaté le coordinà, da e vers qualsëssìa dij formà mantnù.", "maps-displaymap-description": "Visualisé le carte geogràfiche sensa gnun marcador definì ëd wiki ansima a lor.", - "maps-displaypoint-description": "Visualisé le carte geogràfiche con un o pi marcador definì ëd wiki ansima.", "maps-distance-description": "Convertì na distansa dovrand na serta unità mantnùa an sò equivalent dovrand n'àutra unità.", "maps-finddestination-description": "Trové na destinassion dàit un pont ëd partensa (che a peul esse an qualsëssìa dij formà mantnù), n'orientassion inissial e na distansa.", "maps-geocode-description": "A abìlita la geocodìfica d'adrësse, an d'àutre paròle, la trasformassion dle posission lesìbij da n'uman an ansema ëd coordinà. Vàire sërvissi ëd geocodìfica a son mantnù, lòn che a dev nen esse confondù con ij sërvissi ëd cartografìa.", @@ -114,6 +113,7 @@ "maps-par-width": "A përmët d'amposté la larghëssa dla carta. Për predefinission ij pontin a saran contà com unità, ma a peul specifiché ëd fasson esplìssita un-a ëd coste unità: px, ex, em, %.", "maps-par-height": "A përmët d'amposté l'autëssa dla carta. Për predefinission ij pontin a saran considerà com unità, ma a peul ëspessifiché ëd fasson esplìssita un-a ëd coste unità: px, ex, em, %.", "maps-par-centre": "Ël pòst anté che la carta a dovrà esse sentrà", + "maps-par-kml": "Archivi KML da carié dzora a la carta.", "maps-googlemaps3-incompatbrowser": "Tò navigator a l'é pa compatìbil con Google Maps v3.", "maps-googlemaps3-par-type": "La sòrt ëd carta da smon-e inissialment.", "maps-googlemaps3-par-types": "La sòrt ëd carta che a sarà disponìbil travers al contròl ëd sòrt.", @@ -122,7 +122,6 @@ "maps-googlemaps3-par-zoomstyle": "Lë stil dël contròl d'angrandiment.", "maps-googlemaps3-par-typestyle": "Lë stil dël contròl ëd sòrt.", "maps-googlemaps3-par-autoinfowindows": "Duverté automaticament tute le fnestre d'anformassion apress che la pàgina a l'é cariasse.", - "maps-googlemaps3-par-kml": "Archivi KML da carié dzora a la carta.", "maps-googlemaps3-par-gkml": "Archivi KML ospità da Google da carié dzor la carta.", "maps-googlemaps3-par-fusiontables": "ID ëd le tàule ëd Google Fusion ch'a dovrìa esse carià dzora a la carta.", "maps-googlemaps3-par-tilt": "Anclinassion për la Carta quand as deuvra Google Maps.", @@ -130,8 +129,6 @@ "maps-googlemaps3-par-poi": "Smon-e ij pont d'anteresse.", "maps-openlayers-par-controls": "Ël control da piassé an sla carta.", "maps-openlayers-par-layers": "Ij seuj che a saran disponìbij ant ël seletor ëd seul. Ël prim seul a sarà mostrà quand la carta as caria.", - "maps-osm-par-thumbs": "Smon-e dle miniadure", - "maps-osm-par-photos": "Smon-e dle fòto", "mapeditor": "Editor ëd carta", "specialpages-group-maps": "Carte", "mapeditor-parser-error": "A l'é capitaje n'eror an analisand dij metadat. Ignorà l'anseriment ëd l'utent.", @@ -167,5 +164,24 @@ "mapeditor-imageoverlay-button": "Gionté la dzorposission ëd plancia", "mapeditor-form-field-image": "Figura", "mapeditor-imageoverlay-title": "Detaj dla dzorposission ëd plancia", - "mapeditor-form-field-visitedicon": "Plancia visità" + "mapeditor-form-field-visitedicon": "Plancia visità", + "semanticmaps-unrecognizeddistance": "Ël valor $1 a l'é pa na distansa bon-a.", + "semanticmaps-kml-link": "Vëdde l'archivi KML", + "semanticmaps-default-kml-pagelink": "Lese la pàgina $1", + "semanticmaps-latitude": "Latitùdin: $1", + "semanticmaps-longitude": "Longitùdin: $1", + "semanticmaps-altitude": "Autitùdin: $1", + "semanticmaps-forminput-locations": "Locassion", + "semanticmaps-par-staticlocations": "Na lista ëd locassion da gionté a la carta ansema ai dat ciamà. Com con dispay_points, a peul gionté un tìtol, na descrission e na plancia për locassion an dovrand la tilde \"~\" com separator.", + "semanticmaps-par-showtitle": "Smon-e un tìtol ant la fnesta d'anformassion dël marcator opura nò. La disabilitassion ëd sòn a l'é soens ùtil quand as deuvra në stamp për formaté ël contnù dla fnesta d'anformassion.", + "semanticmaps-par-hidenamespace": "Mostré ël tìtol dlë spassi nominal ant la fnestra d'anformassion dël marcador.", + "semanticmaps-par-centre": "Ël sènter ëd la carta. Quand a l'é pa dàit, la carta a trovrà automaticament ël sènter otimal për smon-e tùit ij marcador an sla carta.", + "semanticmaps-par-template": "Në stamp da dovré deje a forma ai contnù dla fnesta d'anformassion.", + "semanticmaps-par-geocodecontrol": "Smon-e ël contròl ëd geocodìfica.", + "semanticmaps-kml-text": "Ël test associà con minca pagina. Coatà da le propietà adissionaj ciamà s'a-i në j'é.", + "semanticmaps-kml-title": "Ël tìtol predefinì për j'arzultà", + "semanticmaps-kml-linkabsolute": "Si le liure a devo esse assolùe o nò (visadì relativ)", + "semanticmaps-kml-pagelinktext": "Ël test da dovré për le liure a la pàgina, dont $1 a sarà rimpiassà da 'l tìtol ëd la pàgina", + "semanticmaps-shapes-improperformat": "Formatà ëd $1 nen bon. Për piasì, ch'a fasa arferiment a la documentassion për ël formà vorsù", + "semanticmaps-shapes-missingshape": "Gnun-e forme trovà për $1. Për piasì, ch'a varda la documentassion për le forme disponìbij" } diff --git a/i18n/pt-br.json b/i18n/pt-br.json index 9be517b82..e06796dc0 100644 --- a/i18n/pt-br.json +++ b/i18n/pt-br.json @@ -7,13 +7,17 @@ "Luckas", "Luckas Blade", "555", - "Macofe" + "Macofe", + "Jaideraf", + "Eduardo Addad de Oliveira", + "Felipe L. Ewald" ] }, "maps-desc": "Permite a incorporação de mapas dinâmicos em páginas wiki, geocodificação de endereços e outras operações geográficas", "maps_map": "Mapa", "maps-loading-map": "Carregando mapa...", "maps-markers": "Marcadores", + "maps-copycoords-prompt": "CTRL+C, ENTER", "maps-others": "outros", "maps-ns-layer": "Camada", "maps-ns-layer-talk": "Camada Discussão", @@ -26,6 +30,14 @@ "validation-error-invalid-layers": "O parâmetro $1 precisa ser uma ou mais camada(s) válida(s).", "maps-layer-of-type": "Camada de tipo $1", "maps-layer-type-supported-by": "Este tipo de camada só pode ser usado com {{PLURAL:$2|o serviço de cartografia $1|os serviços de cartografia: $1}}.", + "maps-finddestination-par-location": "A localização inicial.", + "maps-finddestination-par-bearing": "A direção inicial.", + "maps-finddestination-par-distance": "A distância para percorrer.", + "maps-geodistance-par-unit": "A unidade na qual a distância será retornada.", + "maps-geodistance-par-decimals": "O número máximo de casas decimais para usar no resultado.", + "maps-displaymap-par-lines": "Linhas para mostrar", + "maps-displaymap-par-maxzoom": "O nível máximo de zoom", + "maps-displaymap-par-minzoom": "O nível mínimo de zoom", "validation-error-invalid-location": "O parâmetro $1 precisa ser uma localização válida.", "validation-error-invalid-locations": "O parâmetro $1 precisa ser uma ou mais localização(ões) válida(s).", "validation-error-invalid-width": "O parâmetro $1 precisa ser uma largura válida.", @@ -52,14 +64,15 @@ "maps-geocoder-not-available": "A funcionalidade de georeferenciação do Mapas está indisponível; a sua localização não pode ser georeferenciada.", "maps_click_to_activate": "Clique para ativar o mapa", "maps_centred_on": "Mapa centrado nas coordenadas $1, $2.", - "maps-osm-par-thumbs": "Mostrar miniaturas", - "maps-osm-par-photos": "Mostrar fotos", "mapeditor": "Editor de mapas", "specialpages-group-maps": "Mapas", "mapeditor-none-text": "Nenhum", "mapeditor-done-button": "Feito", "mapeditor-remove-button": "Remover", "mapeditor-import-button2": "Importar", + "mapeditor-export-button": "Exportar para código wiki", + "mapeditor-import-button": "Importar de código wiki", + "mapeditor-select-button": "Seleciona este polígono", "mapeditor-mapparam-button": "Editar parâmetros do mapa", "mapeditor-clear-button": "Limpar mapa", "mapeditor-code-title": "Código wiki", @@ -74,5 +87,31 @@ "mapeditor-mapparam-title": "Editar parâmetros do mapa", "mapeditor-mapparam-defoption": "-Selecionar parâmetro-", "mapeditor-form-field-image": "Imagem", - "mapeditor-form-field-visitedicon": "Ícone visitado" + "mapeditor-form-field-visitedicon": "Ícone visitado", + "semanticmaps-unrecognizeddistance": "O valor $1 não é uma distância válida.", + "semanticmaps-kml-link": "Ver o arquivo KML", + "semanticmaps-default-kml-pagelink": "Ver a página $1", + "semanticmaps-latitude": "Latitude: $1", + "semanticmaps-longitude": "Longitude: $1", + "semanticmaps-altitude": "Altitude: $1", + "semanticmaps-forminput-locations": "Locais", + "semanticmaps-par-staticlocations": "Uma lista de localizações para adicionar ao mapa junto aos dados consultados. Assim como nos pontos a serem exibidos (\"display_points\"), você pode adicionar um título, descrição e ícone por localização, usando o til (\"~\") como separador.", + "semanticmaps-par-showtitle": "Mostrar, ou não, um título na janela informativa do marcador. É frequentemente desejável desativar este recurso quando estiver usando uma predefinição para formatar o conteúdo da janela informativa.", + "semanticmaps-par-hidenamespace": "Mostrar o título do domínio na janela de informações do marcador", + "semanticmaps-par-centre": "O centro do mapa. Quando este não for definido, o mapa escolherá automaticamente o centro ideal para apresentar todos os marcadores do mapa.", + "semanticmaps-par-template": "Uma predefinição que será usada para formatar o conteúdo da janela informativa.", + "semanticmaps-par-geocodecontrol": "Exibir o controle de geocodificação.", + "semanticmaps-par-activeicon": "Ícone a ser exibido ao invés do marcador padrão, quando a página ativa é igual ao resultado da consulta", + "semanticmaps-par-pagelabel": "Quando configurado para \"yes\", todos os marcadores terão um \"inlineLabel\" com um link para a página que contém as coordenadas para o marcador", + "semanticmaps-kml-text": "O texto associado a cada página. Será substituído quando propriedades adicionais consultadas existirem.", + "semanticmaps-kml-title": "O título padrão para os resultados", + "semanticmaps-kml-linkabsolute": "Os links deverão ser absolutos (ao contrário de relativos)", + "semanticmaps-kml-pagelinktext": "O texto a ser usado nos links para a página, onde $1 será substituído pelo título da página", + "semanticmaps-shapes-improperformat": "Formatação imprópria em $1. Por favor, veja a documentação para formatação", + "semanticmaps-shapes-missingshape": "Nenhuma forma foi encontrada para $1. Por favor, veja a documentação para formas disponíveis", + "validator-type-mapscircle-list": "Lista de círculos", + "validator-type-mapslocation-list": "Lista de locais", + "validator-type-mapsrectangle-list": "Lista de retângulos", + "validator-type-mapspolygon": "Polígono geográfico", + "validator-type-mapspolygon-list": "Lista de polígonos geográficos" } diff --git a/i18n/pt.json b/i18n/pt.json index e4410b08c..04553d069 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -9,7 +9,9 @@ "Luckas", "Waldir", "Vitorvicentevalente", - "Macofe" + "Macofe", + "Malafaya", + "Fúlvio" ] }, "maps-desc": "Permite incorporar mapas dinâmicos nas páginas da wiki, converter endereços em geocódigos e outras operações geográficas", @@ -32,12 +34,11 @@ "maps-layer-type-supported-by": "Este tipo de camada só pode ser usado com {{PLURAL:$2|o serviço de cartografia $1|os serviços de cartografia: $1}}.", "maps-coordinates-description": "Hook do analisador sintáctico para formatar coordenadas, a partir de qualquer um dos formatos suportados para qualquer outro formato suportado.", "maps-displaymap-description": "Apresentar os mapas sem qualquer marcador definido na wiki.", - "maps-displaypoint-description": "Apresentar os mapas com um ou mais marcadores definidos na wiki.", "maps-distance-description": "Converter uma distância numa unidade suportada para a distância equivalente noutra unidade.", "maps-finddestination-description": "Encontrar um destino a partir de um ponto de partida (expresso em qualquer um dos formatos suportados), uma orientação inicial e uma distância.", "maps-geocode-description": "Permite a geocodificação de moradas; por outras palavras, transforma locais legíveis por seres humanos em conjuntos de coordenadas. Há apoio para vários serviços de geocodificação, que não devem ser confundidos com serviços de cartografia.", "maps-geodistance-description": "Calcula a distância geográfica entre dois pontos, a partir e para qualquer um dos formatos suportados.", - "maps-mapsdoc-description": "Apresentar uma tabela com os parâmetros de um serviço de cartografia especificado, em conjunto com os respectivos valores por omissão e descrições.", + "maps-mapsdoc-description": "Apresentar uma tabela com os parâmetros de um serviço de cartografia especificado, em conjunto com os respetivos valores por omissão e descrições.", "maps-mapsdoc-par-service": "O serviço de cartografia para o qual será apresentada a documentação dos parâmetros.", "maps-mapsdoc-par-language": "A língua de apresentação da documentação. Se essa tradução não estiver disponível, será usado o inglês.", "maps-coordinates-par-location": "As coordenadas que quer formatar.", @@ -65,7 +66,7 @@ "maps-geodistance-par-unit": "As unidades em que a distância será produzida.", "maps-geodistance-par-decimals": "O número máximo de casas decimais a usar no valor resultante.", "maps-geodistance-par-mappingservice": "O serviço de geocodificação que será usado para geocodificar qualquer endereço.", - "maps-geodistance-par-geoservice": "O serviço de cartografia a utilizar em conjunto.\nIsto pode afetar o valor padrão do serviço de geocodificação.", + "maps-geodistance-par-geoservice": "O serviço de cartografia que é utilizado em conjunto com esta função.\nIsto pode afetar o valor padrão do serviço de geocodificação.", "maps-displaymap-par-mappingservice": "Permite definir o serviço de cartografia que será usado para gerar o mapa.", "maps-displaymap-par-coordinates": "A localização na qual o mapa será inicialmente centrado.", "maps-displaymap-par-zoom": "Permite definir o nível de aproximação do mapa.\nQuando este não for fornecido e existirem vários marcadores no mapa, será usada a aproximação que resulte no melhor dimensionamento, não o valor padrão configurado.", @@ -99,13 +100,15 @@ "maps_unrecognized_coords_for": "{{PLURAL:$2|A seguinte coordenada não foi reconhecida e foi omitida|As seguintes coordenadas não foram reconhecidas e foram omitidas}} do mapa:\n$1", "maps_map_cannot_be_displayed": "Não é possível apresentar o mapa.", "maps-geocoder-not-available": "A funcionalidade de georeferenciação do Mapas está indisponível; a sua localização não pode ser georeferenciada.", + "maps-leaflet-par-layer": "A camada que será mostrada quando o mapa é carregado.", "maps_click_to_activate": "Clique para ativar o mapa", "maps_centred_on": "Mapa centrado nas coordenadas $1, $2.", "maps-par-resizable": "Permite alterar as dimensões do mapa, arrastando o canto inferior direito.", "maps-par-geoservice": "O serviço de geocodificação que será usado para fazer a conversão entre endereços e coordenadas.", "maps-par-zoom": "O nível de aproximação do mapa. Nos mapas com marcadores será usada a maior aproximação que, mesmo assim, mostre todos os marcadores.", - "maps-par-width": "Permite definir a largura do mapa. A unidade por omissão é o pixel, mas pode defini-la explicitamente como: px, ex, em, %.", - "maps-par-height": "Permite definir a altura do mapa. A unidade por omissão é o pixel, mas pode defini-la explicitamente como: px, ex, em, %.", + "maps-par-width": "Permite definir a largura do mapa. A unidade por omissão é o píxel, mas pode defini-la explicitamente como: px, ex, em, %.", + "maps-par-height": "Permite definir a altura do mapa. A unidade por omissão é o píxel, mas pode defini-la explicitamente como: px, ex, em, %.", + "maps-par-kml": "Ficheiros KML que serão carregados no mapa.", "maps-googlemaps3-incompatbrowser": "O seu browser não é compatível com o Google Maps v3.", "maps-googlemaps3-par-type": "O tipo de mapa que será apresentado inicialmente.", "maps-googlemaps3-par-types": "Os tipos de mapas que estarão disponíveis através do controlo de tipos.", @@ -114,14 +117,11 @@ "maps-googlemaps3-par-zoomstyle": "O estilo do controlo da aproximação.", "maps-googlemaps3-par-typestyle": "O estilo do controlo de tipos.", "maps-googlemaps3-par-autoinfowindows": "Abrir automaticamente todas as janelas informativas depois de carregar a página.", - "maps-googlemaps3-par-kml": "Ficheiros KML que serão carregados no mapa.", "maps-googlemaps3-par-gkml": "Ficheiros KML alojados pelo Google que serão carregados no mapa.", "maps-googlemaps3-par-fusiontables": "Identificação das Google Fusion Tables que deverão ser carregadas no mapa.", "maps-googlemaps3-par-poi": "Mostrar pontos de interesse.", "maps-openlayers-par-controls": "Os controlos que serão colocados no mapa.", "maps-openlayers-par-layers": "As camadas que estarão disponíveis no selector de camadas. A primeira camada será apresentada quando o mapa for carregado.", - "maps-osm-par-thumbs": "Mostrar miniaturas", - "maps-osm-par-photos": "Mostrar fotografias", "mapeditor": "Editor de mapa", "specialpages-group-maps": "Mapas", "mapeditor-parser-error": "Ocorreu um erro durante a análise de metadados. A entrada de utilizador será ignorada.", @@ -133,14 +133,45 @@ "mapeditor-import-button": "Importar a partir de código wiki", "mapeditor-code-title": "Código wiki", "mapeditor-import-title": "Importar código wiki", + "mapeditor-import-note": "Por favor, note que o analizador espera um formato muito rigoroso no código wiki. O código inserido aqui deve corresponder ao código gerado pela funcionalidade de exportação.", "mapeditor-form-title": "Editar detalhes", + "mapeditor-link-title-switcher-popup-text": "Popup com texto", "mapeditor-link-title-switcher-link-text": "Ligação", "mapeditor-form-field-title": "Título", "mapeditor-form-field-text": "Texto", "mapeditor-form-field-link": "Ligação", "mapeditor-form-field-icon": "Ícone", "mapeditor-form-field-group": "Grupo", + "mapeditor-form-field-inlinelabel": "Etiqueta em linha", + "mapeditor-form-field-strokecolor": "Cor da linha", + "mapeditor-form-field-strokeopacity": "Opacidade da linha", + "mapeditor-form-field-strokeweight": "Espessura da linha", + "mapeditor-form-field-fillcolor": "Cor de preenchimento", + "mapeditor-form-field-fillopcaity": "Opacidade do preenchimento", "mapeditor-mapparam-title": "Editar parâmetros do mapa", "mapeditor-mapparam-defoption": "-Selecione o parâmetro-", - "mapeditor-form-field-image": "Imagem" + "mapeditor-imageoverlay-button": "Adicionar sobreposição de imagem", + "mapeditor-form-field-image": "Imagem", + "mapeditor-imageoverlay-title": "Detalhes da sobreposição de imagem", + "semanticmaps-unrecognizeddistance": "O valor $1 não é uma distância válida.", + "semanticmaps-kml-link": "Ver o ficheiro KML", + "semanticmaps-default-kml-pagelink": "Ver a página $1", + "semanticmaps-latitude": "Latitude: $1", + "semanticmaps-longitude": "Longitude: $1", + "semanticmaps-altitude": "Altitude: $1", + "semanticmaps-forminput-locations": "Locais", + "semanticmaps-par-staticlocations": "Uma lista de localizações para acrescentar ao mapa em conjunto com os dados consultados. Tal como nos pontos a apresentar (\"display_points\"), pode adicionar um título, descrição e ícone por localização, usando o til \"~\" como separador.", + "semanticmaps-par-showtitle": "Mostrar, ou não, um título na janela informativa do marcador. É frequentemente desejável desativar esta funcionalidade quando usar uma predefinição para formatar o conteúdo da janela informativa.", + "semanticmaps-par-centre": "O centro do mapa. Quando este não for fornecido, o mapa escolherá automaticamente o centro óptimo para apresentar todos os marcadores do mapa.", + "semanticmaps-par-template": "Uma predefinição que será usada para formatar o conteúdo da janela informativa.", + "validator-type-mapscircle": "Círculo geográfico", + "validator-type-mapscircle-list": "Lista de círculos", + "validator-type-mapsimageoverlay": "Sobreposição de imagem", + "validator-type-mapsimageoverlay-list": "Lista de sobreposições de imagem", + "validator-type-mapsline": "Linha geográfica", + "validator-type-mapsline-list": "Lista de linhas", + "validator-type-mapslocation": "Localização geográfica", + "validator-type-mapslocation-list": "Lista de locais", + "validator-type-mapsrectangle": "Retângulo geográfico", + "validator-type-mapsrectangle-list": "Lista de retângulos" } diff --git a/i18n/qqq.json b/i18n/qqq.json index 840a099f2..7b57071d6 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -11,72 +11,145 @@ "Umherirrender", "Тест", "아라", - "Liuxinyu970226" + "Liuxinyu970226", + "Nike", + "Lloffiwr" ] }, - "maps-desc": "{{desc|name=Maps|url=https://www.mediawiki.org/wiki/Extension:Maps}}", + "maps-desc": "{{desc|name=Maps|url=https://www.semantic-mediawiki.org/wiki/Extension:Maps}}", "right-geocode": "{{doc-right|geocode}}", "action-geocode": "{{doc-action|geocode}}", "maps_map": "{{Identical|Map}}", - "maps-tracking-category": "The name of a category for all pages which use the display_map parser extension function or tag.\n\nThe category is automatically added unless the feature is disabled.", + "maps-tracking-category": "The name of a category for all pages which use the #display_map parser function or display_map tag.", + "maps-loading-map": "This is an informatory message.", + "maps-load-failed": "This is an error message.", "maps-markers": "{{Identical|Marker}}", - "maps-copycoords-prompt": "text displayed in JavaScript prompt to indicate first press ctrl+c to copy text, and press enter to close prompt", + "maps-copycoords-prompt": "This is the text displayed in JavaScript prompt to indicate first press ctrl+c to copy text, and press enter to close prompt.", "maps-searchmarkers-text": "{{doc-important|Translate \"Filter\" as being a word.}}\nThis message is located within an input box to assist users with the input. This fuctionality allows to filter the markers based on the input one provides. See the [https://semantic-mediawiki.org/wiki/Maps_examples/OpenLayers_searchmarkers live example].", "maps-others": "{{Identical|Other}}", - "maps-kml-parsing-failed": "text displayed in the event of parsing failure of kml file(s).", - "maps-ns-layer": "{{Identical|Layer}}", + "maps-kml-parsing-failed": "This is an error message.", + "maps-ns-layer": "This is the name of the \"Layer\" namespace. The term \"Layer\" should be identical to the one used for the corresponding namespace. See {{msg-mw|Maps-ns-layer-talk}}\n\n{{Identical|Layer}}", + "maps-ns-layer-talk": "This is the name of the talk page for the \"Layer\" namespace. The term \"Layer\" should be identical to the one used for the corresponding namespace. See {{msg-mw|Maps-ns-layer}}\n\n{{Identical|Layer}}", "maps-layer-property": "{{Identical|Property}}", "maps-layer-value": "{{Identical|Value}}", "maps-layer-errors": "{{Identical|Error}}", - "maps-layerdef-invalid": "Parameters:\n* $1 - number of definitions", - "maps-layerdef-wrong-namespace": "Parameters:\n* $1 - namespace name", - "maps-layerdef-equal-layer-name": "Parameters:\n* $1 - layer name", - "maps-layerpage-usage": "Parameters:\n* $1 - layer name", - "maps-error-invalid-layertype": "Used as error message. Parameters:\n* $1 - a layer type\n* $2 - list of available layer types\n* $3 - number of available layer types", - "maps-error-no-layertype": "Used as error message. Parameters:\n* $1 - list of available layer types\n* $2 - number of available layer types", - "validation-error-invalid-layer": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-layers": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-no-non-numeric": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-no-non-numerics": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "maps-layer-of-type": "Used as

heading. Parameters:\n* $1 - layer type", - "maps-layer-of-type-and-name": "Parameters:\n* $1 - layer type\n* $2 - layer name", - "maps-layer-type-supported-by": "Parameters:\n* $1 - list of supported services (geonames and/or google). not localized.\n* $2 - number of supported services", + "maps-layerdef-invalid": "This is an error message.\n\nParameter:\n* $1 - number of definitions", + "maps-layerdef-invalid-fatal": "This is an error message.", + "maps-layerdef-wrong-namespace": "This is an error message.\n\nParameter:\n* $1 - namespace name", + "maps-layerdef-equal-layer-name": "This is an error message.\n\nParameter:\n* $1 - layer name", + "maps-layerpage-usage": "This is an informatory message.\n\nParameter:\n* $1 - layer name", + "maps-layerpage-nousage": "This is an informatory message.", + "maps-error-invalid-layertype": "This is an error message.\n\nParameters:\n* $1 - a layer type\n* $2 - list of available layer types\n* $3 - number of available layer types", + "maps-error-no-layertype": "This is an error message.\n\nParameters:\n* $1 - list of available layer types\n* $2 - number of available layer types", + "validation-error-invalid-layer": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-layers": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-no-non-numeric": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-no-non-numerics": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "maps-layer-of-type": "This is used as an

heading.\n\nParameter:\n* $1 - layer type", + "maps-layer-of-type-and-name": "This is used as an

heading.\n\nParameters:\n* $1 - layer type\n* $2 - layer name", + "maps-layer-type-supported-by": "This is an informatory and/or error message.\n\nParameters:\n* $1 - list of supported services (geonames and/or google).\n* $2 - number of supported services\n\n{{doc-important|Do not localise the supported services shown in parameter $1!}}", + "maps-coordinates-description": "This message describes the #coordinates parser function as well as the coordinates tag.", + "maps-displaymap-description": "This message describes the #display_map parser function as well as the display_map tag.", + "maps-distance-description": "This message describes the #distance parser function as well as the distance tag.", + "maps-finddestination-description": "This message describes the #finddestination parser function as well as the finddestination tag.", + "maps-geocode-description": "This message describes the #geocode parser function as well as the geocode tag.", + "maps-geodistance-description": "This message describes the #geodistance parser function as well as the geodistance tag.", + "maps-mapsdoc-description": "This message describes the #mapsdoc parser function as well as the mapsdoc tag.", + "maps-layerdefinition-description": "This message describes the #layerdifinition parser function as well as the layerdefinition tag.", + "maps-mapsdoc-par-service": "{{maps-par|mapsdoc|service}}", + "maps-mapsdoc-par-language": "{{maps-par|mapsdoc|language}}", + "maps-coordinates-par-location": "{{maps-par|coordinates|location}}", + "maps-coordinates-par-format": "{{maps-par|coordinates|format}}", + "maps-coordinates-par-directional": "{{maps-par|coordinates|directional}}", + "maps-distance-par-distance": "{{maps-par|distance|distance}}", + "maps-distance-par-decimals": "{{maps-par|distance|decimals}}", + "maps-distance-par-unit": "{{maps-par|distance|unit}}", + "maps-finddestination-par-location": "{{maps-par|finddestination|location}}", + "maps-finddestination-par-bearing": "{{maps-par|finddestination|bearing}}", + "maps-finddestination-par-distance": "{{maps-par|finddestination|distance}}", + "maps-finddestination-par-format": "{{maps-par|finddestination|format}}", + "maps-finddestination-par-directional": "{{maps-par|finddestination|directional}}", + "maps-finddestination-par-allowcoordinates": "{{maps-par|finddestination|allowcoordinates}}", + "maps-finddestination-par-geoservice": "{{maps-par|finddestination|geoservice}}", + "maps-finddestination-par-mappingservice": "{{maps-par|finddestination|mappingservice}}", + "maps-geocode-par-location": "{{maps-par|geocode|location}}", + "maps-geocode-par-mappingservice": "{{maps-par|geocode|mappingservice}}", + "maps-geocode-par-geoservice": "{{maps-par|geocode|geoservice}}", "maps-geocode-par-allowcoordinates": "{{maps-par|geocode|allowcoordinates}}\n\n{{doc-important|Do not translate the parameter values \"yes\" and \"no\".}}", + "maps-geocode-par-format": "{{maps-par|geocode|format}}", + "maps-geocode-par-directional": "{{maps-par|geocode|directional}}", + "maps-geodistance-par-location1": "{{Maps-par|geodistance|location1}}", + "maps-geodistance-par-location2": "{{Maps-par|geodistance|location2}}", + "maps-geodistance-par-unit": "{{Maps-par|geodistance|unit}}", + "maps-geodistance-par-decimals": "{{Maps-par|geodistance|decimals}}", + "maps-geodistance-par-mappingservice": "{{Maps-par|geodistance|mappingservice}}", "maps-geodistance-par-geoservice": "{{Maps-par|geodistance|geoservice}}", + "maps-displaymap-par-mappingservice": "{{Maps-par|displaymap|mappingservice}}", + "maps-displaymap-par-coordinates": "{{Maps-par|displaymap|coordinates}}", "maps-displaymap-par-visitedicon": "{{Maps-par|displaymap|visitedicon}}", - "maps-displaymap-par-copycoords": "{{doc-paramdesc|copycoords}}", - "maps-fullscreen-button": "Text displayed in the map as a button to toggle fullscreen view.\n\nTooltip for this button is {{msg-mw|Maps-fullscreen-button-tooltip}}.", - "maps-fullscreen-button-tooltip": "Text displayed when hovering over the button which is labeled {{msg-mw|Maps-fullscreen-button}}.", - "maps-googlemaps3-par-enable-fullscreen": "{{maps-par|googlemaps3|enablefullscreen}}", - "validation-error-invalid-location": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-locations": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-width": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-height": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-distance": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-distances": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-image": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-images": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-goverlay": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", - "validation-error-invalid-goverlays": "Parameters:\n* $1 - parameter name\n{{Related|Maps-validation}}", + "maps-displaymap-par-zoom": "{{Maps-par|displaymap|zoom}}", + "maps-displaymap-par-centre": "{{Maps-par|displaymap|centre}}", + "maps-displaymap-par-title": "{{Maps-par|displaymap|title}}", + "maps-displaymap-par-label": "{{Maps-par|displaymap|label}}", + "maps-displaymap-par-icon": "{{Maps-par|displaymap|icon}}", + "maps-displaymap-par-circles": "{{Maps-par|displaymap|circles}}", + "maps-displaymap-par-copycoords": "{{Maps-par|displaymap|copycoords}}", + "maps-displaymap-par-lines": "{{Maps-par|displaymap|lines}}", + "maps-displaymap-par-maxzoom": "{{Maps-par|displaymap|maxzoom}}", + "maps-displaymap-par-minzoom": "{{Maps-par|displaymap|minzoom}}", + "maps-displaymap-par-polygons": "{{Maps-par|displaymap|polygons}}", + "maps-displaymap-par-rectangles": "{{Maps-par|displaymap|rectangles}}", + "maps-displaymap-par-static": "{{Maps-par|displaymap|static}}", + "maps-displaymap-par-wmsoverlay": "{{Maps-par|displaymap|wmsoverlay}}\n\nWMS stands for [[wikipedia:en:Web_Map_Service|Web Map Service]].", + "maps-fullscreen-button": "This is the text of a switch.\n\nSee also:\n* {{msg-mw|Maps-fullscreen-button-tooltip}}.", + "maps-fullscreen-button-tooltip": "This is the text of a tooltip popup.\n\nSee also:\n* {{msg-mw|Maps-fullscreen-button}}.", + "validation-error-invalid-location": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-locations": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-width": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-height": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-distance": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-distances": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-image": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-images": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-goverlay": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", + "validation-error-invalid-goverlays": "This is an error message.\n\nParameter:\n* $1 - parameter name\n\n{{Related|Maps-validation}}", "maps-abb-north": "Symbol for representing \"north\" in geolocation coordinates.", - "maps-latitude": "{{Identical|Latitude}}", - "maps-longitude": "{{Identical|Longitude}}", - "maps-invalid-coordinates": "Unused at this time. Parameters:\n* $1 - value", - "maps_geocoding_failed": "Unused at this time. Parameters:\n* $1 - list of addresses\n* $2 - number of addresses", - "maps_geocoding_failed_for": "Parameters:\n* $1 - list of items\n* $2 - number of items, for PLURAL support", - "maps_unrecognized_coords": "Unused at this time. Parameters:\n* $1 - list of coordinates\n* $2 - number of coordinates\nSee also:\n* {{msg-mw|Maps unrecognized coords for}}", - "maps_unrecognized_coords_for": "Unused at this time. Parameters:\n* $1 - list of coordinates\n* $2 - number of coordinates\nSee also:\n* {{msg-mw|Maps unrecognized coords}}", + "maps-abb-east": "Symbol for representing \"east\" in geolocation coordinates.", + "maps-abb-south": "Symbol for representing \"south\" in geolocation coordinates.", + "maps-abb-west": "Symbol for representing \"west\" in geolocation coordinates.", + "maps-latitude": "This is a field label.\n\n{{Identical|Latitude}}", + "maps-longitude": "This is a field label.\n\n{{Identical|Longitude}}", + "maps-invalid-coordinates": "This is an error message.\n\nParameter:\n* $1 - value", + "maps_coordinates_missing": "This is an error message.", + "maps_geocoding_failed": "This is an error message.\n\nParameters:\n* $1 - list of addresses\n* $2 - number of addresses", + "maps_geocoding_failed_for": "This is an error message.\n\nParameters:\n* $1 - list of items\n* $2 - number of items, for PLURAL support", + "maps_unrecognized_coords": "This is an error message.\n\nParameters:\n* $1 - list of coordinates\n* $2 - number of coordinates\n\nSee also:\n* {{msg-mw|Maps unrecognized coords for}}", + "maps_unrecognized_coords_for": "This is an error message.\n\nParameters:\n* $1 - list of coordinates\n* $2 - number of coordinates\n\nSee also:\n* {{msg-mw|Maps unrecognized coords}}", + "maps_map_cannot_be_displayed": "This is an error message.", + "maps-geocoder-not-available": "This is an informatory and/or error message.", "maps_googlemaps3": "Lable for a result format on SMW's special page \"Ask\".\n\n{{optional}}", - "maps_leaflet": "Lable for a result format on SMW's special page \"Ask\".\n\n{{optional}}", - "maps-leaflet-par-zoom": "{{maps-par|leaflet|zoom}}", + "maps_leaflet": "This is a field label.\n\n{{optional}}", "maps-leaflet-par-defzoom": "{{maps-par|leaflet|defzoom}}", - "maps-leaflet-par-resizable": "{{maps-par|leaflet|resizable}}", + "maps-leaflet-par-layer": "{{maps-par|leaflet|layer}}", + "maps-leaflet-par-overlaylayers": "{{maps-par|leaflet|overlaylayers}}", + "maps-leaflet-par-maxclusterradius": "{{maps-par|leaflet|maxclusterradius}}", + "maps-leaflet-par-clusterspiderfy": "{{maps-par|leaflet|clusterspiderfy}}", "maps_openlayers": "Lable for a result format on SMW's special page \"Ask\".\n\n{{optional}}", - "maps_osm": "Lable for a result format on SMW's special page \"Ask\".\n\n{{optional}}", - "maps_centred_on": "Parameters:\n* $1 - latitude\n* $2 - longitude", - "maps-par-searchmarkers": "{{maps-par|maps|searchmarkers}}", + "maps_click_to_activate": "This is an informatory message.", + "maps_centred_on": "This is an informatory message.\n\nParameters:\n* $1 - latitude\n* $2 - longitude", + "maps-par-mappingservice": "{{maps-par-all|mappingservice}}", + "maps-par-resizable": "System message used by several maps services:\n\n{{maps-par|googlemaps3|resizable}}\n{{maps-par|openlayers|resizable}}\n{{maps-par|leaflet|resizable}}", + "maps-par-searchmarkers": "System message used by serveral maps services:\n\n{{maps-par|googlemaps3|searchmarkers}}\n{{maps-par|leaflet|searchmarkers}}", + "maps-par-geoservice": "{{maps-par-all|geoservice}}", + "maps-par-zoom": "System message used by serveral maps services:\n\n{{maps-par|googlemaps3|zoom}}\n{{maps-par|openlayers|zoom}}\n{{maps-par|leaflet|zoom}}", + "maps-par-width": "{{maps-par-all|width}}", + "maps-par-height": "{{maps-par-all|height}}", + "maps-par-centre": "{{maps-par-all|centre}}", + "maps-par-enable-fullscreen": "{{maps-par-all|enablefullscreen}}", + "maps-par-kml": "System message used by serveral maps services:\n\n{{maps-par|googlemaps3|kml}}\n{{maps-par|openlayers|kml}}", + "maps-par-markercluster": "{{maps-par-all|markercluster}}", + "maps-googlemaps3-incompatbrowser": "This is an error message shown to the user instead of a map.", "maps-googlemaps3-par-imageoverlays": "{{maps-par|googlemaps3|imageoverlays}}", - "maps-googlemaps3-par-markercluster": "{{maps-par|googlemaps3|markercluster}}", "maps-googlemaps3-par-type": "{{maps-par|googlemaps3|type}}", "maps-googlemaps3-par-types": "{{maps-par|googlemaps3|types}}", "maps-googlemaps3-par-layers": "{{maps-par|googlemaps3|layers}}", @@ -84,46 +157,90 @@ "maps-googlemaps3-par-zoomstyle": "{{maps-par|googlemaps3|zoomstyle}}", "maps-googlemaps3-par-typestyle": "{{maps-par|googlemaps3|typestyle}}", "maps-googlemaps3-par-autoinfowindows": "{{maps-par|googlemaps3|autoinfowindows}}", - "maps-googlemaps3-par-kml": "{{maps-par|googlemaps3|kml}}", "maps-googlemaps3-par-gkml": "{{maps-par|googlemaps3|gkml}}", "maps-googlemaps3-par-fusiontables": "{{maps-par|googlemaps3|fusiontables}}", "maps-googlemaps3-par-tilt": "{{maps-par|googlemaps3|tilt}}", "maps-googlemaps3-par-kmlrezoom": "{{maps-par|googlemaps3|kmlrezoom}}\n\nKML stands for [[w:Keyhole Markup Language|Keyhole Markup Language]].", "maps-googlemaps3-par-poi": "{{maps-par|googlemaps3|poi}}", - "mapeditor": "title of the special page [[Special:MapEditor]].", - "specialpages-group-maps": "{{doc-special-group|like=[[Special:MapEditor]]}}\n{{Identical|Map}}", - "mapeditor-parser-error": "Error message when parsing error occurs", - "mapeditor-none-text": "Text showing when no value is set (None).\n{{Identical|None}}", - "mapeditor-done-button": "Button text describing that editing details is completed", - "mapeditor-remove-button": "Button text that describes that the given map object should be removed", - "mapeditor-import-button2": "Button text that finishes import process.\n{{Identical|Import}}", - "mapeditor-export-button": "Button text that describes that the process of exporting", - "mapeditor-import-button": "Button text that opens import dialogue", - "mapeditor-select-button": "Button text selects the map object", - "mapeditor-mapparam-button": "Button text that opens map parameter dialogue", - "mapeditor-clear-button": "Button text that clears the map", - "mapeditor-code-title": "Title of dialogue", - "mapeditor-import-title": "Title of dialogue", - "mapeditor-import-note": "Import note", - "mapeditor-form-title": "Title of dialogue", - "mapeditor-link-title-switcher-popup-text": "Text for switch w/popup", - "mapeditor-link-title-switcher-link-text": "Text for switch w/link.\n{{Identical|Link}}", - "mapeditor-form-field-title": "Form field name.\n{{Identical|Title}}", - "mapeditor-form-field-text": "Form field name.\n{{Identical|Text}}", - "mapeditor-form-field-link": "Form field name.\n{{Identical|Link}}", - "mapeditor-form-field-icon": "Form field name.\n{{Identical|Icon}}", - "mapeditor-form-field-group": "Form field name.\n{{Identical|Group}}", - "mapeditor-form-field-inlinelabel": "Form field name", - "mapeditor-form-field-strokecolor": "Form field name", - "mapeditor-form-field-strokeopacity": "Form field name", - "mapeditor-form-field-strokeweight": "Form field name", - "mapeditor-form-field-fillcolor": "Form field name.\n{{Identical|Fill color}}", - "mapeditor-form-field-fillopcaity": "Form field name", - "mapeditor-form-field-showonhover": "Checkbox text", - "mapeditor-mapparam-title": "Title of dialogue", - "mapeditor-mapparam-defoption": "Default option in map parameters select list.\n{{Identical|Select parameter}}", - "mapeditor-imageoverlay-button": "Button text that starts the \"add image overlay process\"", - "mapeditor-form-field-image": "Form field name.\n{{Identical|Image}}", - "mapeditor-imageoverlay-title": "Title of dialogue", - "mapeditor-form-field-visitedicon": "Form field name" + "maps-googlemaps3-par-clustergridsize": "{{maps-par|googlemaps3|clustergridsize}}", + "maps-par-clustermaxzoom": "{{maps-par|googlemaps3|clustermaxzoom}}", + "maps-par-clusterzoomonclick": "{{maps-par|googlemaps3|clusterzoomonclick}}", + "maps-par-maxclusterradius": "{{maps-par|googlemaps3|clustermaxradius}}", + "maps-googlemaps3-par-clusteraveragecenter": "{{maps-par|googlemaps3|clusteraveragecenter}}", + "maps-googlemaps3-par-clusterminsize": "{{maps-par|googlemaps3|clusterminsize}}", + "maps-openlayers-par-controls": "{{maps-par-all|controls}}", + "maps-openlayers-par-layers": "{{maps-par|openlayers|layers}}", + "maps-openlayers-par-overlays": "{{maps-par|openlayers|overlays}}", + "mapeditor": "{{doc-special-group|like=[[Special:MapEditor]]}}", + "specialpages-group-maps": "{{doc-special-group|like=[[Special:MapEditor]]}}\n\n{{Identical|Map}}", + "mapeditor-parser-error": "This is an error message.", + "mapeditor-none-text": "This is an informatory message.\n\n{{Identical|None}}", + "mapeditor-done-button": "This is the text on a button.", + "mapeditor-remove-button": "This is the text on a button.", + "mapeditor-import-button2": "This is the text on a button.\n\n{{Identical|Import}}", + "mapeditor-export-button": "This is the text on a button.", + "mapeditor-import-button": "This is the text on a button.", + "mapeditor-select-button": "This is the text on a button.", + "mapeditor-mapparam-button": "This is the text on a button.", + "mapeditor-clear-button": "This is the text on a button.", + "mapeditor-code-title": "This is the title of a dialogue.", + "mapeditor-import-title": "This is the title of a dialogue.", + "mapeditor-import-note": "This is an informatory message.", + "mapeditor-form-title": "This is the title of a dialogue.", + "mapeditor-link-title-switcher-popup-text": "This is the text of a switch with a popup.", + "mapeditor-link-title-switcher-link-text": "This is the text for a switch with a link.\n\n{{Identical|Link}}", + "mapeditor-form-field-title": "This is and form field name.\n\n{{Identical|Title}}", + "mapeditor-form-field-text": "This is and form field name.\n\n{{Identical|Text}}", + "mapeditor-form-field-link": "This is and form field name.\n\n{{Identical|Link}}", + "mapeditor-form-field-icon": "This is and form field name.\n\n{{Identical|Icon}}", + "mapeditor-form-field-group": "This is and form field name.\n\n{{Identical|Group}}", + "mapeditor-form-field-inlinelabel": "This is and form field name.", + "mapeditor-form-field-strokecolor": "This is and form field name.", + "mapeditor-form-field-strokeopacity": "This is and form field name.", + "mapeditor-form-field-strokeweight": "This is and form field name.", + "mapeditor-form-field-fillcolor": "This is and form field name.\n\n{{Identical|Fill color}}", + "mapeditor-form-field-fillopcaity": "This is and form field name.", + "mapeditor-form-field-showonhover": "This is the text for a checkbox.", + "mapeditor-mapparam-title": "This is the title of a dialogue.", + "mapeditor-mapparam-defoption": "This is the default option in a select list.\n\n{{Identical|Select parameter}}", + "mapeditor-imageoverlay-button": "This is the text on a button.", + "mapeditor-form-field-image": "This is and form field name.\n\n{{Identical|Image}}", + "mapeditor-imageoverlay-title": "This is the title of a dialogue.", + "mapeditor-form-field-visitedicon": "This is and form field name.", + "semanticmaps-unrecognizeddistance": "This is an error message.\n\nParameter:\n* $1 - distance", + "semanticmaps-kml-link": "This is the label of a link.", + "semanticmaps-kml": "{{optional}}", + "semanticmaps-default-kml-pagelink": "Used as default value for \"pagelinktext\" input box.\nSee example: [{{canonicalurl:Special:Ask|format=kml}} Special:Ask]\n\n$1 is not a parameter (appears as is), but it will be replaced by the page title.\n\nSee also:\n* {{msg-mw|Semanticmaps-kml-pagelinktext}}\n{{Identical|View page}}", + "semanticmaps-latitude": "Parameters:\n* $1 - latitude\nSee also:\n* {{msg-mw|Semanticmaps-longitude}}\n* {{msg-mw|Semanticmaps-altitude}}\n{{Identical|Latitude}}", + "semanticmaps-longitude": "Parameters:\n* $1 - longitude\nSee also:\n* {{msg-mw|Semanticmaps-latitude}}\n* {{msg-mw|Semanticmaps-altitude}}\n{{Identical|Longitude}}", + "semanticmaps-altitude": "Parameters:\n* $1 - altitude\nSee also:\n* {{msg-mw|Semanticmaps-latitude}}\n* {{msg-mw|Semanticmaps-longitude}}", + "semanticmaps-forminput-locations": "This is a button label.\n\n{{Identical|Location}}", + "semanticmaps-par-staticlocations": "{{doc-paramdesc|staticlocations}}", + "semanticmaps-par-showtitle": "{{doc-paramdesc|showtitle}}", + "semanticmaps-par-hidenamespace": "{{doc-paramdesc|hidenamespace}}", + "semanticmaps-par-centre": "{{doc-paramdesc|centre}}", + "semanticmaps-par-template": "{{doc-paramdesc|template}}", + "semanticmaps-par-geocodecontrol": "{{doc-paramdesc|geocodecontrol}}", + "semanticmaps-par-activeicon": "{{doc-paramdesc|activeicon}}", + "semanticmaps-par-pagelabel": "{{doc-paramdesc|pagelabel}}\n\n{{doc-important|Do not translate the parameter value \"yes\".}}", + "semanticmaps-par-ajaxcoordproperty": "{{doc-paramdesc|ajaxcoordproperty}}", + "semanticmaps-par-ajaxquery": "{{doc-paramdesc|ajaxquery}}", + "semanticmaps-par-userparam": "{{doc-paramdesc|userparam}}", + "semanticmaps-kml-text": "{{doc-paramdesc|text}}", + "semanticmaps-kml-title": "{{doc-paramdesc|title}}", + "semanticmaps-kml-linkabsolute": "{{doc-paramdesc|absolute}}", + "semanticmaps-kml-pagelinktext": "Used as description for \"pagelinktext\" input box.\nSee example: [{{canonicalurl:Special:Ask|format=kml}} Special:Ask]\n\n$1 is not a parameter, and appears as is.\n\nDefault value for the input box is {{msg-mw|Semanticmaps-default-kml-pagelink}}.", + "semanticmaps-shapes-improperformat": "This is an error message.\n\nParameter:\n* $1 - improper text", + "semanticmaps-shapes-missingshape": "This is an error message.\n\nParameter:\n* $1 - name of the shape", + "validator-type-mapscircle": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapscircle-list": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapsimageoverlay": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapsimageoverlay-list": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapsline": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapsline-list": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapslocation": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapslocation-list": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapsrectangle": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-mapsrectangle-list": "This is the name of a type of values that may be assigned to a parameter.", + "validator-type-wmsoverlay": "This is the name of a type of values that may be assigned to a parameter. WMS stands for [[wikipedia:en:Web_Map_Service|Web Map Service]]." } diff --git a/i18n/ro.json b/i18n/ro.json index 199bcef07..88911cdb0 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -58,8 +58,6 @@ "maps-geocoder-not-available": "Opțiunea de geocodare pentru Hărți nu este disponibilă. Locația dumneavoastră nu a putut fi geocodată.", "maps_click_to_activate": "Apăsați pentru a activa harta", "maps_centred_on": "Hartă centrată la $1, $2.", - "maps-osm-par-thumbs": "Afișează miniaturi", - "maps-osm-par-photos": "Afișează fotografii", "mapeditor": "Editor de hărți", "specialpages-group-maps": "Hărți", "mapeditor-none-text": "Nimic", @@ -93,5 +91,6 @@ "mapeditor-imageoverlay-button": "Adaugă suprapunerea de imagine", "mapeditor-form-field-image": "Imagine", "mapeditor-imageoverlay-title": "Detalii suprapunere imagine", - "mapeditor-form-field-visitedicon": "Pictogramă vizitată" + "mapeditor-form-field-visitedicon": "Pictogramă vizitată", + "semanticmaps-forminput-locations": "Locuri" } diff --git a/i18n/ru.json b/i18n/ru.json index 969c0d448..d7874e86a 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -15,7 +15,11 @@ "Yuriy Apostol", "Александр Сигачёв", "Macofe", - "Perevod16" + "Perevod16", + "Alexandr Efremov", + "Cat1987", + "Туллук", + "Pastakhov" ] }, "maps-desc": "Позволяет встраивать динамические карты в вики-страницы, геокодировать адреса и выполнять другие географические действия", @@ -25,7 +29,7 @@ "maps-tracking-category": "Страницы с картой, сгенерированной расширением Maps", "maps-loading-map": "Идёт загрузка карты…", "maps-load-failed": "Невозможно загрузить карту!", - "maps-markers": "Отметки", + "maps-markers": "Маркеры", "maps-copycoords-prompt": "CTRL+C, ENTER", "maps-searchmarkers-text": "Маркеры фильтра", "maps-others": "другие", @@ -52,7 +56,6 @@ "maps-layer-type-supported-by": "Этот тип слоя может быть использован {{PLURAL:$2|1=только с картографической службой|только со следующими картографическими службами:}} $1", "maps-coordinates-description": "Перехватчик синтаксического анализатора для форматирования координат из любого и в любой поддерживаемый формат.", "maps-displaymap-description": "Отображение географических карт без каких-либо вики-маркеров на них.", - "maps-displaypoint-description": "Отображение географических карт с одним или несколькими вики-маркерами на них.", "maps-distance-description": "Преобразование расстояния, выраженного в определенных поддерживаемых единицах, в его эквивалент в других единицах.", "maps-finddestination-description": "Найти место назначения от заданной начальной точки (может быть в любом формате из поддерживаемых), начальное направление и расстояние.", "maps-geocode-description": "Включает геокодирование адресов. Иными словами, преобразует понятные человеку названия мест в наборы координат. Поддерживается несколько сервисов геокодирования, которые не следует путать с картографическими сервисами.", @@ -106,7 +109,6 @@ "maps-displaymap-par-wmsoverlay": "Использовать слой WMS", "maps-fullscreen-button": "Переключить полноэкранный режим", "maps-fullscreen-button-tooltip": "Посмотреть карту в полноэкранном или встроенном режиме.", - "maps-googlemaps3-par-enable-fullscreen": "Включить кнопку полноэкранного режима", "validation-error-invalid-location": "Параметр $1 должен быть корректным местоположением.", "validation-error-invalid-locations": "Параметр $1 должен содержать одно или несколько корректных местоположений.", "validation-error-invalid-width": "Параметр $1 должен быть корректной шириной.", @@ -132,6 +134,9 @@ "maps_map_cannot_be_displayed": "Карта не может быть показана.", "maps-geocoder-not-available": "Функция геокодирования карт недоступна, ваше местоположение не может быть геокодировано.", "maps_leaflet": "Листовка", + "maps-leaflet-par-defzoom": "Позволяет задавать масштаб карты по умолчанию.", + "maps-leaflet-par-layer": "Уровень, который отображается при загрузке карты.", + "maps-leaflet-par-overlaylayers": "Наложение слоев, которые будут показаны, когда карта загружена.", "maps_click_to_activate": "Нажмите для активации карты", "maps_centred_on": "Центр карты — $1, $2.", "maps-par-mappingservice": "Позволяет выбрать сервис карт, который будет использоваться.", @@ -142,9 +147,11 @@ "maps-par-width": "Позволяет задать ширину карты. По умолчанию единицей измерения будет считаться пиксель, но можно явно указать одну из следующих единиц: px, ex, em, %.", "maps-par-height": "Позволяет задать высоту карты. По умолчанию единицей измерения будет считаться пиксель, но можно явно указать одну из следующих единиц: px, ex, em, %.", "maps-par-centre": "Расположение на карте, по которому она должна быть отцентрована", + "maps-par-enable-fullscreen": "Включить кнопку полноэкранного режима", + "maps-par-kml": "KML файлы для загрузки на карту.", + "maps-par-markercluster": "Позволяет объединить несколько находящихся рядом маркеров в один маркер", "maps-googlemaps3-incompatbrowser": "Ваш браузер несовместим с Google Maps v3.", "maps-googlemaps3-par-imageoverlays": "Позволяет добавить изображение, которое будет показано в определённом месте карты.", - "maps-googlemaps3-par-markercluster": "Позволяет объединить несколько находящихся рядом маркеров в один маркер", "maps-googlemaps3-par-type": "Тип карты для начального отображения.", "maps-googlemaps3-par-types": "Типы карты, которые будут доступны через элемент управления типом карты.", "maps-googlemaps3-par-layers": "Специальные слои для загрузки на карту.", @@ -152,17 +159,17 @@ "maps-googlemaps3-par-zoomstyle": "Стиль элемента управления масштабом.", "maps-googlemaps3-par-typestyle": "Стиль элемента управления типа.", "maps-googlemaps3-par-autoinfowindows": "Автоматически открывает все информационные окна после загрузки страницы.", - "maps-googlemaps3-par-kml": "KML файлы для загрузки на карту.", "maps-googlemaps3-par-gkml": "KML файлы, хранящиеся в Google для загрузки на карту.", "maps-googlemaps3-par-fusiontables": "Идентификаторы Сводных таблиц Google, которые должны быть загружены на карту.", "maps-googlemaps3-par-tilt": "Наклон карты при использовании Google Maps.", "maps-googlemaps3-par-kmlrezoom": "Перемасштабировать карту после загрузки слоёв KML.", "maps-googlemaps3-par-poi": "Показать достопримечательности.", + "maps-googlemaps3-par-clustergridsize": "Размер сетки кластера в пикселях.", + "maps-par-clustermaxzoom": "Максимальный уровень увеличения, при котором может существовать кластер.", + "maps-par-maxclusterradius": "Максимальный радиус, охватываемый кластером.", "maps-openlayers-par-controls": "Элементы управления для размещения на карте.", "maps-openlayers-par-layers": "Слои, которые будут доступны при выборе слоёв. Первый слой будет отображаться при загрузке карты.", "maps-openlayers-par-overlays": "Наложенные слои, которые будут доступны при выборе слоёв. Эти слои будут отображаться поверх обычного слоя, аналогично маркерам.", - "maps-osm-par-thumbs": "Показать превью", - "maps-osm-par-photos": "Показать фото", "mapeditor": "Редактор карт", "specialpages-group-maps": "Карты", "mapeditor-parser-error": "Произошла ошибка обработки метаданных. Введённые данные проигнорированы.", @@ -198,5 +205,29 @@ "mapeditor-imageoverlay-button": "Добавить наложение изображения", "mapeditor-form-field-image": "Изображение", "mapeditor-imageoverlay-title": "Изображение", - "mapeditor-form-field-visitedicon": "Иконка для посещённого" + "mapeditor-form-field-visitedicon": "Иконка для посещённого", + "semanticmaps-unrecognizeddistance": "Значение $1 — это недопустимое расстояние.", + "semanticmaps-kml-link": "Просмотреть файл KML", + "semanticmaps-default-kml-pagelink": "Просмотреть страницу $1", + "semanticmaps-latitude": "Широта: $1", + "semanticmaps-longitude": "Долгота: $1", + "semanticmaps-altitude": "Высота: $1", + "semanticmaps-forminput-locations": "Места", + "semanticmaps-par-staticlocations": "Список мест для добавления на карту вместе с запрашиваемыми данными. Например, к display_points можно добавить название, описание и значок, используя тильду ~ в качестве разделителя.", + "semanticmaps-par-showtitle": "Показывать или нет заголовок в окне информации маркера. Его отключение часто бывает полезно при использовании шаблона для форматирования содержимого окна информация.", + "semanticmaps-par-hidenamespace": "Показывать название пространства имен в информационном окне маркера", + "semanticmaps-par-centre": "Центр карты. Если не задан, карта автоматически выберет оптимальный центр, позволяющий отобразить все маркеры на карте.", + "semanticmaps-par-template": "Шаблон для форматирования содержимого окна информация.", + "semanticmaps-par-geocodecontrol": "Показать панель управления геокодированием.", + "semanticmaps-par-activeicon": "Значок, который будет отображаться вместо стандартного маркера в случаях, когда активная страница совпадает с результатом запроса", + "semanticmaps-par-pagelabel": "Если задано значение «yes» («да»), все маркеры будут иметь «inlineLabel» со ссылкой на страницу, содержащую координаты для маркера", + "semanticmaps-par-userparam": "Значение, которое передается за каждый вызов шаблона, если шаблон используется", + "semanticmaps-kml-text": "Текст, связанный с каждой страницы. Переопределяется дополнительными запрашиваемыми свойствами, если таковые имеются.", + "semanticmaps-kml-title": "Заголовок по умолчанию для результатов", + "semanticmaps-kml-linkabsolute": "Ссылки должны быть абсолютными (а не относительными)", + "semanticmaps-kml-pagelinktext": "Текст, используемый для ссылки на страницу, в которой $1 будет заменён названием страницы.", + "semanticmaps-shapes-improperformat": "Неправильное форматирование $1. Обратитесь к документации по форматированию.", + "semanticmaps-shapes-missingshape": "Фигуры для $1 не найдены. Пожалуйста, обратитесь к документации по доступным фигурам", + "validator-type-mapsline-list": "Список линий", + "validator-type-mapsrectangle-list": "Список прямоугольников" } diff --git a/i18n/si.json b/i18n/si.json index f09615f22..2f3b0ec74 100644 --- a/i18n/si.json +++ b/i18n/si.json @@ -58,15 +58,13 @@ "maps_map_cannot_be_displayed": "සිතියම සංදර්ශනය කල නොහැක.", "maps_click_to_activate": "සිතියම සක්‍රිය කිරීම සඳහා ක්ලික් කරන්න", "maps_centred_on": "$1 හිදී සිතියම මධ්‍යගත වේ, $2.", + "maps-par-kml": "සිතියම මත පැටවිය යුතු KML ගොනු.", "maps-googlemaps3-par-type": "ආරම්භක වශයෙන් පෙන්විය යුතු සිතියම් වර්ගය.", "maps-googlemaps3-par-layers": "සිතියම මත පැටවිය යුතු විශේෂ ස්ථර.", "maps-googlemaps3-par-zoomstyle": "විශාලන පාලකයේ ශෛලිය.", "maps-googlemaps3-par-typestyle": "වර්ග පාලකයේ ශෛලිය.", - "maps-googlemaps3-par-kml": "සිතියම මත පැටවිය යුතු KML ගොනු.", "maps-googlemaps3-par-poi": "අභිරුචි ලක්ෂ්‍ය පෙන්වන්න.", "maps-openlayers-par-controls": "සිතියම මත ස්ථානගත විය යුතු පාලක.", - "maps-osm-par-thumbs": "සංක්ෂිප්ත පෙන්වන්න", - "maps-osm-par-photos": "ඡායාරූප පෙන්වන්න", "mapeditor": "සිතියම් සංස්කාරක", "specialpages-group-maps": "සිතියම්", "mapeditor-none-text": "කිසිවක් නොමැත", @@ -100,5 +98,14 @@ "mapeditor-imageoverlay-button": "පින්තූර වසාලනයක් එක් කරන්න", "mapeditor-form-field-image": "පිංතූරය", "mapeditor-imageoverlay-title": "පින්තූර වසාලන විස්තර", - "mapeditor-form-field-visitedicon": "ගොඩ වැදුණු අයිකනය" + "mapeditor-form-field-visitedicon": "ගොඩ වැදුණු අයිකනය", + "semanticmaps-unrecognizeddistance": "$1 අගය වලංගු දුර ප්‍රමාණයක් නොවේ.", + "semanticmaps-kml-link": "KML ගොනුව නරඹන්න", + "semanticmaps-default-kml-pagelink": "$1 පිටුව නරඹන්න", + "semanticmaps-latitude": "අක්ෂාංශය: $1", + "semanticmaps-longitude": "දේශාංශය: $1", + "semanticmaps-altitude": "උන්නතාංශය: $1", + "semanticmaps-forminput-locations": "ස්ථාන", + "semanticmaps-par-geocodecontrol": "භූකේතීකරණ පාලකය පෙන්වන්න.", + "semanticmaps-kml-title": "ප්‍රතිඑල සඳහා සාමාන්‍ය ශීර්ෂය" } diff --git a/i18n/sv.json b/i18n/sv.json index 332234150..7350ab3be 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -10,7 +10,8 @@ "Per", "Rotsee", "WikiPhoenix", - "Macofe" + "Macofe", + "Martinwiss" ] }, "maps-desc": "Ger möjlighet att bädda in dynamiska kartor i wiki-sidor, geokoding av adresser och andra geografiska åtgärder", @@ -46,7 +47,6 @@ "maps-layer-type-supported-by": "Denna lagertyp kan endast användas med {{PLURAL:$2|kartläggningstjänsten $1|dessa kartläggningstjänster: $1}}.", "maps-coordinates-description": "Tolk-hook för att formatera koordinater, från och till något av de format som stöds.", "maps-displaymap-description": "Visa geografiska kartor utan några wiki-definierade markörer på dem.", - "maps-displaypoint-description": "Visa geografiska kartor med en eller flera wiki-definierade markörer på dem.", "maps-distance-description": "Konvertera ett avstånd mätt i en giltig enhet till en annan enhet.", "maps-finddestination-description": "Hitta ett mål utifrån en given startpunkt (på något giltigt format), en inledande bäring och ett avstånd.", "maps-geocode-description": "Aktiverar geokodning av adresser, med andra ord, konvertering av mänskligt läsbara platser till en uppsättning koordinater. det finns stöd för flera geokodningstjänster, som inte bör förväxlas med karttjänster.", @@ -100,7 +100,6 @@ "maps-displaymap-par-wmsoverlay": "Använd ett WMS-överdrag", "maps-fullscreen-button": "Växla fullskärmsläge", "maps-fullscreen-button-tooltip": "Visa kartan i helskärm eller som inbäddad.", - "maps-googlemaps3-par-enable-fullscreen": "Aktivera helskärmsknappen", "validation-error-invalid-location": "Parameter $1 måste vara en giltig plats.", "validation-error-invalid-locations": "Parameter $1 måste vara en eller flera giltiga platser.", "validation-error-invalid-width": "Parameter $1 måste vara en giltig bredd.", @@ -134,6 +133,8 @@ "maps-par-width": "Tillåter att kartans bredd ställs in. Som standard kommer pixlar att antas som enhet, men du kan uttryckligen ange en av dessa enheter: px, ex, em, %.", "maps-par-height": "Tillåter att kartans höjd ställs in. Som standard kommer pixlar att antas som enhet, men du kan uttryckligen ange en av dessa enheter: px, ex, em, %.", "maps-par-centre": "Platsen där kartan ska vara centrerad", + "maps-par-enable-fullscreen": "Aktivera helskärmsknappen", + "maps-par-kml": "KML-filer att ladda upp på kartan.", "maps-googlemaps3-incompatbrowser": "Din webbläsare är inte kompatibel med Google Maps v3.", "maps-googlemaps3-par-type": "Karttyp att visa initialt", "maps-googlemaps3-par-types": "De karttyper som kommer att finnas tillgänglig via typ-reglaget.", @@ -142,7 +143,6 @@ "maps-googlemaps3-par-zoomstyle": "Stilen för zoomreglaget.", "maps-googlemaps3-par-typestyle": "Stilen för typreglaget.", "maps-googlemaps3-par-autoinfowindows": "Öppna automatiskt alla informationsfönster när sidan har lästs in.", - "maps-googlemaps3-par-kml": "KML-filer att ladda upp på kartan.", "maps-googlemaps3-par-gkml": "KML-filer, tillhandahållna av Google, att ladda på kartan.", "maps-googlemaps3-par-fusiontables": "ID för Google Fusion-tabeller som ska laddas på kartan.", "maps-googlemaps3-par-tilt": "Tilta för karta när du använder Google Maps.", @@ -151,8 +151,6 @@ "maps-openlayers-par-controls": "Kontroller att placera på kartan.", "maps-openlayers-par-layers": "De lager som kommer att finnas tillgängliga i lagerväljaren. Det första lagret visas när kartan laddas.", "maps-openlayers-par-overlays": "Överdragslager som kommer att finnas tillgängliga i lager-väljare. Dessa lager kommer att visas på toppen av ett normalt lager, ungefär som en markör.", - "maps-osm-par-thumbs": "Visa miniatyrer", - "maps-osm-par-photos": "Visa foton", "mapeditor": "Kartredigerare", "specialpages-group-maps": "Kartor", "mapeditor-parser-error": "Ett fel uppstod när metadata tolkades. Ignorerar data från användaren.", @@ -188,5 +186,38 @@ "mapeditor-imageoverlay-button": "Lägg till bildöverdrag", "mapeditor-form-field-image": "Bild", "mapeditor-imageoverlay-title": "Bildöverdragsdetaljer", - "mapeditor-form-field-visitedicon": "Besökt ikon" + "mapeditor-form-field-visitedicon": "Besökt ikon", + "semanticmaps-unrecognizeddistance": "Värdet $1 är inte ett giltigt avstånd.", + "semanticmaps-kml-link": "Visa KML-filen", + "semanticmaps-default-kml-pagelink": "Visa sida $1", + "semanticmaps-latitude": "Breddgrad: $1", + "semanticmaps-longitude": "Längdgrad: $1", + "semanticmaps-altitude": "Höjd över havet: $1", + "semanticmaps-forminput-locations": "Platser", + "semanticmaps-par-staticlocations": "En lista med platser som man kan placera på kartan tillsammans med efterfrågad data. Precis som för display_points, så kan du lägga till en titel, en beskrivning och en ikon för varje plats med hjälp av tilde \"~\" som avgränsare.", + "semanticmaps-par-showtitle": "Visa en titel i markörens informationsruta eller inte. Det är ofta lämpligt att inte använda denna funktion när en mall används för informationsrutans innehåll.", + "semanticmaps-par-hidenamespace": "Visa namnrymdens titel i markörens informationsruta.", + "semanticmaps-par-centre": "Kartans mitt. Om inte angiven så kommer kartan automatiskt att hitta markörernas mittpunkt.", + "semanticmaps-par-template": "En mall som ska användas för informationsrutorna.", + "semanticmaps-par-geocodecontrol": "Visa formulär för geokodning.", + "semanticmaps-par-activeicon": "Ikon som bör visas istället för standardmarkören när den aktiva sidan är samma som resultatet från förfrågan", + "semanticmaps-par-pagelabel": "När satt till \"yes\" (ja), kommer alla markörer att ha en \"inlineLabel\" med en länk till sidan som innehåller koordinaterna för den markören", + "semanticmaps-kml-text": "Texten som hör ihop med varje sida. Om det finns efterfrågade egenskaper så tar de överhand.", + "semanticmaps-kml-title": "Förvald titel för resultaten", + "semanticmaps-kml-linkabsolute": "Ska länkar vara absoluta (i motsats till relativa)", + "semanticmaps-kml-pagelinktext": "Texten som ska användas för länkar till sidan, där $1 kommer att bytas ut med sidtiteln", + "semanticmaps-shapes-improperformat": "Felaktig formatering av $1. Se dokumentationen för formatering", + "semanticmaps-shapes-missingshape": "Inga former hittade för $1. Se dokumentationen för tillgängliga former", + "validator-type-mapscircle": "Geografisk cirkel", + "validator-type-mapscircle-list": "Lista över cirklar", + "validator-type-mapsimageoverlay": "Bildöverlägg", + "validator-type-mapsimageoverlay-list": "Lista över bildöverlägg", + "validator-type-mapsline": "Geografisk linje", + "validator-type-mapsline-list": "Lista över linjer", + "validator-type-mapslocation": "Geografisk plats", + "validator-type-mapslocation-list": "Lista över platser", + "validator-type-mapsrectangle": "Geografisk rektangel", + "validator-type-mapsrectangle-list": "Lista över rektanglar", + "validator-type-mapspolygon": "Geografisk polygon", + "validator-type-mapspolygon-list": "Lista över geografiska polygoner" } diff --git a/i18n/tl.json b/i18n/tl.json index 47f813080..a9d10823b 100644 --- a/i18n/tl.json +++ b/i18n/tl.json @@ -1,7 +1,8 @@ { "@metadata": { "authors": [ - "AnakngAraw" + "AnakngAraw", + "Jojit fb" ] }, "maps-desc": "Nagpapagana ng pagbabaon ng gumagalaw na mga mapa papaloob sa mga pahina ng wiki, pagkokodigong pangheograpiya ng mga tirahan at ibang mga gawaing pangheograpiya. ([http://mapping.referata.com/wiki/Examples mga pagpapatunghay])\n\nkakayahang ipakita ang dato ng tugmaang-pampook sa loob ng mga mapa, at mga triahan ([http://mapping.referata.com/wiki/Maps_examples mga pagpapatunghay])", @@ -26,7 +27,6 @@ "maps-layer-type-supported-by": "Ang ganitong uri ng patong ay {{PLURAL:$2|magagamit lamang sa $1 na palingkuran ng pagmamapa|magagamit lamang sa ganitong mga palingkuran ng pagmamapa: $1}}.", "maps-coordinates-description": "Kawint ng banghay upang maianyo ang mga tugmaang-pampook, magmula at papunta sa anuman sa tinatangkilik na mga anyo.", "maps-displaymap-description": "Ipakita ang mga mapang pangheograpiya na walang anumang tinukoy na pangwiking mga pananda sa ibabaw nila.", - "maps-displaypoint-description": "Ipakita ang mga mapang pangheograpiya na may isa o higit pang tinukoy na pangwiking mga pananda sa ibabaw nila.", "maps-distance-description": "Palitan ang isang kalayuan na ginagamit ang isang partikular na sinusuportahang yunit papunta sa katumbas nito na ginagamit ang isa pang yunit.", "maps-finddestination-description": "Maghanap ng isang patutunguhan na binigyan ng tuldok ng pagsisimula (na maaaring nasa loob ng anuman sa tinatangkilik na mga anyo), isang paunang kapupuntahan at isang layo.", "maps-geocode-description": "Nagpapagana ng pagsasakodigo na pangheograpiya ng mga tirahan, na sa ibang pananalita ay ang pagpapaglit ng mga kinalalagyan na mababasa ng tao upang maging mga pangkat ng mga tugmaang pampook. Mayroong suporta para sa ilang mga paglilingkod na pangkodigo ng heograpiya, na hindi dapat ikalito sa mga paglilingkod ng pagmamapa.", @@ -93,7 +93,6 @@ "maps-geocoder-not-available": "Wala ang katangiang-kasangkapang pang-geokodigo ng Mga Mapa. Hindi mageokodigo ang lokasyon mo.", "maps_googlemaps3": "Google Maps v3", "maps_openlayers": "OpenLayers", - "maps_osm": "OpenStreetMap", "maps_click_to_activate": "Pindutin upang mabuhay ang mapa", "maps_centred_on": "Nakagitna ang mapa sa $1, $2.", "maps-par-resizable": "Nakagagawang mababago ang sukat ng mapa sa pamamagitan ng pagkaladkad doon sa pang-ibabang kanang sulok nito.", @@ -101,6 +100,7 @@ "maps-par-zoom": "Ang antas ng paglapit para sa mapa. Para sa mga mapang mayroong mga pangmarka, ito ay likas na nakatakda sa pinaka malapit na antas ng pagkakatutok na nagpapakita pa rin ng lahat ng mga pangmarka.", "maps-par-width": "Nagpapahintulot ng pagtatakda ng lapad ng mapa. Ayon sa likas na pagkakatakda, ang mga piksel ay ipapalagay bilang yunit, subalit maaari mong maliwanag na tukuyin ang isa sa mga yunit na ito: px, ex, em, %.", "maps-par-height": "Nagpapahintulot ng pagtatakda ng taas ng mapa. Ayon sa likas na pagkakatakda, ang mga piksel ay ipapalagay bilang yunit, subalit maaari mong maliwanag na tukuyin ang isa sa mga yunit na ito: px, ex, em, %.", + "maps-par-kml": "Mga talaksan ng Wikang Pangmarka ng Butas ng Susian (Keyhole Markup Language, KML) na ikakarga sa ibabaw ng mapa.", "maps-googlemaps3-incompatbrowser": "Ang pantingin-tingin mo ay hindi katambal ng Mga Mapa ng Google v3.", "maps-googlemaps3-par-type": "Ang uri ng mapa na unang ipapakita.", "maps-googlemaps3-par-types": "Ang mga uri ng mapa na magiging makukuha sa pamamagitan ng pantaban ng uri.", @@ -109,7 +109,6 @@ "maps-googlemaps3-par-zoomstyle": "Ang estilo ng pantaban ng paglapit.", "maps-googlemaps3-par-typestyle": "Ang estilo ng pantaban ng uri.", "maps-googlemaps3-par-autoinfowindows": "Kusang buksan ang lahat ng mga dungawan ng kabatiran pagkaraang maikarga ang pahina.", - "maps-googlemaps3-par-kml": "Mga talaksan ng Wikang Pangmarka ng Butas ng Susian (Keyhole Markup Language, KML) na ikakarga sa ibabaw ng mapa.", "maps-googlemaps3-par-gkml": "Mga talaksan ng Wikang Pangmarka ng Butas ng Susian (Keyhole Markup Language, KML) na pinasisinayahan ng Google upang ikarga sa ibabaw ng mapa.", "maps-googlemaps3-par-fusiontables": "Mga ID ng mga Talahanayan ng Pagtutumbaga ng Google na dapat ikarga sa ibabaw ng mapa.", "maps-googlemaps3-par-tilt": "Pagkiling para sa Mapa kapag ginagamit ang Mga Mapa ng Google.", @@ -117,8 +116,6 @@ "maps-googlemaps3-par-poi": "Ipakita ang mga tuldok na mapagtutuunan ng pansin.", "maps-openlayers-par-controls": "Ang mga pantaban na ilalagay sa ibabaw ng mapa.", "maps-openlayers-par-layers": "Ang mga patong ay magiging makukuha sa loob ng pilian ng patong. Ang unang patong ay ipapakita kapag kumarga na ang mapa.", - "maps-osm-par-thumbs": "Ipakita ang mga kagyat", - "maps-osm-par-photos": "Ipakita ang mga larawan", "mapeditor": "Patnugot ng mapa", "specialpages-group-maps": "Mga mapa", "mapeditor-parser-error": "Naganap ang isang kamalian noong binabanghay ang metadato. Hindi papansinin ang ipinasok ng tagagamit.", @@ -135,10 +132,10 @@ "mapeditor-import-note": "Paki tandaan na ang pambanghay ay umaasa ng isang napaka higpit na kaanyuan sa kodigo ng wiki. Ang ipinasok na kodigo rito ay dapat na tumugma sa kodigong inilibas ng panunungkulan ng pagluluwas.", "mapeditor-form-title": "Baguhin ang mga detalye", "mapeditor-link-title-switcher-popup-text": "Pagsulpot na mayroong teksto", - "mapeditor-link-title-switcher-link-text": "Kawing", + "mapeditor-link-title-switcher-link-text": "Link", "mapeditor-form-field-title": "Pamagat", "mapeditor-form-field-text": "Teksto", - "mapeditor-form-field-link": "Kawing", + "mapeditor-form-field-link": "Link", "mapeditor-form-field-icon": "Kinatawang larawan", "mapeditor-form-field-group": "Pangkat", "mapeditor-form-field-inlinelabel": "Katatakang nasa guhit", @@ -153,5 +150,23 @@ "mapeditor-imageoverlay-button": "Idagdag ang kalupkop ng larawan", "mapeditor-form-field-image": "Larawan", "mapeditor-imageoverlay-title": "Mga detalye ng kalupkop ng larawan", - "mapeditor-form-field-visitedicon": "Kinatawang larawan ng pagka nadalaw" + "mapeditor-form-field-visitedicon": "Kinatawang larawan ng pagka nadalaw", + "semanticmaps-unrecognizeddistance": "Hindi isang tanggap na layo ang halagang $1.", + "semanticmaps-kml-link": "Tingnan ang talaksang KML", + "semanticmaps-kml": "KML", + "semanticmaps-default-kml-pagelink": "Tingnan ang pahinang $1", + "semanticmaps-latitude": "Latitud: $1", + "semanticmaps-longitude": "Longhitud: $1", + "semanticmaps-altitude": "Altitud: $1", + "semanticmaps-forminput-locations": "Mga kinalalagyan", + "semanticmaps-par-staticlocations": "Isang listahan ng mga lokasyon na idaragdag sa mapa na kasama ng inusisang dato. Katulad ng sa tuldok_ng_pagpapakita, makapagdaragdag ka ng isang pamagat, paglalarawan at kinatawang larawan sa bawat lokasyon na ginagamit ang tilde \"~\" bilang panghiwalay.", + "semanticmaps-par-showtitle": "Magpapakita o hindi magpapakita ng isang pamagat sa loob ng pangmarkang bintana ng impormasyon. Ang hindi pagpapagana nito ay kadasalang mas kapakipakinabang kapag gumagamit ng isang suleras upang maiayos ang nilalaman ng bintana ng kabatiran.", + "semanticmaps-par-hidenamespace": "Ipakita o huwag ipakita ang pamagat ng puwang na pampangalan sa loob ng pangmarkang bintana ng impormasyon.", + "semanticmaps-par-centre": "Ang gitna ng mapa. Kapag hindi ibinigay, kusang pipiliin ng mapa ang pinakamabuting gitna na pagpapakitaan ng lahat ng mga pangmarka", + "semanticmaps-par-template": "Isang suleras na gagamit upang iayos ang mga nilalaman ng bintana ng kabatiran.", + "semanticmaps-par-geocodecontrol": "Ipakita ang pantaban ng pagkokodigong pangheograpiya.", + "semanticmaps-kml-text": "Umuugnay ang teksto sa bawat isang pahina. Pinangingibabawan ng karagdagang sinisiyasat na mga katangiang angkin kung mayroon.", + "semanticmaps-kml-title": "Ang likas na nakatakdang pamagat para sa mga resulta", + "semanticmaps-kml-linkabsolute": "Kung ang mga kawing ay magiging lubos o hindi (iyong nauukol)", + "semanticmaps-kml-pagelinktext": "Ang tekstong gagamitin para sa mga kawing sa pahina, kung saan ang $1 ay mapapalitan ng pamagat ng pahina" } diff --git a/i18n/tr.json b/i18n/tr.json index 8ff6514c0..b18d3b8d1 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -8,7 +8,8 @@ "Trncmvsr", "Vito Genovese", "McAang", - "Hbseren" + "Hbseren", + "Sadrettin" ] }, "right-geocode": "Coğrafi kod", @@ -43,14 +44,19 @@ "maps_unrecognized_coords": "Şu {{PLURAL:$2|koordinat|koordinatlar}} tanınamadı: $1", "maps_map_cannot_be_displayed": "Harita görüntülenemiyor.", "maps-geocoder-not-available": "Haritanın coğrafi kodlama özelliği etkin değil. Konumunuz kodlanamıyor.", - "maps-leaflet-par-zoom": "Harita yakınlaştırma düzeyini ayarlamaya olanak sağlar.", "maps-leaflet-par-defzoom": "Haritanın varsayılan yakınlaştırma düzeyini ayarlamaya olanak sağlar.", - "maps-leaflet-par-resizable": "Haritanın sağ alt köşesinden sürüklenerek yeniden boyutlandırılabilir hale getirilmesine olanak sağlar.", "maps_click_to_activate": "Haritayı etkinleştirmek için tıkla", "maps_centred_on": "Harita, $1 $2 koordinatlarında ortalandı.", "mapeditor": "Harita düzenleyici", + "specialpages-group-maps": "Haritalar", + "mapeditor-parser-error": "Metaveri ayrıştırılırken bir hata oluştu. Kullanıcı girişi yok sayılıyor.", + "mapeditor-none-text": "Hiçbiri", + "mapeditor-done-button": "Yapıldı", + "mapeditor-remove-button": "Kaldır", + "mapeditor-import-button2": "İçe aktar", "mapeditor-export-button": "Viki kodu dışa aktar", "mapeditor-import-button": "Viki kodunu içe aktar", + "mapeditor-select-button": "Bu çokgeni seçin", "mapeditor-mapparam-button": "Harita parametrelerini düzenle", "mapeditor-clear-button": "Haritayı temizle", "mapeditor-code-title": "Viki kodu", @@ -58,6 +64,19 @@ "mapeditor-form-title": "Ayrıntıları düzenle", "mapeditor-form-field-title": "Başlık", "mapeditor-form-field-text": "Metin", + "mapeditor-form-field-link": "Bağlantı", + "mapeditor-form-field-icon": "Simge", + "mapeditor-form-field-group": "Grup", + "mapeditor-form-field-inlinelabel": "Satır içi etiket", + "mapeditor-form-field-strokecolor": "Çizgi rengi", + "mapeditor-form-field-strokeopacity": "Çizgi saydamlığı", + "mapeditor-form-field-strokeweight": "Çizgi kalınlığı", + "mapeditor-form-field-fillcolor": "Dolgu rengi", + "mapeditor-form-field-fillopcaity": "Dolgu saydamlığı", + "mapeditor-form-field-showonhover": "Yalnızca vurgulu olanı göster", "mapeditor-mapparam-title": "Harita parametrelerini düzenle", - "mapeditor-mapparam-defoption": "-Parametre seçiniz-" + "mapeditor-mapparam-defoption": "-Parametre seçiniz-", + "mapeditor-imageoverlay-button": "Resim katmanı ekle", + "mapeditor-form-field-image": "Resim", + "mapeditor-imageoverlay-title": "Resim katmanı ayrıntıları" } diff --git a/i18n/uk.json b/i18n/uk.json index 4e381e583..67b8ace5e 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -7,7 +7,9 @@ "Ата", "Тест", "Olion", - "Piramidion" + "Piramidion", + "Alex Khimich", + "SteveR" ] }, "maps-desc": "Дає змогу вбудовування динамічних карт у сторінки вікі, геокодування адрес та інші географічні операції", @@ -44,7 +46,6 @@ "maps-layer-type-supported-by": "Цей тип шару може бути використано {{PLURAL:$2|1=лише із картографічним сервісом|лише із наступними картографічними сервісами:}} $1", "maps-coordinates-description": "Перехопиник парсеру для форматування координат із будь-якого у будьякий формат, що підтримується.", "maps-displaymap-description": "Відображення географічних карт без жодних вікі-маркерів на них.", - "maps-displaypoint-description": "Показ географічних карт із одією або декількома вікі-позначками на них.", "maps-distance-description": "Перетворення відстані, вираженої в одних одиницях, у їх еквівалент у інших одиницях.", "maps-finddestination-description": "Знаходить місце призначення від заданої початкової точки (може бути у будь якому із підтримуваних форматів), початкового нарямку і відстані.", "maps-geocode-description": "Дозволяє геокодування адрес, іншими словами перетворює зрозумілі для людини розташування у набори координат. Підтримується декілька сервісів геокодування, які не варто плутати з сервісами картографування.", @@ -98,7 +99,6 @@ "maps-displaymap-par-wmsoverlay": "Використовувати накладення WMS", "maps-fullscreen-button": "Перемкнути повноекранний режим", "maps-fullscreen-button-tooltip": "Переглянути мапу на весь екран або як вбудовану.", - "maps-googlemaps3-par-enable-fullscreen": "Увімкнути кнопку повноекранного режиму", "validation-error-invalid-location": "Параметр $1 повинен бути коректним місцем розташування.", "validation-error-invalid-locations": "Параметр $1 повинен бути одним або більше коректних місць розташування.", "validation-error-invalid-width": "Параметр $1 повинен бути коректною шириною.", @@ -124,7 +124,12 @@ "maps_map_cannot_be_displayed": "Мапа не може бути відображена.", "maps-geocoder-not-available": "Функція геокодування мап недоступна. Ваше місце розташування не може бути геокодоване.", "maps_leaflet": "Leaflet", - "maps_click_to_activate": "Натисність щоб активувати мапу", + "maps-leaflet-par-defzoom": "Дозволяє задавати масштаб карти за замовчуванням.", + "maps-leaflet-par-layer": "Шар, що буде показано, коли мапа завантажиться.", + "maps-leaflet-par-overlaylayers": "Накладення шарів, що будуть показані, коли завантажиться мапа.", + "maps-leaflet-par-maxclusterradius": "Максимальний радіус, що буде покритий кластером від центрального маркера (в пікселях).", + "maps-leaflet-par-clusterspiderfy": "При клацанні на кластер при нижньому рівні масштабу ми розгортаємо його так, щоб Ви могли побачити всі його маркери.", + "maps_click_to_activate": "Натисність, щоб активувати мапу", "maps_centred_on": "Центр мапи — $1, $2.", "maps-par-mappingservice": "Дозволяє налаштувати картографічний сервіс, який буде використовуватися для генерації карти.", "maps-par-resizable": "Робить карту змінного розміру, перетяганням в правому нижньому куті.", @@ -134,9 +139,11 @@ "maps-par-width": "Дозволяє задати ширину карти. За замовчуванням пікселі прийняті як одиниці, але ви можете вибрати одну з цих одиниць: px, ex, em, %.", "maps-par-height": "Дозволяє задати висоту карти. За замовчуванням пікселі прийняті як одиниці, але ви можете вибрати одну з цих одиниць: px, ex, em, %.", "maps-par-centre": "Місцевість відносно якої карта має центруватися", + "maps-par-enable-fullscreen": "Увімкнути кнопку повноекранного режиму", + "maps-par-kml": "Файли KML для завантаження на карту.", + "maps-par-markercluster": "Дозволяє об'єднувати декілька прилеглих маркерів в один маркер", "maps-googlemaps3-incompatbrowser": "Веб-переглядач несумісний із Картами Google версії 3.", "maps-googlemaps3-par-imageoverlays": "Дозволяє додати зображення, яке буде показано в зазначеному місці на карті.", - "maps-googlemaps3-par-markercluster": "Дозволяє об'єднувати декілька прилеглих маркерів в один маркер", "maps-googlemaps3-par-type": "Тим карти, який буде показуватись спочатку.", "maps-googlemaps3-par-types": "Типи карти, які будуть доступні через керування типом.", "maps-googlemaps3-par-layers": "Спеціальні шари для завантаження у карту.", @@ -144,17 +151,20 @@ "maps-googlemaps3-par-zoomstyle": "Стиль елементу керування масштабом.", "maps-googlemaps3-par-typestyle": "Стиль елементу керування типом.", "maps-googlemaps3-par-autoinfowindows": "Автоматично відкрити всі інформаційні вікна, після завантаження сторінки.", - "maps-googlemaps3-par-kml": "Файли KML для завантаження на карту.", "maps-googlemaps3-par-gkml": "Файли KML, розташовані на серверах Google для завантаження на карту.", "maps-googlemaps3-par-fusiontables": "Ідентифікатори таблиць Google Fusion, які повинні бути завантажені на карту.", "maps-googlemaps3-par-tilt": "Нахил карти при використанні Карт Google.", "maps-googlemaps3-par-kmlrezoom": "Масштабування карти після завантаження KML шарів.", "maps-googlemaps3-par-poi": "Показати визначні пам'ятки.", + "maps-googlemaps3-par-clustergridsize": "Розмір сітки кластера в пікселях.", + "maps-par-clustermaxzoom": "Максимальний рівень наближення, де кластери можуть існувати.", + "maps-par-clusterzoomonclick": "Чи є збільшення до кластеру поведінкою за замовчуванням при натисканні на нього.", + "maps-par-maxclusterradius": "Максимальний радіус, який буде покритий кластером.", + "maps-googlemaps3-par-clusteraveragecenter": "Чи повинен центр кожного кластеру бути середнім усіх міток у ньому.", + "maps-googlemaps3-par-clusterminsize": "Мінімальне число міток у кластері, починаючи з якого мітки сховані, а показано їх число.", "maps-openlayers-par-controls": "Елементи керування, які буде розміщено на карті.", "maps-openlayers-par-layers": "Шари, які будуть доступні в селекторі шару. Перший шар буде показано під час завантаження карти.", "maps-openlayers-par-overlays": "Накладання шарів, які будуть доступні у селекторі шару. Ці шари відображаються поверх звичайного шару на кшталт маркеру.", - "maps-osm-par-thumbs": "Показувати мініатюри", - "maps-osm-par-photos": "Показувати фото", "mapeditor": "Редактор карт", "specialpages-group-maps": "Карти", "mapeditor-parser-error": "Сталася помилка при обробці метаданих. Ігноруються введені дані.", @@ -190,5 +200,42 @@ "mapeditor-imageoverlay-button": "Додати накладення зображення", "mapeditor-form-field-image": "Зображення", "mapeditor-imageoverlay-title": "Деталі накладання зображення", - "mapeditor-form-field-visitedicon": "Іконка для відвіданого" + "mapeditor-form-field-visitedicon": "Іконка для відвіданого", + "semanticmaps-unrecognizeddistance": "Значення $1 є недопустимою відстанню.", + "semanticmaps-kml-link": "Переглянути KML-файл", + "semanticmaps-default-kml-pagelink": "Переглянути сторінку $1", + "semanticmaps-latitude": "Широта: $1", + "semanticmaps-longitude": "Довгота: $1", + "semanticmaps-altitude": "Висота над рівнем моря: $1", + "semanticmaps-forminput-locations": "Місця", + "semanticmaps-par-staticlocations": "Перелік місць для додавання на карту разом із запитуваними даними. Наприклад, до display_points можна додати назву, опис та піктограму, використовуючи тильду „~“ в якості роздільника.", + "semanticmaps-par-showtitle": "Показує чи не показує заголовок в інформаційному вікні маркера. Вимикання цього корисне при використанні шаблону для форматування інформаційного вмісту вікна.", + "semanticmaps-par-hidenamespace": "Показувати заголовок простору назв у інформаційному вікні маркера", + "semanticmaps-par-centre": "Центр карти. Якщо не задано, то карта автоматично вибере оптимальний центр, який дозволяє відобразити всі маркери на карті.", + "semanticmaps-par-template": "Шаблон для форматування вмісту інформаційного вікна.", + "semanticmaps-par-geocodecontrol": "Показати управління геокодуваням.", + "semanticmaps-par-activeicon": "Піктограма, яка буде відображатися замість типового маркера, коли активна сторінка рівна результату запиту", + "semanticmaps-par-pagelabel": "Коли задано \"так\", то усі маркери матимуть \"inlineLabel\" з посиланням на сторінку, яка містить координати для маркера", + "semanticmaps-par-ajaxcoordproperty": "Назва властивості координат, яка використовується для побудови ajax-запиту.", + "semanticmaps-par-ajaxquery": "Другий запит, що надсилається через ajax для отримання додаткових координат.", + "semanticmaps-par-userparam": "Значення, що передається в кожен виклик шаблону, якщо шаблон використовується", + "semanticmaps-kml-text": "Текст, пов'язаний з кожною сторінкою. Нехтується запитаними додатковими властивостями, якщо такі є.", + "semanticmaps-kml-title": "Типовий заголовок для результатів", + "semanticmaps-kml-linkabsolute": "Посилання мають бути абсолютними (на відміну від відносних)", + "semanticmaps-kml-pagelinktext": "Текст, який використовується для посилань на сторінку, в яких $1 буде замінено на назву сторінки", + "semanticmaps-shapes-improperformat": "Неправильне форматування з $1. Будь ласка, дивіться документацію для форматування", + "semanticmaps-shapes-missingshape": "Немає форм для $1, див. документацію за доступними формами", + "validator-type-mapscircle": "Географічне коло", + "validator-type-mapscircle-list": "Список кіл", + "validator-type-mapsimageoverlay": "Накладення зображення", + "validator-type-mapsimageoverlay-list": "Список накладень зображень", + "validator-type-mapsline": "Географічна лінія", + "validator-type-mapsline-list": "Список ліній", + "validator-type-mapslocation": "Географічна місцевість", + "validator-type-mapslocation-list": "Список місцевостей", + "validator-type-mapsrectangle": "Географічний прямокутник", + "validator-type-mapsrectangle-list": "Список прямокутників", + "validator-type-mapspolygon": "Географічний багатокутник", + "validator-type-mapspolygon-list": "Список географічних багатокутників", + "validator-type-wmsoverlay": "Накладення Web Map Service" } diff --git a/i18n/vi.json b/i18n/vi.json index d7b130ca1..36cb04a6c 100644 --- a/i18n/vi.json +++ b/i18n/vi.json @@ -64,13 +64,10 @@ "maps_unrecognized_coords_for": "Không thể nhận ra {{PLURAL:$2|tọa độ|các tọa độ}} sau nên bản đồ bỏ qua nó:\n$1", "maps_map_cannot_be_displayed": "Không thể hiển thị bản đồ.", "maps-geocoder-not-available": "Không thể mã hóa vị trí của bạn vì tính năng mã hóa địa lý của Bản đồ không có sẵn.", - "maps_osm": "OpenStreetMap", "maps_click_to_activate": "Nhấn chuột vào bản đồ để kích hoạt", "maps_centred_on": "Bản đồ với trung tậm tại $1, $2.", "maps-openlayers-par-controls": "Các điều khiển đặt trên bản đồ.", "maps-openlayers-par-layers": "Các lớp sẽ có sẵn trong hộp chọn lớp. Lớp đầu tiên là lớp mặc định.", - "maps-osm-par-thumbs": "Hiện hình thu nhỏ", - "maps-osm-par-photos": "Hiện hình ảnh", "mapeditor": "Sửa đổi bản đồ", "specialpages-group-maps": "Bản đồ", "mapeditor-none-text": "Không có", @@ -98,5 +95,14 @@ "mapeditor-mapparam-defoption": "—Chọn tham số—", "mapeditor-imageoverlay-button": "Thêm lớp phủ hình ảnh", "mapeditor-form-field-image": "Hình ảnh", - "mapeditor-imageoverlay-title": "Chi tiết lớp phủ hình ảnh" + "mapeditor-imageoverlay-title": "Chi tiết lớp phủ hình ảnh", + "semanticmaps-unrecognizeddistance": "Giá trị $1 không phải là tầm hợp lệ.", + "semanticmaps-kml-link": "Xem tập tin KML", + "semanticmaps-default-kml-pagelink": "Xem trang $1", + "semanticmaps-forminput-locations": "Các vị trí", + "semanticmaps-par-staticlocations": "Danh sách các vị trí để thêm vào bản đồ cùng với dữ liệu được truy vấn. Giống như với display_points, bạn có thể đặt tên, miêu tả, và hình tượng cho mỗi đánh dấu bằng cách phân tách dùng dấu ngã (~).", + "semanticmaps-par-showtitle": "Tên tùy chọn của cửa sổ thông tin đánh dấu. Có thể để trống để định dạng nội dung cửa sổ thông tin dùng bản mẫu.", + "semanticmaps-par-centre": "Trung tâm của bản đồ. Nếu không có, bản đồ sẽ tự động chọn trung tâm tối ưu bao gồm tất cả các dấu trên bản đồ.", + "semanticmaps-par-template": "Bản đồ dùng để định dạng nội dung của cửa sổ thông tin.", + "semanticmaps-par-geocodecontrol": "Hiện điều khiển mã hóa địa lý." } diff --git a/i18n/zh-hans.json b/i18n/zh-hans.json index 4ea0c01aa..5d3e967b8 100644 --- a/i18n/zh-hans.json +++ b/i18n/zh-hans.json @@ -8,21 +8,23 @@ "PhiLiP", "Qiyue2001", "Xiaomingyan", - "Yfdyh000" + "Yfdyh000", + "Byfserag", + "Linforest" ] }, - "maps-desc": "允许嵌入动态地图到wiki页面、地址的地理编码等地理学操作", + "maps-desc": "允许嵌入动态地图到wiki页面,将地址转换为地理编码,及进行其他地理学操作", "right-geocode": "地理编码", "action-geocode": "在此wiki进行地理编码", "maps_map": "地图", "maps-tracking-category": "有由地图扩展描绘地图的页面", - "maps-loading-map": "载入地图中……", + "maps-loading-map": "正在载入地图...", "maps-load-failed": "无法加载地图!", "maps-markers": "标记", "maps-copycoords-prompt": "CTRL+C, ENTER", "maps-searchmarkers-text": "筛选标记", "maps-others": "其他", - "maps-kml-parsing-failed": "解析一个或更多KML文件失败。这通常是因为检索失败或格式不正确的XML。", + "maps-kml-parsing-failed": "解析一个或多个KML文件失败。这通常是因为检索失败或格式不正确的XML。", "maps-ns-layer": "图层", "maps-ns-layer-talk": "图层讨论", "maps-layer-property": "属性", @@ -31,7 +33,7 @@ "maps-layerdef-invalid": "$1个无效定义", "maps-layerdef-invalid-fatal": "致命的无效定义", "maps-layerdef-wrong-namespace": "图层定义仅在“$1”名字空间的页面有效", - "maps-layerdef-equal-layer-name": "图层名称必须在相同图层页面中是唯一的。“$1”已被另一图层使用。", + "maps-layerdef-equal-layer-name": "图层名称在相同图层页面中必须唯一。“$1”已被另一图层使用。", "maps-layerpage-usage": "带有使用图层“$1”的地图页面", "maps-layerpage-nousage": "目前没有页面使用此图层。", "maps-error-invalid-layertype": "没有类型“$1”的图层。只支持{{PLURAL:$3|此|这些}}类型:$2", @@ -39,29 +41,53 @@ "validation-error-invalid-layer": "参数“$1”必须是一个有效图层。", "validation-error-invalid-layers": "参数“$1”必须是一个或多个有效图层。", "validation-error-no-non-numeric": "参数“$1”必须是一个非数值字符串。", - "validation-error-no-non-numerics": "参数“$1”必须是一个或更多非数值字符串。", + "validation-error-no-non-numerics": "参数“$1”必须是一个或多个非数值字符串。", "maps-layer-of-type": "图层类型“$1”", "maps-layer-of-type-and-name": "类型“$1”的图层“$2”", - "maps-layer-type-supported-by": "此图层类型只能与{{PLURAL:$2|此|这些}}映射服务使用:$1。", + "maps-layer-type-supported-by": "此图层类型{{PLURAL:$2|只能与$1映射服务一起使用|可与这些映射服务一起使用:$1}}。", "maps-coordinates-description": "要格式化坐标的解析器钩,来自并转换至任何支持的格式。", + "maps-displaymap-description": "显示地理地图,而不需要在上面显示任何wiki定义的标记。", + "maps-distance-description": "将使用某个受支持单位的距离转换为其使用其他单位的等值。", + "maps-finddestination-description": "提供起点(可以是任意支持的格式)、起始方位角和一段距离来查找目的地。", + "maps-geocode-description": "启用地址的地理编码,换句话说,将人类可读的位置变成一组坐标。这支持几种地理编码服务,而这不应与映射服务相混淆。", + "maps-geodistance-description": "计算两点之间的地理距离,可使用任何支持的格式作为起点和终点。", + "maps-mapsdoc-description": "显示带参数的表格,用以显示指定的映射服务与其默认值和描述。", + "maps-layerdefinition-description": "描述一个可以通过其他地图功能显示的自定义图册。", + "maps-mapsdoc-par-service": "显示参数文档的映射服务。", "maps-mapsdoc-par-language": "显示文档的语言。如果没有翻译可用,将使用英语。", "maps-coordinates-par-location": "您希望格式化的坐标。", "maps-coordinates-par-format": "目标坐标的格式。", + "maps-coordinates-par-directional": "指示坐标是否应输出方向。", + "maps-distance-par-distance": "要转换至其使用指定单位的等值的距离。", + "maps-distance-par-decimals": "结果值中使用的小数位数最大数。", "maps-distance-par-unit": "输出的距离单位。", "maps-finddestination-par-location": "初始位置。", "maps-finddestination-par-bearing": "最初的影响。", "maps-finddestination-par-distance": "旅行的距离。", "maps-finddestination-par-format": "输出目的地的格式。", - "maps-geocode-par-location": "您希望发送到的地址。", + "maps-finddestination-par-directional": "指示目的地格式是否应有方向性。", + "maps-finddestination-par-allowcoordinates": "指示是否允许坐标。如设置为否,将只接受地址。", + "maps-finddestination-par-geoservice": "当值是一个地址时,要对其进行编码的地理编码服务。", + "maps-finddestination-par-mappingservice": "表明使用此函数的映射服务的参数。这将允许地图使用映射服务最佳参数,覆盖服务参数的默认值。(例如:当使用Google地图时,Google地理编码将被使用。)", + "maps-geocode-par-location": "您希望进行地理编码的地址。", + "maps-geocode-par-mappingservice": "您要使用的地理编码服务。参见可用地理编码服务。", + "maps-geocode-par-geoservice": "此参数允许您表明您在将此地理编码请求与特定映射服务结合使用。每个映射服务可以覆盖地理编码服务的默认值。这是出于法律上的考虑,因为除了与Google地图一起使用的情况外,您不能使用Google地理编码服务。设置此参数而不是用于服务的参数,将确保您不会使用无效的组合。", "maps-geocode-par-allowcoordinates": "允许禁用此功能的坐标支持。值必须为“yes”或“no”。如果为no,所有值将被编码,即便坐标有效。", "maps-geocode-par-format": "生成坐标的格式。", + "maps-geocode-par-directional": "指示坐标是否应输出方向。", "maps-geodistance-par-location1": "要计算间距的集中第一个点。", "maps-geodistance-par-location2": "要计算间距的集中第二个点。", "maps-geodistance-par-unit": "要输出的距离单位。", + "maps-geodistance-par-decimals": "结果值中使用的小数位数最大数。", "maps-geodistance-par-mappingservice": "要用于对任意地址编码的地址编码服务。", "maps-geodistance-par-geoservice": "映射服务与此解析器函数一起工作。这会影响默认的地理编码服务值。", "maps-displaymap-par-mappingservice": "允许设置将被用于生成地图的映射服务。", "maps-displaymap-par-coordinates": "要在地图上显示的一个或多个位置。它们将以标记显示。", + "maps-displaymap-par-visitedicon": "原始标记被点击后,要被用作标记图标的图片文件名", + "maps-displaymap-par-zoom": "允许设置地图的缩放级别。当未提供并且地图上存在多个标记时,将使用最合适缩放级别而非默认配置。", + "maps-displaymap-par-centre": "允许设置地图中心点的坐标以用于display_point。同时接受地址和坐标。当此属性未提供时,地图将集中于提供的标记上,或提供的标记之间。", + "maps-displaymap-par-title": "允许设置将在所有没有具体标题的标记弹窗中显示的文本。当与标签一起使用时,标题将被加粗,并加下划线。", + "maps-displaymap-par-label": "允许设置将在所有标记中的弹出窗口显示的文本,只要它们不包含特定标签的话。", "maps-displaymap-par-icon": "允许设置图标用于所有标记。", "maps-displaymap-par-circles": "圈起以显示", "maps-displaymap-par-copycoords": "当点击可以复制坐标的位置时显示对话框", @@ -74,7 +100,6 @@ "maps-displaymap-par-wmsoverlay": "使用一个WMS覆盖", "maps-fullscreen-button": "切换全屏显示", "maps-fullscreen-button-tooltip": "全屏查看地图或嵌入。", - "maps-googlemaps3-par-enable-fullscreen": "启用全屏按钮", "validation-error-invalid-location": "参数 $1 必须是一个有效的位置。", "validation-error-invalid-locations": "参数 $1 必须有一个或多个有效的位置。", "validation-error-invalid-width": "参数 $1 必须是一个有效的宽度。", @@ -100,18 +125,26 @@ "maps_map_cannot_be_displayed": "该地图无法显示。", "maps-geocoder-not-available": "地图的地理编码功能不可用。您所在地区不能被编码。", "maps_leaflet": "Leaflet", - "maps-leaflet-par-zoom": "允许设置地图的缩放级别。", "maps-leaflet-par-defzoom": "允许设置地图的默认缩放级别。", - "maps-leaflet-par-resizable": "允许地图通过拖放右下角改变大小。", + "maps-leaflet-par-layer": "在地图加载时将显示的图层。", + "maps-leaflet-par-overlaylayers": "在地图加载时将显示的覆盖图层。", + "maps-leaflet-par-maxclusterradius": "群集将从中心标记处遮住的最大半径(像素)。", + "maps-leaflet-par-clusterspiderfy": "当您在下方缩放级别点击群集时,我们使其蜘蛛化,这样您可以看见它所有的标记。", "maps_click_to_activate": "点击激活地图", "maps_centred_on": "地图居中在$1,$2。", + "maps-par-mappingservice": "允许设置将被用于生成地图的映射服务。", + "maps-par-resizable": "通过拖放右下角使地图大小可变。", "maps-par-searchmarkers": "允许通过嵌入在地图中的字段搜索特定标记。", + "maps-par-geoservice": "要用于地址和坐标间翻译的地理编码服务。", + "maps-par-zoom": "地图的缩放级别。对于带标记的地图,这将默认放大到仍可显示所有标记的最大级别。", "maps-par-width": "允许设置地图宽度。默认情况下像素将被假定为单位,但您可以明确指定这些单位之一:px、ex、em、%。", "maps-par-height": "允许设置地图高度。默认情况下像素将被假定为单位,但您可以明确指定这些单位之一:px、ex、em、%。", "maps-par-centre": "地图上的位置应该居中", + "maps-par-enable-fullscreen": "启用全屏按钮", + "maps-par-kml": "加载地图上的KML文件。", + "maps-par-markercluster": "允许将多个附近标记合并为一个标记", "maps-googlemaps3-incompatbrowser": "您的浏览器不兼容Google Maps v3。", "maps-googlemaps3-par-imageoverlays": "允许添加图片以在地图的特定地点显示。", - "maps-googlemaps3-par-markercluster": "允许将多个附近标记合并为一个标记", "maps-googlemaps3-par-type": "首先显示的地图类型。", "maps-googlemaps3-par-types": "将通过类型控制可用的地图类型。", "maps-googlemaps3-par-layers": "要加载在地图上的特殊图层。", @@ -119,15 +152,20 @@ "maps-googlemaps3-par-zoomstyle": "缩放控制的样式。", "maps-googlemaps3-par-typestyle": "类型控制的样式。", "maps-googlemaps3-par-autoinfowindows": "在页面加载后,自动打开所有信息窗口。", - "maps-googlemaps3-par-kml": "加载地图上的KML文件。", "maps-googlemaps3-par-gkml": "由Google运营的加载地图上的KML文件。", "maps-googlemaps3-par-fusiontables": "应加载至地图的Google融合表的ID。", "maps-googlemaps3-par-tilt": "使用Google地图时的地图标题。", "maps-googlemaps3-par-kmlrezoom": "在KML图层加载后重新缩放地图。", "maps-googlemaps3-par-poi": "显示感兴趣的点。", + "maps-googlemaps3-par-clustergridsize": "群集的网格大小(像素)。", + "maps-par-clustermaxzoom": "可能存在群集的最大缩放级别。", + "maps-par-clusterzoomonclick": "在群集上默认的点击行为是否为放大。", + "maps-par-maxclusterradius": "群集将覆盖的半径最大值。", + "maps-googlemaps3-par-clusteraveragecenter": "每个集群的中心是否应为集群中所有标记的平均值。", + "maps-googlemaps3-par-clusterminsize": "在标记被隐藏并且显示计数时,集群中标记的最小值。", "maps-openlayers-par-controls": "要放置地图上的控件。", - "maps-osm-par-thumbs": "显示大拇指", - "maps-osm-par-photos": "显示图片", + "maps-openlayers-par-layers": "将在图层选择器中可用的图层。第一个图层将在地图加载时显示。", + "maps-openlayers-par-overlays": "将在图层选择器中可用的覆盖图层。这些图层将在一般图层上方显示,就像一个标记。", "mapeditor": "地图编辑器", "specialpages-group-maps": "地图", "mapeditor-parser-error": "解析元数据时出错。忽略用户输入。", @@ -142,6 +180,7 @@ "mapeditor-clear-button": "明确地图", "mapeditor-code-title": "维基代码", "mapeditor-import-title": "导入维基代码", + "mapeditor-import-note": "请注意解析器期望在wiki代码上应用非常严格的格式。这里输入的代码应匹配由导出功能输出的代码。", "mapeditor-form-title": "编辑详情", "mapeditor-link-title-switcher-popup-text": "带文本的弹出菜单", "mapeditor-link-title-switcher-link-text": "链接", @@ -162,5 +201,42 @@ "mapeditor-imageoverlay-button": "加入图像覆盖", "mapeditor-form-field-image": "图片", "mapeditor-imageoverlay-title": "图像覆盖详细信息", - "mapeditor-form-field-visitedicon": "已浏览图标" + "mapeditor-form-field-visitedicon": "已浏览图标", + "semanticmaps-unrecognizeddistance": "取值$1不是有效的距离。", + "semanticmaps-kml-link": "查看KML文件", + "semanticmaps-default-kml-pagelink": "检视页面 $1", + "semanticmaps-latitude": "纬度:$1", + "semanticmaps-longitude": "经度:$1", + "semanticmaps-altitude": "绝对海拔高度:$1", + "semanticmaps-forminput-locations": "位置", + "semanticmaps-par-staticlocations": "要添加至地图的位置及查询的数据的列表。如同display_points,你可以给每个位置添加标题、说明,用浪纹分隔“~”。", + "semanticmaps-par-showtitle": "是否在标记信息窗口之中显示标题。当采用模板对信息窗口内容进行格式编排的时候,关闭此项往往会有所帮助。", + "semanticmaps-par-hidenamespace": "在标记信息窗口中显示命名空间标题", + "semanticmaps-par-centre": "地图的中心。当未加提供的时候,地图会自动挑选最佳的中心,从而在地图上显示所有的标记。", + "semanticmaps-par-template": "用来对信息窗口内容进行格式编排的模板。", + "semanticmaps-par-geocodecontrol": "显示地理编码控件。", + "semanticmaps-par-activeicon": "当活跃页面等于查询结果时将显示选定标记而不是默认标记", + "semanticmaps-par-pagelabel": "当您设置为“yes”时,所有标记将拥有一个“inlineLabel”带有一个链接至包含坐标标记的页面", + "semanticmaps-par-ajaxcoordproperty": "用于构造ajax查询的坐标属性名称。", + "semanticmaps-par-ajaxquery": "通过ajax发送以取得额外坐标的第二查询。", + "semanticmaps-par-userparam": "当模板被使用时,传递到每个模板调用的值", + "semanticmaps-kml-text": "与每个页面相关联的文本。会被额外的查询属性(如果有的话)所覆盖。", + "semanticmaps-kml-title": "结果的默认标题", + "semanticmaps-kml-linkabsolute": "链接究竟应当是绝对地址还是相对地址", + "semanticmaps-kml-pagelinktext": "用于那些指向该页面的链接的文本;其中,页面标题将取代$1", + "semanticmaps-shapes-improperformat": "$1 的格式不正确。请参阅文档格式", + "semanticmaps-shapes-missingshape": "找不到用于$1的形状。请参见文档以查看可用形状", + "validator-type-mapscircle": "地理圈", + "validator-type-mapscircle-list": "圈列表", + "validator-type-mapsimageoverlay": "图片覆盖", + "validator-type-mapsimageoverlay-list": "图片覆盖列表", + "validator-type-mapsline": "地理线", + "validator-type-mapsline-list": "线列表", + "validator-type-mapslocation": "地理位置", + "validator-type-mapslocation-list": "位置列表", + "validator-type-mapsrectangle": "地理矩形", + "validator-type-mapsrectangle-list": "矩形列表", + "validator-type-mapspolygon": "地理多边形", + "validator-type-mapspolygon-list": "地理多边形列表", + "validator-type-wmsoverlay": "网络地图服务覆盖" } diff --git a/i18n/zh-hant.json b/i18n/zh-hant.json index 6aeccb8f1..a1185f381 100644 --- a/i18n/zh-hant.json +++ b/i18n/zh-hant.json @@ -10,7 +10,10 @@ "Simon Shek", "Waihorace", "LNDDYL", - "Macofe" + "Macofe", + "1233thehongkonger", + "Liuxinyu970226", + "Oapbtommy" ] }, "maps-desc": "可讓 Wiki 頁面嵌入動態地圖,支援使用地理編碼標記位置,以及地理相關操作", @@ -46,7 +49,6 @@ "maps-layer-type-supported-by": "此類型圖層{{PLURAL:$2|只可使用 $1 地圖服務|可使用以下地圖服務:$1}}。", "maps-coordinates-description": "用來格式化座標的分析器連結(Hook),可在支援的格式之間轉換。", "maps-displaymap-description": "顯示地理地圖,不顯示任何 Wiki 定義的標記於地圖上。", - "maps-displaypoint-description": "顯示地理地圖,顯示所有 Wiki 定義的標記於地圖上。", "maps-distance-description": "可以使用任何支援的單位轉換距離的單位", "maps-finddestination-description": "根據起點 (可使用支援的任何格式)、初始方位與距離找尋目的地。", "maps-geocode-description": "開啟地圖編碼位置,將可閱讀的位置名稱轉換為座標。地圖編碼有許多不同服務可選擇,與地圖服務不同。", @@ -64,7 +66,6 @@ "maps-displaymap-par-wmsoverlay": "使用 WMS 圖層", "maps-fullscreen-button": "切換全螢幕", "maps-fullscreen-button-tooltip": "使用全螢幕或嵌入方式檢視地圖。", - "maps-googlemaps3-par-enable-fullscreen": "開啟全螢幕的按鈕", "validation-error-invalid-location": "參數 \"$1\" 必須是一個有效的位置。", "validation-error-invalid-locations": "參數 \"$1\" 必須有一個或多個有效的位置。", "validation-error-invalid-width": "參數 \"$1\" 必須是一個有效的寬度。", @@ -82,11 +83,12 @@ "maps-latitude": "緯度:", "maps-longitude": "經度:", "maps_map_cannot_be_displayed": "該地圖無法顯示。", + "maps-leaflet-par-layer": "此圖層將於地圖加載時顯示", + "maps-leaflet-par-overlaylayers": "此覆蓋圖層將於地圖加載時顯示。", "maps_click_to_activate": "按一下以啟動地圖", "maps_centred_on": "地圖以 $1, $2 為中心。", + "maps-par-enable-fullscreen": "開啟全螢幕的按鈕", "maps-openlayers-par-overlays": "將會在圖層選擇器中可用的覆蓋層。這些圖層將顯示在一個正常的圖層,有點像一個標記。", - "maps-osm-par-thumbs": "顯示大拇指", - "maps-osm-par-photos": "顯示圖片", "mapeditor": "地圖編輯器", "specialpages-group-maps": "地圖", "mapeditor-parser-error": "分析描述資料錯誤,忽略使用者輸入。", @@ -121,5 +123,27 @@ "mapeditor-imageoverlay-button": "新增圖片圖層", "mapeditor-form-field-image": "圖片", "mapeditor-imageoverlay-title": "圖片圖層詳細資料", - "mapeditor-form-field-visitedicon": "已瀏覽的圖示" + "mapeditor-form-field-visitedicon": "已瀏覽的圖示", + "semanticmaps-unrecognizeddistance": "數值 $1 不是有效的距離。", + "semanticmaps-kml-link": "檢視 KML 檔案", + "semanticmaps-default-kml-pagelink": "檢視頁面 $1", + "semanticmaps-latitude": "緯度:$1", + "semanticmaps-longitude": "經度:$1", + "semanticmaps-altitude": "海拔:$1", + "semanticmaps-forminput-locations": "位置", + "semanticmaps-par-staticlocations": "與查詢的資料一起新增到地圖的位置清單。 如 display_points,您可新增每個位置的標題、描述與圖示使用波浪號 \"~\" 作為分隔符號。", + "semanticmaps-par-showtitle": "是否在標記資訊視窗之中顯示標題。當使用模板對資訊視窗內容進行格式編排的時,關閉此選項通常會有所幫助。", + "semanticmaps-par-hidenamespace": "在標記資訊視窗中顯示命名空間的標題", + "semanticmaps-par-centre": "地圖的中心位置。若不指定,地圖會自動挑選可顯示所有標記於地圖上的最佳中心位置。", + "semanticmaps-par-template": "用來對資訊視窗內容進行格式編排的模板。", + "semanticmaps-par-geocodecontrol": "顯示地理編碼控制元件。", + "semanticmaps-par-activeicon": "當使用的頁面為查詢結果時,用來替代預設標記要顯示的圖示", + "semanticmaps-par-pagelabel": "當設為 \"是\" 時,所有的標記會有 \"inlineLabel\" 並連結至含有標記座標的頁面。", + "semanticmaps-kml-text": "與每個頁面關聯的文字。可被額外的查詢屬性所覆蓋 (若有設定)。", + "semanticmaps-kml-title": "查詢結果的預設標題", + "semanticmaps-kml-linkabsolute": "連結應為絕對位址 (相反於相對位址)", + "semanticmaps-kml-pagelinktext": "連結至頁面要使用的文字,文字中的 $1 會取代為頁面標題", + "semanticmaps-shapes-improperformat": "$1 的格式有誤,請參考格式說明文件", + "semanticmaps-shapes-missingshape": "查無 $1 的形狀。請查看說明文件瞭解可用的形狀", + "validator-type-mapslocation": "地理座標" } diff --git a/includes/Element.php b/includes/Element.php index 2725a6c47..5a4ee5c5d 100644 --- a/includes/Element.php +++ b/includes/Element.php @@ -5,11 +5,10 @@ use MWException; /** - * Interface for elements that can be places upon a map. + * Interface for elements that can be placed upon a map. * * @since 3.0 * - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -45,14 +44,9 @@ public function setOptions( ElementOptions $options ); } -class OptionsObject { +class ElementOptions { - /** - * @since 3.0 - * - * @var array - */ - protected $options = array(); + private $options = []; /** * @since 3.0 @@ -60,11 +54,11 @@ class OptionsObject { * @param string $name * @param mixed $value * - * @throws MWException + * @throws \InvalidArgumentException */ public function setOption( $name, $value ) { if ( !is_string( $name ) ) { - throw new MWException( 'Option name should be a string' ); + throw new \InvalidArgumentException( 'Option name should be a string' ); } $this->options[$name] = $value; @@ -75,15 +69,16 @@ public function setOption( $name, $value ) { * * @param string $name * - * @throws MWException + * @throws \InvalidArgumentException + * @throws \OutOfBoundsException */ public function getOption( $name ) { if ( !is_string( $name ) ) { - throw new MWException( 'Option name should be a string' ); + throw new \InvalidArgumentException( 'Option name should be a string' ); } if ( !array_key_exists( $name, $this->options ) ) { - throw new MWException( 'Tried to obtain option "' . $name . '" while it has not been set' ); + throw new \OutOfBoundsException( 'Tried to obtain option "' . $name . '" while it has not been set' ); } return $this->options[$name]; @@ -95,15 +90,14 @@ public function getOption( $name ) { * @param string $name * * @return boolean + * @throws \InvalidArgumentException */ public function hasOption( $name ) { + if ( !is_string( $name ) ) { + throw new \InvalidArgumentException( 'Option name should be a string' ); + } + return array_key_exists( $name, $this->options ); } -} - -class ElementOptions extends OptionsObject { - - - } \ No newline at end of file diff --git a/includes/Geocoder.php b/includes/Geocoder.php index 5b54810e1..4fc14d7e2 100644 --- a/includes/Geocoder.php +++ b/includes/Geocoder.php @@ -3,7 +3,7 @@ namespace Maps; /** - * Base geocoder class to be inherited by classes with a specific geocding implementation. + * Base geocoder class to be inherited by classes with a specific geocoding implementation. * * @since 0.7 * @@ -143,7 +143,7 @@ public function geocode( $address ) { * @return string or false */ protected static function getXmlElementValue( $xml, $tagName ) { - $match = array(); + $match = []; preg_match( "/<$tagName>(.*?)<\/$tagName>/", $xml, $match ); return count( $match ) > 1 ? $match[1] : false; } @@ -159,7 +159,7 @@ protected static function getXmlElementValue( $xml, $tagName ) { * @return array */ public static function getOverrides() { - return array(); + return []; } /** diff --git a/includes/Geocoders.php b/includes/Geocoders.php index 389fdd00a..5145609c2 100644 --- a/includes/Geocoders.php +++ b/includes/Geocoders.php @@ -2,14 +2,14 @@ namespace Maps; -use DataValues\Geo\Formatters\GeoCoordinateFormatter; use DataValues\Geo\Parsers\GeoCoordinateParser; use DataValues\Geo\Values\LatLongValue; +use MapsOldGeocoderAdapter; use MWException; use ValueParsers\ParseException; /** - * Class for geocoder functionality of the Maps extension. + * Class for geocoder functionality of the Maps extension. * * FIXME: this is procedural spaghetti * @@ -22,29 +22,29 @@ final class Geocoders { /** * Associative with geoservice identifiers as keys containing instances of - * the geocoder classes. - * + * the geocoder classes. + * * Note: This list only contains the instances, so is not to be used for - * looping over all available services, as not all of them are guaranteed + * looping over all available services, as not all of them are guaranteed * to have an instance already, use $registeredServices for this purpouse. - * + * * @since 0.7 - * + * * @var Geocoder[] */ - protected static $geocoders = array(); - + protected static $geocoders = []; + /** * Associative with geoservice identifiers as keys containing the class * name of the geocoders. This is used for registration of a geocoder * without immediately instantiating it. - * + * * @since 0.7 - * + * * @var array of string => string */ - public static $registeredGeocoders = array(); - + public static $registeredGeocoders = []; + /** * The global geocoder cache, holding geocoded data when enabled. * @@ -52,181 +52,130 @@ final class Geocoders { * * @var array */ - private static $globalGeocoderCache = array(); - + private static $globalGeocoderCache = []; + /** * Can geocoding happen, ie are there any geocoders available. - * + * * @since 1.0.3 * @var boolean */ protected static $canGeocode = false; - + /** * Returns if this class can do geocoding operations. * Ie. if there are any geocoders available. - * + * * @since 0.7 - * + * * @return boolean */ public static function canGeocode() { self::init(); return self::$canGeocode; } - + /** * Gets a list of available geocoders. - * + * * @since 1.0.3 - * + * * @return array */ public static function getAvailableGeocoders() { self::init(); return array_keys( self::$registeredGeocoders ); } - + /** * Initiate the geocoding functionality. - * + * * @since 1.0.3 - * + * * @return boolean Indicates if init happened */ public static function init() { static $initiated = false; - + if ( $initiated ) { return false; } - + $initiated = true; - + // Register the geocoders. \Hooks::run( 'GeocoderFirstCallInit' ); - + // Determine if there are any geocoders. self::$canGeocode = count( self::$registeredGeocoders ) > 0; - + return true; } - + /** - * This function first determines wether the provided string is a pair or coordinates + * This function first determines whether the provided string is a pair or coordinates * or an address. If it's the later, an attempt to geocode will be made. The function will - * return the coordinates or false, in case a geocoding attempt was made but failed. - * + * return the coordinates or false, in case a geocoding attempt was made but failed. + * * @since 0.7 - * + * * @param string $coordsOrAddress - * @param string $geoservice - * @param string|false $mappingService + * @param string $geoService * @param boolean $checkForCoords * * @return LatLongValue|false */ - public static function attemptToGeocode( $coordsOrAddress, $geoservice = '', $mappingService = false, $checkForCoords = true ) { + public static function attemptToGeocode( $coordsOrAddress, $geoService = '', $checkForCoords = true ) { if ( $checkForCoords ) { - $coordinateParser = new GeoCoordinateParser( new \ValueParsers\ParserOptions() ); + $coordinateParser = new GeoCoordinateParser(); try { return $coordinateParser->parse( $coordsOrAddress ); } catch ( ParseException $parseException ) { - return self::geocode( $coordsOrAddress, $geoservice, $mappingService ); + return self::geocode( $coordsOrAddress, $geoService ); } } else { - return self::geocode( $coordsOrAddress, $geoservice, $mappingService ); + return self::geocode( $coordsOrAddress, $geoService ); } } - - /** - * - * - * @since 0.7 - * - * @param string $coordsOrAddress - * @param string $geoService - * @param string|false $mappingService - * - * @return boolean - */ - public static function isLocation( $coordsOrAddress, $geoService = '', $mappingService = false ) { - return self::attemptToGeocode( $coordsOrAddress, $geoService, $mappingService ) !== false; - } - - /** - * Geocodes an address with the provided geocoding service and returns the result - * as a string with the optionally provided format, or false when the geocoding failed. - * - * @since 0.7 - * - * @param string $coordsOrAddress - * @param string $service - * @param string $mappingService - * @param boolean $checkForCoords - * @param string $targetFormat The notation to which they should be formatted. Defaults to floats. - * @param boolean $directional Indicates if the target notation should be directional. Defaults to false. - * - * @return string|false - */ - public static function attemptToGeocodeToString( $coordsOrAddress, $service = '', $mappingService = false, $checkForCoords = true, $targetFormat = Maps_COORDS_FLOAT, $directional = false ) { - $geoCoordinate = self::attemptToGeocode( $coordsOrAddress, $service, $mappingService, $checkForCoords ); - - if ( $geoCoordinate === false ) { - return false; - } - - $options = new \ValueFormatters\FormatterOptions( array( - GeoCoordinateFormatter::OPT_FORMAT => $targetFormat, - GeoCoordinateFormatter::OPT_DIRECTIONAL => $directional, - GeoCoordinateFormatter::OPT_PRECISION => 1 / 360000 - ) ); - - $formatter = new GeoCoordinateFormatter( $options ); - return $formatter->format( $geoCoordinate ); - } /** - * Geocodes an address with the provided geocoding service and returns the result + * Geocodes an address with the provided geocoding service and returns the result * as an array, or false when the geocoding failed. * - * FIXME: complexity - * * @since 0.7 * * @param string $address * @param string $geoService - * @param string|false $mappingService - * + * * @return LatLongValue|false * @throws MWException */ - public static function geocode( $address, $geoService = '', $mappingService = false ) { + public static function geocode( $address, $geoService = '' ) { if ( !is_string( $address ) ) { throw new MWException( 'Parameter $address must be a string at ' . __METHOD__ ); - } - + } + if ( !self::canGeocode() ) { return false; } - - $geocoder = self::getValidGeocoderInstance( $geoService, $mappingService ); + + $geocoder = self::getValidGeocoderInstance( $geoService ); // This means there was no suitable geocoder found, so return false. if ( $geocoder === false ) { return false; } - + if ( $geocoder->hasGlobalCacheSupport() ) { $cacheResult = self::cacheRead( $address ); - + // This means the cache returned an already computed set of coordinates. if ( $cacheResult !== false ) { assert( $cacheResult instanceof LatLongValue ); return $cacheResult; - } + } } $coordinates = self::getGeocoded( $geocoder, $address ); @@ -265,20 +214,20 @@ private static function getGeocodedAsArray( Geocoder $geocoder, $address ) { return $coordinates; } - + /** * Returns already coordinates already known from previous geocoding operations, * or false if there is no match found in the cache. - * + * * @since 0.7 - * + * * @param string $address - * + * * @return LatLongValue|boolean false */ - protected static function cacheRead( $address ) { + private static function cacheRead( $address ) { global $egMapsEnableGeoCache; - + if ( $egMapsEnableGeoCache && array_key_exists( $address, self::$globalGeocoderCache ) ) { return self::$globalGeocoderCache[$address]; } @@ -286,73 +235,82 @@ protected static function cacheRead( $address ) { return false; } } - + /** * Writes the geocoded result to the cache if the cache is on. - * + * * @since 0.7 - * + * * @param string $address * @param LatLongValue $coordinates */ - protected static function cacheWrite( $address, LatLongValue $coordinates ) { + private static function cacheWrite( $address, LatLongValue $coordinates ) { global $egMapsEnableGeoCache; - + // Add the obtained coordinates to the cache when there is a result and the cache is enabled. if ( $egMapsEnableGeoCache && $coordinates ) { self::$globalGeocoderCache[$address] = $coordinates; } } - + /** * Registers a geocoder linked to an identifier. - * + * * @since 0.7 - * + * * @param string $geocoderIdentifier - * @param string $geocoderClassName + * @param string|\Maps\Geocoders\Geocoder $geocoder */ - public static function registerGeocoder( $geocoderIdentifier, $geocoderClassName ) { - self::$registeredGeocoders[$geocoderIdentifier] = $geocoderClassName; + public static function registerGeocoder( $geocoderIdentifier, $geocoder ) { + self::$registeredGeocoders[$geocoderIdentifier] = $geocoder; } - + /** * Returns the instance of the geocoder linked to the provided identifier * or the default one when it's not valid. False is returned when there * are no geocoders available. - * + * * @since 0.7 - * + * * @param string $geocoderIdentifier - * - * @return \Maps\Geocoder or false + * + * @return Geocoder|bool */ - protected static function getValidGeocoderInstance( $geocoderIdentifier ) { + private static function getValidGeocoderInstance( $geocoderIdentifier ) { return self::getGeocoderInstance( self::getValidGeocoderIdentifier( $geocoderIdentifier ) ); } - + /** * Returns the instance of a geocoder. This function assumes there is a * geocoder linked to the identifier you provide - if you are not sure * it does, use getValidGeocoderInstance instead. - * + * * @since 0.7 - * + * * @param string $geocoderIdentifier - * - * @return \Maps\Geocoder or false + * + * @return Geocoder|bool + * @throws MWException */ - protected static function getGeocoderInstance( $geocoderIdentifier ) { + private static function getGeocoderInstance( $geocoderIdentifier ) { if ( !array_key_exists( $geocoderIdentifier, self::$geocoders ) ) { if ( array_key_exists( $geocoderIdentifier, self::$registeredGeocoders ) ) { - $geocoder = new self::$registeredGeocoders[$geocoderIdentifier]( $geocoderIdentifier ); - - //if ( $service instanceof iMappingService ) { - self::$geocoders[$geocoderIdentifier] = $geocoder; - //} - //else { - // throw new MWException( 'The geocoder linked to identifier ' . $geocoderIdentifier . ' does not implement .' ); - //} + if ( is_string( self::$registeredGeocoders[$geocoderIdentifier] ) ) { + $geocoderClass = self::$registeredGeocoders[$geocoderIdentifier]; + $geocoder = new $geocoderClass( $geocoderIdentifier ); + } + elseif ( self::$registeredGeocoders[$geocoderIdentifier] instanceof \Maps\Geocoders\Geocoder ) { + $geocoder = new MapsOldGeocoderAdapter( + self::$registeredGeocoders[$geocoderIdentifier], + $geocoderIdentifier + ); + } + else { + throw new MWException( 'Need either class name or Geocoder instance' ); + } + + + self::$geocoders[$geocoderIdentifier] = $geocoder; } else { throw new MWException( 'There is geocoder linked to identifier ' . $geocoderIdentifier . '.' ); @@ -361,23 +319,24 @@ protected static function getGeocoderInstance( $geocoderIdentifier ) { return self::$geocoders[$geocoderIdentifier]; } - + /** * Returns a valid geocoder idenifier. If the given one is a valid main identifier, * it will simply be returned. If it's an alias, it will be turned into the correponding * main identifier. If it's not recognized at all (or empty), the default will be used. * Only call this function when there are geocoders available, else an erro will be thrown. - * + * * @since 0.7 * * @param string $geocoderIdentifier - * - * @return string or false + * + * @return string|bool + * @throws MWException */ - protected static function getValidGeocoderIdentifier( $geocoderIdentifier ) { + private static function getValidGeocoderIdentifier( $geocoderIdentifier ) { global $egMapsDefaultGeoService; static $validatedDefault = false; - + if ( $geocoderIdentifier === '' || !array_key_exists( $geocoderIdentifier, self::$registeredGeocoders ) ) { if ( !$validatedDefault ) { if ( !array_key_exists( $egMapsDefaultGeoService, self::$registeredGeocoders ) ) { @@ -388,7 +347,7 @@ protected static function getValidGeocoderIdentifier( $geocoderIdentifier ) { } } } - + if ( array_key_exists( $egMapsDefaultGeoService, self::$registeredGeocoders ) ) { $geocoderIdentifier = $egMapsDefaultGeoService; } @@ -396,8 +355,8 @@ protected static function getValidGeocoderIdentifier( $geocoderIdentifier ) { return false; } } - + return $geocoderIdentifier; } - -} \ No newline at end of file + +} diff --git a/includes/Maps_BaseFillableElement.php b/includes/Maps_BaseFillableElement.php index 09bbffc5a..e0a459d73 100644 --- a/includes/Maps_BaseFillableElement.php +++ b/includes/Maps_BaseFillableElement.php @@ -3,7 +3,7 @@ /** * @since 2.0 */ -class MapsBaseFillableElement extends MapsBaseStrokableElement implements iFillableMapElement { +class MapsBaseFillableElement extends MapsBaseStrokableElement { protected $fillColor; protected $fillOpacity; @@ -34,10 +34,10 @@ public function hasFillOpacity() { public function getJSONObject( $defText = '' , $defTitle = '' ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $array = array( + $array = [ 'fillColor' => $this->hasFillColor() ? $this->getFillColor() : '#FF0000' , 'fillOpacity' => $this->hasFillOpacity() ? $this->getFillOpacity() : '0.5' , - ); + ]; return array_merge( $parentArray , $array ); } } diff --git a/includes/Maps_BaseStrokableElement.php b/includes/Maps_BaseStrokableElement.php index 6e7f37258..1d4bd674b 100644 --- a/includes/Maps_BaseStrokableElement.php +++ b/includes/Maps_BaseStrokableElement.php @@ -8,7 +8,7 @@ * @licence GNU GPL v2+ * @author Kim Eik < kim@heldig.org > */ -class MapsBaseStrokableElement extends BaseElement implements iStrokableMapElement { +class MapsBaseStrokableElement extends BaseElement { protected $strokeColor; protected $strokeOpacity; @@ -52,11 +52,11 @@ public function hasStrokeWeight() { public function getJSONObject( $defText = '' , $defTitle = '' ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $array = array( + $array = [ 'strokeColor' => $this->hasStrokeColor() ? $this->getStrokeColor() : '#FF0000' , 'strokeOpacity' => $this->hasStrokeOpacity() ? $this->getStrokeOpacity() : '1' , 'strokeWeight' => $this->hasStrokeWeight() ? $this->getStrokeWeight() : '2' - ); + ]; return array_merge( $parentArray , $array ); } diff --git a/includes/Maps_DisplayMapRenderer.php b/includes/Maps_DisplayMapRenderer.php index 262fba024..4daa97ed7 100644 --- a/includes/Maps_DisplayMapRenderer.php +++ b/includes/Maps_DisplayMapRenderer.php @@ -1,7 +1,9 @@ service = $service; - } + private $locationParser; - /** - * Returns the HTML to display the map. - * - * @since 2.0 - * - * @param array $params - * @param Parser $parser - * @param string $mapName - * - * @return string - */ - protected function getMapHTML( array $params, Parser $parser, $mapName ) { - return Html::rawElement( - 'div', - array( - 'id' => $mapName, - 'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;", - 'class' => 'maps-map maps-' . $this->service->getName() - ), - wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() . - Html::element( - 'div', - array( 'style' => 'display:none', 'class' => 'mapdata' ), - FormatJson::encode( $this->getJSONObject( $params, $parser ) ) - ) - ); - } - - /** - * Returns a PHP object to encode to JSON with the map data. - * - * @since 2.0 - * - * @param array $params - * @param Parser $parser - * - * @return mixed - */ - protected function getJSONObject( array $params, Parser $parser ) { - return $params; + public function __construct( MapsMappingService $service ) { + $this->service = $service; } /** @@ -80,35 +35,63 @@ protected function getJSONObject( array $params, Parser $parser ) { * @return string */ public final function renderMap( array $params, Parser $parser ) { + $this->initializeLocationParser( $params ); + $this->handleMarkerData( $params, $parser ); $mapName = $this->service->getMapId(); - $output = $this->getMapHTML( $params, $parser, $mapName ); + $output = $this->getMapHTML( $params, $mapName ); $configVars = Skin::makeVariablesScript( $this->service->getConfigVariables() ); + $this->service->addHtmlDependencies( + self::getLayerDependencies( $params['mappingservice'], $params ) + ); + $this->service->addDependencies( $parser ); $parser->getOutput()->addHeadItem( $configVars ); return $output; } + private function initializeLocationParser( array $params ) { + $this->locationParser = new LocationParser( new ValueParserOptions( [ + 'geoService' => $params['geoservice'] + ] ) ); + } + /** - * Converts the data in the coordinates parameter to JSON-ready objects. - * These get stored in the locations parameter, and the coordinates on gets deleted. - * - * FIXME: complexity + * Returns the HTML to display the map. * - * @since 1.0 + * @param array $params + * @param string $mapName * - * @param array &$params - * @param Parser $parser + * @return string */ - protected function handleMarkerData( array &$params, Parser $parser ) { - if ( is_object( $params['centre'] ) ) { - $params['centre'] = $params['centre']->getJSONObject(); - } + protected function getMapHTML( array $params, $mapName ) { + return Html::rawElement( + 'div', + [ + 'id' => $mapName, + 'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;", + 'class' => 'maps-map maps-' . $this->service->getName() + ], + wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() . + Html::element( + 'div', + [ 'style' => 'display:none', 'class' => 'mapdata' ], + FormatJson::encode( $params ) + ) + ); + } + + /** + * Converts the data in the coordinates parameter to JSON-ready objects. + * These get stored in the locations parameter, and the coordinates on gets deleted. + */ + private function handleMarkerData( array &$params, Parser $parser ) { + $params['centre'] = $this->getCenter( $params['centre'] ); $parserClone = clone $parser; @@ -116,44 +99,80 @@ protected function handleMarkerData( array &$params, Parser $parser ) { $params['wmsoverlay'] = $params['wmsoverlay']->getJSONObject(); } + $params['locations'] = $this->getLocationJson( $params, $parserClone ); + + unset( $params['coordinates'] ); + + $this->handleShapeData( $params, $parserClone ); + + if ( $params['mappingservice'] === 'openlayers' ) { + $params['layers'] = self::evilOpenLayersHack( $params['layers'] ); + } + } + + private function getCenter( $coordinatesOrAddress ) { + if ( $coordinatesOrAddress === false ) { + return false; + } + + try { + // FIXME: a Location makes no sense here, since the non-coordinate data is not used + $location = $this->locationParser->stringParse( $coordinatesOrAddress ); + } + catch ( \Exception $ex ) { + // TODO: somehow report this to the user + return false; + } + + return $location->getJSONObject(); + } + + private function getLocationJson( array $params, $parserClone ) { $iconUrl = MapsMapper::getFileUrl( $params['icon'] ); $visitedIconUrl = MapsMapper::getFileUrl( $params['visitedicon'] ); - $params['locations'] = array(); - - /** - * @var Location $location - */ - foreach ( $params['coordinates'] as $location ) { - $jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '',$visitedIconUrl); - $jsonObj['title'] = $parserClone->parse( $jsonObj['title'], $parserClone->getTitle(), new ParserOptions() )->getText(); - $jsonObj['text'] = $parserClone->parse( $jsonObj['text'], $parserClone->getTitle(), new ParserOptions() )->getText(); - $jsonObj['inlineLabel'] = strip_tags($parserClone->parse( $jsonObj['inlineLabel'], $parserClone->getTitle(), new ParserOptions() )->getText(),''); + $locationJsonObjects = []; - $hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== ''; - $jsonObj['text'] = ( $hasTitleAndtext ? '' . $jsonObj['title'] . '
' : $jsonObj['title'] ) . $jsonObj['text']; - $jsonObj['title'] = strip_tags( $jsonObj['title'] ); + foreach ( $params['coordinates'] as $coordinatesOrAddress ) { + try { + $location = $this->locationParser->stringParse( $coordinatesOrAddress ); + } + catch ( \Exception $ex ) { + // TODO: somehow report this to the user + continue; + } - $params['locations'][] = $jsonObj; + $locationJsonObjects[] = $this->getLocationJsonObject( $location, $params, $iconUrl, $visitedIconUrl, $parserClone ); } - unset( $params['coordinates'] ); + return $locationJsonObjects; + } - $this->handleShapeData( $params, $parserClone ); + private function getLocationJsonObject( Location $location, array $params, $iconUrl, $visitedIconUrl, Parser $parserClone ) { + $jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl ); - if ( $params['mappingservice'] === 'openlayers' ) { - $params['layers'] = self::evilOpenLayersHack( $params['layers'] ); + $jsonObj['title'] = $parserClone->parse( $jsonObj['title'], $parserClone->getTitle(), new ParserOptions() )->getText(); + $jsonObj['text'] = $parserClone->parse( $jsonObj['text'], $parserClone->getTitle(), new ParserOptions() )->getText(); + + if ( isset( $jsonObj['inlineLabel'] ) ) { + $jsonObj['inlineLabel'] = strip_tags($parserClone->parse( $jsonObj['inlineLabel'], $parserClone->getTitle(), new ParserOptions() )->getText(),'
'); } + + $hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== ''; + $jsonObj['text'] = ( $hasTitleAndtext ? '' . $jsonObj['title'] . '
' : $jsonObj['title'] ) . $jsonObj['text']; + $jsonObj['title'] = strip_tags( $jsonObj['title'] ); + + return $jsonObj; } - protected function handleShapeData( array &$params, Parser $parserClone ) { - $textContainers = array( + private function handleShapeData( array &$params, Parser $parserClone ) { + $textContainers = [ &$params['lines'] , &$params['polygons'] , &$params['circles'] , &$params['rectangles'], &$params['imageoverlays'], // FIXME: this is Google Maps specific!! - ); + ]; foreach ( $textContainers as &$textContainer ) { if ( is_array( $textContainer ) ) { @@ -189,8 +208,8 @@ protected function handleShapeData( array &$params, Parser $parserClone ) { public static function evilOpenLayersHack( $layers ) { global $egMapsOLLayerGroups, $egMapsOLAvailableLayers; - $layerDefs = array(); - $layerNames = array(); + $layerDefs = []; + $layerNames = []; foreach ( $layers as $layerOrGroup ) { $lcLayerOrGroup = strtolower( $layerOrGroup ); @@ -222,91 +241,40 @@ public static function evilOpenLayersHack( $layers ) { $layerNames[] = $lcLayerOrGroup; } } - // Image layers. Check validity and add if not present yet: - else { - $layerParts = explode( ';', $layerOrGroup, 2 ); - $layerGroup = $layerParts[0]; - $layerName = count( $layerParts ) > 1 ? $layerParts[1] : null; - - $title = Title::newFromText( $layerGroup, Maps_NS_LAYER ); - - if ( $title !== null && $title->getNamespace() == Maps_NS_LAYER ) { - // TODO: FIXME: This shouldn't be here and using $wgParser, instead it should - // be somewhere around MapsBaseMap::renderMap. But since we do a lot more than - // 'parameter manipulation' in here, we already diminish the information needed - // for this which will never arrive there. - global $wgParser; - // add dependency to the layer page so if the layer definition gets updated, - // the page where it is used will be updated as well: - $rev = Revision::newFromTitle( $title ); - $revId = null; - if( $rev !== null ) { - $revId = $rev->getId(); - } - $wgParser->getOutput()->addTemplate( $title, $title->getArticleID(), $revId ); - - // if the whole layer group is not yet loaded into the map and the group exists: - if( !in_array( $layerGroup, $layerNames ) - && $title->exists() - ) { - if( $layerName !== null ) { - // load specific layer with name: - $layer = MapsLayers::loadLayer( $title, $layerName ); - $layers = new MapsLayerGroup( $layer ); - $usedLayer = $layerOrGroup; - } - else { - // load all layers from group: - $layers = MapsLayers::loadLayerGroup( $title ); - $usedLayer = $layerGroup; - } - - foreach( $layers->getLayers() as $layer ) { - if( ( // make sure named layer is only taken once (in case it was requested on its own before) - $layer->getName() === null - || !in_array( $layerGroup . ';' . $layer->getName(), $layerNames ) - ) - && $layer->isOk() - ) { - $layerDefs[] = $layer->getJavaScriptDefinition(); - } - } - - $layerNames[] = $usedLayer; // have to add this after loop of course! - } - } - else { - wfWarn( "Invalid layer ($layerOrGroup) encountered after validation." ); - } - } } - - MapsMappingServices::getServiceInstance( 'openlayers' )->addLayerDependencies( self::getLayerDependencies( $layerNames ) ); - -// print_r( $layerDefs ); -// die(); return $layerDefs; } - /** - * FIXME - * @see evilOpenLayersHack - */ - private static function getLayerDependencies( array $layerNames ) { - global $egMapsOLLayerDependencies, $egMapsOLAvailableLayers; - - $layerDependencies = array(); - - foreach ( $layerNames as $layerName ) { - if ( array_key_exists( $layerName, $egMapsOLAvailableLayers ) // The layer must be defined in php - && is_array( $egMapsOLAvailableLayers[$layerName] ) // The layer must be an array... - && count( $egMapsOLAvailableLayers[$layerName] ) > 1 // ...with a second element... - && array_key_exists( $egMapsOLAvailableLayers[$layerName][1], $egMapsOLLayerDependencies ) ) { //...that is a dependency. - $layerDependencies[] = $egMapsOLLayerDependencies[$egMapsOLAvailableLayers[$layerName][1]]; + public static function getLayerDependencies( $service, $params ) { + global $egMapsOLLayerDependencies, $egMapsOLAvailableLayers, + $egMapsLeafletLayerDependencies, $egMapsLeafletAvailableLayers, + $egMapsLeafletLayersApiKeys; + + $layerDependencies = []; + + if ( $service === 'leaflet' ) { + $layerName = $params['layer']; + if ( array_key_exists( $layerName, $egMapsLeafletAvailableLayers ) + && $egMapsLeafletAvailableLayers[$layerName] + && array_key_exists( $layerName, $egMapsLeafletLayersApiKeys ) + && array_key_exists( $layerName, $egMapsLeafletLayerDependencies ) ) { + $layerDependencies[] = ''; } + } else if ( $service === 'openlayers' ) { + $layerNames = $params['layers']; + foreach ( $layerNames as $layerName ) { + if ( array_key_exists( $layerName, $egMapsOLAvailableLayers ) // The layer must be defined in php + && is_array( $egMapsOLAvailableLayers[$layerName] ) // The layer must be an array... + && count( $egMapsOLAvailableLayers[$layerName] ) > 1 // ...with a second element... + && array_key_exists( $egMapsOLAvailableLayers[$layerName][1], $egMapsOLLayerDependencies ) ) { //...that is a dependency. + $layerDependencies[] = $egMapsOLLayerDependencies[$egMapsOLAvailableLayers[$layerName][1]]; + } + } + } return array_unique( $layerDependencies ); } - + } diff --git a/includes/Maps_DistanceParser.php b/includes/Maps_DistanceParser.php index d3b906295..fd58bb73f 100644 --- a/includes/Maps_DistanceParser.php +++ b/includes/Maps_DistanceParser.php @@ -34,7 +34,7 @@ public static function parseDistance( $distance ) { self::initUnitRegex(); - $matches = array(); + $matches = []; preg_match( '/^\d+(\.\d+)?\s?(' . self::$unitRegex . ')?$/', $distance, $matches ); $value = (float)( $matches[0] . $matches[1] ); @@ -161,7 +161,7 @@ protected static function normalizeDistance( $distance ) { $strlen = strlen( $distance ); for ( $i = 0; $i < $strlen; $i++ ) { - if ( !ctype_digit( $distance{$i} ) && !in_array( $distance{$i}, array( ',', '.' ) ) ) { + if ( !ctype_digit( $distance{$i} ) && !in_array( $distance{$i}, [ ',', '.' ] ) ) { $value = substr( $distance, 0, $i ); $unit = substr( $distance, $i ); break; @@ -171,7 +171,7 @@ protected static function normalizeDistance( $distance ) { $value = str_replace( ',', '.', isset( $value ) ? $value : $distance ); if ( isset( $unit ) ) { - $value .= ' ' . str_replace( array( ' ', "\t" ), '', $unit ); + $value .= ' ' . str_replace( [ ' ', "\t" ], '', $unit ); } return $value; diff --git a/includes/Maps_GeoFunctions.php b/includes/Maps_GeoFunctions.php index 77696b5f9..94c33dbf1 100644 --- a/includes/Maps_GeoFunctions.php +++ b/includes/Maps_GeoFunctions.php @@ -72,10 +72,10 @@ public static function calculateDistance( LatLongValue $start, LatLongValue $end * @return array The destination coordinates, as non-directional floats in an array with lat and lon keys. */ public static function findDestination( LatLongValue $startingCoordinates, $bearing, $distance ) { - $startingCoordinates = array( + $startingCoordinates = [ 'lat' => deg2rad( $startingCoordinates->getLatitude() ), 'lon' => deg2rad( $startingCoordinates->getLongitude() ), - ); + ]; $radBearing = deg2rad ( (float)$bearing ); $angularDistance = $distance / Maps_EARTH_RADIUS; @@ -83,10 +83,10 @@ public static function findDestination( LatLongValue $startingCoordinates, $bear $lat = asin (sin ( $startingCoordinates['lat'] ) * cos ( $angularDistance ) + cos ( $startingCoordinates['lat'] ) * sin ( $angularDistance ) * cos ( $radBearing ) ); $lon = $startingCoordinates['lon'] + atan2 ( sin ( $radBearing ) * sin ( $angularDistance ) * cos ( $startingCoordinates['lat'] ), cos ( $angularDistance ) - sin ( $startingCoordinates['lat'] ) * sin ( $lat ) ); - return array( + return [ 'lat' => rad2deg( $lat ), 'lon' => rad2deg( $lon ) - ); + ]; } } \ No newline at end of file diff --git a/includes/Maps_KMLFormatter.php b/includes/Maps_KMLFormatter.php index 71acb3ae3..f99244fbe 100644 --- a/includes/Maps_KMLFormatter.php +++ b/includes/Maps_KMLFormatter.php @@ -33,7 +33,7 @@ class MapsKMLFormatter { * * @param array $params */ - public function __construct( array $params = array() ) { + public function __construct( array $params = [] ) { $this->params = $params; $this->clearElements(); } @@ -98,7 +98,7 @@ public function clearElements() { * @since 0.7.3 */ public function clearPlacemarks() { - $this->placemarks = array(); + $this->placemarks = []; } /** @@ -109,7 +109,7 @@ public function clearPlacemarks() { * @return string */ protected function getKMLElements() { - $elements = array(); + $elements = []; $elements = array_merge( $elements, $this->getPlacemarks() ); @@ -125,7 +125,7 @@ protected function getKMLElements() { * @return array */ protected function getPlacemarks() { - $placemarks = array(); + $placemarks = []; foreach ( $this->placemarks as $location ) { $placemarks[] = $this->getKMLForLocation( $location ); @@ -153,7 +153,7 @@ protected function getKMLForLocation( Location $location ) { // lon,lat[,alt] $coordinates = Xml::element( 'coordinates', - array(), + [], $coordinates->getLongitude() . ',' . $coordinates->getLatitude() . ',0' ); diff --git a/includes/Maps_Layer.php b/includes/Maps_Layer.php deleted file mode 100644 index 5cbd5b80d..000000000 --- a/includes/Maps_Layer.php +++ /dev/null @@ -1,339 +0,0 @@ - - * @author Daniel Werner - */ -abstract class MapsLayer { - - /** - * Returns a string containing the JavaScript definition of this layer. - * Only call this function when you are sure the layer is valid! - * - * @since 0.7.1 - * - * @return string - */ - public abstract function getJavaScriptDefinition(); - - /** - * @since 0.7.1 - * - * @var array - */ - protected $properties; - - /** - * @since 3.0 - * - * @var array - */ - protected $originalPropertyValues; - - /** - * @since 0.7.1 - * - * @var array - */ - protected $errors = array(); - - /** - * Keeps track if the layer has been validated, to prevent doing redundant work. - * - * @since 0.7.1 - * - * @var boolean - */ - protected $hasValidated = false; - - /** - * Optional name of a layer within its group. This is for identifying a layer for only - * displaying this specific layer instead of all layers within a agroup. If this layer - * should not be selectable on its own without any other group members, the value is null - * - * @var string - */ - protected $name; - - /** - * Constructor. - * - * @since 0.7.1 ($name since 3.0) - * - * @param array $properties - * @param string $name optional name of the layer within its group for being able to select - * the layer on its own without having other members of the group available to be - * displayed in the maps layer control. - */ - public function __construct( array $properties, $name = null ) { - $this->properties = $properties; - $this->name = $name; - $this->originalPropertyValues = $properties; - } - - /** - * Returns the error messages, optionally filtered by an error tag. - * - * @since 0.7.1 - * - * @param mixed $tag - * - * @return array of string - */ - public function getErrorMessages( $tag = false ) { - $messages = array(); - - foreach ( $this->errors as $error ) { - if ( $tag === false || $error->hasTag( $tag ) ) { - $messages[] = $error->getMessage(); - } - } - - return $messages; - } - - /** - * Returns the layers properties. - * - * @since 0.7.1 - * - * @return array - */ - public function getProperties() { - return $this->properties; - } - - /** - * Returns the layer type represented by the class of this layer instance. - * - * @since 3.0 - * - * @return string - */ - final public function getType() { - return MapsLayerTypes::getTypeOfLayer( $this ); - } - - /** - * Returns the layers name within its group. If not name is defined, this will - * return null - * - * @since 3.0 - * - * @return string|null - */ - public function getName() { - return $this->name; - } - - /** - * Convenient function for getting mapping services supported by this layer. - * - * @since 3.0 - * - * @return string[] - */ - final public function getSupportedServices() { - return MapsLayerTypes::getServicesForType( $this->getType() ); - - } - - /** - * Convenience function to find out whether the layer is supporting a certain mapping service. - * - * @since 3.0 - * @param string $service - * - * @return boolean - */ - final public function isSupportingService( $service ) { - $services = $this->getSupportedServices(); - return in_array( $service, $services ); - } - - /** - * Validates the layer. - * - * @since 0.7.1 - */ - protected function validate() { - if( $this->hasValidated ) { - return; - } - $this->hasValidated = true; - - $validator = Processor::newDefault(); - - $validator->setParameters( $this->properties, $this->getParameterDefinitions() ); - $validator->validateParameters(); - - if ( $validator->hasErrors() !== false ) { - $this->errors = $validator->getErrors(); - } - $params = $validator->getParameterValues(); - $this->properties = $params; - } - - /** - * Returns whether the properties make up a valid layer definition without any errors. - * - * @since 0.7.1 - * - * @return boolean - */ - public function isValid() { - if ( !$this->hasValidated ) { - $this->validate(); - } - return empty( $this->errors ); - } - - /** - * Returns whether the layer can be used as it is defined. Returns true even if errors - * which are non fatal have occurred. - * - * @since 3.0 - * - * @return boolean - */ - public function isOk() { - if ( ! $this->isValid() ) { - // check whether one fatal error has occurred: - foreach( $this->errors as $error ) { - if( $error->isFatal() ) { - return false; - } - } - } - return true; - } - - /** - * Returns an array of parameter definitions. - * - * @since 3.0 (and before as abstract function since 0.7.2) - * - * @return array - */ - protected function getParameterDefinitions() { - $params = array(); - - $params['label'] = array( - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - // units for extent data: - $params['units'] = array( - 'default' => 'degree', - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - 'values' => array( 'degree', 'm', 'ft', 'km', 'mi', 'inches' ), - ); - - // zoom information: - $params['minscale'] = array( - 'type' => 'float', - 'default' => false, - 'manipulatedefault' => false, - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['maxscale'] = array( - 'type' => 'float', - 'default' => false, - 'manipulatedefault' => false, - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - // TODO-customMaps: addManipulations( new MapsParamSwitchIfGreaterThan( $params['minscale'] ) ); - ); - - $params['zoomlevels'] = array( - 'type' => 'integer', - 'default' => false, - 'manipulatedefault' => false, - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - // TODO-customMaps: addManipulations( new MapsParamSwitchIfGreaterThan( $params['minscale'] ) ); - ); - - return $params; - } - - /** - * Returns the value of a property value formated for html output. - * The result contains pure html. - * - * @since 3.0 - * - * @param string $name Name of the property value - * @param Parser $parser - * - * @return array - */ - public function getPropertiesHtmlRepresentation( &$parser ) { - $this->validate(); // make sure properties are available! - $transformed = array(); - foreach( $this->properties as $property => $value ) { - - if( ! $this->isValid() ) { - // datermine whether value for this parameter is valid: - $errors = $this->getErrorMessages( $property ); - - if ( $errors ) { - $transformed[ $property ] = '' . implode( '
', array_map( 'htmlspecialchars', $errors ) ) . '
'; - continue; - } - } - $transformed[ $property ] = $this->getPropertyHtmlRepresentation( $property, $parser ); - } - $this->doPropertiesHtmlTransform( $transformed ); - return $transformed; - } - - /** - * Returns the value of a property value formatted for html output - * - * @since 3.0 - * - * @param string $name Name of the property value - * @param Parser $parser - * - * @return string - */ - protected function getPropertyHtmlRepresentation( $name, &$parser ) { - $value = $this->properties[ $name ]; - - switch( $name ) { - case 'maxscale': - case 'minscale': - // if default value is in use: - if( $value === false ) { - return 'auto'; - } - break; - } - - return htmlspecialchars( $value ); - } - - /** - * Does the final transform of the properties array for html representation after - * each single property value is transformed by 'getPropertyHtmlRepresentation()' - * already. This is used to group certain properties for nicer output. - * - * @since 3.0 - * - * @param array &$properties - * - * @return array - */ - protected function doPropertiesHtmlTransform( &$properties ) { - $properties['scale'] = "max: {$properties['maxscale']}, min: {$properties['minscale']}"; - unset( $properties['maxscale'], $properties['minscale'] ); - } -} - diff --git a/includes/Maps_LayerGroup.php b/includes/Maps_LayerGroup.php deleted file mode 100644 index 3f4538bad..000000000 --- a/includes/Maps_LayerGroup.php +++ /dev/null @@ -1,254 +0,0 @@ -addLayer( $layer ); - } - } - - /** - * Returns the layers which are members of this group. An empty array will be - * returned in case no layers belong to this group. - * - * @since 3.0 - * - * @param integer $types bitfield defining whether named, numeric or all layers should be returned. - * MapsLayerGroup::LAYERS_NAMED, MapsLayerGroup::LAYERS_NUMERIC or MapsLayerGroup::LAYERS_ALL - * - * @return MapsLayer[] - */ - public function getLayers( $types = self::LAYERS_ALL ) { - /* - * For all layers: If given, take the name as key. - * by not doing this in the constructor we won't have conflicts with layer - * name changes later on. - */ - $namedLayers = array(); - - foreach( $this->layers as $layer ) { - - if( $layer->getName() !== null ) { - - if( $types & self::LAYERS_NAMED ) { - // name as key: - $namedLayers[ $layer->getName() ] = $layer; - } - } - elseif( $types & self::LAYERS_NUMERIC ) { - // numeric (random) key: - $namedLayers[] = $layer; - } - } - return $namedLayers; - } - - /** - * Returns the layer with the given name. If the layer doesn't exist, return null. - * - * @since 3.0 - * - * @param string $name - * - * @return MapsLayer|null - */ - public function getLayerByName( $name ) { - // get Layers in array with named index for named layers: - $layers = $this->getLayers(); - - if( array_key_exists( $name, $layers ) ) { - return $layers[ $name ]; - } - return null; - } - - /** - * Returns whether a specific layer exists within the group. - * - * @since 3.0 - * - * @param MapsLayer $layer - * - * @return boolean - */ - public function hasLayer( MapsLayer $layer ) { - foreach( $this->layers as $groupLayer ) { - if( $layer === $groupLayer ) { - return true; - } - } - return false; - } - - /** - * This will add a layer to the collection of layers in this group if it is not a - * member already. - * Does NOT automatically store the layer in the database if the group is loaded - * from a page. - * - * @since 3.0 - * - * @param MapsLayer $layer - * - * @return boolean whether a layer with the same name has been overwritten. Also - * returns false in case the same layer exists within the group already. - */ - public function addLayer( MapsLayer $layer ) { - - if( $this->hasLayer( $layer ) ) { - return false; // exact same layer already exists within group - } - - $overwritten = false; - - // check for layer with same name in this group - if( $layer->getName() !== null ) { - - // remove all layers with same name (shouldn't be more than one but be paranoid): - do { - $existingLayer = $this->getLayerByName( $layer->getName() ); - - if( $existingLayer !== null ) { - $this->removeLayer( $existingLayer ); - $overwritten = true; - } - } - while( $existingLayer !== null ); - } - - $this->layers[] = $layer; - return $overwritten; // layer with same name overwritten? - } - - /** - * This will remove a layer from the collection of layers in this group. - * Does NOT automatically store the layer in the database if the group is loaded - * from a page. - * - * @since 3.0 - * - * @param MapsLayer $layer - * - * @return boolean whether the layer was a member of the group and has been removed. - */ - public function removeLayer ( MapsLayer $layer ) { - foreach( $this->layers as $key => $groupLayer ) { - if( $layer === $groupLayer ) { - unset( $this->layers[ $key ] ); - return true; - } - } - return false; - } - - /** - * Get a group of layers by the title of the group. If the page doesn't contain - * any layers, the group will be returned anyway but won't contain any layers. - * - * @since 3.0 - * - * @param Title $title - * - * @return MapsLayerGroup - */ - public static function newFromTitle( Title $title ) { - // load all members defined on the page $title: - $db = wfGetDB( DB_SLAVE ); - $conditions = array( 'layer_page_id' => $title->getArticleID() ); - - $layers = self::loadMembersFromConds( $db, $conditions ); - if( $layers === false && wfGetLB()->getServerCount() > 1 ) { - $db = wfGetDB( DB_MASTER ); - $layers = self::loadMembersFromConds( $db, $conditions ); - } - $obj = new MapsLayerGroup( $layers ); - return $obj; - } - - /** - * Given a set of conditions, fetch all matching layers from the given database - * connection and return them in an array - * - * @param Database $db - * @param array $conditions - * - * @return array|false - */ - protected static function loadMembersFromConds( $db, $conditions ) { - $results = array(); - $res = self::fetchMembersFromConds( $db, $conditions ); - if( $res ) { - // load all matching layer objects into the layer group: - foreach( $res as $row ) { - if( $row ) { - $obj = MapsLayers::newLayerFromRow( $row ); - $results[] = $obj; - } - } - $res->free(); - return $results; - } - return false; - } - - /** - * Given a set of conditions, return a ResultWrapper - * which will return matching database rows with the - * fields necessary to build the group. - * - * @param Database $db - * @param array $conditions - * - * @return ResultWrapper|false - */ - protected static function fetchMembersFromConds( $db, $conditions ) { - $fields = MapsLayers::databaseFields(); - $res = $db->select( - array( 'maps_layers' ), - $fields, - $conditions, - __METHOD__ - ); - return $res; - } -} diff --git a/includes/Maps_LayerPage.php b/includes/Maps_LayerPage.php deleted file mode 100644 index b569cefdd..000000000 --- a/includes/Maps_LayerPage.php +++ /dev/null @@ -1,179 +0,0 @@ - - * @author Daniel Werner - */ -class MapsLayerPage extends Article { - - protected $usageTitles = null; - - function __construct( Title $title, $oldId = null ) { - parent::__construct( $title, $oldId ); - } - - /** - * Designed similar to CategoryPage. - * - * @see Article::view - * - * @since 3.0 - */ - public function view() { - global $wgRequest, $wgUser; - - $diff = $wgRequest->getVal( 'diff' ); - $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); - - if( isset( $diff ) && $diffOnly ) { - return parent::view(); - } - - if( !Hooks::run( 'MapsLayerPageView', array( &$this ) ) ) { - return; - } - - if( Maps_NS_LAYER == $this->mTitle->getNamespace() ) { - $this->openShowLayer(); - } - - parent::view(); - - if( Maps_NS_LAYER == $this->mTitle->getNamespace() ) { - $this->closeShowLayer(); - } - } - - /** - * Function called before page rendering. - * - * @since 3.0 - */ - protected function openShowLayer() { - } - - /** - * Function called at the end of page rendering. - * - * @since 3.0 - */ - protected function closeShowLayer() { - $this->renderUsage(); - } - - /** - * Renders the category-page like view which shows the usage of this - * layer page in other pages. - * - * @since 3.0 - */ - public function renderUsage() { - global $wgOut; - $out = ''; - - $titles = $this->getUsageTitles(); - - $viewer = new CategoryViewer( $this->mTitle, $this->getContext() ); - $viewer->limit = 9999; // just overwrite the default limit of pages displayed in a normal category - - // now add apges in sorted order to category viewer: - foreach( $titles as $title ) { - $viewer->addPage( $title, $title->getPrefixedText(), null ); - } - - //$wgOut->addHTML( $viewer->formatList( $viewer->articles, '' ) ); - $out = "
\n"; - $out .= '

' . wfMessage( 'maps-layerpage-usage', $this->mTitle->getText() )->text() . "

\n"; - - if( !empty( $viewer->articles ) ) { - $out .= $viewer->formatList( $viewer->articles, $viewer->articles_start_char ); - } else { - $out .= wfMessage( 'maps-layerpage-nousage' )->text(); - } - $out .= "\n
"; - - $wgOut->addHTML( $out ); - } - - /** - * returns all Titles using this layer page - * - * @since 3.0 - * - * @return Array - */ - public function getUsageTitles() { - // cached result: - if( $this->usageTitles !== null ) { - return $this->usageTitles; - } - - $db = wfGetDB( DB_SLAVE ); - $items = $db->select( - 'templatelinks', - '*', - array( - 'tl_title = "' . $this->mTitle->getDBkey() . '"', - 'tl_namespace = ' . $this->mTitle->getNamespace(), - ), - __METHOD__ - ); - - // get pages and sort them first: - $titles = array(); - foreach( $items as $item ) { - $title = Title::newFromID( $item->tl_from ); - - if( $title !== null ) { - $titles[ $title->getPrefixedText() ] = $title; - } - } - unset( $items, $item ); - ksort( $titles, SORT_STRING ); - - return $this->usageTitles = $titles; - } - - /** - * Returns if the layer page has any layer defined which has a definition that is 'ok', - * meaning, the layer can be used in a map. - * - * @since 3.0 - * - * @param string $name if set, only for the layer definition with this name will be searched. - * @param string $service if set, only layers supporthing this service will be taken in account. - * - * @return boolean - */ - public function hasUsableLayer( $name = null, $service = null ) { - // if name is given, get only that layer to check on, otherwise all: - if( $name !== null ) { - $layer = MapsLayers::loadLayer( $this->getTitle(), $name ); - - if( $layer === null ) { - return false; - } - $layers = array( $layer ); - } else { - $layers = MapsLayers::loadLayerGroup( $this->getTitle() ); - $layers = $layers->getLayers(); - } - - // datermine whether any layer is usable: - foreach( $layers as $layerName => $layer ) { - if( - $layer->isOk() // doesn't have to be 100% valid, just valid enough to be usable! - && ( $service === null || $layer->isSupportingService( $service ) ) - ) { - return true; - } - } - return false; - } -} diff --git a/includes/Maps_LayerTypes.php b/includes/Maps_LayerTypes.php deleted file mode 100644 index 725803a56..000000000 --- a/includes/Maps_LayerTypes.php +++ /dev/null @@ -1,161 +0,0 @@ - $supportedServices ) { - if ( in_array( $service, $supportedServices ) ) { - $layers[] = $layerType; - } - } - - return $layers; - } - } - - /** - * Returns the mapping services supported by the provided layer type. - * - * @since 3.0 (available in MapsLayers class in 0.7.2 to 3.0) - * - * @param string $type - * - * @return array - */ - public static function getServicesForType( $type ) { - return array_key_exists( $type, self::$services ) ? self::$services[$type] : array(); - } - - /** - * Returns whether the layer type exists (that's the case if the type is associated - * with a layer class). - * - * @since 3.0 (previously 'hasLayer' since 0.7.2) - * - * @param string $type - * @param string $service - * - * @return boolean - */ - public static function hasType( $type, $service = null ) { - self::initializeTypes(); - - if ( array_key_exists( $type, self::$classes ) && array_key_exists( $type, self::$services ) ) { - return is_null( $service ) || in_array( $service, self::$services[$type] ); - } - else { - return false; - } - } - - /** - * Returns the class of a layer template class or null if the type doesn't exist. - * - * @since 3.0 - * - * @param string $type - * - * @return string|null - */ - public static function getTypesClass( $type ) { - if( ! self::hasType( $type ) ) - return null; - - return self::$classes[ $type ]; - } - - /** - * Register a layer type by associating a specific class with it. - * - * @param string $type - * @param string $layerClass - * @param string[]|string $serviceIdentifier - * - * @since 3.0 - */ - public static function registerLayerType( $type, $layerClass, $serviceIdentifier ) { - self::$classes[$type] = $layerClass; - if( is_array( $serviceIdentifier ) ) { - self::$services[$type] = $serviceIdentifier; - } else { - self::$services[$type] = array( $serviceIdentifier ); - } - } - - /** - * Initializes the layers functionality by registering the layer types - * by firing the hook. - * - * @since 3.0 - */ - protected static function initializeTypes() { - // only initialize once! - if( empty( self::$classes ) ) { - Hooks::run( 'MappingLayersInitialization' ); - } - } -} diff --git a/includes/Maps_Layers.php b/includes/Maps_Layers.php deleted file mode 100644 index e0bcae302..000000000 --- a/includes/Maps_Layers.php +++ /dev/null @@ -1,229 +0,0 @@ - - * @author Daniel Werner - */ -class MapsLayers { - - /** - * Array with layer page site names as keys and MapsLayerGroup - * objects as values. - * - * @since 3.0 - * - * @var MapsLayerGroup - */ - protected static $layerGroups = array(); - - /** - * Returns a new instance of a layer class for the provided layer type to create - * an actual layer definition based on the basic layer type class. - * - * @since 3.0 - * - * @param string $type name of the basic layer type. - * @param array $properties definition describing the layer characteristics. - * @param string $name optional name to identify this particular layer within a - * group of layers within a layer page. If not set, an increasing numeric - * name will be assigned. - * - * @return MapsLayer - */ - public static function newLayerFromDefinition( $type, array $properties, $name = null ) { - - $class = MapsLayerTypes::getTypesClass( $type ); - - if ( $class !== null ) { - return new $class( $properties, $name ); - } - else { - throw new exception( "There is no layer class for layers of type \"$type\"." ); - } - } - - /** - * Creates a new type specific MapsLayer from a feteched database row. - * - * @since 3.0 - * - * @param object $row - * - * @return MapsLayer - */ - public static function newLayerFromRow( $row ) { - if( is_object( $row ) ) { - $type = $row->layer_type; - $name = $row->layer_name; // might be null - $data = self::parseLayerParameters( $row->layer_data ); - - return self::newLayerFromDefinition( $type, $data, $name ); - } - else { - throw new MWException( 'Invalid row format for "MapsLayer" creation.' ); - } - } - - /** - * Reads layer parameter definition in string form and returns and array containing - * all parameters as structured data where the key is the parameter name and the - * associated value its value. - * - * @since 3.0 - * - * @param string $parameters - * @param string $itemSep separator between prameters. - * @param string $keyValueSep separator between parameter name and associated value. - * - * @return array - */ - public static function parseLayerParameters( $parameters, $itemSep = "\n", $keyValueSep = '=' ) { - $keyValuePairs = array(); - - // get 'key=value' pairs and put them into an array where key is the index for each value - foreach ( explode( $itemSep, $parameters ) as $line ) { - $parts = explode( $keyValueSep, $line, 2 ); - - if ( count( $parts ) == 2 ) { - // only allow basic characters as layer-description parameters: - $key = preg_replace( '/[^a-z0-9]/', '', strtolower( $parts[0] ) ); - $keyValuePairs[ $key ] = trim( $parts[1] ); - } - } - return $keyValuePairs; - } - - /** - * This will load an already defined layer from a layer page within the wiki. Since - * there can be several layers as a group on one page, this also requires the layers - * name within the group to identify it. - * If the requested layer doesn't exist, this will return null. - * - * @since 3.0 - * - * @param Title $layerPage title of a page with layer definitions - * @param string $name layers name within the group of all layers defined in $layerPage - * - * @return MapsLayer|null - */ - public static function loadLayer( Title $layerPage, $name ) { - $layers = self::loadLayerGroup( $layerPage ); - return $layers->getLayerByName( $name ); - } - - /** - * This will load all layers defined on a layer page and return them as - * MapsLayerGroup object. - * - * @since 3.0 - * - * @param Title $layerPage - * - * @return MapsLayerGroup - */ - public static function loadLayerGroup( Title $layerPage ) { - // try to get it from cached layers: - $groupId = $layerPage->getPrefixedDBkey(); - if( array_key_exists( $groupId, self::$layerGroups ) ) { - return self::$layerGroups[ $groupId ]; - } - - $layerGroup = MapsLayerGroup::newFromTitle( $layerPage ); - - self::$layerGroups[ $groupId ] = $layerGroup; - return $layerGroup; - } - - /** - * Store layers of a page to database. This will remove all previous layers - * of that page from the database first. - * - * @since 3.0 - * - * @param MapsLayerGroup $layerGroup contains all layers of the page. - * @param Title $title the page title the layers are associated with. - * - * @return boolean - */ - public static function storeLayers( MapsLayerGroup $layerGroup, Title $title ) { - - // clear cache for this one: - unset( self::$layerGroups[ $title->getPrefixedDBkey() ] ); - - /* - * create data for multiple row insert: - */ - $pageId = $title->getArticleID(); - - foreach( $layerGroup->getLayers() as $layer ) { - $dbLayers[] = self::databaseRowFromLayer( $layer, $pageId ); - } - - /* - * insert all layer rows of the page into database: - */ - $db = wfGetDB( DB_MASTER ); - - // delete old, stored layers first: - $db->delete( 'maps_layers', array( 'layer_page_id' => $pageId ), __METHOD__ ); - - if( empty( $dbLayers ) ) { - // empty group, nothing to insert - return true; - } - else { - // insert new rows: - return $db->insert( 'maps_layers', $dbLayers, __METHOD__ ); - } - } - - /** - * Return the list of database fields that should be selected to create a new MapsLayer. - * - * @since 3.0 - */ - public static function databaseFields() { - return array( - 'layer_page_id', - 'layer_name', - 'layer_type', - 'layer_data' - ); - } - - /** - * Returns database fields as keys and an associated value taken from a layer as value, ready - * for database insert. - * - * @since 3.0 - * - * @param MapsLayer $layer - * @param integer $pageId The article id of the page the layer should be associated to. - * For example "Title::getArticleID()". - * - * @return array - */ - public static function databaseRowFromLayer( MapsLayer $layer, $pageId ) { - - // format layer properties array: - $properties = array(); - foreach( $layer->getProperties() as $key => $prop ) { - $properties[] = "$key=$prop"; - } - $properties = implode( "\n", $properties ); - - return array( - 'layer_page_id' => $pageId, - 'layer_name' => $layer->getName(), // might be null - 'layer_type' => $layer->getType(), - 'layer_data' => $properties - ); - } -} - diff --git a/includes/Maps_Mapper.php b/includes/Maps_Mapper.php index 5bc42fd87..e1d9faf23 100644 --- a/includes/Maps_Mapper.php +++ b/includes/Maps_Mapper.php @@ -54,12 +54,12 @@ public static function encodeJsVar( $value ) { if ( $s != '{' ) { $s .= ', '; } - $s .= '"' . Xml::escapeJsString( $name ) . '": ' . + $s .= '"' . Xml::encodeJsVar( $name ) . '": ' . self::encodeJsVar( $elt ); } $s .= '}'; } else { - $s = '"' . Xml::escapeJsString( $value ) . '"'; + $s = '"' . Xml::encodeJsVar( $value ) . '"'; } return $s; } @@ -67,50 +67,48 @@ public static function encodeJsVar( $value ) { /** * This function returns the definitions for the parameters used by every map feature. * - * @deprecated - * * @return array */ public static function getCommonParameters() { global $egMapsAvailableGeoServices, $egMapsDefaultGeoService, $egMapsMapWidth, $egMapsMapHeight, $egMapsDefaultService; - $params = array(); + $params = []; - $params['mappingservice'] = array( + $params['mappingservice'] = [ 'type' => 'mappingservice', 'aliases' => 'service', 'default' => $egMapsDefaultService, - ); + ]; - $params['geoservice'] = array( + $params['geoservice'] = [ 'default' => $egMapsDefaultGeoService, 'values' => $egMapsAvailableGeoServices, 'dependencies' => 'mappingservice', // TODO 'manipulations' => new MapsParamGeoService( 'mappingservice' ), - ); + ]; - $params['width'] = array( + $params['width'] = [ 'type' => 'dimension', 'allowauto' => true, - 'units' => array( 'px', 'ex', 'em', '%', '' ), + 'units' => [ 'px', 'ex', 'em', '%', '' ], 'default' => $egMapsMapWidth, - ); + ]; - $params['height'] = array( + $params['height'] = [ 'type' => 'dimension', - 'units' => array( 'px', 'ex', 'em', '' ), + 'units' => [ 'px', 'ex', 'em', '' ], 'default' => $egMapsMapHeight, - ); + ]; // TODO$manipulation = new MapsParamLocation(); // TODO$manipulation->toJSONObj = true; - $params['centre'] = array( - 'type' => 'mapslocation', - 'aliases' => array( 'center' ), + $params['centre'] = [ + 'type' => 'string', + 'aliases' => [ 'center' ], 'default' => false, 'manipulatedefault' => false, - ); + ]; // Give grep a chance to find the usages: // maps-par-mappingservice, maps-par-geoservice, maps-par-width, @@ -120,6 +118,102 @@ public static function getCommonParameters() { $data['message'] = 'maps-par-' . $name; } + return array_merge( $params, self::getEvenMawrCommonParameters() ); + } + + private static function getEvenMawrCommonParameters() { + global $egMapsDefaultTitle, $egMapsDefaultLabel; + + $params = []; + + $params['title'] = [ + 'name' => 'title', + 'default' => $egMapsDefaultTitle, + ]; + + $params['label'] = [ + 'default' => $egMapsDefaultLabel, + 'aliases' => 'text', + ]; + + $params['icon'] = [ + 'default' => '', // TODO: image param + ]; + + $params['visitedicon'] = [ + 'default' => '', //TODO: image param + ]; + + $params['lines'] = [ + 'type' => 'mapsline', + 'default' => [], + 'delimiter' => ';', + 'islist' => true, + ]; + + $params['polygons'] = [ + 'type' => 'mapspolygon', + 'default' => [], + 'delimiter' => ';', + 'islist' => true, + ]; + + $params['circles'] = [ + 'type' => 'mapscircle', + 'default' => [], + 'delimiter' => ';', + 'islist' => true, + ]; + + $params['rectangles'] = [ + 'type' => 'mapsrectangle', + 'default' => [], + 'delimiter' => ';', + 'islist' => true, + ]; + + $params['wmsoverlay'] = [ + 'type' => 'wmsoverlay', + 'default' => false, + 'delimiter' => ' ', + ]; + + $params['maxzoom'] = [ + 'type' => 'integer', + 'default' => false, + 'manipulatedefault' => false, + 'dependencies' => 'minzoom', + ]; + + $params['minzoom'] = [ + 'type' => 'integer', + 'default' => false, + 'manipulatedefault' => false, + 'lowerbound' => 0, + ]; + + $params['copycoords'] = [ + 'type' => 'boolean', + 'default' => false, + ]; + + $params['static'] = [ + 'type' => 'boolean', + 'default' => false, + ]; + + // Give grep a chance to find the usages: + // maps-displaymap-par-title, maps-displaymap-par-label, maps-displaymap-par-icon, + // maps-displaymap-par-visitedicon, aps-displaymap-par-lines, maps-displaymap-par-polygons, + // maps-displaymap-par-circles, maps-displaymap-par-rectangles, maps-displaymap-par-wmsoverlay, + // maps-displaymap-par-maxzoom, maps-displaymap-par-minzoom, maps-displaymap-par-copycoords, + // maps-displaymap-par-static + foreach ( $params as $name => &$param ) { + if ( !array_key_exists( 'message', $param ) ) { + $param['message'] = 'maps-displaymap-par-' . $name; + } + } + return $params; } @@ -140,7 +234,7 @@ public static function getFileUrl( $file ) { $imagePage = new ImagePage( $title ); return $imagePage->getDisplayedFile()->getURL(); } - return ''; + return $file; } /** @@ -155,7 +249,7 @@ public static function getFileUrl( $file ) { */ public static function getBaseMapJSON( $serviceName ) { static $baseInit = false; - static $serviceInit = array(); + static $serviceInit = []; $json = ''; diff --git a/includes/Maps_MappingService.php b/includes/Maps_MappingService.php index 365d6925d..6af2943fa 100644 --- a/includes/Maps_MappingService.php +++ b/includes/Maps_MappingService.php @@ -9,13 +9,11 @@ * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ -abstract class MapsMappingService implements iMappingService { +abstract class MapsMappingService { /** * The internal name of the service. * - * @since 0.6.3 - * * @var string */ protected $serviceName; @@ -23,8 +21,6 @@ abstract class MapsMappingService implements iMappingService { /** * A list of aliases for the internal name. * - * @since 0.6.3 - * * @var array */ protected $aliases; @@ -32,8 +28,6 @@ abstract class MapsMappingService implements iMappingService { /** * A list of features that support the service, used for validation and defaulting. * - * @since 0.6.3 - * * @var array */ protected $features; @@ -41,46 +35,34 @@ abstract class MapsMappingService implements iMappingService { /** * A list of names of resource modules to add. * - * @since 0.7.3 - * * @var array */ - protected $resourceModules = array(); + protected $resourceModules = []; /** * A list of dependencies (header items) that have been added. * - * @since 0.6.3 - * * @var array */ - private $addedDependencies = array(); + private $addedDependencies = []; /** * A list of dependencies (header items) that need to be added. * - * @since 0.6.3 - * * @var array */ - private $dependencies = array(); + private $dependencies = []; /** - * Constructor. Creates a new instance of MapsMappingService. - * - * @since 0.6.3 - * * @param string $serviceName * @param array $aliases */ - public function __construct( $serviceName, array $aliases = array() ) { + public function __construct( $serviceName, array $aliases = [] ) { $this->serviceName = $serviceName; $this->aliases = $aliases; } /** - * @see iMappingService::addParameterInfo - * * @since 0.7 * * @param $parameterInfo array of IParam @@ -89,8 +71,6 @@ public function addParameterInfo( array &$parameterInfo ) { } /** - * @see iMappingService::addFeature - * * @since 0.6.3 */ public function addFeature( $featureName, $handlingClass ) { @@ -98,8 +78,6 @@ public function addFeature( $featureName, $handlingClass ) { } /** - * @see iMappingService::addDependencies - * * @since 0.6.3 */ public final function addDependencies( &$parserOrOut ) { @@ -130,17 +108,15 @@ public final function addDependencies( &$parserOrOut ) { * @return array */ public function getConfigVariables() { - return array(); + return []; } /** - * @see iMappingService::getDependencyHtml - * * @since 0.6.3 */ public final function getDependencyHtml() { $allDependencies = array_merge( $this->getDependencies(), $this->dependencies ); - $dependencies = array(); + $dependencies = []; // Only add dependnecies that have not yet been added. foreach ( $allDependencies as $dependency ) { @@ -151,7 +127,7 @@ public final function getDependencyHtml() { } // If there are dependencies, put them all together in a string, otherwise return false. - return $dependencies !== array() ? implode( '', $dependencies ) : false; + return $dependencies !== [] ? implode( '', $dependencies ) : false; } /** @@ -162,12 +138,10 @@ public final function getDependencyHtml() { * @return array */ protected function getDependencies() { - return array(); + return []; } /** - * @see iMappingService::getName - * * @since 0.6.3 */ public function getName() { @@ -175,8 +149,6 @@ public function getName() { } /** - * @see iMappingService::getFeature - * * @since 0.6.3 */ public function getFeature( $featureName ) { @@ -184,8 +156,6 @@ public function getFeature( $featureName ) { } /** - * @see iMappingService::getFeatureInstance - * * @since 0.6.6 */ public function getFeatureInstance( $featureName ) { @@ -199,8 +169,6 @@ public function getFeatureInstance( $featureName ) { } /** - * @see iMappingService::getAliases - * * @since 0.6.3 */ public function getAliases() { @@ -208,8 +176,6 @@ public function getAliases() { } /** - * @see iMappingService::hasAlias - * * @since 0.6.3 */ public function hasAlias( $alias ) { @@ -239,21 +205,30 @@ public function addResourceModules( $modules ) { } /** - * @see iMappingService::addDependency - * * @since 0.6.3 + * + * @param $dependencyHtml */ - public final function addDependency( $dependencyHtml ) { + public final function addHtmlDependency( $dependencyHtml ) { $this->dependencies[] = $dependencyHtml; } /** - * @see iMappingService::getEarthZoom - * + * @param array $dependencies + */ + public function addHtmlDependencies(array $dependencies ) { + foreach ( $dependencies as $dependency ) { + $this->addHtmlDependency( $dependency ); + } + } + + /** * @since 1.0 */ public function getEarthZoom() { return 1; } -} \ No newline at end of file + public abstract function getMapId( $increment = true ); + +} diff --git a/includes/Maps_MappingServices.php b/includes/Maps_MappingServices.php index 3d35d65ec..a6ebaa4d6 100644 --- a/includes/Maps_MappingServices.php +++ b/includes/Maps_MappingServices.php @@ -18,7 +18,7 @@ final class MapsMappingServices { * * @var string[] */ - protected static $registeredServices = array(); + protected static $registeredServices = []; /** * Associative with service identifiers as keys containing instances of @@ -30,9 +30,9 @@ final class MapsMappingServices { * * @since 0.6.6 * - * @var iMappingService[] + * @var MapsMappingService[] */ - protected static $services = array(); + protected static $services = []; /** * Registers a service class linked to an identifier. @@ -40,11 +40,11 @@ final class MapsMappingServices { * * @since 0.6.6 * - * @param $serviceIdentifier String: internal service identifier - * @param $serviceClassName String - * @param $features Array + * @param string $serviceIdentifier + * @param string $serviceClassName + * @param string[] $features */ - public static function registerService( $serviceIdentifier, $serviceClassName, array $features = array() ) { + public static function registerService( $serviceIdentifier, $serviceClassName, array $features = [] ) { self::$registeredServices[$serviceIdentifier] = $serviceClassName; foreach( $features as $featureName => $featureClassName ) { @@ -79,16 +79,17 @@ public static function registerServiceFeature( $serviceIdentifier, $featureName, * * @since 0.6.6 * - * @param $serviceIdentifier String: internal service identifier + * @param string $serviceIdentifier * - * @return iMappingService + * @return MapsMappingService + * @throws MWException */ public static function getServiceInstance( $serviceIdentifier ) { if ( !array_key_exists( $serviceIdentifier, self::$services ) ) { if ( array_key_exists( $serviceIdentifier, self::$registeredServices ) ) { $service = new self::$registeredServices[$serviceIdentifier]( $serviceIdentifier ); - if ( $service instanceof iMappingService ) { + if ( $service instanceof MapsMappingService ) { self::$services[$serviceIdentifier] = $service; } else { @@ -114,7 +115,7 @@ public static function getServiceInstance( $serviceIdentifier ) { * @param $service String: service name or alias, does not need to be secure * @param $feature String * - * @return iMappingService + * @return MapsMappingService */ public static function getValidServiceInstance( $service, $feature ) { return self::getServiceInstance( self::getValidServiceName( $service, $feature ) ); @@ -207,7 +208,7 @@ protected static function getMainServiceName( $serviceName ) { public static function getAllServiceValues() { global $egMapsAvailableServices; - $allServiceValues = array(); + $allServiceValues = []; foreach ( $egMapsAvailableServices as $availableService ) { $allServiceValues[] = $availableService; @@ -225,7 +226,7 @@ public static function getAllServiceValues() { * @return array of MappingService */ public static function getAllObjects() { - $objects = array(); + $objects = []; foreach ( self::$registeredServices as $service => $class ) { $objects[] = self::getServiceInstance( $service ); diff --git a/includes/api/ApiGeocode.php b/includes/api/ApiGeocode.php index 067d94b7a..e7cda4b5c 100644 --- a/includes/api/ApiGeocode.php +++ b/includes/api/ApiGeocode.php @@ -24,20 +24,20 @@ public function execute() { global $wgUser; if ( !$wgUser->isAllowed( 'geocode' ) || $wgUser->isBlocked() ) { - $this->dieUsageMsg( array( 'badaccess-groups' ) ); + $this->dieUsageMsg( [ 'badaccess-groups' ] ); } $params = $this->extractRequestParams(); - $results = array(); + $results = []; foreach ( array_unique( $params['locations'] ) as $location ) { $result = \Maps\Geocoders::geocode( $location, $params['service'] ); - $results[$location] = array( + $results[$location] = [ 'count' => $result === false ? 0 : 1, - 'locations' => array() - ); + 'locations' => [] + ]; if ( $result !== false ) { $results[$location]['locations'][] = $result; @@ -54,42 +54,42 @@ public function execute() { } public function getAllowedParams() { - return array( - 'locations' => array( + return [ + 'locations' => [ ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true, ApiBase::PARAM_ISMULTI => true, - ), - 'service' => array( + ], + 'service' => [ ApiBase::PARAM_TYPE => \Maps\Geocoders::getAvailableGeocoders(), - ), - 'props' => array( + ], + 'props' => [ ApiBase::PARAM_ISMULTI => true, - ApiBase::PARAM_TYPE => array( 'lat', 'lon', 'alt' ), + ApiBase::PARAM_TYPE => [ 'lat', 'lon', 'alt' ], ApiBase::PARAM_DFLT => 'lat|lon', - ), - ); + ], + ]; } public function getParamDescription() { - return array( + return [ 'locations' => 'The locations to geocode', 'service' => 'The geocoding service to use', - ); + ]; } public function getDescription() { - return array( + return [ 'API module for geocoding.' - ); + ]; } public function getExamples() { - return array( + return [ 'api.php?action=geocode&locations=new york', 'api.php?action=geocode&locations=new york|brussels|london', 'api.php?action=geocode&locations=new york&service=geonames', - ); + ]; } /** diff --git a/includes/criteria/CriterionIsNonNumeric.php b/includes/criteria/CriterionIsNonNumeric.php deleted file mode 100644 index 9f04d61dd..000000000 --- a/includes/criteria/CriterionIsNonNumeric.php +++ /dev/null @@ -1,46 +0,0 @@ -getOriginalName() )->parse(); - } - - /** - * @see ItemParameterCriterion::getFullListErrorMessage - */ - protected function getFullListErrorMessage( Parameter $parameter ) { - global $wgLang; - return wfMessage( 'validation-error-no-non-numerics', $parameter->getOriginalName() )->parse(); - } -} diff --git a/includes/criteria/CriterionMapLayer.php b/includes/criteria/CriterionMapLayer.php deleted file mode 100644 index c404a617a..000000000 --- a/includes/criteria/CriterionMapLayer.php +++ /dev/null @@ -1,74 +0,0 @@ -groupNameSep = $groupNameSeparator; - } - - /** - * @see ItemParameterCriterion::validate - */ - protected function doValidation( $value, Parameter $parameter, array $parameters ) { - - $parts = explode( $this->groupNameSep, $value, 2 ); - $layerTitle = Title::newFromText( $parts[0], Maps_NS_LAYER ); - - // if page with layer definition doesn't exist: - if ( $layerTitle === null - || $layerTitle->getNamespace() !== Maps_NS_LAYER - || ! $layerTitle->exists() - ) { - return false; - } - - $layerName = count( $parts ) > 1 ? $parts[1] : null; - - $layerPage = new MapsLayerPage( $layerTitle ); - return $layerPage->hasUsableLayer( $layerName ); - } - - /** - * @see ItemParameterCriterion::getItemErrorMessage - */ - protected function getItemErrorMessage( Parameter $parameter ) { - return wfMessage( 'validation-error-invalid-layer', $parameter->getOriginalName() )->parse(); - } - - /** - * @see ItemParameterCriterion::getFullListErrorMessage - */ - protected function getFullListErrorMessage( Parameter $parameter ) { - return wfMessage( 'validation-error-invalid-layers', $parameter->getOriginalName() )->parse(); - } - -} diff --git a/includes/editor/MapEditorHTML.php b/includes/editor/MapEditorHTML.php index 21aa70397..4829b8e64 100644 --- a/includes/editor/MapEditorHTML.php +++ b/includes/editor/MapEditorHTML.php @@ -22,7 +22,7 @@ class MapEditorHtml extends ContextSource{ * @param ContextSource|null $ * @since 2.1 */ - public function __construct( $attribs = array(), ContextSource $contextSource = null ){ + public function __construct( $attribs = [], ContextSource $contextSource = null ){ $this->attribs = $attribs; } diff --git a/includes/ext.maps.common.js b/includes/ext.maps.common.js index f61da8854..4fe9045e5 100644 --- a/includes/ext.maps.common.js +++ b/includes/ext.maps.common.js @@ -14,5 +14,8 @@ window.maps = new ( function( $, mw ) { mw.log( message ); } }; - -} )( jQuery, mediaWiki ); \ No newline at end of file + + this.googlemapsList = []; + this.leafletList = []; + this.openlayersList = []; +} )( jQuery, mediaWiki ); diff --git a/includes/ext.maps.layers.css b/includes/ext.maps.layers.css deleted file mode 100644 index 50b364589..000000000 --- a/includes/ext.maps.layers.css +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Stylesheet for layer pages - * The definitions for the maps layer box is based on Semantic-MediaWikis - * (http://semantic-mediawiki.org) factbox styles. - * - * @since 3.0 - * @ingroup Maps - * - * @licence GNU GPL v3+ - * @author Daniel Werner < daniel.a.r.werner@gmail.com > - */ - -div.mapslayer { - clear: both; - background-color: #F9F9F9; - padding: 5px; - margin-top: 1em; - margin-bottom: 1em; - border: 1px solid #AAAAAA; - font-size: 95%; -} - -div.mapslayererror { - border-color: #cc0000; -} - -div.mapslayer td, div.mapslayer tr, div.mapslayer table { - background-color: #F9F9F9; -} - -span.mapslayerhead { - font-size: 110%; - font-weight: bold; - float: left; -} - -span.mapslayersupports { - font-size: 90%; - margin-left: 0.8em; -} - -table.mapslayertable, table.mapslayerwarntable, table.mapslayererrortable { - border-top: 1px dotted #AAAAAA; - width: 100%; - clear: both; -} - -table.mapslayerwarntable, td.mapslayerpropval .error { - color: #ff7f00; -} - -table.mapslayererrortable { - color: #cc0000; -} - -td.mapslayerpropname { - text-align: right; - vertical-align: middle; - padding-right: 1em; - font-weight: bold; -} - -td.mapslayerpropval { - vertical-align: top; - width: 75%; -} - -td.mapslayerpropval .thumb { - margin: 0; -} diff --git a/includes/geocoders/Maps_GeocoderusGeocoder.php b/includes/geocoders/Maps_GeocoderusGeocoder.php index 825e05e3a..87d5194d8 100644 --- a/includes/geocoders/Maps_GeocoderusGeocoder.php +++ b/includes/geocoders/Maps_GeocoderusGeocoder.php @@ -38,7 +38,7 @@ protected function getRequestUrl( $address ) { * * @since 3.0 * - * @param string $address + * @param string $response * * @return array */ @@ -49,9 +49,9 @@ protected function parseResponse( $response ) { // In case one of the values is not found, return false. if ( !$lon || !$lat ) return false; - return array( + return [ 'lat' => (float)$lat, 'lon' => (float)$lon - ); + ]; } } diff --git a/includes/geocoders/Maps_GeonamesGeocoder.php b/includes/geocoders/Maps_GeonamesGeocoder.php index 5fd8b85a5..c64608c00 100644 --- a/includes/geocoders/Maps_GeonamesGeocoder.php +++ b/includes/geocoders/Maps_GeonamesGeocoder.php @@ -47,7 +47,7 @@ protected function getRequestUrl( $address ) { * * @since 1.0 * - * @param string $address + * @param string $response * * @return array */ @@ -58,10 +58,10 @@ protected function parseResponse( $response ) { // In case one of the values is not found, return false. if ( !$lon || !$lat ) return false; - return array( + return [ 'lat' => (float)$lat, 'lon' => (float)$lon - ); + ]; } } \ No newline at end of file diff --git a/includes/geocoders/Maps_GoogleGeocoder.php b/includes/geocoders/Maps_GoogleGeocoder.php index d73347a19..456436de3 100644 --- a/includes/geocoders/Maps_GoogleGeocoder.php +++ b/includes/geocoders/Maps_GoogleGeocoder.php @@ -35,7 +35,17 @@ public static function register() { * @return string */ protected function getRequestUrl( $address ) { - return 'http://maps.googleapis.com/maps/api/geocode/xml?address=' . urlencode( $address ) . '&sensor=false'; + $urlArgs = [ + 'address' => $address + ]; + if ( $GLOBALS['egMapsGMaps3ApiKey'] !== '' ) { + $urlArgs['key'] = $GLOBALS['egMapsGMaps3ApiKey']; + } + if ( $GLOBALS['egMapsGMaps3ApiVersion'] !== '' ) { + $urlArgs['v'] = $GLOBALS['egMapsGMaps3ApiVersion']; + } + + return 'https://maps.googleapis.com/maps/api/geocode/xml?' . wfArrayToCgi($urlArgs); } /** @@ -43,7 +53,7 @@ protected function getRequestUrl( $address ) { * * @since 0.7 * - * @param string $address + * @param string $response * * @return array */ @@ -54,10 +64,10 @@ protected function parseResponse( $response ) { // In case on of the values is not found, return false. if ( !$lon || !$lat ) return false; - return array( + return [ 'lat' => (float)$lat, 'lon' => (float)$lon - ); + ]; } /** @@ -68,7 +78,7 @@ protected function parseResponse( $response ) { * @return array */ public static function getOverrides() { - return array( 'googlemaps3' ); + return [ 'googlemaps3' ]; } -} \ No newline at end of file +} diff --git a/includes/geocoders/Maps_OldGeocoderAdapter.php b/includes/geocoders/Maps_OldGeocoderAdapter.php new file mode 100644 index 000000000..1b29ffa74 --- /dev/null +++ b/includes/geocoders/Maps_OldGeocoderAdapter.php @@ -0,0 +1,45 @@ + + */ +final class MapsOldGeocoderAdapter extends \Maps\Geocoder { + + private $geocoder; + + /** + * @param Geocoder $geocoder + * @param string $identifier + */ + public function __construct( Geocoder $geocoder, $identifier ) { + $this->geocoder = $geocoder; + + parent::__construct( $identifier ); + } + + public function geocode( $address ) { + $result = $this->geocoder->geocode( $address ); + + if ( $result === null ) { + return false; + } + + return [ + 'lat' => $result->getLatitude(), + 'lon' => $result->getLongitude(), + ]; + } + + protected function getRequestUrl( $address ) {} + + protected function parseResponse( $response ) {} + +} diff --git a/includes/iMappingService.php b/includes/iMappingService.php deleted file mode 100644 index d73fc7455..000000000 --- a/includes/iMappingService.php +++ /dev/null @@ -1,125 +0,0 @@ - - */ -interface iMappingService { - - /** - * Returns the internal name of the service. - * - * @since 0.6.5 - * - * @return string - */ - public function getName(); - - /** - * Adds the dependencies to the parser output as head items. - * - * @since 0.6.3 - * - * @param mixed $parserOrOut - */ - public function addDependencies( &$parserOrOut ); - - /** - * Adds service-specific parameter definitions to the provided parameter list. - * - * @since 0.7 - * - * @param array $parameterInfo - * - * @return array - */ - public function addParameterInfo( array &$parameterInfo ); - - /** - * Adds a feature to this service. This is to indicate this service has support for this feature. - * - * @since 0.6.5 - * - * @param string $featureName - * @param string $handlingClass - */ - public function addFeature( $featureName, $handlingClass ); - - /** - * Returns the name of the class that handles the provided feature in this service, or false if there is none. - * - * @since 0.6.5 - * - * @param string $featureName. - * - * @return mixed String or false - */ - public function getFeature( $featureName ); - - /** - * Returns an instance of the class handling the provided feature with this service, or false if there is none. - * - * @since 0.6.6 - * - * @param string $featureName. - * - * @return object or false - */ - public function getFeatureInstance( $featureName ); - - /** - * Returns a list of aliases. - * - * @since 0.6.5 - * - * @return array - */ - public function getAliases(); - - /** - * Returns if the service has a certain alias or not. - * - * @since 0.6.5 - * - * @param string $alias - * - * @return boolean - */ - public function hasAlias( $alias ); - - /** - * Returns the default zoomlevel for the mapping service. - * - * @since 0.6.5 - * - * @return integer - */ - public function getDefaultZoom(); - - /** - * Returns the zoomlevel that shows the whole earth for the mapping service. - * - * @since 1.0 - * - * @return integer - */ - public function getEarthZoom(); - - /** - * Returns a string that can be used as an unique ID for the map html element. - * Increments the number by default, providing false for $increment will get - * you the same ID as on the last request. - * - * @since 0.6.5 - * - * @param boolean $increment - * - * @return string - */ - public function getMapId( $increment = true ); - -} \ No newline at end of file diff --git a/includes/images/m1.png b/includes/images/m1.png new file mode 100644 index 000000000..329ff524c Binary files /dev/null and b/includes/images/m1.png differ diff --git a/includes/images/m2.png b/includes/images/m2.png new file mode 100644 index 000000000..b999cbcf6 Binary files /dev/null and b/includes/images/m2.png differ diff --git a/includes/images/m3.png b/includes/images/m3.png new file mode 100644 index 000000000..9f30b3092 Binary files /dev/null and b/includes/images/m3.png differ diff --git a/includes/images/m4.png b/includes/images/m4.png new file mode 100644 index 000000000..0d3f8263b Binary files /dev/null and b/includes/images/m4.png differ diff --git a/includes/images/m5.png b/includes/images/m5.png new file mode 100644 index 000000000..61387d2ab Binary files /dev/null and b/includes/images/m5.png differ diff --git a/includes/layers/Maps_ImageLayer.php b/includes/layers/Maps_ImageLayer.php deleted file mode 100644 index be1f7f0ec..000000000 --- a/includes/layers/Maps_ImageLayer.php +++ /dev/null @@ -1,198 +0,0 @@ - - * @author Daniel Werner - */ -class MapsImageLayer extends MapsLayer { - - /** - * Registers the layer. - * - * @since 0.7.2 - */ - public static function register() { - MapsLayerTypes::registerLayerType( 'image', __CLASS__, 'openlayers' ); - return true; - } - - /** - * @see MapsLayer::getParameterDefinitions - * - * @since 0.7.2 - * - * @return array - */ - protected function getParameterDefinitions() { - $params = parent::getParameterDefinitions(); - - // map extent for extents bound object: - $params['topextent'] = array( - 'type' => 'float', - 'aliases' => array( 'upperbound', 'topbound' ), - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['rightextent'] = array( - 'type' => 'float', - 'aliases' => array( 'rightbound' ), - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['bottomextent'] = array( - 'type' => 'float', - 'aliases' => array( 'lowerbound', 'bottombound' ), - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['leftextent'] = array( - 'type' => 'float', - 'aliases' => array( 'leftbound' ), - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - // image-source information: - $params['source'] = array( - // TODO-customMaps: addCriteria( new CriterionIsImage() ) - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - 'post-format' => function( $source ) { - $imageUrl = MapsMapper::getFileUrl( $source ); - - global $egMapsAllowExternalImages; - if( $imageUrl === '' && $egMapsAllowExternalImages ) { - return $source; - } - return $imageUrl; - } - ); - - $params['width'] = array( - 'type' => 'float', - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['height'] = array( - 'type' => 'float', - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - return $params; - } - - /** - * @see MapsLayer::getPropertyHtmlRepresentation - * - * @since 3.0 - * - * @return array - */ - protected function getPropertyHtmlRepresentation( $name, &$parser ) { - $value = $this->properties[ $name ]; - - switch( $name ) { - case 'source': - $value = $this->originalPropertyValues['source']; // get original, non-modified value - - $title = Title::newFromText( $value, NS_FILE ); - - // if title has invalid characters or doesn't exist and has url-style - if( $title === null - || ( !$title->exists() && preg_match( '|^.+\://.+\..+$|', $value ) ) - ) { - // url link: - $value = $parser->recursiveTagParse( "[$value $value]" ); - } else { - // wikilink (can be red link to non-existant file): - $imgName = $title->getPrefixedText(); - $value = $parser->recursiveTagParse( "[[$imgName|thumb|[[:$imgName]]|left]]" ); - } - return $value; // html already - - default: - // if we don't have any special handling here, leave it to base class: - return parent::getPropertyHtmlRepresentation( $name, $parser ); - } - return htmlspecialchars( $value );; - } - - /** - * @see MapsLayer::doPropertiesHtmlTransform - * - * @since 3.0 - * - * @return array - */ - protected function doPropertiesHtmlTransform( &$properties ) { - parent::doPropertiesHtmlTransform( $properties ); - - $sp = ' '; // non-breaking thin space - - // image-size: - $properties['image-size'] = "width: {$properties['width']}{$sp}pixel, height: {$properties['height']}{$sp}pixel"; - unset( $properties['width'], $properties['height'] ); - - // extent: - $unit = $properties['units']; - $properties['extent'] = - "left: {$properties['leftextent']}{$sp}$unit, " . - "bottom: {$properties['bottomextent']}{$sp}$unit, " . - "right: {$properties['rightextent']}{$sp}$unit, " . - "top: {$properties['topextent']}{$sp}$unit"; - unset( $properties['leftextent'], $properties['bottomextent'], $properties['rightextent'], $properties['topextent'] ); - } - - /** - * @see MapsLayer::getJavaScriptDefinition - * - * @since 0.7.2 - * - * @return string - */ - public function getJavaScriptDefinition() { - $this->validate(); - - // do image layer options: - - $options = array( - 'isImage' => true, - 'units' => $this->properties['units'], - ); - - if( $this->properties['zoomlevels'] !== false ) { - $options['numZoomLevels'] = $this->properties['zoomlevels']; - } - if( $this->properties['minscale'] !== false ) { - $options['minScale'] = $this->properties['minscale']; - } - if( $this->properties['maxscale'] !== false ) { - $options['maxScale'] = $this->properties['maxscale']; - } - - $options = Xml::encodeJsVar( (object)$options ); //js-encode all options ); - - // for non-option params, get JavaScript-encoded config values: - foreach( $this->properties as $name => $value ) { - ${ $name } = MapsMapper::encodeJsVar( $value ); - } - - return <<itemSep = $itemSep; - $this->keyValueSep = $keyValueSep; - } - - /** - * @see ItemParameterManipulation::doManipulation - * - * @since 3.0 - */ - public function doManipulation( &$value, Parameter $parameter, array &$parameters ) { - // string to array describing layer parameters: - $value = MapsLayers::parseLayerParameters( $value, $this->itemSep, $this->keyValueSep ); - } -} - diff --git a/includes/manipulations/Maps_ParamSwitchIfGreaterThan.php b/includes/manipulations/Maps_ParamSwitchIfGreaterThan.php deleted file mode 100644 index 4b66ce2c1..000000000 --- a/includes/manipulations/Maps_ParamSwitchIfGreaterThan.php +++ /dev/null @@ -1,49 +0,0 @@ -greaterParam = $param; - } - - /** - * @see ItemParameterManipulation::doManipulation - * - * @since 3.0 - */ - public function doManipulation( &$value, Parameter $parameter, array &$parameters ) { - /* - * make sure maxScale is lower than minScale. Base layers would work fine anyhow - * but overlays would behave strange in some cases. Also useres could be confused - * by this so we take care of it. - */ - if ( $value > $this->greaterParam->getValue() ) { - $minScale = $value; - $value = $this->greaterParam->getValue(); - $this->greaterParam->setValue( $minScale ); - } - } -} - diff --git a/includes/parserhooks/Maps_Coordinates.php b/includes/parserhooks/Maps_Coordinates.php index 132f37929..39e4e1fc0 100644 --- a/includes/parserhooks/Maps_Coordinates.php +++ b/includes/parserhooks/Maps_Coordinates.php @@ -1,4 +1,5 @@ 'coordinate', - ); + ]; - $params['format'] = array( + $params['format'] = [ 'default' => $egMapsCoordinateNotation, 'values' => $egMapsAvailableCoordNotations, 'aliases' => 'notation', 'tolower' => true, - ); + ]; - $params['directional'] = array( + $params['directional'] = [ 'type' => 'boolean', 'default' => $egMapsCoordinateDirectional, - ); + ]; // Give grep a chance to find the usages: // maps-coordinates-par-location, maps-coordinates-par-format, maps-coordinates-par-directional @@ -73,7 +74,7 @@ protected function getParameterInfo( $type ) { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'location', 'format', 'directional' ); + return [ 'location', 'format', 'directional' ]; } /** @@ -87,11 +88,11 @@ protected function getDefaultParameters( $type ) { * @return string */ public function render( array $parameters ) { - $options = new \ValueFormatters\FormatterOptions( array( + $options = new \ValueFormatters\FormatterOptions( [ GeoCoordinateFormatter::OPT_FORMAT => $parameters['format'], GeoCoordinateFormatter::OPT_DIRECTIONAL => $parameters['directional'], GeoCoordinateFormatter::OPT_PRECISION => 1 / 360000 - ) ); + ] ); $coordinateFormatter = new GeoCoordinateFormatter( $options ); diff --git a/includes/parserhooks/Maps_DisplayMap.php b/includes/parserhooks/Maps_DisplayMap.php index a053fc67d..f38e2c971 100644 --- a/includes/parserhooks/Maps_DisplayMap.php +++ b/includes/parserhooks/Maps_DisplayMap.php @@ -30,7 +30,7 @@ protected function getName() { * @return array */ protected function getNames() { - return array( $this->getName(), 'display_point', 'display_points', 'display_line' ); + return [ $this->getName(), 'display_point', 'display_points', 'display_line' ]; } /** @@ -46,121 +46,18 @@ protected function getParameterInfo( $type ) { $params['mappingservice']['feature'] = 'display_map'; - $params['coordinates'] = array( - 'type' => 'mapslocation', - 'aliases' => array( 'coords', 'location', 'address', 'addresses', 'locations', 'points' ), - 'dependencies' => array( 'mappingservice', 'geoservice' ), - 'default' => array(), + $params['coordinates'] = [ + 'type' => 'string', + 'aliases' => [ 'coords', 'location', 'address', 'addresses', 'locations', 'points' ], + 'default' => [], 'islist' => true, 'delimiter' => $type === ParserHook::TYPE_FUNCTION ? ';' : "\n", 'message' => 'maps-displaymap-par-coordinates', - ); + ]; - $params = array_merge( $params, self::getCommonMapParams() ); - return $params; } - /** - * Temporary hack. Do not rely upon. - * @since 3.0 - * @deprecated - * @return array - */ - public static function getCommonMapParams() { - global $egMapsDefaultTitle, $egMapsDefaultLabel; - - $params['title'] = array( - 'name' => 'title', - 'default' => $egMapsDefaultTitle, - ); - - $params['label'] = array( - 'default' => $egMapsDefaultLabel, - 'aliases' => 'text', - ); - - $params['icon'] = array( - 'default' => '', // TODO: image param - ); - - $params['visitedicon'] = array( - 'default' => '', //TODO: image param - ); - - $params['lines'] = array( - 'type' => 'mapsline', - 'default' => array(), - 'delimiter' => ';', - 'islist' => true, - ); - - $params['polygons'] = array( - 'type' => 'mapspolygon', - 'default' => array(), - 'delimiter' => ';', - 'islist' => true, - ); - - $params['circles'] = array( - 'type' => 'mapscircle', - 'default' => array(), - 'delimiter' => ';', - 'islist' => true, - ); - - $params['rectangles'] = array( - 'type' => 'mapsrectangle', - 'default' => array(), - 'delimiter' => ';', - 'islist' => true, - ); - - $params['wmsoverlay'] = array( - 'type' => 'wmsoverlay', - 'default' => false, - 'delimiter' => ' ', - ); - - $params['maxzoom'] = array( - 'type' => 'integer', - 'default' => false, - 'manipulatedefault' => false, - 'dependencies' => 'minzoom', - ); - - $params['minzoom'] = array( - 'type' => 'integer', - 'default' => false, - 'manipulatedefault' => false, - 'lowerbound' => 0, - ); - - $params['copycoords'] = array( - 'type' => 'boolean', - 'default' => false, - ); - - $params['static'] = array( - 'type' => 'boolean', - 'default' => false, - ); - - // Give grep a chance to find the usages: - // maps-displaymap-par-title, maps-displaymap-par-label, maps-displaymap-par-icon, - // maps-displaymap-par-visitedicon, aps-displaymap-par-lines, maps-displaymap-par-polygons, - // maps-displaymap-par-circles, maps-displaymap-par-rectangles, maps-displaymap-par-wmsoverlay, - // maps-displaymap-par-maxzoom, maps-displaymap-par-minzoom, maps-displaymap-par-copycoords, - // maps-displaymap-par-static - foreach ( $params as $name => &$param ) { - if ( !array_key_exists( 'message', $param ) ) { - $param['message'] = 'maps-displaymap-par-' . $name; - } - } - - return $params; - } - /** * Returns the list of default parameters. * @see ParserHook::getDefaultParameters @@ -170,7 +67,7 @@ public static function getCommonMapParams() { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'coordinates' ); + return [ 'coordinates' ]; } /** @@ -184,22 +81,26 @@ protected function getDefaultParameters( $type ) { * @return string */ public function render( array $parameters ) { - // Get the instance of the service class. - $service = MapsMappingServices::getServiceInstance( $parameters['mappingservice'], $this->getName() ); - - $mapClass = new MapsDisplayMapRenderer( $service ); + $this->defaultMapZoom( $parameters ); + $this->trackMap(); + + $renderer = new MapsDisplayMapRenderer( MapsMappingServices::getServiceInstance( $parameters['mappingservice'] ) ); + return $renderer->renderMap( $parameters, $this->parser ); + } + + private function defaultMapZoom( &$parameters ) { $fullParams = $this->validator->getParameters(); if ( array_key_exists( 'zoom', $fullParams ) && $fullParams['zoom']->wasSetToDefault() && count( $parameters['coordinates'] ) > 1 ) { $parameters['zoom'] = false; } + } - global $egMapsEnableCategory; - if ($egMapsEnableCategory) { + private function trackMap() { + if ( $GLOBALS['egMapsEnableCategory'] ) { $this->parser->addTrackingCategory( 'maps-tracking-category' ); } - return $mapClass->renderMap( $parameters, $this->parser ); } /** @@ -211,10 +112,10 @@ public function render( array $parameters ) { * @return array */ protected function getFunctionOptions() { - return array( + return [ 'noparse' => true, 'isHTML' => true - ); + ]; } /** diff --git a/includes/parserhooks/Maps_Distance.php b/includes/parserhooks/Maps_Distance.php index 45f2cccbb..5295759b3 100644 --- a/includes/parserhooks/Maps_Distance.php +++ b/includes/parserhooks/Maps_Distance.php @@ -34,21 +34,21 @@ protected function getName() { protected function getParameterInfo( $type ) { global $egMapsDistanceUnit, $egMapsDistanceDecimals; - $params = array(); + $params = []; - $params['distance'] = array( + $params['distance'] = [ 'type' => 'distance', - ); + ]; - $params['unit'] = array( + $params['unit'] = [ 'default' => $egMapsDistanceUnit, 'values' => MapsDistanceParser::getUnits(), - ); + ]; - $params['decimals'] = array( + $params['decimals'] = [ 'type' => 'integer', 'default' => $egMapsDistanceDecimals, - ); + ]; // Give grep a chance to find the usages: // maps-distance-par-distance, maps-distance-par-unit, maps-distance-par-decimals @@ -70,7 +70,7 @@ protected function getParameterInfo( $type ) { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'distance', 'unit', 'decimals' ); + return [ 'distance', 'unit', 'decimals' ]; } /** diff --git a/includes/parserhooks/Maps_Finddestination.php b/includes/parserhooks/Maps_Finddestination.php index 1cde0d341..6bd08629f 100644 --- a/includes/parserhooks/Maps_Finddestination.php +++ b/includes/parserhooks/Maps_Finddestination.php @@ -1,4 +1,5 @@ */ - class MapsFinddestination extends ParserHook { /** @@ -37,50 +37,50 @@ protected function getParameterInfo( $type ) { global $egMapsAvailableGeoServices, $egMapsDefaultGeoService, $egMapsAvailableCoordNotations; global $egMapsCoordinateNotation, $egMapsAllowCoordsGeocoding, $egMapsCoordinateDirectional; - $params = array(); + $params = []; - $params['location'] = array( - 'dependencies' => array( 'mappingservice', 'geoservice' ), - 'type' => 'mapslocation', - ); + $params['location'] = [ + 'dependencies' => [ 'mappingservice', 'geoservice' ], + 'type' => 'mapslocation', // FIXME: geoservice is not used + ]; - $params['format'] = array( + $params['format'] = [ 'default' => $egMapsCoordinateNotation, 'values' => $egMapsAvailableCoordNotations, 'aliases' => 'notation', 'tolower' => true, - ); + ]; - $params['directional'] = array( + $params['directional'] = [ 'type' => 'boolean', 'default' => $egMapsCoordinateDirectional, - ); + ]; - $params['bearing'] = array( + $params['bearing'] = [ 'type' => 'float', - ); + ]; - $params['distance'] = array( + $params['distance'] = [ 'type' => 'distance', - ); + ]; - $params['mappingservice'] = array( + $params['mappingservice'] = [ 'default' => '', 'values' => MapsMappingServices::getAllServiceValues(), 'tolower' => true, - ); + ]; - $params['geoservice'] = array( + $params['geoservice'] = [ 'default' => $egMapsDefaultGeoService, 'aliases' => 'service', 'values' => $egMapsAvailableGeoServices, 'tolower' => true, - ); + ]; - $params['allowcoordinates'] = array( + $params['allowcoordinates'] = [ 'type' => 'boolean', 'default' => $egMapsAllowCoordsGeocoding, - ); + ]; // Give grep a chance to find the usages: // maps-finddestination-par-location, maps-finddestination-par-format, @@ -103,7 +103,7 @@ protected function getParameterInfo( $type ) { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'location', 'bearing', 'distance' ); + return [ 'location', 'bearing', 'distance' ]; } /** @@ -123,11 +123,11 @@ public function render( array $parameters ) { $parameters['distance'] ); - $options = new \ValueFormatters\FormatterOptions( array( + $options = new \ValueFormatters\FormatterOptions( [ GeoCoordinateFormatter::OPT_FORMAT => $parameters['format'], GeoCoordinateFormatter::OPT_DIRECTIONAL => $parameters['directional'], GeoCoordinateFormatter::OPT_PRECISION => 1 / 360000 - ) ); + ] ); $formatter = new GeoCoordinateFormatter( $options ); diff --git a/includes/parserhooks/Maps_Geocode.php b/includes/parserhooks/Maps_Geocode.php index 69df034b7..3604cbea7 100644 --- a/includes/parserhooks/Maps_Geocode.php +++ b/includes/parserhooks/Maps_Geocode.php @@ -1,5 +1,7 @@ 'mapslocation', - 'dependencies' => array( 'mappingservice', 'geoservice' ), - ); + $params = []; - $params['mappingservice'] = array( - 'default' => '', - 'values' => MapsMappingServices::getAllServiceValues(), - 'tolower' => true, - ); + $params['location'] = [ + 'type' => 'string', + 'message' => 'maps-geocode-par-location', + ]; - $params['geoservice'] = array( + $params['geoservice'] = [ 'default' => $egMapsDefaultGeoService, 'aliases' => 'service', 'values' => $egMapsAvailableGeoServices, 'tolower' => true, - ); + 'message' => 'maps-geocode-par-geoservice', + ]; - $params['allowcoordinates'] = array( + $params['allowcoordinates'] = [ 'type' => 'boolean', 'default' => $egMapsAllowCoordsGeocoding, - ); + 'message' => 'maps-geocode-par-allowcoordinates', + ]; - $params['format'] = array( + $params['format'] = [ 'default' => $egMapsCoordinateNotation, 'values' => $egMapsAvailableCoordNotations, 'aliases' => 'notation', 'tolower' => true, - ); + 'message' => 'maps-geocode-par-format', + ]; - $params['directional'] = array( + $params['directional'] = [ 'type' => 'boolean', 'default' => $egMapsCoordinateDirectional, - ); - - // Give grep a chance to find the usages: - // maps-geocode-par-location, maps-geocode-par-mappingservice, maps-geocode-par-geoservice, - // maps-geocode-par-allowcoordinates, maps-geocode-par-format, maps-geocode-par-directional - foreach ( $params as $name => &$param ) { - $param['message'] = 'maps-geocode-par-' . $name; - } + 'message' => 'maps-geocode-par-directional', + ]; return $params; } @@ -93,7 +86,7 @@ protected function getParameterInfo( $type ) { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'location', 'geoservice', 'mappingservice' ); + return [ 'location', 'geoservice' ]; } /** @@ -107,16 +100,25 @@ protected function getDefaultParameters( $type ) { * @return string */ public function render( array $parameters ) { - /** - * @var \DataValues\LatLongValue $coordinates - */ - $coordinates = $parameters['location']->getCoordinates(); + if ( !Geocoders::canGeocode() ) { + return 'No geocoders available'; + } + + $coordinates = Geocoders::attemptToGeocode( + $parameters['location'], + $parameters['geoservice'], + $parameters['allowcoordinates'] + ); + + if ( $coordinates === false ) { + return 'Geocoding failed'; + } - $options = new \ValueFormatters\FormatterOptions( array( + $options = new \ValueFormatters\FormatterOptions( [ GeoCoordinateFormatter::OPT_FORMAT => $parameters['format'], GeoCoordinateFormatter::OPT_DIRECTIONAL => $parameters['directional'], GeoCoordinateFormatter::OPT_PRECISION => 1 / 360000 - ) ); + ] ); $formatter = new GeoCoordinateFormatter( $options ); diff --git a/includes/parserhooks/Maps_Geodistance.php b/includes/parserhooks/Maps_Geodistance.php index 34ee88d11..f691a0c8c 100644 --- a/includes/parserhooks/Maps_Geodistance.php +++ b/includes/parserhooks/Maps_Geodistance.php @@ -9,7 +9,6 @@ * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ - class MapsGeodistance extends ParserHook { /** @@ -35,42 +34,42 @@ protected function getName() { protected function getParameterInfo( $type ) { global $egMapsDistanceUnit, $egMapsDistanceDecimals, $egMapsAvailableGeoServices, $egMapsDefaultGeoService; - $params = array(); + $params = []; - $params['mappingservice'] = array( + $params['mappingservice'] = [ 'default' => '', 'values' => MapsMappingServices::getAllServiceValues(), 'tolower' => true, - ); + ]; - $params['geoservice'] = array( + $params['geoservice'] = [ 'default' => $egMapsDefaultGeoService, 'aliases' => 'service', 'values' => $egMapsAvailableGeoServices, 'tolower' => true, - ); + ]; - $params['unit'] = array( + $params['unit'] = [ 'default' => $egMapsDistanceUnit, 'values' => MapsDistanceParser::getUnits(), - ); + ]; - $params['decimals'] = array( + $params['decimals'] = [ 'type' => 'integer', 'default' => $egMapsDistanceDecimals, - ); + ]; - $params['location1'] = array( - 'type' => 'mapslocation', + $params['location1'] = [ + 'type' => 'mapslocation', // FIXME: geoservice is not used 'aliases' => 'from', - 'dependencies' => array( 'mappingservice', 'geoservice' ), - ); + 'dependencies' => [ 'mappingservice', 'geoservice' ], + ]; - $params['location2'] = array( - 'type' => 'mapslocation', + $params['location2'] = [ + 'type' => 'mapslocation', // FIXME: geoservice is not used 'aliases' => 'to', - 'dependencies' => array( 'mappingservice', 'geoservice' ), - ); + 'dependencies' => [ 'mappingservice', 'geoservice' ], + ]; // Give grep a chance to find the usages: // maps-geodistance-par-mappingservice, maps-geodistance-par-geoservice, @@ -94,7 +93,7 @@ protected function getParameterInfo( $type ) { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'location1', 'location2', 'unit', 'decimals' ); + return [ 'location1', 'location2', 'unit', 'decimals' ]; } /** diff --git a/includes/parserhooks/Maps_LayerDefinition.php b/includes/parserhooks/Maps_LayerDefinition.php deleted file mode 100644 index b5d59285b..000000000 --- a/includes/parserhooks/Maps_LayerDefinition.php +++ /dev/null @@ -1,426 +0,0 @@ - false, - 'manipulatedefault' => false, - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['name'] = array( - 'default' => false, - 'manipulatedefault' => false, - // TODO-customMaps: addCriteria( new CriterionIsNonNumeric ); - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - ); - - $params['definition'] = array( - 'default' => false, - 'manipulatedefault' => false, - 'message' => 'maps-displaymap-par-coordinates', // TODO-customMaps: create a message - 'post-format' => function( $value ) { - return MapsLayers::parseLayerParameters( $value, "\n", '=' ); - } - ); - - return $params; - } - - /** - * Returns the list of default parameters. - * @see ParserHook::getDefaultParameters - * - * @since 3.0 - * - * @return array - */ - protected function getDefaultParameters( $type ) { - return array( 'definition' ); - } - - /** - * Returns the parser function options. - * @see ParserHook::getFunctionOptions - * - * @since 3.0 - * - * @return array - */ - protected function getFunctionOptions() { - return array( - 'noparse' => true, - 'isHTML' => true - ); - } - - /** - * @see ParserHook::getMessage() - * - * @since 3.0 - */ - public function getMessage() { - return 'maps-layerdefinition-description'; - } - - /** - * Returns the MapsLayerGroup with all layers of the same page which have been - * processed already. If the store is not attached to the parser object yet, - * an empty MapsLayerGroup will be attached as store after calling the function. - * - * @since 3.0 - * - * @return MapsLayerGroup - */ - protected function getLayerStore() { - $parserOutput = $this->parser->getOutput(); - - // make sure layers store in current parsers ParserOutput is initialized: - if( ! isset( $parserOutput->mExtMapsLayers ) ) { - $parserOutput->mExtMapsLayers = new MapsLayerGroup(); - } - return $parserOutput->mExtMapsLayers; - } - - /** - * This will attach a user defined layer to the parser output of the parser which has - * started the rendering. All added layers will be stored in the database - * after page parsing. - * $layer will only be stored in case it is a subclass of MapsLayer and its definition - * is at least considered 'ok'. - * - * @since 3.0 - * - * @param type $layer - * - * @return boolean whether $layer has been added to the store - */ - protected function addLayerToStore( $layer ) { - - $store = $this->getLayerStore(); - - // check whether $layer is a layer worthy to end up in the database: - if( $layer === null || $layer === false - || ! is_subclass_of( $layer, 'MapsLayer' ) - || ! $layer->isOk() - || $store->getLayerByName( $layer->getName() ) !== null // layer of same name in store already - - ) { - return false; - } - // add layer to store: - $overwritten = $store->addLayer( $layer ); - - if( $overwritten ) { - /** @ToDo: Message that a layer was defined twice on that site */ - } - return true; - } - - /** - * Renders and returns the output. - * @see ParserHook::renderTag - * - * @since 3.0 - * - * @param array $parameters - * - * @return string - */ - public function render( array $parameters ) { - global $wgLang; - - // Check whether parser tag is used in the right namespace context, abort if not - if( $this->parser->getTitle()->getNamespace() !== Maps_NS_LAYER ) { - global $wgContLang; - return $this->rawErrorbox( - wfMessage( - 'maps-layerdef-wrong-namespace', - $wgContLang->getNsText( Maps_NS_LAYER ) - )->inContentLanguage()->text() - ); - } - - $type = $parameters['type']; - - if( $type === false ) { - // no layer type specified - - $availableLayerTypes = MapsLayerTypes::getAvailableTypes(); - - $out = $this->rawErrorbox( - wfMessage( - 'maps-error-no-layertype', - $wgLang->listToText( $availableLayerTypes ), - count( $availableLayerTypes ) - )->inContentLanguage()->text() - ); - } - elseif( MapsLayerTypes::hasType( $type ) ) { - // get layer name if any: - $name = $parameters['name'] !== false ? $parameters['name'] : null; - - // make sure the layer has a label, if no user data, make something up: - if( empty( $parameters['definition']['label'] ) ) { - if( $name !== null ) { - $labelSuffix = "- $name"; - } else { - // label for unnamed layer: - $labelSuffix = '#' . ( count( $this->getLayerStore()->getLayers( MapsLayerGroup::LAYERS_NUMERIC ) ) + 1 ); - } - $parameters['definition']['label'] = $this->parser->getTitle()->getText() . ' ' . $labelSuffix; - } - - // new layer from user input (could still be invalid): - $layer = MapsLayers::newLayerFromDefinition( $type, $parameters['definition'], $name ); - - $out = $this->renderLayerInfo( $layer ); - } - else { - // specified layer type is non-existant! - - $availableLayerTypes = MapsLayerTypes::getAvailableTypes(); - - $out = $this->rawErrorbox( - wfMessage( - 'maps-error-invalid-layertype', - $this->validator->getParameter('type')->getOriginalValue(), - $wgLang->listToText( $availableLayerTypes ), - count( $availableLayerTypes ) - )->inContentLanguage()->text() - ); - } - - // add the layer to the store after all info has been rendered: - $this->addLayerToStore( $layer ); - - return $out; - } - - /** - * Responsible for actual output on the layer page which gives an overview of the layer definition. - * - * @since 3.0 - * - * @param MapsLayer - * - * @return string - */ - public function renderLayerInfo( MapsLayer $layer ) { - global $wgLang; - - // appropriate layer header: - if( $layer->getName() !== null ) { - - // if layer with same name is defined on same page already: - if( $this->getLayerStore()->getLayerByName( $layer->getName() ) !== null ) { - return - $this->errorbox( - wfMessage( - 'maps-layerdef-equal-layer-name', - $layer->getName() - )->inContentLanguage()->text() - ); - } - $outHeader = wfMessage( - 'maps-layer-of-type-and-name', - $layer->getType(), - $layer->getName() - )->inContentLanguage()->text(); - } - else { - $outHeader = wfMessage( - 'maps-layer-of-type', - $layer->getType() - )->inContentLanguage()->text(); - } - $outHeader = "$outHeader"; - - // info message about which services are supporting the layer(-type): - $supportedServices = MapsLayerTypes::getServicesForType( $layer->getType() ); - $outServices = '' . - wfMessage( - 'maps-layer-type-supported-by', - $wgLang->listToText( $supportedServices ), - count( $supportedServices ) - )->inContentLanguage()->escaped() . ''; - - $outTable = $this->getLayerDefinitionTable( $layer ); - - return - Html::rawElement( - 'div', - array( 'class' => 'mapslayer' . ( $layer->isOk() ? '' : ' mapslayererror' ) ), - $outHeader . $outServices . $outTable - ); - } - - /** - * Displays the layer definition as a table. - * - * @since 3.0 - * - * @param MapsLayer $layer - * - * @return string - */ - protected function getLayerDefinitionTable( MapsLayer $layer ) { - $out = ''; - $outWarning = ''; - - // check whether any error occurred during parameter validaton: - if ( ! $layer->isValid() ) { - $messages = $layer->getErrorMessages(); - $warnings = ''; - - if( count( $messages ) === 1 ) { - $warnings = htmlspecialchars( $messages[0] ); - } else { - $warnings = '
  • ' . implode( '
  • ', array_map( 'htmlspecialchars', $messages ) ) . '
'; - } - - $warnings = - '' . - wfMessage( - 'maps-layerdef-invalid' . ( $layer->isOk() ? '' : '-fatal' ), - count( $messages ) - )->inContentLanguage()->escaped() . - "{$warnings}"; - - $outWarning .= Html::rawElement( - 'table', - array( 'width' => '100%', 'class' => ( $layer->isOk() ? 'mapslayerwarntable' : 'mapslayererrortable' ) ), - $warnings - ); - - if( ! $layer->isOk() ) { - // fatal error occurred, don't print definition table since this would be quite empty since - // parameter validation aborted after fatal error parameter! - return $outWarning; - } - } - - global $wgOut; - $wgOut->addModules( 'ext.maps.layers' ); - - $rows = array(); - - // rows with layer definition: - $properties = $layer->getPropertiesHtmlRepresentation( $this->parser ); - - foreach ( $properties as $property => $value ) { - $rows[] = Html::rawElement( - 'tr', - array(), - Html::element( - 'td', - array( 'class' => 'mapslayerpropname' ), - $property - ) . - Html::rawElement( - 'td', - array( 'class' => 'mapslayerpropval' ), - $value - ) - ); - } - - $out .= Html::rawElement( - 'table', - array( 'width' => '100%', 'class' => 'mapslayertable' ), - implode( "\n", $rows ) - ); - - return ( $out . $outWarning ); - } - - /** - * wraps text inside an error box. - * - * @since 3.0 - * - * @param string $text text of the error, html-escaped. - * - * @return string - */ - protected function errorbox( $text, $raw = true ) { - /** - * FIXME: using 'errorbox' isn't the best idea since it has - * some weird css definition, better would be introducing a - * own class and puttin the whole definition into a nicer box. - */ - return '
' . $text .'
'; - } - - /** - * wraps text inside an error box. - * - * @since 3.0 - * - * @param string $text text of the error, NOT html-escaped - * - * @return string - */ - protected function rawErrorbox( $text ) { - $text = htmlspecialchars( $text ); - return $this->errorbox( $text ); - } -} diff --git a/includes/parserhooks/Maps_MapsDoc.php b/includes/parserhooks/Maps_MapsDoc.php index cbde24940..babc211a3 100644 --- a/includes/parserhooks/Maps_MapsDoc.php +++ b/includes/parserhooks/Maps_MapsDoc.php @@ -43,16 +43,16 @@ protected function getName() { * @return array */ protected function getParameterInfo( $type ) { - $params = array(); + $params = []; - $params['service'] = array( + $params['service'] = [ 'values' => $GLOBALS['egMapsAvailableServices'], 'tolower' => true, - ); + ]; - $params['language'] = array( + $params['language'] = [ 'default' => $GLOBALS['wgLanguageCode'], - ); + ]; // Give grep a chance to find the usages: // maps-geocode-par-service, maps-geocode-par-language @@ -72,7 +72,7 @@ protected function getParameterInfo( $type ) { * @return array */ protected function getDefaultParameters( $type ) { - return array( 'service', 'language' ); + return [ 'service', 'language' ]; } /** @@ -103,7 +103,7 @@ public function render( array $parameters ) { * * @return string */ - protected function msg() { + private function msg() { $args = func_get_args(); $key = array_shift( $args ); return wfMessage( $key, $args )->inLanguage( $this->language )->text(); @@ -118,8 +118,8 @@ protected function msg() { * * @return string */ - protected function getParameterTable( array $parameters ) { - $tableRows = array(); + private function getParameterTable( array $parameters ) { + $tableRows = []; $parameters = ParamDefinition::getCleanDefinitions( $parameters ); @@ -130,13 +130,13 @@ protected function getParameterTable( array $parameters ) { $table = ''; if ( count( $tableRows ) > 0 ) { - $tableRows = array_merge( array( + $tableRows = array_merge( [ '!' . $this->msg( 'validator-describe-header-parameter' ) ."\n" . //'!' . $this->msg( 'validator-describe-header-aliases' ) ."\n" . '!' . $this->msg( 'validator-describe-header-type' ) ."\n" . '!' . $this->msg( 'validator-describe-header-default' ) ."\n" . '!' . $this->msg( 'validator-describe-header-description' ) - ), $tableRows ); + ], $tableRows ); $table = implode( "\n|-\n", $tableRows ); @@ -152,16 +152,14 @@ protected function getParameterTable( array $parameters ) { /** * Returns the wikitext for a table row describing a single parameter. * - * @since 1.0 - * * @param ParamDefinition $parameter * * @return string */ - protected function getDescriptionRow( ParamDefinition $parameter ) { + private function getDescriptionRow( ParamDefinition $parameter ) { $description = $this->msg( $parameter->getMessage() ); - $type = $parameter->getTypeMessage(); + $type = $this->msg( $parameter->getTypeMessage() ); $default = $parameter->isRequired() ? "''" . $this->msg( 'validator-describe-required' ) . "''" : $parameter->getDefault(); if ( is_array( $default ) ) { @@ -181,15 +179,15 @@ protected function getDescriptionRow( ParamDefinition $parameter ) { EOT; } - protected function getServiceParameters( $service ) { + private function getServiceParameters( $service ) { $service = MapsMappingServices::getServiceInstance( $service ); - $params = array(); + $params = []; - $params['zoom'] = array( + $params['zoom'] = [ 'type' => 'integer', 'message' => 'maps-par-zoom', - ); + ]; $service->addParameterInfo( $params ); diff --git a/includes/parsers/CircleParser.php b/includes/parsers/CircleParser.php index fd9120b77..3e6bd5a02 100644 --- a/includes/parsers/CircleParser.php +++ b/includes/parsers/CircleParser.php @@ -37,31 +37,31 @@ public function stringParse( $value ) { $circle = new Circle( $this->stringToLatLongValue( $circleData[0] ), (float)$circleData[1] ); - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setTitle( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setText( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setStrokeColor( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setStrokeOpacity( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setStrokeWeight( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setFillColor( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $circle->setFillOpacity( array_shift( $metaData ) ); } diff --git a/includes/parsers/LineParser.php b/includes/parsers/LineParser.php index f08a00329..d92746a30 100644 --- a/includes/parsers/LineParser.php +++ b/includes/parsers/LineParser.php @@ -52,7 +52,7 @@ public function stringParse( $value ) { * @return LatLongValue[] */ protected function parseCoordinates( array $coordinateStrings ) { - $coordinates = array(); + $coordinates = []; $coordinateParser = new GeoCoordinateParser( new \ValueParsers\ParserOptions() ); $supportsGeocoding = $this->supportGeocoding && \Maps\Geocoders::canGeocode(); diff --git a/includes/parsers/LocationParser.php b/includes/parsers/LocationParser.php index 5c609f015..f47b3ef42 100644 --- a/includes/parsers/LocationParser.php +++ b/includes/parsers/LocationParser.php @@ -7,6 +7,7 @@ use Maps\Elements\Location; use MWException; use Title; +use ValueParsers\ParserOptions; use ValueParsers\ParseException; use ValueParsers\StringValueParser; @@ -20,8 +21,15 @@ */ class LocationParser extends StringValueParser { - // TODO - private $supportGeocoding = true; + /** + * @param ParserOptions|null $options + */ + public function __construct( ParserOptions $options = null ) { + parent::__construct( $options ); + + $this->defaultOption( 'useaddressastitle', false ); + $this->defaultOption( 'geoService', '' ); + } /** * @see StringValueParser::stringParse @@ -31,34 +39,40 @@ class LocationParser extends StringValueParser { * @param string $value * * @return Location - * @throws MWException + * @throws ParseException */ public function stringParse( $value ) { $separator = '~'; + $useaddressastitle = $this->getOption( 'useaddressastitle' ); + $metaData = explode( $separator, $value ); - $coordinates = $this->stringToLatLongValue( array_shift( $metaData ) ); + $coordinatesOrAddress = array_shift( $metaData ); + $coordinates = $this->stringToLatLongValue( $coordinatesOrAddress ); $location = new Location( $coordinates ); - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $this->setTitleOrLink( $location, array_shift( $metaData ) ); } + else if ( $useaddressastitle && $this->isAddress( $coordinatesOrAddress ) ) { + $location->setTitle( $coordinatesOrAddress ); + } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $location->setText( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $location->setIcon( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $location->setGroup( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $location->setInlineLabel( array_shift( $metaData ) ); } @@ -94,7 +108,7 @@ private function getExpandedLink( $link ) { return ''; } - return $title->getFullUrl(); + return $title->getFullURL(); } /** @@ -104,19 +118,37 @@ private function getExpandedLink( $link ) { * @throws ParseException */ private function stringToLatLongValue( $location ) { - if ( $this->supportGeocoding && Geocoders::canGeocode() ) { - $location = Geocoders::attemptToGeocode( $location ); + if ( Geocoders::canGeocode() ) { + $latLongValue = Geocoders::attemptToGeocode( $location, $this->getOption( 'geoService' ) ); - if ( $location === false ) { + if ( $latLongValue === false ) { throw new ParseException( 'Failed to parse or geocode' ); } - assert( $location instanceof LatLongValue ); - return $location; + assert( $latLongValue instanceof LatLongValue ); + return $latLongValue; } $parser = new GeoCoordinateParser( new \ValueParsers\ParserOptions() ); return $parser->parse( $location ); } + /** + * @param string $coordsOrAddress + * + * @return boolean + */ + private function isAddress( $coordsOrAddress ) { + $coordinateParser = new GeoCoordinateParser( new \ValueParsers\ParserOptions() ); + + try { + $coordinateParser->parse( $coordsOrAddress ); + } + catch ( ParseException $parseException ) { + return true; + } + + return false; + } + } diff --git a/includes/parsers/RectangleParser.php b/includes/parsers/RectangleParser.php index 7fdb61373..981d8a21e 100644 --- a/includes/parsers/RectangleParser.php +++ b/includes/parsers/RectangleParser.php @@ -40,23 +40,23 @@ public function stringParse( $value ) { $this->stringToLatLongValue( $rectangleData[1] ) ); - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $rectangle->setTitle( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $rectangle->setText( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $rectangle->setStrokeColor( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $rectangle->setStrokeOpacity( array_shift( $metaData ) ); } - if ( $metaData !== array() ) { + if ( $metaData !== [] ) { $rectangle->setStrokeWeight( array_shift( $metaData ) ); } diff --git a/includes/properties/iBubbleMapElement.php b/includes/properties/iBubbleMapElement.php deleted file mode 100644 index 74203daff..000000000 --- a/includes/properties/iBubbleMapElement.php +++ /dev/null @@ -1,24 +0,0 @@ - @@ -18,110 +18,86 @@ } call_user_func( function() { - global $wgResourceModules, $wgHooks; + global $wgResourceModules; $pathParts = ( explode( DIRECTORY_SEPARATOR . 'extensions' . DIRECTORY_SEPARATOR, __DIR__, 2 ) ); - $wgResourceModules['ext.maps.googlemaps3'] = array( - 'dependencies' => array( 'ext.maps.common' ), + $wgResourceModules['ext.maps.googlemaps3'] = [ + 'dependencies' => [ 'ext.maps.common' ], 'localBasePath' => __DIR__, 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'jquery.googlemap.js', 'ext.maps.googlemaps3.js' - ), - 'messages' => array( + ], + 'messages' => [ 'maps-googlemaps3-incompatbrowser', 'maps-copycoords-prompt', 'maps-searchmarkers-text', 'maps-fullscreen-button', 'maps-fullscreen-button-tooltip', - ) - ); + ] + ]; - $wgResourceModules['ext.maps.gm3.markercluster'] = array( + $wgResourceModules['ext.maps.gm3.markercluster'] = [ 'localBasePath' => __DIR__ . '/gm3-util-library', 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'markerclusterer.js', - ), - ); + ], + ]; - $wgResourceModules['ext.maps.gm3.markerwithlabel'] = array( + $wgResourceModules['ext.maps.gm3.markerwithlabel'] = [ 'localBasePath' => __DIR__ . '/gm3-util-library', 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'markerwithlabel.js', - ), - 'styles' => array( + ], + 'styles' => [ 'markerwithlabel.css', - ), - ); + ], + ]; - $wgResourceModules['ext.maps.gm3.geoxml'] = array( + $wgResourceModules['ext.maps.gm3.geoxml'] = [ 'localBasePath' => __DIR__ . '/geoxml3', 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'geoxml3.js', 'ZipFile.complete.js', //kmz handling 'ProjectedOverlay.js', //Overlay handling - ), - ); + ], + ]; - $wgResourceModules['ext.maps.gm3.earth'] = array( + $wgResourceModules['ext.maps.gm3.earth'] = [ 'localBasePath' => __DIR__ . '/gm3-util-library', 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'googleearth-compiled.js', - ), - ); - - $wgHooks['MappingServiceLoad'][] = 'efMapsInitGoogleMaps3'; + ], + ]; } ); - -/** - * Initialization function for the Google Maps v3 service. - * - * @since 0.6.3 - * @ingroup MapsGoogleMaps3 - * - * @return boolean true - */ -function efMapsInitGoogleMaps3() { - global $wgAutoloadClasses; - - $wgAutoloadClasses['MapsGoogleMaps3'] = __DIR__ . '/Maps_GoogleMaps3.php'; - - MapsMappingServices::registerService( 'googlemaps3', 'MapsGoogleMaps3' ); - - // TODO: kill below code - $googleMaps = MapsMappingServices::getServiceInstance( 'googlemaps3' ); - $googleMaps->addFeature( 'display_map', 'MapsDisplayMapRenderer' ); - - return true; -} diff --git a/includes/services/GoogleMaps3/Maps_GoogleMaps3.php b/includes/services/GoogleMaps3/Maps_GoogleMaps3.php index a2c84008c..c8a9615eb 100644 --- a/includes/services/GoogleMaps3/Maps_GoogleMaps3.php +++ b/includes/services/GoogleMaps3/Maps_GoogleMaps3.php @@ -8,18 +8,15 @@ * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > + * @author Peter Grassberger < petertheone@gmail.com > */ class MapsGoogleMaps3 extends MapsMappingService { /** - * List of map types (keys) and their internal values (values). - * - * @since 0.7 - * - * @var array + * Maps user input map types to the Google Maps names for the map types. */ - public static $mapTypes = array( + private static $mapTypes = [ 'normal' => 'ROADMAP', 'roadmap' => 'ROADMAP', 'satellite' => 'SATELLITE', @@ -27,50 +24,32 @@ class MapsGoogleMaps3 extends MapsMappingService { 'terrain' => 'TERRAIN', 'physical' => 'TERRAIN', 'earth' => 'earth' - ); + ]; - /** - * List of supported map layers. - * - * @since 1.0 - * - * @var array - */ - protected static $mapLayers = array( + private static $mapLayers = [ 'traffic', 'bicycling' - ); + ]; - public static $typeControlStyles = array( + private static $typeControlStyles = [ 'default' => 'DEFAULT', 'horizontal' => 'HORIZONTAL_BAR', 'dropdown' => 'DROPDOWN_MENU' - ); + ]; - /** - * List of supported control names. - * - * @since 1.0 - * - * @var array - */ - protected static $controlNames = array( + private static $controlNames = [ 'pan', 'zoom', 'type', 'scale', - 'streetview' - ); + 'streetview', + 'rotate' + ]; - /** - * Constructor. - * - * @since 0.6.6 - */ public function __construct( $serviceName ) { parent::__construct( $serviceName, - array( 'googlemaps', 'google' ) + [ 'googlemaps', 'google' ] ); } @@ -84,23 +63,23 @@ public function addParameterInfo( array &$params ) { global $egMapsGMaps3DefTypeStyle, $egMapsGMaps3DefZoomStyle, $egMapsGMaps3AutoInfoWindows; global $egMapsResizableByDefault, $egMapsGMaps3DefaultTilt; - $params['zoom'] = array( + $params['zoom'] = [ 'type' => 'integer', - 'range' => array( 0, 20 ), + 'range' => [ 0, 20 ], 'default' => self::getDefaultZoom(), - 'message' => 'maps-googlemaps3-par-zoom', - ); + 'message' => 'maps-par-zoom', + ]; - $params['type'] = array( + $params['type'] = [ 'default' => $egMapsGMaps3Type, 'values' => self::getTypeNames(), 'message' => 'maps-googlemaps3-par-type', 'post-format' => function( $value ) { return MapsGoogleMaps3::$mapTypes[strtolower( $value )]; }, - ); + ]; - $params['types'] = array( + $params['types'] = [ 'dependencies' => 'type', 'default' => $egMapsGMaps3Types, 'values' => self::getTypeNames(), @@ -108,21 +87,21 @@ public function addParameterInfo( array &$params ) { 'islist' => true, 'post-format' => function( array $value ) { foreach ( $value as &$part ) { - $part = MapsGoogleMaps3::$mapTypes[strtolower( $part )]; + $part = self::$mapTypes[strtolower( $part )]; } return $value; }, - ); + ]; - $params['layers'] = array( + $params['layers'] = [ 'default' => $egMapsGMaps3Layers, 'values' => self::getLayerNames(), 'message' => 'maps-googlemaps3-par-layers', 'islist' => true, - ); + ]; - $params['controls'] = array( + $params['controls'] = [ 'default' => $egMapsGMaps3Controls, 'values' => self::$controlNames, 'message' => 'maps-googlemaps3-par-controls', @@ -130,103 +109,131 @@ public function addParameterInfo( array &$params ) { 'post-format' => function( $value ) { return array_map( 'strtolower', $value ); }, - ); + ]; - $params['zoomstyle'] = array( + $params['zoomstyle'] = [ 'default' => $egMapsGMaps3DefZoomStyle, - 'values' => array( 'default', 'small', 'large' ), + 'values' => [ 'default', 'small', 'large' ], 'message' => 'maps-googlemaps3-par-zoomstyle', 'post-format' => 'strtoupper', - ); + ]; - $params['typestyle'] = array( + $params['typestyle'] = [ 'default' => $egMapsGMaps3DefTypeStyle, 'values' => array_keys( self::$typeControlStyles ), 'message' => 'maps-googlemaps3-par-typestyle', 'post-format' => function( $value ) { - return MapsGoogleMaps3::$typeControlStyles[strtolower( $value )]; + return self::$typeControlStyles[strtolower( $value )]; }, - ); + ]; - $params['autoinfowindows'] = array( + $params['autoinfowindows'] = [ 'type' => 'boolean', 'default' => $egMapsGMaps3AutoInfoWindows, 'message' => 'maps-googlemaps3-par-autoinfowindows', - ); + ]; - $params['resizable'] = array( + $params['resizable'] = [ 'type' => 'boolean', 'default' => $egMapsResizableByDefault, - 'message' => 'maps-googlemaps3-par-resizable', - ); + 'message' => 'maps-par-resizable', + ]; - $params['kmlrezoom'] = array( + $params['kmlrezoom'] = [ 'type' => 'boolean', 'default' => $GLOBALS['egMapsRezoomForKML'], 'message' => 'maps-googlemaps3-par-kmlrezoom', - ); + ]; - $params['poi'] = array( + $params['poi'] = [ 'type' => 'boolean', 'default' => $GLOBALS['egMapsShowPOI'], 'message' => 'maps-googlemaps3-par-poi', - ); + ]; - $params['markercluster'] = array( + $params['markercluster'] = [ 'type' => 'boolean', 'default' => false, - 'message' => 'maps-googlemaps3-par-markercluster', - ); + 'message' => 'maps-par-markercluster', + ]; + + $params['clustergridsize'] = [ + 'type' => 'integer', + 'default' => 60, + 'message' => 'maps-googlemaps3-par-clustergridsize', + ]; + + $params['clustermaxzoom'] = [ + 'type' => 'integer', + 'default' => 20, + 'message' => 'maps-par-clustermaxzoom', + ]; + + $params['clusterzoomonclick'] = [ + 'type' => 'boolean', + 'default' => true, + 'message' => 'maps-par-clusterzoomonclick', + ]; + + $params['clusteraveragecenter'] = [ + 'type' => 'boolean', + 'default' => true, + 'message' => 'maps-googlemaps3-par-clusteraveragecenter', + ]; + + $params['clusterminsize'] = [ + 'type' => 'integer', + 'default' => 2, + 'message' => 'maps-googlemaps3-par-clusterminsize', + ]; - $params['tilt'] = array( + $params['tilt'] = [ 'type' => 'integer', 'default' => $egMapsGMaps3DefaultTilt, 'message' => 'maps-googlemaps3-par-tilt', - ); + ]; - $params['imageoverlays'] = array( + $params['imageoverlays'] = [ 'type' => 'mapsimageoverlay', - 'default' => array(), + 'default' => [], 'delimiter' => ';', 'islist' => true, 'message' => 'maps-googlemaps3-par-imageoverlays', - ); + ]; - $params['kml'] = array( - 'default' => array(), - 'message' => 'maps-googlemaps3-par-kml', + $params['kml'] = [ + 'default' => [], + 'message' => 'maps-par-kml', 'islist' => true, // new MapsParamFile() FIXME - ); + ]; - $params['gkml'] = array( - 'default' => array(), + $params['gkml'] = [ + 'default' => [], 'message' => 'maps-googlemaps3-par-gkml', 'islist' => true, - ); + ]; - $params['fusiontables'] = array( - 'default' => array(), + $params['fusiontables'] = [ + 'default' => [], 'message' => 'maps-googlemaps3-par-fusiontables', 'islist' => true, - ); + ]; - $params['searchmarkers'] = array( + $params['searchmarkers'] = [ 'default' => '', - 'message' => 'maps-googlemaps3-par-searchmarkers', + 'message' => 'maps-par-searchmarkers', // new CriterionSearchMarkers() FIXME - ); + ]; - $params['enablefullscreen'] = array( + $params['enablefullscreen'] = [ 'type' => 'boolean', 'default' => false, - 'message' => 'maps-googlemaps3-par-enable-fullscreen', - ); + 'message' => 'maps-par-enable-fullscreen', + ]; } /** - * @see iMappingService::getDefaultZoom - * * @since 0.6.5 */ public function getDefaultZoom() { @@ -275,22 +282,27 @@ public static function getLayerNames() { * @return array */ protected function getDependencies() { - return array( + return [ self::getApiScript( is_string( $GLOBALS['egMapsGMaps3Language'] ) ? $GLOBALS['egMapsGMaps3Language'] : $GLOBALS['egMapsGMaps3Language']->getCode() ) - ); + ]; } - public static function getApiScript( $langCode, array $urlArgs = array() ) { + public static function getApiScript( $langCode, array $urlArgs = [] ) { $urlArgs = array_merge( - array( - 'language' => self::getMappedLanguageCode( $langCode ), - 'sensor' => 'false' - ), + [ + 'language' => self::getMappedLanguageCode( $langCode ) + ], $urlArgs ); + if ( $GLOBALS['egMapsGMaps3ApiKey'] !== '' ) { + $urlArgs['key'] = $GLOBALS['egMapsGMaps3ApiKey']; + } + if ( $GLOBALS['egMapsGMaps3ApiVersion'] !== '' ) { + $urlArgs['v'] = $GLOBALS['egMapsGMaps3ApiVersion']; + } return Html::linkedScript( '//maps.googleapis.com/maps/api/js?' . wfArrayToCgi( $urlArgs ) ); } @@ -303,11 +315,11 @@ public static function getApiScript( $langCode, array $urlArgs = array() ) { * @return string The mapped code */ protected static function getMappedLanguageCode( $code ) { - $mappings = array( + $mappings = [ 'en_gb' => 'en-gb',// v3 supports en_gb - but wants us to call it en-gb 'he' => 'iw', // iw is googlish for hebrew 'fj' => 'fil', // google does not support Fijian - use Filipino as close(?) supported relative - ); + ]; if ( array_key_exists( $code, $mappings ) ) { $code = $mappings[$code]; @@ -326,7 +338,7 @@ protected static function getMappedLanguageCode( $code ) { public function getResourceModules() { return array_merge( parent::getResourceModules(), - array( 'ext.maps.googlemaps3' ) + [ 'ext.maps.googlemaps3' ] ); } } diff --git a/includes/services/GoogleMaps3/ext.maps.googlemaps3.js b/includes/services/GoogleMaps3/ext.maps.googlemaps3.js index e91248554..ce5880c2e 100644 --- a/includes/services/GoogleMaps3/ext.maps.googlemaps3.js +++ b/includes/services/GoogleMaps3/ext.maps.googlemaps3.js @@ -15,10 +15,11 @@ else { $( '.maps-googlemaps3' ).each( function() { var $this = $( this ); - $this.googlemaps( $.parseJSON( $this.find( 'div').text() ) ); + var map = $this.googlemaps( $.parseJSON( $this.find( 'div').text() ) ); + window.maps.googlemapsList.push(map); } ); } } ); -})( window.jQuery, mediaWiki ); \ No newline at end of file +})( window.jQuery, mediaWiki ); diff --git a/includes/services/GoogleMaps3/gm3-util-library/README b/includes/services/GoogleMaps3/gm3-util-library/README index e6cb45c71..64a2208cf 100644 --- a/includes/services/GoogleMaps3/gm3-util-library/README +++ b/includes/services/GoogleMaps3/gm3-util-library/README @@ -1,2 +1,6 @@ ==markerclusterer.js and markerwithlabel.js== -Is fetched from trunk @ http://google-maps-utility-library-v3.googlecode.com +Is fetched from trunk @ https://github.com/googlemaps/v3-utility-library + +On update don't forget to add the following line at the end of the file: + + window.MarkerClusterer = MarkerClusterer; diff --git a/includes/services/GoogleMaps3/gm3-util-library/markerclusterer.js b/includes/services/GoogleMaps3/gm3-util-library/markerclusterer.js index f8dcc5830..e5379c62a 100644 --- a/includes/services/GoogleMaps3/gm3-util-library/markerclusterer.js +++ b/includes/services/GoogleMaps3/gm3-util-library/markerclusterer.js @@ -3,7 +3,7 @@ /** * @name MarkerClustererPlus for Google Maps V3 - * @version 2.0.9 [February 20, 2012] + * @version 2.1.2 [May 28, 2014] * @author Gary Little * @fileoverview * The library creates and manages per-zoom-level clusters for large amounts of markers. @@ -15,14 +15,13 @@ * >V3 MarkerClusterer
port by Luke Mahe. MarkerClustererPlus was created by Gary Little. *

* v2.0 release: MarkerClustererPlus v2.0 is backward compatible with MarkerClusterer v1.0. It - * adds support for the ignoreHidden, title, printable, - * batchSizeIE, and calculator properties as well as support for - * four more events. It also allows greater control over the styling of the text that appears - * on the cluster marker. The documentation has been significantly improved and the overall - * code has been simplified and polished. Very large numbers of markers can now be managed - * without causing Javascript timeout errors on Internet Explorer. Note that the name of the - * clusterclick event has been deprecated. The new name is click, - * so please change your application code now. + * adds support for the ignoreHidden, title, batchSizeIE, + * and calculator properties as well as support for four more events. It also allows + * greater control over the styling of the text that appears on the cluster marker. The + * documentation has been significantly improved and the overall code has been simplified and + * polished. Very large numbers of markers can now be managed without causing Javascript timeout + * errors on Internet Explorer. Note that the name of the clusterclick event has been + * deprecated. The new name is click, so please change your application code now. */ /** @@ -47,36 +46,34 @@ * style the cluster icon is determined by calling the calculator function. * * @property {string} url The URL of the cluster icon image file. Required. - * @property {number} height The height (in pixels) of the cluster icon. Required. - * @property {number} width The width (in pixels) of the cluster icon. Required. - * @property {Array} [anchor] The anchor position (in pixels) of the label text to be shown on - * the cluster icon, relative to the top left corner of the icon. - * The format is [yoffset, xoffset]. The yoffset must be positive - * and less than height and the xoffset must be positive and less - * than width. The default is to anchor the label text so that it is centered - * on the icon. + * @property {number} height The display height (in pixels) of the cluster icon. Required. + * @property {number} width The display width (in pixels) of the cluster icon. Required. + * @property {Array} [anchorText] The position (in pixels) from the center of the cluster icon to + * where the text label is to be centered and drawn. The format is [yoffset, xoffset] + * where yoffset increases as you go down from center and xoffset + * increases to the right of center. The default is [0, 0]. * @property {Array} [anchorIcon] The anchor position (in pixels) of the cluster icon. This is the * spot on the cluster icon that is to be aligned with the cluster position. The format is * [yoffset, xoffset] where yoffset increases as you go down and - * xoffset increases to the right. The default anchor position is the center of the - * cluster icon. + * xoffset increases to the right of the top-left corner of the icon. The default + * anchor position is the center of the cluster icon. * @property {string} [textColor="black"] The color of the label text shown on the * cluster icon. * @property {number} [textSize=11] The size (in pixels) of the label text shown on the * cluster icon. - * @property {number} [textDecoration="none"] The value of the CSS text-decoration + * @property {string} [textDecoration="none"] The value of the CSS text-decoration * property for the label text shown on the cluster icon. - * @property {number} [fontWeight="bold"] The value of the CSS font-weight + * @property {string} [fontWeight="bold"] The value of the CSS font-weight * property for the label text shown on the cluster icon. - * @property {number} [fontStyle="normal"] The value of the CSS font-style + * @property {string} [fontStyle="normal"] The value of the CSS font-style * property for the label text shown on the cluster icon. - * @property {number} [fontFamily="Arial,sans-serif"] The value of the CSS font-family + * @property {string} [fontFamily="Arial,sans-serif"] The value of the CSS font-family * property for the label text shown on the cluster icon. * @property {string} [backgroundPosition="0 0"] The position of the cluster icon image * within the image defined by url. The format is "xpos ypos" * (the same format as for the CSS background-position property). You must set * this property appropriately when the image defined by url represents a sprite - * containing multiple images. + * containing multiple images. Note that the position must be specified in px units. */ /** * @name ClusterIconInfo @@ -86,6 +83,9 @@ * @property {string} text The text of the label to be shown on the cluster icon. * @property {number} index The index plus 1 of the element in the styles * array to be used to style the cluster icon. + * @property {string} title The tooltip to display when the mouse moves over the cluster icon. + * If this value is undefined or "", title is set to the + * value of the title property passed to the MarkerClusterer. */ /** * A cluster icon. @@ -101,6 +101,7 @@ function ClusterIcon(cluster, styles) { cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView); this.cluster_ = cluster; + this.className_ = cluster.getMarkerClusterer().getClusterClass(); this.styles_ = styles; this.center_ = null; this.div_ = null; @@ -120,6 +121,7 @@ ClusterIcon.prototype.onAdd = function () { var cDraggingMapByCluster; this.div_ = document.createElement("div"); + this.div_.className = this.className_; if (this.visible_) { this.show(); } @@ -127,7 +129,7 @@ ClusterIcon.prototype.onAdd = function () { this.getPanes().overlayMouseTarget.appendChild(this.div_); // Fix for Issue 157 - google.maps.event.addListener(this.getMap(), "bounds_changed", function () { + this.boundsChangedListener_ = google.maps.event.addListener(this.getMap(), "bounds_changed", function () { cDraggingMapByCluster = cMouseDownInCluster; }); @@ -139,6 +141,7 @@ ClusterIcon.prototype.onAdd = function () { google.maps.event.addDomListener(this.div_, "click", function (e) { cMouseDownInCluster = false; if (!cDraggingMapByCluster) { + var theBounds; var mz; var mc = cClusterIcon.cluster_.getMarkerClusterer(); /** @@ -155,11 +158,16 @@ ClusterIcon.prototype.onAdd = function () { if (mc.getZoomOnClick()) { // Zoom into the cluster. mz = mc.getMaxZoom(); - mc.getMap().fitBounds(cClusterIcon.cluster_.getBounds()); - // Don't zoom beyond the max zoom level - if (mz !== null && (mc.getMap().getZoom() > mz)) { - mc.getMap().setZoom(mz + 1); - } + theBounds = cClusterIcon.cluster_.getBounds(); + mc.getMap().fitBounds(theBounds); + // There is a fix for Issue 170 here: + setTimeout(function () { + mc.getMap().fitBounds(theBounds); + // Don't zoom beyond the max zoom level + if (mz !== null && (mc.getMap().getZoom() > mz)) { + mc.getMap().setZoom(mz + 1); + } + }, 100); } // Prevent event propagation to the map: @@ -200,6 +208,7 @@ ClusterIcon.prototype.onAdd = function () { ClusterIcon.prototype.onRemove = function () { if (this.div_ && this.div_.parentNode) { this.hide(); + google.maps.event.removeListener(this.boundsChangedListener_); google.maps.event.clearInstanceListeners(this.div_); this.div_.parentNode.removeChild(this.div_); this.div_ = null; @@ -235,15 +244,38 @@ ClusterIcon.prototype.hide = function () { */ ClusterIcon.prototype.show = function () { if (this.div_) { + var img = ""; + // NOTE: values must be specified in px units + var bp = this.backgroundPosition_.split(" "); + var spriteH = parseInt(bp[0].replace(/^\s+|\s+$/g, ""), 10); + var spriteV = parseInt(bp[1].replace(/^\s+|\s+$/g, ""), 10); var pos = this.getPosFromLatLng_(this.center_); this.div_.style.cssText = this.createCss(pos); - if (this.cluster_.printable_) { - // (Would like to use "width: inherit;" below, but doesn't work with MSIE) - this.div_.innerHTML = "

" + this.sums_.text + "
"; + img = ""; + this.div_.innerHTML = img + "
" + this.sums_.text + "
"; + if (typeof this.sums_.title === "undefined" || this.sums_.title === "") { + this.div_.title = this.cluster_.getMarkerClusterer().getTitle(); } else { - this.div_.innerHTML = this.sums_.text; + this.div_.title = this.sums_.title; } - this.div_.title = this.cluster_.getMarkerClusterer().getTitle(); this.div_.style.display = ""; } this.visible_ = true; @@ -263,7 +295,7 @@ ClusterIcon.prototype.useStyle = function (sums) { this.url_ = style.url; this.height_ = style.height; this.width_ = style.width; - this.anchor_ = style.anchor; + this.anchorText_ = style.anchorText || [0, 0]; this.anchorIcon_ = style.anchorIcon || [parseInt(this.height_ / 2, 10), parseInt(this.width_ / 2, 10)]; this.textColor_ = style.textColor || "black"; this.textSize_ = style.textSize || 11; @@ -293,38 +325,9 @@ ClusterIcon.prototype.setCenter = function (center) { */ ClusterIcon.prototype.createCss = function (pos) { var style = []; - if (!this.cluster_.printable_) { - style.push('background-image:url(' + this.url_ + ');'); - style.push('background-position:' + this.backgroundPosition_ + ';'); - } - - if (typeof this.anchor_ === 'object') { - if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 && - this.anchor_[0] < this.height_) { - style.push('height:' + (this.height_ - this.anchor_[0]) + - 'px; padding-top:' + this.anchor_[0] + 'px;'); - } else { - style.push('height:' + this.height_ + 'px; line-height:' + this.height_ + - 'px;'); - } - if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 && - this.anchor_[1] < this.width_) { - style.push('width:' + (this.width_ - this.anchor_[1]) + - 'px; padding-left:' + this.anchor_[1] + 'px;'); - } else { - style.push('width:' + this.width_ + 'px; text-align:center;'); - } - } else { - style.push('height:' + this.height_ + 'px; line-height:' + - this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;'); - } - - style.push('cursor:pointer; top:' + pos.y + 'px; left:' + - pos.x + 'px; color:' + this.textColor_ + '; position:absolute; font-size:' + - this.textSize_ + 'px; font-family:' + this.fontFamily_ + '; font-weight:' + - this.fontWeight_ + '; font-style:' + this.fontStyle_ + '; text-decoration:' + - this.textDecoration_ + ';'); - + style.push("cursor: pointer;"); + style.push("position: absolute; top: " + pos.y + "px; left: " + pos.x + "px;"); + style.push("width: " + this.width_ + "px; height: " + this.height_ + "px;"); return style.join(""); }; @@ -339,6 +342,8 @@ ClusterIcon.prototype.getPosFromLatLng_ = function (latlng) { var pos = this.getProjection().fromLatLngToDivPixel(latlng); pos.x -= this.anchorIcon_[1]; pos.y -= this.anchorIcon_[0]; + pos.x = parseInt(pos.x, 10); + pos.y = parseInt(pos.y, 10); return pos; }; @@ -356,7 +361,6 @@ function Cluster(mc) { this.gridSize_ = mc.getGridSize(); this.minClusterSize_ = mc.getMinimumClusterSize(); this.averageCenter_ = mc.getAverageCenter(); - this.printable_ = mc.getPrintable(); this.markers_ = []; this.center_ = null; this.bounds_ = null; @@ -598,11 +602,9 @@ Cluster.prototype.isMarkerAlreadyAdded_ = function (marker) { * text property of the result returned by the default calculator). * If set to true and you change the visibility of a marker being clustered, be * sure to also call MarkerClusterer.repaint(). - * @property {boolean} [printable=false] Whether to make the cluster icons printable. Do not - * set to true if the url fields in the styles array - * refer to image sprite files. * @property {string} [title=""] The tooltip to display when the mouse moves over a cluster - * marker. + * marker. (Alternatively, you can use a custom calculator function to specify a + * different tooltip for each cluster marker.) * @property {function} [calculator=MarkerClusterer.CALCULATOR] The function used to determine * the text to be displayed on a cluster marker and the index indicating which style to use * for the cluster marker. The input parameters for the function are (1) the array of markers @@ -615,13 +617,23 @@ Cluster.prototype.isMarkerAlreadyAdded_ = function (marker) { * index minus 1. For example, the default calculator returns a * text value of "125" and an index of 3 * for a cluster icon representing 125 markers so the element used in the styles - * array is 2. + * array is 2. A calculator may also return a title + * property that contains the text of the tooltip to be used for the cluster marker. If + * title is not defined, the tooltip is set to the value of the title + * property for the MarkerClusterer. + * @property {string} [clusterClass="cluster"] The name of the CSS class defining general styles + * for the cluster markers. Use this class to define CSS styles that are not set up by the code + * that processes the styles array. * @property {Array} [styles] An array of {@link ClusterIconStyle} elements defining the styles * of the cluster markers to be used. The element to be used to style a given cluster marker * is determined by the function defined by the calculator property. * The default is an array of {@link ClusterIconStyle} elements whose properties are derived * from the values for imagePath, imageExtension, and * imageSizes. + * @property {boolean} [enableRetinaIcons=false] Whether to allow the use of cluster icons that + * have sizes that are some multiple (typically double) of their actual display size. Icons such + * as these look better when viewed on high-resolution monitors such as Apple's Retina displays. + * Note: if this property is true, sprites cannot be used as cluster icons. * @property {number} [batchSize=MarkerClusterer.BATCH_SIZE] Set this property to the * number of markers to be processed in a single batch when using a browser other than * Internet Explorer (for Internet Explorer, use the batchSizeIE property instead). @@ -685,9 +697,9 @@ function MarkerClusterer(map, opt_markers, opt_options) { if (opt_options.ignoreHidden !== undefined) { this.ignoreHidden_ = opt_options.ignoreHidden; } - this.printable_ = false; - if (opt_options.printable !== undefined) { - this.printable_ = opt_options.printable; + this.enableRetinaIcons_ = false; + if (opt_options.enableRetinaIcons !== undefined) { + this.enableRetinaIcons_ = opt_options.enableRetinaIcons; } this.imagePath_ = opt_options.imagePath || MarkerClusterer.IMAGE_PATH; this.imageExtension_ = opt_options.imageExtension || MarkerClusterer.IMAGE_EXTENSION; @@ -695,6 +707,7 @@ function MarkerClusterer(map, opt_markers, opt_options) { this.calculator_ = opt_options.calculator || MarkerClusterer.CALCULATOR; this.batchSize_ = opt_options.batchSize || MarkerClusterer.BATCH_SIZE; this.batchSizeIE_ = opt_options.batchSizeIE || MarkerClusterer.BATCH_SIZE_IE; + this.clusterClass_ = opt_options.clusterClass || "cluster"; if (navigator.userAgent.toLowerCase().indexOf("msie") !== -1) { // Try to avoid IE timeout when processing a huge number of markers: @@ -728,8 +741,8 @@ MarkerClusterer.prototype.onAdd = function () { // zoom slider is clicked, a "zoom_changed" event is fired even though // the map doesn't zoom out any further. In this situation, no "idle" // event is triggered so the cluster markers that have been removed - // do not get redrawn. - if (this.getZoom() === 0) { + // do not get redrawn. Same goes for a zoom in at maxZoom. + if (this.getZoom() === (this.get("minZoom") || 0) || this.getZoom() === this.get("maxZoom")) { google.maps.event.trigger(this, "idle"); } }), @@ -751,7 +764,9 @@ MarkerClusterer.prototype.onRemove = function () { // Put all the managed markers back on the map: for (i = 0; i < this.markers_.length; i++) { - this.markers_[i].setMap(this.activeMap_); + if (this.markers_[i].getMap() !== this.activeMap_) { + this.markers_[i].setMap(this.activeMap_); + } } // Remove all clusters: @@ -972,6 +987,26 @@ MarkerClusterer.prototype.setIgnoreHidden = function (ignoreHidden) { }; +/** + * Returns the value of the enableRetinaIcons property. + * + * @return {boolean} True if enableRetinaIcons property is set. + */ +MarkerClusterer.prototype.getEnableRetinaIcons = function () { + return this.enableRetinaIcons_; +}; + + +/** + * Sets the value of the enableRetinaIcons property. + * + * @param {boolean} enableRetinaIcons The value of the enableRetinaIcons property. + */ +MarkerClusterer.prototype.setEnableRetinaIcons = function (enableRetinaIcons) { + this.enableRetinaIcons_ = enableRetinaIcons; +}; + + /** * Returns the value of the imageExtension property. * @@ -1054,42 +1089,42 @@ MarkerClusterer.prototype.setCalculator = function (calculator) { /** - * Returns the value of the printable property. + * Returns the value of the batchSizeIE property. * - * @return {boolean} the value of the printable property. + * @return {number} the value of the batchSizeIE property. */ -MarkerClusterer.prototype.getPrintable = function () { - return this.printable_; +MarkerClusterer.prototype.getBatchSizeIE = function () { + return this.batchSizeIE_; }; /** - * Sets the value of the printable property. + * Sets the value of the batchSizeIE property. * - * @param {boolean} printable The value of the printable property. + * @param {number} batchSizeIE The value of the batchSizeIE property. */ -MarkerClusterer.prototype.setPrintable = function (printable) { - this.printable_ = printable; +MarkerClusterer.prototype.setBatchSizeIE = function (batchSizeIE) { + this.batchSizeIE_ = batchSizeIE; }; /** - * Returns the value of the batchSizeIE property. + * Returns the value of the clusterClass property. * - * @return {number} the value of the batchSizeIE property. + * @return {string} the value of the clusterClass property. */ -MarkerClusterer.prototype.getBatchSizeIE = function () { - return this.batchSizeIE_; +MarkerClusterer.prototype.getClusterClass = function () { + return this.clusterClass_; }; /** - * Sets the value of the batchSizeIE property. + * Sets the value of the clusterClass property. * - * @param {number} batchSizeIE The value of the batchSizeIE property. + * @param {string} clusterClass The value of the clusterClass property. */ -MarkerClusterer.prototype.setBatchSizeIE = function (batchSizeIE) { - this.batchSizeIE_ = batchSizeIE; +MarkerClusterer.prototype.setClusterClass = function (clusterClass) { + this.clusterClass_ = clusterClass; }; @@ -1156,9 +1191,11 @@ MarkerClusterer.prototype.addMarker = function (marker, opt_nodraw) { * @param {boolean} [opt_nodraw] Set to true to prevent redrawing. */ MarkerClusterer.prototype.addMarkers = function (markers, opt_nodraw) { - var i; - for (i = 0; i < markers.length; i++) { - this.pushMarkerTo_(markers[i]); + var key; + for (key in markers) { + if (markers.hasOwnProperty(key)) { + this.pushMarkerTo_(markers[key]); + } } if (!opt_nodraw) { this.redraw_(); @@ -1380,7 +1417,7 @@ MarkerClusterer.prototype.distanceBetweenPoints_ = function (p1, p2) { var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * - Math.sin(dLon / 2) * Math.sin(dLon / 2); + Math.sin(dLon / 2) * Math.sin(dLon / 2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var d = R * c; return d; @@ -1535,6 +1572,7 @@ MarkerClusterer.prototype.extend = function (obj1, obj2) { */ MarkerClusterer.CALCULATOR = function (markers, numStyles) { var index = 0; + var title = ""; var count = markers.length.toString(); var dv = count; @@ -1546,7 +1584,8 @@ MarkerClusterer.CALCULATOR = function (markers, numStyles) { index = Math.min(index, numStyles); return { text: count, - index: index + index: index, + title: title }; }; @@ -1575,7 +1614,7 @@ MarkerClusterer.BATCH_SIZE_IE = 500; * @type {string} * @constant */ -MarkerClusterer.IMAGE_PATH = "//google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m"; +MarkerClusterer.IMAGE_PATH = "../images/m"; /** diff --git a/includes/services/GoogleMaps3/jquery.googlemap.js b/includes/services/GoogleMaps3/jquery.googlemap.js index 09065a133..194e775cc 100644 --- a/includes/services/GoogleMaps3/jquery.googlemap.js +++ b/includes/services/GoogleMaps3/jquery.googlemap.js @@ -3,6 +3,7 @@ * @see http://www.mediawiki.org/wiki/Extension:Maps * * @author Jeroen De Dauw + * @author Peter Grassberger < petertheone@gmail.com > */ (function ($, mw) { @@ -53,7 +54,7 @@ var getBounds = function() { if (( options.centre === false || options.zoom === false ) && options.locations.length > 1) { - bounds = new google.maps.LatLngBounds(); + var bounds = new google.maps.LatLngBounds(); for (var i = _this.markers.length - 1; i >= 0; i--) { bounds.extend(_this.markers[i].getPosition()); @@ -64,7 +65,7 @@ }; var setZoom = function(bounds) { - if (options.zoom === false) { + if (options.zoom === false) { _this.map.fitBounds(bounds); } else { @@ -89,7 +90,7 @@ labelClass:'markerwithlabel' }; - if (markerData.icon !== '') { + if (!markerData.hasOwnProperty('icon') || markerData.icon !== '') { markerOptions.icon = markerData.icon; } @@ -161,6 +162,10 @@ * Removes all markers from the map. */ this.removeMarkers = function () { + if (this.markercluster) { + this.markercluster.setMap(null); + this.markercluster = null; + } for (var i = this.markers.length - 1; i >= 0; i--) { this.markers[i].setMap(null); } @@ -215,7 +220,7 @@ doc[i].gpolygons, doc[i].gpolylines, doc[i].ggroundoverlays - ]); + ]); } } } @@ -225,7 +230,7 @@ map:_this.map, zoom:options.kmlrezoom, failedParse:function(){ - alert(mediaWiki.msg('maps-kml-parsing-failed')); + alert(mw.msg('maps-kml-parsing-failed')); } }); geoXml.options.afterParse = function(docs){ @@ -255,8 +260,6 @@ label.appendChild(text); toggleDiv.appendChild(label); - - console.log(toggleDiv); })(docs[i]); } _this.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleDiv); @@ -444,7 +447,26 @@ } } this.map.fitBounds(bounds); - } + }; + + this.createMarkerCluster = function() { + if ( !options.markercluster ) { + return; + } + if (this.markercluster) { + this.markercluster.setMap(null); + this.markercluster = null; + } + this.markercluster = new MarkerClusterer( this.map, this.markers, { + imagePath: mw.config.get( 'wgScriptPath' ) + + '/extensions/Maps/includes/images/m', + gridSize: this.options.clustergridsize, + maxZoom: this.options.clustermaxzoom, + zoomOnClick: this.options.clusterzoomonclick, + averageCenter: this.options.clusteraveragecenter, + minimumClusterSize: this.options.clusterminsize + } ); + }; this.initializeMap = function () { var mapOptions = { @@ -458,6 +480,7 @@ mapOptions.mapTypeControl = $.inArray('type', options.controls) != -1; mapOptions.scaleControl = $.inArray('scale', options.controls) != -1; mapOptions.streetViewControl = $.inArray('streetview', options.controls) != -1; + mapOptions.rotateControl = $.inArray('rotate', options.controls) != -1; for (i in options.types) { if (typeof( options.types[i] ) !== 'function') { @@ -613,21 +636,11 @@ /** * Allows grouping of markers. */ - if ( options.markercluster ) { - mw.loader.using( - 'ext.maps.gm3.markercluster', - function() { - _this.markercluster = new MarkerClusterer( _this.map, _this.markers, { - averageCenter: true - } ); - } - ); - } - + this.createMarkerCluster(); if (options.searchmarkers) { - var searchBoxValue = mediaWiki.msg('maps-searchmarkers-text'); + var searchBoxValue = mw.msg('maps-searchmarkers-text'); var searchBox = $(''); var searchContainer = document.createElement('div'); searchContainer.style.padding = '5px'; @@ -647,7 +660,7 @@ var marker = _this.markers[i]; if (options.searchmarkers == 'title') { haystack = marker.title; - } else if (options.searchmarkers == 'all') { + } else { haystack = marker.title + marker.text; } @@ -780,7 +793,7 @@ controlUI.style.textAlign = 'center'; controlUI.style.boxShadow = 'rgba(0, 0, 0, 0.298039) 0px 1px 4px -1px'; controlUI.style.backgroundClip = 'padding-box'; - controlUI.title = mediaWiki.msg('maps-fullscreen-button-tooltip'); + controlUI.title = mw.msg('maps-fullscreen-button-tooltip'); controlDiv.appendChild(controlUI); var controlText = document.createElement('div'); @@ -789,7 +802,7 @@ controlText.style.fontWeight = '400'; controlText.style.color = 'rgb(86, 86, 86)'; controlText.style.padding = '1px 6px'; - controlText.innerHTML = mediaWiki.msg('maps-fullscreen-button'); + controlText.innerHTML = mw.msg('maps-fullscreen-button'); controlUI.appendChild(controlText); google.maps.event.addDomListener(controlUI, 'click', function() { @@ -846,10 +859,10 @@ }; if ( event.latLng === undefined ) { - this.openWindow.open( this.map, this ); + this.openWindow.open( _this.map, this ); } else { - this.openWindow.open( this.map ); + this.openWindow.open( _this.map ); } } @@ -860,14 +873,20 @@ } }else{ google.maps.event.addListener(object, 'rightclick', function (event) { - prompt(mediaWiki.msg('maps-copycoords-prompt'), event.latLng.lat() + ',' + event.latLng.lng()); + prompt(mw.msg('maps-copycoords-prompt'), event.latLng.lat() + ',' + event.latLng.lng()); }); } } //Complete path to OpenLayers WMS layer - this.setup(); + if (!options.markercluster) { + this.setup(); + } else { + mw.loader.using( 'ext.maps.gm3.markercluster', function() { + _this.setup(); + } ); + } return this; diff --git a/includes/services/Leaflet/Leaflet.php b/includes/services/Leaflet/Leaflet.php index 00b6f7256..9baaac852 100644 --- a/includes/services/Leaflet/Leaflet.php +++ b/includes/services/Leaflet/Leaflet.php @@ -1,7 +1,7 @@ array( 'ext.maps.common' ), + $wgResourceModules['ext.maps.leaflet'] = [ + 'dependencies' => [ 'ext.maps.common' ], 'localBasePath' => __DIR__, 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'jquery.leaflet.js', 'ext.maps.leaflet.js', - ), - 'messages' => array( + ], + 'messages' => [ 'maps-markers', 'maps-copycoords-prompt', 'maps-searchmarkers-text', - ), - ); -} ); - -/** - * Initialization function for the Leaflet service. - * - * @ingroup Leaflet - * - * @return boolean true - */ -function efMapsInitLeaflet() { - global $wgAutoloadClasses; + ], + ]; - $wgAutoloadClasses['MapsLeaflet'] = __DIR__ . '/Maps_Leaflet.php'; + $wgResourceModules['ext.maps.leaflet.fullscreen'] = [ + 'localBasePath' => __DIR__ . '/leaflet.fullscreen', + 'remoteExtPath' => end( $pathParts ) . '/leaflet.fullscreen', + 'group' => 'ext.maps', + 'targets' => [ + 'mobile', + 'desktop' + ], + 'scripts' => [ + 'Control.FullScreen.js', + ], + 'styles' => [ + 'Control.FullScreen.css', + ], + ]; - MapsMappingServices::registerService( 'leaflet', 'MapsLeaflet' ); - $leafletMaps = MapsMappingServices::getServiceInstance( 'leaflet' ); - $leafletMaps->addFeature( 'display_map', 'MapsDisplayMapRenderer' ); + $wgResourceModules['ext.maps.leaflet.markercluster'] = [ + 'localBasePath' => __DIR__ . '/leaflet.markercluster', + 'remoteExtPath' => end( $pathParts ), + 'group' => 'ext.maps', + 'targets' => [ + 'mobile', + 'desktop' + ], + 'scripts' => [ + 'leaflet.markercluster.js', + ], + 'styles' => [ + 'MarkerCluster.css', + ], + ]; - return true; -} + $wgResourceModules['ext.maps.leaflet.providers'] = [ + 'localBasePath' => __DIR__ . '/leaflet-providers', + 'remoteExtPath' => end( $pathParts ) . '/leaflet-providers', + 'group' => 'ext.maps', + 'targets' => [ + 'mobile', + 'desktop' + ], + 'scripts' => [ + 'leaflet-providers.js', + ], + ]; +} ); diff --git a/includes/services/Leaflet/Maps_Leaflet.php b/includes/services/Leaflet/Maps_Leaflet.php index ad8f246ee..0aad0d1e8 100644 --- a/includes/services/Leaflet/Maps_Leaflet.php +++ b/includes/services/Leaflet/Maps_Leaflet.php @@ -9,13 +9,10 @@ */ class MapsLeaflet extends MapsMappingService { - /** - * Constructor - */ public function __construct( $serviceName ) { parent::__construct( $serviceName, - array( 'leafletmaps', 'leaflet' ) + [ 'leafletmaps', 'leaflet' ] ); } @@ -25,30 +22,81 @@ public function __construct( $serviceName ) { * @since 3.0 */ public function addParameterInfo( array &$params ) { - $params['zoom'] = array( + global $GLOBALS; + + $params['zoom'] = [ 'type' => 'integer', - 'range' => array( 0, 20 ), + 'range' => [ 0, 20 ], 'default' => false, - 'message' => 'maps-leaflet-par-zoom' - ); + 'message' => 'maps-par-zoom' + ]; - $params['defzoom'] = array( + $params['defzoom'] = [ 'type' => 'integer', - 'range' => array( 0, 20 ), + 'range' => [ 0, 20 ], 'default' => self::getDefaultZoom(), 'message' => 'maps-leaflet-par-defzoom' - ); + ]; + + $params['layer'] = [ + 'type' => 'string', + 'values' => array_keys( $GLOBALS['egMapsLeafletAvailableLayers'], true, true ), + 'default' => $GLOBALS['egMapsLeafletLayer'], + 'message' =>'maps-leaflet-par-layer', + ]; - $params['resizable'] = array( + $params['overlaylayers'] = [ + 'type' => 'string', + 'values' => array_keys( $GLOBALS['egMapsLeafletAvailableOverlayLayers'], true, true ), + 'default' => $GLOBALS['egMapsLeafletOverlayLayers'], + 'message' =>'maps-leaflet-par-overlaylayers', + 'islist' => true, + ]; + + $params['resizable'] = [ 'type' => 'boolean', 'default' => $GLOBALS['egMapsResizableByDefault'], - 'message' => 'maps-leaflet-par-resizable' - ); + 'message' => 'maps-par-resizable' + ]; + + $params['enablefullscreen'] = [ + 'type' => 'boolean', + 'default' => false, + 'message' => 'maps-par-enable-fullscreen', + ]; + + $params['markercluster'] = [ + 'type' => 'boolean', + 'default' => false, + 'message' => 'maps-par-markercluster', + ]; + + $params['clustermaxzoom'] = [ + 'type' => 'integer', + 'default' => 20, + 'message' => 'maps-par-clustermaxzoom', + ]; + + $params['clusterzoomonclick'] = [ + 'type' => 'boolean', + 'default' => true, + 'message' => 'maps-par-clusterzoomonclick', + ]; + + $params['clustermaxradius'] = [ + 'type' => 'integer', + 'default' => 80, + 'message' => 'maps-par-maxclusterradius', + ]; + + $params['clusterspiderfy'] = [ + 'type' => 'boolean', + 'default' => true, + 'message' => 'maps-leaflet-par-clusterspiderfy', + ]; } /** - * @see iMappingService::getDefaultZoom - * * @since 3.0 */ public function getDefaultZoom() { @@ -80,17 +128,16 @@ public function getMapId( $increment = true ) { public function getResourceModules() { return array_merge( parent::getResourceModules(), - array( 'ext.maps.leaflet' ) + [ 'ext.maps.leaflet' ] ); } protected function getDependencies() { $leafletPath = $GLOBALS['wgScriptPath'] . '/extensions/Maps/includes/services/Leaflet/leaflet'; - return array( + return [ Html::linkedStyle( "$leafletPath/leaflet.css" ), - '', Html::linkedScript( "$leafletPath/leaflet.js" ), - ); + ]; } } diff --git a/includes/services/Leaflet/ext.maps.leaflet.js b/includes/services/Leaflet/ext.maps.leaflet.js index 175b8c2d7..94e23b9e1 100644 --- a/includes/services/Leaflet/ext.maps.leaflet.js +++ b/includes/services/Leaflet/ext.maps.leaflet.js @@ -11,7 +11,8 @@ $( '.maps-leaflet' ).each( function() { var $this = $( this ); - $this.leafletmaps( $.parseJSON( $this.find( 'div').text() ) ); + var map = $this.leafletmaps( $.parseJSON( $this.find( 'div').text() ) ); + window.maps.leafletList.push(map); } ); } ); diff --git a/includes/services/Leaflet/jquery.leaflet.js b/includes/services/Leaflet/jquery.leaflet.js index a2d6e3ef2..79d355a74 100644 --- a/includes/services/Leaflet/jquery.leaflet.js +++ b/includes/services/Leaflet/jquery.leaflet.js @@ -3,13 +3,16 @@ * @see https://www.mediawiki.org/wiki/Extension:Maps * * @author Pavel Astakhov < pastakhov@yandex.ru > + * @author Peter Grassberger < petertheone@gmail.com > */ -(function ($, mw) { +(function ($, mw, L, MQ) { $.fn.leafletmaps = function ( options ) { var _this = this; this.map = null; this.options = options; + this.markers = []; + this.markercluster = null; /** * array point of all map elements (markers, lines, polygons, etc.) @@ -18,15 +21,14 @@ this.points = []; /** - * Creates a new marker with the provided data, - * adds it to the map, and returns it. + * Creates a new marker with the provided data and returns it. * @param {Object} markerData Contains the fields lat, lon, title, text and icon * @return {L.Marker} */ - this.addMarker = function (properties) { + this.createMarker = function (properties) { this.points.push( new L.LatLng(properties.lat, properties.lon) ); - if (properties.icon === '') { + if (!properties.hasOwnProperty('icon') || properties.icon === '') { var icon = new L.Icon.Default(); } else { var icon = new L.Icon({ @@ -39,8 +41,47 @@ icon:icon }; - var marker = L.marker( [properties.lat, properties.lon], markerOptions ).addTo( this.map ); - if( properties.text.length > 0 ) marker.bindPopup( properties.text ); + var marker = L.marker( [properties.lat, properties.lon], markerOptions ); + if( properties.hasOwnProperty('text') && properties.text.length > 0 ) marker.bindPopup( properties.text ); + + return marker; + }; + + /** + * Creates a new marker with the provided data, adds it to the map + * and returns it. + * @param {Object} markerData Contains the fields lat, lon, title, text and icon + * @return {L.Marker} + */ + this.addMarker = function (properties) { + var marker = this.createMarker(properties); + if (!this.options.markercluster) { + marker.addTo( this.map ); + } + this.markers.push( marker ); + return marker; + }; + + this.removeMarker = function (marker) { + this.map.removeLayer(marker); + this.points = []; + this.markers = this.markers.filter(function(object) { + return object !== marker; + }); + }; + + this.removeMarkers = function () { + if (this.markercluster) { + this.map.removeLayer(this.markercluster); + this.markercluster = null; + } + var map = this.map; + $.each(this.markers, function(index, marker) { + map.removeLayer(marker); + }); + + this.points = []; + this.markers = []; }; this.addLine = function (properties) { @@ -121,34 +162,133 @@ L.rectangle( bounds, options ).addTo(this.map); }; + this.createMarkerCluster = function () { + if ( !options.markercluster ) { + return; + } + var markers = this.markers; + + var markercluster = new L.MarkerClusterGroup({ + maxClusterRadius: options.clustermaxradius, + disableClusteringAtZoom: options.clustermaxzoom + 1, + zoomToBoundsOnClick: options.clusterzoomonclick, + spiderfyOnMaxZoom: options.clusterspiderfy, + iconCreateFunction: function(cluster) { + var childCount = cluster.getChildCount(); + + var imagePath = mw.config.get( 'wgScriptPath' ) + + '/extensions/Maps/includes/images/m'; + + var styles = [ + { + iconUrl: imagePath + '1.png', + iconSize: [53, 52] + }, + { + iconUrl: imagePath + '2.png', + iconSize: [56, 55] + }, + { + iconUrl: imagePath + '3.png', + iconSize: [66, 65] + }, + { + iconUrl: imagePath + '4.png', + iconSize: [78, 77] + }, + { + iconUrl: imagePath + '5.png', + iconSize: [90, 89] + } + ]; + + var index = 0; + var dv = childCount; + while (dv !== 0) { + dv = parseInt(dv / 10, 10); + index++; + } + var index = Math.min(index, styles.length); + index = Math.max(0, index - 1); + index = Math.min(styles.length - 1, index); + var style = styles[index]; + + return new L.divIcon({ + iconSize: style.iconSize, + className: '', + html: '' + + '' + childCount + '' + }); + } + }); + $.each(this.markers, function(index, marker) { + markercluster.addLayer(marker); + }); + if (this.markercluster) { + this.map.removeLayer(this.markercluster); + this.markercluster = null; + } + this.map.addLayer(markercluster); + this.markercluster = markercluster; + }; + this.setup = function () { var mapOptions = {}; if (options.minzoom !== false ) mapOptions.minZoom = options.minzoom; if (options.maxzoom !== false ) mapOptions.maxZoom = options.maxzoom; + if (options.enablefullscreen) { + mapOptions.fullscreenControl = true; + mapOptions.fullscreenControlOptions= { + position: 'topleft' + }; + } + var map = L.map( this.get(0), mapOptions ).fitWorld(); this.map = map; // add an OpenStreetMap tile layer - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + var layerOptions = { attribution: '© OpenStreetMap contributors' - }).addTo(map); + }; + if (options.layer === 'OpenStreetMap') { + new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', layerOptions).addTo(map); + } else if (options.layer === 'MapQuestOpen') { + new MQ.TileLayer(layerOptions).addTo(map); + } else { + new L.tileLayer.provider(options.layer, layerOptions).addTo(map); + } + + $.each(options.overlaylayers, function(index, overlaylayer) { + L.tileLayer.provider(overlaylayer).addTo(_this.map); + }); if (options.resizable) { - mw.loader.using('ext.maps.resizable', function () { //TODO: Fix moving map when resized - _this.resizable(); - }); + //TODO: Fix moving map when resized + _this.resizable(); } if (!options.locations) { options.locations = []; } + // Add the markers. for (var i = options.locations.length - 1; i >= 0; i--) { this.addMarker(options.locations[i]); } + // Add markercluster + if (options.markercluster) { + this.createMarkerCluster(); + } + // Add lines if (options.lines) { for (var i = 0; i < options.lines.length; i++) { @@ -197,6 +337,7 @@ } break; } + this.points = []; } else { centre = new L.LatLng(options.centre.lat, options.centre.lon); } @@ -205,9 +346,28 @@ } }; - this.setup(); + this.getDependencies = function ( options ) { + var dependencies = []; + if (options.layer !== 'OpenStreetMap' || options.overlaylayers.length > 0) { + dependencies.push( 'ext.maps.leaflet.providers' ); + } + if (options.enablefullscreen) { + dependencies.push( 'ext.maps.leaflet.fullscreen' ); + } + if (options.resizable) { + dependencies.push( 'ext.maps.resizable' ); + } + if (options.markercluster) { + dependencies.push( 'ext.maps.leaflet.markercluster' ); + } + return dependencies; + }; + + mw.loader.using( this.getDependencies( options ) ).then( function() { + _this.setup(); + } ); return this; }; -})(jQuery, window.mediaWiki); +})(jQuery, window.mediaWiki, L, window.MQ); diff --git a/includes/services/Leaflet/leaflet-providers/.eslintrc b/includes/services/Leaflet/leaflet-providers/.eslintrc new file mode 100644 index 000000000..62f190384 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/.eslintrc @@ -0,0 +1,39 @@ +{ + "rules": { + "camelcase": 2, + "quotes": [2, "single", "avoid-escape"], + "no-mixed-spaces-and-tabs": [2, "smart-tabs"], + "space-before-function-paren": 2, + "space-in-parens": 2, + "object-curly-spacing": 2, + "array-bracket-spacing": 2, + "computed-property-spacing": 2, + "space-before-blocks": 2, + "keyword-spacing": 2, + "no-lonely-if": 2, + "comma-style": 2, + "no-underscore-dangle": 0, + "no-constant-condition": 0, + "no-multi-spaces": 0, + "strict": 0, + "key-spacing": 0, + "no-shadow": 0, + "no-unused-vars": 2, + "eqeqeq": 2 + }, + "globals": { + "L": true, + "module": false, + "define": false, + "require": true + }, + "plugins": [ + "html" + ], + "settings": { + "html/report-bad-indent": 2 + }, + "env": { + "browser": true + } +} diff --git a/includes/services/Leaflet/leaflet-providers/.gitignore b/includes/services/Leaflet/leaflet-providers/.gitignore new file mode 100644 index 000000000..0e6b7ded0 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/.gitignore @@ -0,0 +1 @@ +leaflet-providers.min.js diff --git a/includes/services/Leaflet/leaflet-providers/.mversionrc b/includes/services/Leaflet/leaflet-providers/.mversionrc new file mode 100644 index 000000000..2d7fc1a87 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/.mversionrc @@ -0,0 +1,8 @@ +{ + "commitMessage": "Bumped version to %s", + "tagName": "%s", + "scripts": { + "preupdate": "npm run min", + "postupdate": "git push && git push --tags && npm publish" + } +} diff --git a/includes/services/Leaflet/leaflet-providers/.travis.yml b/includes/services/Leaflet/leaflet-providers/.travis.yml new file mode 100644 index 000000000..204dab530 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/.travis.yml @@ -0,0 +1,8 @@ +--- +language: node_js +node_js: + - "0.10" +notifications: + email: false +git: + depth: 10 diff --git a/includes/services/Leaflet/leaflet-providers/CHANGELOG.md b/includes/services/Leaflet/leaflet-providers/CHANGELOG.md new file mode 100644 index 000000000..c6ba59db2 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/CHANGELOG.md @@ -0,0 +1,46 @@ + +# Leaflet-providers changelog + +## 1.1.14 (2016-07-15) +- Remove MapQuest, fixes #219 +- Accidently skipped v1.1.12 and v1.1.13 + +## 1.1.11 (2016-06-04) + - Added protocol relativity to OSM FR, OSM HOT and Hydda providers (#214, #215). + +## 1.1.9 (2016-03-23) + - Re-added HERE layers #209, discussion in #206. + +## 1.1.8 (2016-03-22) + - Removed HERE layers #206 + +## 1.1.7 (2015-12-16) + - Removed Acetate tile layers #198 + +## 1.1.6 (2015-11-03) + - Removed most of the NLS layers per NLS request #193, fixes #178 + - Added new variants to the HERE provider #183 by [@andreaswc](https://github.com/andreaswc) + - Added some tests to make sure all the placeholders in the url template are replaced #188 + +## 1.1.5 (2015-10-01) + - Improvements for the NLS layers #182 by [@tomhughes](https://github.com/tomhughes) + - Check for valid bounds before fitting the preview map to undefined (fixes #185) + - Add bounds for FreeMapSK (fixes #184) + - Fix Stamen layers with `.jpg` extension (#187, fixes #184) + +## 1.1.4 (2015-09-27) + - Only include the interesting files in the npm package #180 + - Add GSGS_Ireland to NLS provider with `tms:true` to invert y-axis #181 + +## 1.1.3 (2015-09-26) + - Add various historical layers of the Natioanal library of Scotland (NLS) #179 + - Add a page to visually check bounds #179 + +## 1.1.2 (2015-09-05) + - Add CartoDB labels-only styles #170 by [@almccon](https://github.com/almccon) + - Implement commonjs module #172 + - Added retina URL option #177, [@routexl](https://github.com/routexl) + +## 1.1.1 (2015-06-22) + - Update Mapbox API to v4 #167 by [@gutenye](https://github.com/gutenye) + - Started maintaining a changelog in CHANGELOG.md. diff --git a/includes/services/Leaflet/leaflet-providers/CONTRIBUTING.md b/includes/services/Leaflet/leaflet-providers/CONTRIBUTING.md new file mode 100644 index 000000000..87766e997 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/CONTRIBUTING.md @@ -0,0 +1,10 @@ +So you want to add a layer? +======= + +Yay! go add it to the leaflet-providers.js as long as it follows the following +rules: + +- Don't violate a providers TOS (if it exists, include a link to it) +- Don't pre-populate api keys with working keys. +- It should be a basic tile source, no exteral libraries etc. +- The owner hasn't asked us to remove it (hasn't happened yet) \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet-providers/README.md b/includes/services/Leaflet/leaflet-providers/README.md new file mode 100644 index 000000000..0819e15ed --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/README.md @@ -0,0 +1,63 @@ +Leaflet-providers +================= +An extension to [Leaflet](http://leafletjs.com/) that contains configurations for various free[1](#what-is-free) tile providers. + +# Usage +Leaflet-providers [providers](#providers) are refered to with a `provider[.]`-string. Let's say you want to add the nice [Watercolor](http://maps.stamen.com/#watercolor/) style from Stamen to your map, you pass `Stamen.Watercolor` to the `L.tileLayer.provider`-constructor, which will return a [L.TileLayer](http://leafletjs.com/reference.html#tilelayer) instance for Stamens Watercolor tile layer. + +```Javascript +// add Stamen Watercolor to map. +L.tileLayer.provider('Stamen.Watercolor').addTo(map); +``` + +## Protocol relativity (`https://`-urls) + +Leaflet-providers tries to use `https://` if the page uses `https://` and the provider supports it. +You can force the use of `http://` by passing `force_http: true` in the options argument. + +## Retina tiles + +Some providers have retina tiles for which the URL only needs to be slightly adjusted, e.g. `-----@2x.png`. For this, add the retina option in the URL, e.g. `-----{retina}.png`, and set a retina value in the options, e.g. `retina: '@2x'`. If Leaflet detects a retina screen (`L.Browser.retina`), the retina option passed to the tileLayer is set to the value supplied, otherwise it's replaced by an empty string. + +# Providers + +Leaflet-providers provides tile layers from different providers, including *OpenStreetMap*, *Stamen*, *Esri* and *OpenWeatherMap*. The full listing of free to use layers can be [previewed](http://leaflet-extras.github.io/leaflet-providers/preview/index.html). The page will show you the name to use with `leaflet-providers.js` and the code to use it without dependencies. + +## Providers requiring registration + +In addition to the providers you are free1 to use, we support some layers which require registration. + +### HERE (formerly Nokia). + +In order to use HERE layers, you must [register](http://developer.here.com/). Once registered, you can create an `app_id` and `app_code` which you have to pass to `L.tileLayer.provider` in the options: + +```Javascript +L.tileLayer.provider('HERE.terrainDay', { + app_id: '', + app_code: '' +}).addTo(map); +``` + +[Available HERE layers](http://leaflet-extras.github.io/leaflet-providers/preview/#filter=HERE) + +### Mapbox + +In order to use Mapbox maps, you must [register](https://tiles.mapbox.com/signup). You can get map ID and ACCESS_TOKEN from [Mapbox projects](https://www.mapbox.com/projects): +```JavaScript +L.tileLayer.provider('MapBox', {id: 'ID', accessToken: 'ACCESS_TOKEN'}).addTo(map); +``` + +### Esri/ArcGIS + +In order to use ArcGIS maps, you must [register](https://developers.arcgis.com/en/sign-up/) and abide by the [terms of service](https://developers.arcgis.com/en/terms/). No special syntax is required. + +[Available Esri layers](http://leaflet-extras.github.io/leaflet-providers/preview/#filter=Esri) + +# Attribution + +This work was inspired from , and originally created by [Stefan Seelmann](https://github.com/seelmann). + +### What do we mean by *free*? +1 +We try to maintain leaflet-providers in such a way that you'll be able to use the layers we include without paying money. +This doesn't mean no limits apply, you should always check before using these layers for anything serious. diff --git a/includes/services/Leaflet/leaflet-providers/bower.json b/includes/services/Leaflet/leaflet-providers/bower.json new file mode 100644 index 000000000..744fd4c91 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/bower.json @@ -0,0 +1,25 @@ +{ + "name": "leaflet-providers", + "version": "1.1.15", + "homepage": "https://github.com/leaflet-extras/leaflet-providers", + "description": "An extension to Leaflet that contains configurations for various free tile providers.", + "dependencies": { + "leaflet": "~0.7.3" + }, + "main": "leaflet-providers.js", + "keywords": [ + "leaflet", + "stamen", + "osm" + ], + "license": "BSD-2-Clause", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests", + "preview", + "*.html" + ] +} diff --git a/includes/services/Leaflet/leaflet-providers/css/gh-fork-ribbon.css b/includes/services/Leaflet/leaflet-providers/css/gh-fork-ribbon.css new file mode 100644 index 000000000..84af6ac27 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/css/gh-fork-ribbon.css @@ -0,0 +1,127 @@ +/* Left will inherit from right (so we don't need to duplicate code */ +.github-fork-ribbon { + /* The right and left lasses determine the side we attach our banner to */ + position: absolute; + + /* Add a bit of padding to give some substance outside the "stitching" */ + padding: 2px 0; + + /* Set the base colour */ + background-color: #a00; + + /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */ + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.00)), to(rgba(0, 0, 0, 0.15))); + background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); + background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); + background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); + background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); + background-image: linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#000000', EndColorStr='#000000'); + + /* Add a drop shadow */ + -webkit-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5); + box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5); + + z-index: 9999; +} + +.github-fork-ribbon a { + /* Set the font */ + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: 700; + color: white; + + /* Set the text properties */ + text-decoration: none; + text-shadow: 0 -1px rgba(0,0,0,0.5); + text-align: center; + + /* Set the geometry. If you fiddle with these you'll also need to tweak the top and right values in #github-fork-ribbon. */ + width: 200px; + line-height: 20px; + + /* Set the layout properties */ + display: inline-block; + padding: 2px 0; + + /* Add "stitching" effect */ + border-width: 1px 0; + border-style: dotted; + border-color: rgba(255,255,255,0.7); +} + +.github-fork-ribbon-wrapper { + width: 150px; + height: 150px; + position: absolute; + overflow: hidden; + top: 0; +} + +.github-fork-ribbon-wrapper.left { + left: 0; +} + +.github-fork-ribbon-wrapper.right { + right: 0; +} + +.github-fork-ribbon-wrapper.left-bottom { + position: fixed; + top: inherit; + bottom: 0; + left: 0; +} + +.github-fork-ribbon-wrapper.right-bottom { + position: fixed; + top: inherit; + bottom: 0; + right: 0; +} + +.github-fork-ribbon-wrapper.right .github-fork-ribbon { + top: 42px; + right: -43px; + + /* Rotate the banner 45 degrees */ + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); +} + +.github-fork-ribbon-wrapper.left .github-fork-ribbon { + top: 42px; + left: -43px; + + /* Rotate the banner -45 degrees */ + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + transform: rotate(-45deg); +} + + +.github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon { + top: 80px; + left: -43px; + + /* Rotate the banner -45 degrees */ + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); +} + +.github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon { + top: 80px; + right: -43px; + + /* Rotate the banner -45 degrees */ + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + transform: rotate(-45deg); +} \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet-providers/css/gh-fork-ribbon.ie.css b/includes/services/Leaflet/leaflet-providers/css/gh-fork-ribbon.ie.css new file mode 100644 index 000000000..77fcab505 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/css/gh-fork-ribbon.ie.css @@ -0,0 +1,68 @@ +/* IE voodoo courtesy of http://stackoverflow.com/a/4617511/263871 and + * http://www.useragentman.com/IETransformsTranslator */ +.github-fork-ribbon-wrapper.right .github-fork-ribbon { + /* IE positioning hack (couldn't find a transform-origin alternative for IE) */ + top: -22px; + right: -62px; + + /* IE8+ */ + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.7071067811865474, M12=-0.7071067811865477, M21=0.7071067811865477, M22=0.7071067811865474, SizingMethod='auto expand')"; + /* IE6 and 7 */ + filter: progid:DXImageTransform.Microsoft.Matrix( + M11=0.7071067811865474, + M12=-0.7071067811865477, + M21=0.7071067811865477, + M22=0.7071067811865474, + SizingMethod='auto expand' + ); +} + +.github-fork-ribbon-wrapper.left .github-fork-ribbon { + top: -22px; + left: -22px; + + /* IE8+ */ + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.7071067811865483, M12=0.7071067811865467, M21=-0.7071067811865467, M22=0.7071067811865483, SizingMethod='auto expand')"; + /* IE6 and 7 */ + filter: progid:DXImageTransform.Microsoft.Matrix( + M11=0.7071067811865483, + M12=0.7071067811865467, + M21=-0.7071067811865467, + M22=0.7071067811865483, + SizingMethod='auto expand' + ); +} + +.github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon { + /* IE positioning hack (couldn't find a transform-origin alternative for IE) */ + top: 12px; + left: -22px; + + + /* IE8+ */ + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.7071067811865474, M12=-0.7071067811865477, M21=0.7071067811865477, M22=0.7071067811865474, SizingMethod='auto expand')"; + /* IE6 and 7 */ +/* filter: progid:DXImageTransform.Microsoft.Matrix( + M11=0.7071067811865474, + M12=-0.7071067811865477, + M21=0.7071067811865477, + M22=0.7071067811865474, + SizingMethod='auto expand' + ); +*/} + +.github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon { + top: 12px; + right: -62px; + + /* IE8+ */ + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.7071067811865483, M12=0.7071067811865467, M21=-0.7071067811865467, M22=0.7071067811865483, SizingMethod='auto expand')"; + /* IE6 and 7 */ + filter: progid:DXImageTransform.Microsoft.Matrix( + M11=0.7071067811865483, + M12=0.7071067811865467, + M21=-0.7071067811865467, + M22=0.7071067811865483, + SizingMethod='auto expand' + ); +} \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet-providers/index.html b/includes/services/Leaflet/leaflet-providers/index.html new file mode 100644 index 000000000..df73cc780 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/index.html @@ -0,0 +1,94 @@ + + + + Leaflet Provider Demo + + + + + + + + + + + + +
+ + + + + + diff --git a/includes/services/Leaflet/leaflet-providers/leaflet-providers.js b/includes/services/Leaflet/leaflet-providers/leaflet-providers.js new file mode 100644 index 000000000..22e2cbdbd --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/leaflet-providers.js @@ -0,0 +1,639 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['leaflet'], factory); + } else if (typeof modules === 'object' && module.exports) { + // define a Common JS module that relies on 'leaflet' + module.exports = factory(require('leaflet')); + } else { + // Assume Leaflet is loaded into global object L already + factory(L); + } +}(this, function (L) { + 'use strict'; + + L.TileLayer.Provider = L.TileLayer.extend({ + initialize: function (arg, options) { + var providers = L.TileLayer.Provider.providers; + + var parts = arg.split('.'); + + var providerName = parts[0]; + var variantName = parts[1]; + + if (!providers[providerName]) { + throw 'No such provider (' + providerName + ')'; + } + + var provider = { + url: providers[providerName].url, + options: providers[providerName].options + }; + + // overwrite values in provider from variant. + if (variantName && 'variants' in providers[providerName]) { + if (!(variantName in providers[providerName].variants)) { + throw 'No such variant of ' + providerName + ' (' + variantName + ')'; + } + var variant = providers[providerName].variants[variantName]; + var variantOptions; + if (typeof variant === 'string') { + variantOptions = { + variant: variant + }; + } else { + variantOptions = variant.options; + } + provider = { + url: variant.url || provider.url, + options: L.Util.extend({}, provider.options, variantOptions) + }; + } + + var forceHTTP = window.location.protocol === 'file:' || provider.options.forceHTTP; + if (provider.url.indexOf('//') === 0 && forceHTTP) { + provider.url = 'http:' + provider.url; + } + + // If retina option is set + if (provider.options.retina) { + // Check retina screen + if (options.detectRetina && L.Browser.retina) { + // The retina option will be active now + // But we need to prevent Leaflet retina mode + options.detectRetina = false; + } else { + // No retina, remove option + provider.options.retina = ''; + } + } + + // replace attribution placeholders with their values from toplevel provider attribution, + // recursively + var attributionReplacer = function (attr) { + if (attr.indexOf('{attribution.') === -1) { + return attr; + } + return attr.replace(/\{attribution.(\w*)\}/, + function (match, attributionName) { + return attributionReplacer(providers[attributionName].options.attribution); + } + ); + }; + provider.options.attribution = attributionReplacer(provider.options.attribution); + + // Compute final options combining provider options with any user overrides + var layerOpts = L.Util.extend({}, provider.options, options); + L.TileLayer.prototype.initialize.call(this, provider.url, layerOpts); + } + }); + + /** + * Definition of providers. + * see http://leafletjs.com/reference.html#tilelayer for options in the options map. + */ + + L.TileLayer.Provider.providers = { + OpenStreetMap: { + url: '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + options: { + maxZoom: 19, + attribution: + '© OpenStreetMap' + }, + variants: { + Mapnik: {}, + BlackAndWhite: { + url: 'http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', + options: { + maxZoom: 18 + } + }, + DE: { + url: 'http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', + options: { + maxZoom: 18 + } + }, + France: { + url: '//{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', + options: { + maxZoom: 20, + attribution: '© Openstreetmap France | {attribution.OpenStreetMap}' + } + }, + HOT: { + url: '//{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', + options: { + attribution: '{attribution.OpenStreetMap}, Tiles courtesy of Humanitarian OpenStreetMap Team' + } + } + } + }, + OpenSeaMap: { + url: 'http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', + options: { + attribution: 'Map data: © OpenSeaMap contributors' + } + }, + OpenTopoMap: { + url: '//{s}.tile.opentopomap.org/{z}/{x}/{y}.png', + options: { + maxZoom: 17, + attribution: 'Map data: {attribution.OpenStreetMap}, SRTM | Map style: © OpenTopoMap (CC-BY-SA)' + } + }, + Thunderforest: { + url: '//{s}.tile.thunderforest.com/{variant}/{z}/{x}/{y}.png', + options: { + attribution: + '© Thunderforest, {attribution.OpenStreetMap}', + variant: 'cycle' + }, + variants: { + OpenCycleMap: 'cycle', + Transport: { + options: { + variant: 'transport', + maxZoom: 19 + } + }, + TransportDark: { + options: { + variant: 'transport-dark', + maxZoom: 19 + } + }, + SpinalMap: { + options: { + variant: 'spinal-map', + maxZoom: 11 + } + }, + Landscape: 'landscape', + Outdoors: 'outdoors', + Pioneer: 'pioneer' + } + }, + OpenMapSurfer: { + url: 'http://korona.geog.uni-heidelberg.de/tiles/{variant}/x={x}&y={y}&z={z}', + options: { + maxZoom: 20, + variant: 'roads', + attribution: 'Imagery from GIScience Research Group @ University of Heidelberg — Map data {attribution.OpenStreetMap}' + }, + variants: { + Roads: 'roads', + AdminBounds: { + options: { + variant: 'adminb', + maxZoom: 19 + } + }, + Grayscale: { + options: { + variant: 'roadsg', + maxZoom: 19 + } + } + } + }, + Hydda: { + url: '//{s}.tile.openstreetmap.se/hydda/{variant}/{z}/{x}/{y}.png', + options: { + variant: 'full', + attribution: 'Tiles courtesy of OpenStreetMap Sweden — Map data {attribution.OpenStreetMap}' + }, + variants: { + Full: 'full', + Base: 'base', + RoadsAndLabels: 'roads_and_labels' + } + }, + MapBox: { + url: '//api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', + options: { + attribution: + 'Imagery from MapBox — ' + + 'Map data {attribution.OpenStreetMap}', + subdomains: 'abcd' + } + }, + Stamen: { + url: '//stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}', + options: { + attribution: + 'Map tiles by Stamen Design, ' + + 'CC BY 3.0 — ' + + 'Map data {attribution.OpenStreetMap}', + subdomains: 'abcd', + minZoom: 0, + maxZoom: 20, + variant: 'toner', + ext: 'png' + }, + variants: { + Toner: 'toner', + TonerBackground: 'toner-background', + TonerHybrid: 'toner-hybrid', + TonerLines: 'toner-lines', + TonerLabels: 'toner-labels', + TonerLite: 'toner-lite', + Watercolor: { + options: { + variant: 'watercolor', + minZoom: 1, + maxZoom: 16 + } + }, + Terrain: { + options: { + variant: 'terrain', + minZoom: 0, + maxZoom: 18 + } + }, + TerrainBackground: { + options: { + variant: 'terrain-background', + minZoom: 0, + maxZoom: 18 + } + }, + TopOSMRelief: { + options: { + variant: 'toposm-color-relief', + ext: 'jpg', + bounds: [[22, -132], [51, -56]] + } + }, + TopOSMFeatures: { + options: { + variant: 'toposm-features', + bounds: [[22, -132], [51, -56]], + opacity: 0.9 + } + } + } + }, + Esri: { + url: '//server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{z}/{y}/{x}', + options: { + variant: 'World_Street_Map', + attribution: 'Tiles © Esri' + }, + variants: { + WorldStreetMap: { + options: { + attribution: + '{attribution.Esri} — ' + + 'Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012' + } + }, + DeLorme: { + options: { + variant: 'Specialty/DeLorme_World_Base_Map', + minZoom: 1, + maxZoom: 11, + attribution: '{attribution.Esri} — Copyright: ©2012 DeLorme' + } + }, + WorldTopoMap: { + options: { + variant: 'World_Topo_Map', + attribution: + '{attribution.Esri} — ' + + 'Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community' + } + }, + WorldImagery: { + options: { + variant: 'World_Imagery', + attribution: + '{attribution.Esri} — ' + + 'Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' + } + }, + WorldTerrain: { + options: { + variant: 'World_Terrain_Base', + maxZoom: 13, + attribution: + '{attribution.Esri} — ' + + 'Source: USGS, Esri, TANA, DeLorme, and NPS' + } + }, + WorldShadedRelief: { + options: { + variant: 'World_Shaded_Relief', + maxZoom: 13, + attribution: '{attribution.Esri} — Source: Esri' + } + }, + WorldPhysical: { + options: { + variant: 'World_Physical_Map', + maxZoom: 8, + attribution: '{attribution.Esri} — Source: US National Park Service' + } + }, + OceanBasemap: { + options: { + variant: 'Ocean_Basemap', + maxZoom: 13, + attribution: '{attribution.Esri} — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri' + } + }, + NatGeoWorldMap: { + options: { + variant: 'NatGeo_World_Map', + maxZoom: 16, + attribution: '{attribution.Esri} — National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC' + } + }, + WorldGrayCanvas: { + options: { + variant: 'Canvas/World_Light_Gray_Base', + maxZoom: 16, + attribution: '{attribution.Esri} — Esri, DeLorme, NAVTEQ' + } + } + } + }, + OpenWeatherMap: { + url: 'http://{s}.tile.openweathermap.org/map/{variant}/{z}/{x}/{y}.png', + options: { + maxZoom: 19, + attribution: 'Map data © OpenWeatherMap', + opacity: 0.5 + }, + variants: { + Clouds: 'clouds', + CloudsClassic: 'clouds_cls', + Precipitation: 'precipitation', + PrecipitationClassic: 'precipitation_cls', + Rain: 'rain', + RainClassic: 'rain_cls', + Pressure: 'pressure', + PressureContour: 'pressure_cntr', + Wind: 'wind', + Temperature: 'temp', + Snow: 'snow' + } + }, + HERE: { + /* + * HERE maps, formerly Nokia maps. + * These basemaps are free, but you need an API key. Please sign up at + * http://developer.here.com/getting-started + * + * Note that the base urls contain '.cit' whichs is HERE's + * 'Customer Integration Testing' environment. Please remove for production + * envirionments. + */ + url: + '//{s}.{base}.maps.cit.api.here.com/maptile/2.1/' + + '{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?' + + 'app_id={app_id}&app_code={app_code}&lg={language}', + options: { + attribution: + 'Map © 1987-2014 HERE', + subdomains: '1234', + mapID: 'newest', + 'app_id': '', + 'app_code': '', + base: 'base', + variant: 'normal.day', + maxZoom: 20, + type: 'maptile', + language: 'eng', + format: 'png8', + size: '256' + }, + variants: { + normalDay: 'normal.day', + normalDayCustom: 'normal.day.custom', + normalDayGrey: 'normal.day.grey', + normalDayMobile: 'normal.day.mobile', + normalDayGreyMobile: 'normal.day.grey.mobile', + normalDayTransit: 'normal.day.transit', + normalDayTransitMobile: 'normal.day.transit.mobile', + normalNight: 'normal.night', + normalNightMobile: 'normal.night.mobile', + normalNightGrey: 'normal.night.grey', + normalNightGreyMobile: 'normal.night.grey.mobile', + + basicMap: { + options: { + type: 'basetile' + } + }, + mapLabels: { + options: { + type: 'labeltile', + format: 'png' + } + }, + trafficFlow: { + options: { + base: 'traffic', + type: 'flowtile' + } + }, + carnavDayGrey: 'carnav.day.grey', + hybridDay: { + options: { + base: 'aerial', + variant: 'hybrid.day' + } + }, + hybridDayMobile: { + options: { + base: 'aerial', + variant: 'hybrid.day.mobile' + } + }, + pedestrianDay: 'pedestrian.day', + pedestrianNight: 'pedestrian.night', + satelliteDay: { + options: { + base: 'aerial', + variant: 'satellite.day' + } + }, + terrainDay: { + options: { + base: 'aerial', + variant: 'terrain.day' + } + }, + terrainDayMobile: { + options: { + base: 'aerial', + variant: 'terrain.day.mobile' + } + } + } + }, + FreeMapSK: { + url: 'http://t{s}.freemap.sk/T/{z}/{x}/{y}.jpeg', + options: { + minZoom: 8, + maxZoom: 16, + subdomains: '1234', + bounds: [[47.204642, 15.996093], [49.830896, 22.576904]], + attribution: + '{attribution.OpenStreetMap}, vizualization CC-By-SA 2.0 Freemap.sk' + } + }, + MtbMap: { + url: 'http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png', + options: { + attribution: + '{attribution.OpenStreetMap} & USGS' + } + }, + CartoDB: { + url: 'http://{s}.basemaps.cartocdn.com/{variant}/{z}/{x}/{y}.png', + options: { + attribution: '{attribution.OpenStreetMap} © CartoDB', + subdomains: 'abcd', + maxZoom: 19, + variant: 'light_all' + }, + variants: { + Positron: 'light_all', + PositronNoLabels: 'light_nolabels', + PositronOnlyLabels: 'light_only_labels', + DarkMatter: 'dark_all', + DarkMatterNoLabels: 'dark_nolabels', + DarkMatterOnlyLabels: 'dark_only_labels' + } + }, + HikeBike: { + url: 'http://{s}.tiles.wmflabs.org/{variant}/{z}/{x}/{y}.png', + options: { + maxZoom: 19, + attribution: '{attribution.OpenStreetMap}', + variant: 'hikebike' + }, + variants: { + HikeBike: {}, + HillShading: { + options: { + maxZoom: 15, + variant: 'hillshading' + } + } + } + }, + BasemapAT: { + url: '//maps{s}.wien.gv.at/basemap/{variant}/normal/google3857/{z}/{y}/{x}.{format}', + options: { + maxZoom: 19, + attribution: 'Datenquelle: basemap.at', + subdomains: ['', '1', '2', '3', '4'], + format: 'png', + bounds: [[46.358770, 8.782379], [49.037872, 17.189532]], + variant: 'geolandbasemap' + }, + variants: { + basemap: 'geolandbasemap', + grau: 'bmapgrau', + overlay: 'bmapoverlay', + highdpi: { + options: { + variant: 'bmaphidpi', + format: 'jpeg' + } + }, + orthofoto: { + options: { + variant: 'bmaporthofoto30cm', + format: 'jpeg' + } + } + } + }, + NASAGIBS: { + url: '//map1.vis.earthdata.nasa.gov/wmts-webmerc/{variant}/default/{time}/{tilematrixset}{maxZoom}/{z}/{y}/{x}.{format}', + options: { + attribution: + 'Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System ' + + '(ESDIS) with funding provided by NASA/HQ.', + bounds: [[-85.0511287776, -179.999999975], [85.0511287776, 179.999999975]], + minZoom: 1, + maxZoom: 9, + format: 'jpg', + time: '', + tilematrixset: 'GoogleMapsCompatible_Level' + }, + variants: { + ModisTerraTrueColorCR: 'MODIS_Terra_CorrectedReflectance_TrueColor', + ModisTerraBands367CR: 'MODIS_Terra_CorrectedReflectance_Bands367', + ViirsEarthAtNight2012: { + options: { + variant: 'VIIRS_CityLights_2012', + maxZoom: 8 + } + }, + ModisTerraLSTDay: { + options: { + variant: 'MODIS_Terra_Land_Surface_Temp_Day', + format: 'png', + maxZoom: 7, + opacity: 0.75 + } + }, + ModisTerraSnowCover: { + options: { + variant: 'MODIS_Terra_Snow_Cover', + format: 'png', + maxZoom: 8, + opacity: 0.75 + } + }, + ModisTerraAOD: { + options: { + variant: 'MODIS_Terra_Aerosol', + format: 'png', + maxZoom: 6, + opacity: 0.75 + } + }, + ModisTerraChlorophyll: { + options: { + variant: 'MODIS_Terra_Chlorophyll_A', + format: 'png', + maxZoom: 7, + opacity: 0.75 + } + } + } + }, + NLS: { + // NLS maps are copyright National library of Scotland. + // http://maps.nls.uk/projects/api/index.html + // Please contact NLS for anything other than non-commercial low volume usage + // + // Map sources: Ordnance Survey 1:1m to 1:63K, 1920s-1940s + // z0-9 - 1:1m + // z10-11 - quarter inch (1:253440) + // z12-18 - one inch (1:63360) + url: '//nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg', + options: { + attribution: 'National Library of Scotland Historic Maps', + bounds: [[49.6, -12], [61.7, 3]], + minZoom: 1, + maxZoom: 18, + subdomains: '0123', + } + } + }; + + L.tileLayer.provider = function (provider, options) { + return new L.TileLayer.Provider(provider, options); + }; + + return L; +})); diff --git a/includes/services/Leaflet/leaflet-providers/license.md b/includes/services/Leaflet/leaflet-providers/license.md new file mode 100644 index 000000000..4c48832e5 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/license.md @@ -0,0 +1,9 @@ +Copyright (c) 2013 Leaflet Providers contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +_THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE._ \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet-providers/package.json b/includes/services/Leaflet/leaflet-providers/package.json new file mode 100644 index 000000000..f4cbdc36d --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/package.json @@ -0,0 +1,45 @@ +{ + "name": "leaflet-providers", + "version": "1.1.15", + "description": "An extension to Leaflet that contains configurations for various free tile providers.", + "main": "leaflet-providers.js", + "repository": { + "type": "git", + "url": "git://github.com/leaflet-extras/leaflet-providers.git" + }, + "scripts": { + "test": "npm run lint && npm run testsuite", + "testsuite": "mocha-phantomjs tests/index.html", + "lint": "eslint --config .eslintrc leaflet-providers.js index.html preview/*.js preview/*.html tests/*", + "min": "uglifyjs leaflet-providers.js -mc -o leaflet-providers.min.js", + "release": "mversion patch -m" + }, + "license": "BSD-2-Clause", + "bugs": { + "url": "https://github.com/leaflet-extras/leaflet-providers/issues" + }, + "files": [ + "leaflet-providers.js", + "README.md", + "CHANGELOG.md", + "licence.md" + ], + "devDependencies": { + "chai": "^2.3.0", + "eslint": "^2.7.0", + "eslint-plugin-html": "^1.4.0", + "mocha": "^2.2.4", + "mocha-phantomjs": "^3.5.3", + "mversion": "^1.3.0", + "phantomjs": "1.9.7-15", + "uglify-js": "^2.4.15" + }, + "autoupdate": { + "source": "git", + "target": "git://github.com/leaflet-extras/leaflet-providers.git", + "basePath": "/", + "files": [ + "leaflet-providers.js" + ] + } +} diff --git a/includes/services/Leaflet/leaflet-providers/preview/https-support.js b/includes/services/Leaflet/leaflet-providers/preview/https-support.js new file mode 100644 index 000000000..de079787a --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/https-support.js @@ -0,0 +1,57 @@ +L.TileLayer.prototype._tileOnError = function () { + if (this.errorContainer) { + this.errorContainer.innerHTML = 'seems to be not supported'; + } +} + + +var container = L.DomUtil.get('maps'); + +function addLayer (provider) { + var layer = L.tileLayer.provider(provider); + + var httpsSupported = layer._url.indexOf('//') === 0; + var table = L.DomUtil.get('table-' + (httpsSupported ? 'supported' : 'unknown')); + + var url = layer._url.replace('{variant}', layer.options.variant); + var options = L.extend({}, layer.options, layer._options); + + if (url.indexOf('http:') === 0) { + url = url.slice(5); + } else if (url.indexOf('https:') === 0) { + url = url.slice(6); + } + + var row = L.DomUtil.create('tr', '', table); + L.DomUtil.create('td', '', row).innerHTML = provider; + var result = L.DomUtil.create('td', '', row); + L.DomUtil.create('button', '', result).innerHTML = 'test...'; + if (httpsSupported) { + result.innerHTML = ' ' + result.innerHTML; + } + + L.DomEvent.on(result, 'click', function () { + var center = [52, 4]; + if ('bounds' in options && options.bounds) { + center = L.latLngBounds(options.bounds).getCenter(); + } + result.innerHTML = 'testing...'; + container.innerHTML = ''; + L.DomUtil.create('h2', '', container).innerHTML = provider + ' (http):'; + + var map1 = L.map(L.DomUtil.create('div', 'map', container)).setView(center, 9); + map1.addLayer(L.tileLayer('http:' + url, options)); + + L.DomUtil.create('h2', '', container).innerHTML = provider + ' (https):'; + var map2 = L.map(L.DomUtil.create('div', 'map', container)).setView(center, 9); + + var httpsLayer = L.tileLayer('https:' + url, options).addTo(map2); + + httpsLayer.errorContainer = result; + httpsLayer.on('load', function () { + result.innerHTML = 'seems to be OK'; + }); + }); +} + +L.tileLayer.provider.eachLayer(addLayer); diff --git a/includes/services/Leaflet/leaflet-providers/preview/index.html b/includes/services/Leaflet/leaflet-providers/preview/index.html new file mode 100644 index 000000000..f6645b854 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/index.html @@ -0,0 +1,90 @@ + + + + Leaflet Provider Demo + + + + + + + + + + + + + + + + +
+

Leaflet-providers preview

+

+ This page shows mini maps for all the layers available in Leaflet-providers. +

+
+
+ + + + + + + + + + + + diff --git a/includes/services/Leaflet/leaflet-providers/preview/layer-bounds.js b/includes/services/Leaflet/leaflet-providers/preview/layer-bounds.js new file mode 100644 index 000000000..14b415bc2 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/layer-bounds.js @@ -0,0 +1,63 @@ +var table = L.DomUtil.get('table'); +var container = L.DomUtil.get('maps'); +var result = L.DomUtil.get('result'); + +var map, rect; + +function showBounds () { + if (!(map && result)) { + return; + } + var b = rect.getBounds() + result.innerHTML = '

Bounds for this layer:

' + + '\n\n[' + + '[' + b.getSouth() + ', ' + b.getWest() + '], ' + + '[' + b.getNorth() + ', ' + b.getEast() + ']' + + ']

' + + 'zoomlevel: ' + map.getZoom(); +} + +function addLayer (provider) { + var layer = L.tileLayer.provider(provider); + + // we're only interested in layers with bounds here. + if (!layer.options.bounds) { + return; + } + var bounds = L.latLngBounds(layer.options.bounds); + + var row = L.DomUtil.create('tr', '', table); + L.DomUtil.create('td', '', row).innerHTML = provider; + + L.DomEvent.on(row, 'click', function () { + if (map && map.remove) { + map.remove(); + } + for (var i = 0; i < table.children.length; i++) { + L.DomUtil.removeClass(table.children[i], 'active'); + } + L.DomUtil.addClass(row, 'active'); + + container.innerHTML = ''; + L.DomUtil.create('h2', '', container).innerHTML = provider; + + map = L.map(L.DomUtil.create('div', 'map', container)).setView([52, 4], 6); + map.addLayer(L.tileLayer.provider('Hydda.Base')); + map.addLayer(layer); + + rect = L.rectangle(bounds, { + fill: false, + weight: 2, + opacity: 1 + }).addTo(map); + + rect.editing.enable(); + map.on('click zoomend', showBounds); + showBounds(); + + map.fitBounds(bounds); + }); +} +L.DomEvent.on(L.DomUtil.get('dump-bounds'), 'click', showBounds); + +L.tileLayer.provider.eachLayer(addLayer); diff --git a/includes/services/Leaflet/leaflet-providers/preview/preview.js b/includes/services/Leaflet/leaflet-providers/preview/preview.js new file mode 100644 index 000000000..9e8c85da4 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/preview.js @@ -0,0 +1,227 @@ +(function () { + 'use strict'; + + var map = new L.Map('map', { + zoomControl: false, + center: [48, -3], + zoom: 5 + }); + + function escapeHtml (string) { + return string + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + function renderValue (value) { + if (typeof value === 'string') { + return "'" + escapeHtml(value) + "'"; + } else { + return JSON.stringify(value).replace(/,/g, ', '); + } + } + + L.TileLayer.include({ + getExampleJS: function () { + var layerName = this._providerName.replace('.', '_'); + + var url = this._exampleUrl || this._url; + var options = L.extend({}, this._options, this._exampleAPIcodes || {}); + + // replace {variant} in urls with the selected variant, since + // keeping it in the options map doesn't make sense for one layer + if (options.variant) { + url = url.replace('{variant}', options.variant); + delete options.variant; + } + + var code = ''; + if (url.indexOf('//') === 0) { + code += '// https: also suppported.\n'; + url = 'http:' + url; + } + code += 'var ' + layerName + ' = L.tileLayer(\'' + url + '\', {\n'; + + var first = true; + for (var option in options) { + if (first) { + first = false; + } else { + code += ',\n'; + } + code += '\t' + option + ': ' + renderValue(options[option]); + } + code += '\n});\n'; + + return code; + } + }); + + var isOverlay = function (providerName, layer) { + if (layer.options.opacity && layer.options.opacity < 1) { + return true; + } + var overlayPatterns = [ + '^(OpenWeatherMap|OpenSeaMap)', + 'OpenMapSurfer.AdminBounds', + 'Stamen.Toner(Hybrid|Lines|Labels)', + 'Acetate.(foreground|labels|roads)', + 'Hydda.RoadsAndLabels' + ]; + + return providerName.match('(' + overlayPatterns.join('|') + ')') !== null; + }; + + // Ignore some providers in the preview + var isIgnored = function (providerName) { + if (providerName === 'ignored') { + return true; + } + // reduce the number of layers previewed for some providers + if (providerName.startsWith('HERE') || providerName.startsWith('OpenWeatherMap')) { + var whitelist = [ + 'HERE.normalDay', + 'HERE.basicMap', + 'HERE.hybridDay', + 'OpenWeatherMap.Clouds', + 'OpenWeatherMap.Pressure', + 'OpenWeatherMap.Wind' + ]; + return whitelist.indexOf(providerName) === -1; + } + return false; + }; + + // collect all layers available in the provider definition + var baseLayers = {}; + var overlays = {}; + + var addLayer = function (name) { + if (isIgnored(name)) { + return; + } + var layer = L.tileLayer.provider(name); + if (isOverlay(name, layer)) { + overlays[name] = layer; + } else { + baseLayers[name] = layer; + } + }; + L.tileLayer.provider.eachLayer(addLayer); + + // add minimap control to the map + var layersControl = L.control.layers.minimap(baseLayers, overlays, { + collapsed: false + }).addTo(map); + + // Pass a filter in the hash tag to show only layers containing that string + // for example: #filter=Open + var filterLayersControl = function () { + var hash = window.location.hash; + var filterIndex = hash.indexOf('filter='); + if (filterIndex !== -1) { + var filterString = hash.substr(filterIndex + 7).trim(); + var visible = layersControl.filter(filterString); + + // enable first layer as actual layer. + var first = Object.keys(visible)[0]; + if (first in baseLayers) { + map.addLayer(baseLayers[first]); + map.eachLayer(function (layer) { + if (layer._providerName !== first) { + map.removeLayer(layer); + } + }); + layersControl.filter(filterString); + } + } + }; + L.DomEvent.on(window, 'hashchange', filterLayersControl); + + // Does not work if called immediately, so ugly hack to apply filter + // at first page load + setTimeout(filterLayersControl, 100); + + // add OpenStreetMap.Mapnik, or the first if it does not exist + if (baseLayers['OpenStreetMap.Mapnik']) { + baseLayers['OpenStreetMap.Mapnik'].addTo(map); + } else { + baseLayers[Object.keys(baseLayers)[0]].addTo(map); + } + + // if a layer is selected and if it has bounds an the bounds are not in the + // current view, move the map view to contain the bounds + map.on('baselayerchange', function (e) { + var layer = e.layer; + if (!map.hasLayer(layer)) { + return; + } + if (layer.options.minZoom > 1 && map.getZoom() > layer.options.minZoom) { + map.setZoom(layer.options.minZoom); + } + if (!layer.options.bounds) { + return; + } + var bounds = L.latLngBounds(layer.options.bounds); + map.fitBounds(bounds, { + paddingTopLeft: [0, 200], + paddingBottomRight: [200, 0] + }); + }); + + // Add the TileLayer source code control to the map + map.addControl(new (L.Control.extend({ + options: { + position: 'topleft' + }, + onAdd: function (map) { + var container = L.DomUtil.get('info'); + L.DomEvent.disableClickPropagation(container); + + L.DomUtil.create('h4', null, container).innerHTML = 'Provider names for leaflet-providers.js'; + var providerNames = L.DomUtil.create('code', 'provider-names', container); + + L.DomUtil.create('h4', '', container).innerHTML = 'Plain JavaScript:'; + var pre = L.DomUtil.create('pre', null, container); + var code = L.DomUtil.create('code', 'javascript', pre); + + var update = function (event) { + code.innerHTML = ''; + + var names = []; + + // loop over the layers in the map and add the JS + for (var key in map._layers) { + var layer = map._layers[key]; + if (!layer.getExampleJS) { + continue; + } + + // do not add the layer currently being removed + if (event && event.type === 'layerremove' && layer === event.layer) { + continue; + } + names.push(L.Util.template('{name}', { + name: layer._providerName + })); + code.innerHTML += layer.getExampleJS(); + } + providerNames.innerHTML = names.join(', '); + + /* global hljs:true */ + hljs.highlightBlock(code); + }; + + map.on({ + 'layeradd': update, + 'layerremove': update + }); + update(); + + return container; + } + }))()); +})(); diff --git a/includes/services/Leaflet/leaflet-providers/preview/shared.js b/includes/services/Leaflet/leaflet-providers/preview/shared.js new file mode 100644 index 000000000..4d4162652 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/shared.js @@ -0,0 +1,63 @@ +// This is a list of example API codes, to make this preview +// functioning. Please register with the providers to use them +// with your own app. +var exampleAPIcodes = { + 'HERE': { + 'app_id': 'oenPwMCqbQkUSqj1WhRx', + 'app_code': 'kBxLcdTofTHUlsT7tl2X5w' + }, + 'MapBox': { + 'id': 'mapbox.streets', + 'accessToken': 'pk.eyJ1IjoiZ3V0ZW55ZSIsImEiOiJmNjJlMDNmYTUyMzNjMzQxZmY4Mzc1ZmFiYmExNjMxOSJ9.xgl1PBwQV9CtwW-usedrcQ' + } +}; + +var origProviderInit = L.TileLayer.Provider.prototype.initialize; +L.TileLayer.Provider.include({ + initialize: function (providerName, options) { + this._providerName = providerName; + options = options || {}; + + // replace example API codes in options + var provider = this._providerName.split('.')[0]; + if (provider in exampleAPIcodes) { + + // overwrite exampleAPIcodes with a placeholder to prevent accidental use + // of these API codes. + this._exampleAPIcodes = {}; + for (var key in exampleAPIcodes[provider]) { + this._exampleAPIcodes[key] = ''; + } + L.extend(options, exampleAPIcodes[provider]); + } + origProviderInit.call(this, providerName, options); + } +}); + +// save the options while creating tilelayers to cleanly access them later. +var origTileLayerInit = L.TileLayer.prototype.initialize; +L.TileLayer.include({ + initialize: function (url, options) { + this._options = options; + origTileLayerInit.apply(this, arguments); + } +}); + +L.tileLayer.provider.eachLayer = function (callback) { + for (var provider in L.TileLayer.Provider.providers) { + if (L.TileLayer.Provider.providers[provider].variants) { + for (var variant in L.TileLayer.Provider.providers[provider].variants) { + callback(provider + '.' + variant); + } + } else { + callback(provider); + } + } +}; + +if (!String.prototype.startsWith) { + String.prototype.startsWith = function (searchString, position) { + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; +} diff --git a/includes/services/Leaflet/leaflet-providers/preview/test-bounds.html b/includes/services/Leaflet/leaflet-providers/preview/test-bounds.html new file mode 100644 index 000000000..50aa246e4 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/test-bounds.html @@ -0,0 +1,87 @@ + + + + Leaflet Provider - layer bounds check page + + + + + + + + + + + + + + + + +
+ + + + + + + + + diff --git a/includes/services/Leaflet/leaflet-providers/preview/test-https-support.html b/includes/services/Leaflet/leaflet-providers/preview/test-https-support.html new file mode 100644 index 000000000..7e7b0bff8 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/preview/test-https-support.html @@ -0,0 +1,79 @@ + + + + Leaflet Provider - HTTPS support check page + + + + + + + + + + + + + + +

Testing provider protocols

+
+

Known https support:

+ + +
ProviderHTTPS
+
+ +
+

Unknown https support:

+ + +
ProviderHTTPS
+
+
+ + + + + + + + diff --git a/includes/services/Leaflet/leaflet-providers/tests/index.html b/includes/services/Leaflet/leaflet-providers/tests/index.html new file mode 100644 index 000000000..cfa30c13c --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/tests/index.html @@ -0,0 +1,44 @@ + + + + leaflet-poviders Mocha Tests + + + + + + + +
+
+ + + + + + + + + + + + + + + diff --git a/includes/services/Leaflet/leaflet-providers/tests/test.js b/includes/services/Leaflet/leaflet-providers/tests/test.js new file mode 100644 index 000000000..28ef6e981 --- /dev/null +++ b/includes/services/Leaflet/leaflet-providers/tests/test.js @@ -0,0 +1,99 @@ +/* global describe, chai, it */ + +function isEmpty (obj) { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + return false; + } + } + + return true; +} + +// List of valid L.TileLayer options to check options against +var validTileLayerOptions = [ + 'minZoom', 'maxZoom', 'maxNativeZoom', 'tileSize', 'subdomains', 'errorTileUrl', + 'attribution', 'tms', 'continuousWorld', 'noWrap', 'zoomOffset', 'zoomReverse', + 'opacity', 'zIndex', 'unloadInvisibleTiles', 'updateWhenIdle', 'detectRetina', + 'reuseTiles', 'bounds', 'crossOrigin', 'updateInterval', 'pane', 'nonBubblingEvents' +]; + +// monkey-patch getTileUrl with fake values. +L.TileLayer.prototype.getTileUrl = function (coords) { + return L.Util.template(this._url, L.extend({ + r: '', + s: this._getSubdomain(coords), + x: coords.x, + y: coords.y, + z: 15 + }, this.options)); +}; + +describe('leaflet-providers', function () { + chai.should(); + var providers = L.TileLayer.Provider.providers; + + describe('variant definition structure', function () { + it('each provider has keys url, options, variants', function () { + for (var name in providers) { + providers[name].should.contain.any.keys('url', 'options', 'variants'); + } + }); + it('each variant should be an object or a string', function () { + for (var name in providers) { + var variants = providers[name].variants; + + for (var v in variants) { + if (typeof variants[v] === 'string' || isEmpty(variants[v])) { + // string or empty object, which is fine. + continue; + } else { + variants[v].should.be.an.instanceof(Object); + variants[v].should.contain.any.keys('url', 'options'); + } + } + } + }); + }); + + describe('Nonexistant providers', function () { + it('should fail for non-existant providers', function () { + var fn = function () { + L.tileLayer.provider('Example'); + }; + fn.should.throw('No such provider (Example)'); + }); + it('should fail for non-existant variants of existing providers', function () { + var fn = function () { + L.tileLayer.provider('OpenStreetMap.Example'); + }; + fn.should.throw('No such variant of OpenStreetMap (Example)'); + }); + }); + + describe('Each layer', function () { + L.tileLayer.provider.eachLayer(function (name) { + describe(name, function () { + var layer = L.tileLayer.provider(name); + + it('should be a L.TileLayer', function () { + layer.should.be.an.instanceof(L.TileLayer); + }); + + it('should not throw while requesting a tile url', function () { + layer.getTileUrl({x: 16369, y: 10896}); + }); + + it('should have valid options', function () { + for (var key in layer.options) { + if (validTileLayerOptions.indexOf(key) !== -1) { + continue; + } + var placeholder = '{' + key + '}'; + layer._url.should.contain(placeholder); + } + }) + }); + }); + }) +}); diff --git a/includes/services/Leaflet/leaflet.fullscreen/.jshintrc b/includes/services/Leaflet/leaflet.fullscreen/.jshintrc new file mode 100644 index 000000000..b76361190 --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/.jshintrc @@ -0,0 +1,12 @@ +{ + "browser": true, + "curly": true, + "eqeqeq": true, + "undef": true, + "quotmark": "single", + "trailing": true, + "globals": { + "L": true, + "jQuery": true + } +} \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet.fullscreen/Control.FullScreen.css b/includes/services/Leaflet/leaflet.fullscreen/Control.FullScreen.css new file mode 100644 index 000000000..c93b1bf96 --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/Control.FullScreen.css @@ -0,0 +1,4 @@ +.leaflet-control-zoom-fullscreen { background-image: url(icon-fullscreen.png); } +.leaflet-retina .leaflet-control-zoom-fullscreen { background-image: url(icon-fullscreen-2x.png); background-size: 26px 26px; } +.leaflet-container:-webkit-full-screen { width: 100% !important; height: 100% !important; z-index: 99999; } +.leaflet-pseudo-fullscreen { position: fixed !important; width: 100% !important; height: 100% !important; top: 0px !important; left: 0px !important; z-index: 99999; } \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet.fullscreen/Control.FullScreen.js b/includes/services/Leaflet/leaflet.fullscreen/Control.FullScreen.js new file mode 100644 index 000000000..f1cd7ccc0 --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/Control.FullScreen.js @@ -0,0 +1,164 @@ +(function() { + +L.Control.FullScreen = L.Control.extend({ + options: { + position: 'topleft', + title: 'Full Screen', + forceSeparateButton: false, + forcePseudoFullscreen: false + }, + + onAdd: function (map) { + var className = 'leaflet-control-zoom-fullscreen', container; + + if (map.zoomControl && !this.options.forceSeparateButton) { + container = map.zoomControl._container; + } else { + container = L.DomUtil.create('div', 'leaflet-bar'); + } + + this._createButton(this.options.title, className, container, this.toggleFullScreen, this); + + return container; + }, + + _createButton: function (title, className, container, fn, context) { + var link = L.DomUtil.create('a', className, container); + link.href = '#'; + link.title = title; + + L.DomEvent + .addListener(link, 'click', L.DomEvent.stopPropagation) + .addListener(link, 'click', L.DomEvent.preventDefault) + .addListener(link, 'click', fn, context); + + L.DomEvent + .addListener(container, fullScreenApi.fullScreenEventName, L.DomEvent.stopPropagation) + .addListener(container, fullScreenApi.fullScreenEventName, L.DomEvent.preventDefault) + .addListener(container, fullScreenApi.fullScreenEventName, this._handleEscKey, context); + + L.DomEvent + .addListener(document, fullScreenApi.fullScreenEventName, L.DomEvent.stopPropagation) + .addListener(document, fullScreenApi.fullScreenEventName, L.DomEvent.preventDefault) + .addListener(document, fullScreenApi.fullScreenEventName, this._handleEscKey, context); + + return link; + }, + + toggleFullScreen: function () { + var map = this._map; + map._exitFired = false; + if (map._isFullscreen) { + if (fullScreenApi.supportsFullScreen && !this.options.forcePseudoFullscreen) { + fullScreenApi.cancelFullScreen(map._container); + } else { + L.DomUtil.removeClass(map._container, 'leaflet-pseudo-fullscreen'); + } + map.invalidateSize(); + map.fire('exitFullscreen'); + map._exitFired = true; + map._isFullscreen = false; + } + else { + if (fullScreenApi.supportsFullScreen && !this.options.forcePseudoFullscreen) { + fullScreenApi.requestFullScreen(map._container); + } else { + L.DomUtil.addClass(map._container, 'leaflet-pseudo-fullscreen'); + } + map.invalidateSize(); + map.fire('enterFullscreen'); + map._isFullscreen = true; + } + }, + + _handleEscKey: function () { + var map = this._map; + if (!fullScreenApi.isFullScreen(map) && !map._exitFired) { + map.fire('exitFullscreen'); + map._exitFired = true; + map._isFullscreen = false; + } + } +}); + +L.Map.addInitHook(function () { + if (this.options.fullscreenControl) { + this.fullscreenControl = L.control.fullscreen(this.options.fullscreenControlOptions); + this.addControl(this.fullscreenControl); + } +}); + +L.control.fullscreen = function (options) { + return new L.Control.FullScreen(options); +}; + +/* +Native FullScreen JavaScript API +------------- +Assumes Mozilla naming conventions instead of W3C for now + +source : http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ + +*/ + + var + fullScreenApi = { + supportsFullScreen: false, + isFullScreen: function() { return false; }, + requestFullScreen: function() {}, + cancelFullScreen: function() {}, + fullScreenEventName: '', + prefix: '' + }, + browserPrefixes = 'webkit moz o ms khtml'.split(' '); + + // check for native support + if (typeof document.exitFullscreen !== 'undefined') { + fullScreenApi.supportsFullScreen = true; + } else { + // check for fullscreen support by vendor prefix + for (var i = 0, il = browserPrefixes.length; i < il; i++ ) { + fullScreenApi.prefix = browserPrefixes[i]; + if (typeof document[fullScreenApi.prefix + 'CancelFullScreen' ] !== 'undefined' ) { + fullScreenApi.supportsFullScreen = true; + break; + } + } + } + + // update methods to do something useful + if (fullScreenApi.supportsFullScreen) { + fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange'; + fullScreenApi.isFullScreen = function() { + switch (this.prefix) { + case '': + return document.fullScreen; + case 'webkit': + return document.webkitIsFullScreen; + default: + return document[this.prefix + 'FullScreen']; + } + }; + fullScreenApi.requestFullScreen = function(el) { + return (this.prefix === '') ? el.requestFullscreen() : el[this.prefix + 'RequestFullScreen'](); + }; + fullScreenApi.cancelFullScreen = function(el) { + return (this.prefix === '') ? document.exitFullscreen() : document[this.prefix + 'CancelFullScreen'](); + }; + } + + // jQuery plugin + if (typeof jQuery !== 'undefined') { + jQuery.fn.requestFullScreen = function() { + return this.each(function() { + var el = jQuery(this); + if (fullScreenApi.supportsFullScreen) { + fullScreenApi.requestFullScreen(el); + } + }); + }; + } + + // export api + window.fullScreenApi = fullScreenApi; +})(); diff --git a/includes/services/Leaflet/leaflet.fullscreen/LICENSE b/includes/services/Leaflet/leaflet.fullscreen/LICENSE new file mode 100644 index 000000000..07ddddccb --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013, Bruno Bergot +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/includes/services/Leaflet/leaflet.fullscreen/README.md b/includes/services/Leaflet/leaflet.fullscreen/README.md new file mode 100644 index 000000000..a111801fe --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/README.md @@ -0,0 +1,68 @@ +Leaflet.Control.FullScreen +============ + +What ? +------ + +Simple plugin for Leaflet that adds fullscreen button to your maps. + +Inspired by http://elidupuis.github.com/leaflet.zoomfs/ + +Use the native javascript fullscreen API http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ + +Released under the MIT License http://opensource.org/licenses/mit-license.php + +How ? +------ + +Include Control.FullScreen.js and Control.FullScreen.css in your page: + +``` html + + +``` + +Add the fullscreen control to the map: + +``` js +var map = new L.Map('map', { + fullscreenControl: true, + fullscreenControlOptions: { + position: 'topleft' + } +}); +``` + +If your map have a zoomControl the fullscreen button will be added at the bottom of this one. + +If your map doesn't have a zoomContron the fullscreen button will be added to topleft corner of the map (same as the zoomcontrol). + +__Events and options__: + +``` js +// create a fullscreen button and add it to the map +L.control.fullscreen({ + position: 'topleft', // change the position of the button can be topleft, topright, bottomright or bottomleft, defaut topleft + title: 'Show me the fullscreen !', // change the title of the button, default Full Screen + forceSeparateButton: true, // force seperate button to detach from zoom buttons, default false + forcePseudoFullscreen: true // force use of pseudo full screen even if full screen API is available, default false +}).addTo(map); + +// events are fired when entering or exiting fullscreen. +map.on('enterFullscreen', function(){ + console.log('entered fullscreen'); +}); + +map.on('exitFullscreen', function(){ + console.log('exited fullscreen'); +}); +``` + +Where ? +------ + +Source code : https://github.com/brunob/leaflet.fullscreen + +Downloads : https://github.com/brunob/leaflet.fullscreen/releases + +Demo : http://brunob.github.com/leaflet.fullscreen/ diff --git a/includes/services/Leaflet/leaflet.fullscreen/bower.json b/includes/services/Leaflet/leaflet.fullscreen/bower.json new file mode 100644 index 000000000..6de9eee81 --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/bower.json @@ -0,0 +1,30 @@ +{ + "name": "leaflet.fullscreen", + "version": "1.1.4", + "homepage": "https://github.com/brunob/leaflet.fullscreen", + "authors": [ + "brunob " + ], + "description": "Leaflet.Control.FullScreen for Leaflet", + "main": [ + "Control.FullScreen.js", + "Control.FullScreen.css", + "icon-fullscreen.png", + "icon-fullscreen-2x.png" + ], + "keywords": [ + "leaflet", + "plugins", + "maps", + "fullscreen" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests", + "index.html" + ] +} diff --git a/includes/services/Leaflet/leaflet.fullscreen/icon-fullscreen-2x.png b/includes/services/Leaflet/leaflet.fullscreen/icon-fullscreen-2x.png new file mode 100644 index 000000000..7320d953b Binary files /dev/null and b/includes/services/Leaflet/leaflet.fullscreen/icon-fullscreen-2x.png differ diff --git a/includes/services/Leaflet/leaflet.fullscreen/icon-fullscreen.png b/includes/services/Leaflet/leaflet.fullscreen/icon-fullscreen.png new file mode 100644 index 000000000..17478145d Binary files /dev/null and b/includes/services/Leaflet/leaflet.fullscreen/icon-fullscreen.png differ diff --git a/includes/services/Leaflet/leaflet.fullscreen/index.html b/includes/services/Leaflet/leaflet.fullscreen/index.html new file mode 100644 index 000000000..87b345c4d --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/index.html @@ -0,0 +1,48 @@ + + + + + Leaflet.Control.FullScreen Demo + + + + + + + +
+ + + + diff --git a/includes/services/Leaflet/leaflet.fullscreen/package.json b/includes/services/Leaflet/leaflet.fullscreen/package.json new file mode 100644 index 000000000..e0c9aa7b5 --- /dev/null +++ b/includes/services/Leaflet/leaflet.fullscreen/package.json @@ -0,0 +1,25 @@ +{ + "name": "leaflet.fullscreen", + "version": "1.1.4", + "description": "Simple plugin for Leaflet that adds fullscreen button to your maps.", + "main": "Control.FullScreen.js", + "scripts": { + "test": "jshint Control.FullScreen.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/brunob/leaflet.fullscreen.git" + }, + "keywords": [ + "leaflet", + "plugins", + "maps", + "fullscreen" + ], + "devDependencies": { + "jshint": "2.5.0" + }, + "author": "b_b", + "license": "MIT License", + "readmeFilename": "README.md" +} diff --git a/includes/services/Leaflet/leaflet.markercluster/MarkerCluster.Default.css b/includes/services/Leaflet/leaflet.markercluster/MarkerCluster.Default.css new file mode 100644 index 000000000..bbc8c9fb0 --- /dev/null +++ b/includes/services/Leaflet/leaflet.markercluster/MarkerCluster.Default.css @@ -0,0 +1,60 @@ +.marker-cluster-small { + background-color: rgba(181, 226, 140, 0.6); + } +.marker-cluster-small div { + background-color: rgba(110, 204, 57, 0.6); + } + +.marker-cluster-medium { + background-color: rgba(241, 211, 87, 0.6); + } +.marker-cluster-medium div { + background-color: rgba(240, 194, 12, 0.6); + } + +.marker-cluster-large { + background-color: rgba(253, 156, 115, 0.6); + } +.marker-cluster-large div { + background-color: rgba(241, 128, 23, 0.6); + } + + /* IE 6-8 fallback colors */ +.leaflet-oldie .marker-cluster-small { + background-color: rgb(181, 226, 140); + } +.leaflet-oldie .marker-cluster-small div { + background-color: rgb(110, 204, 57); + } + +.leaflet-oldie .marker-cluster-medium { + background-color: rgb(241, 211, 87); + } +.leaflet-oldie .marker-cluster-medium div { + background-color: rgb(240, 194, 12); + } + +.leaflet-oldie .marker-cluster-large { + background-color: rgb(253, 156, 115); + } +.leaflet-oldie .marker-cluster-large div { + background-color: rgb(241, 128, 23); +} + +.marker-cluster { + background-clip: padding-box; + border-radius: 20px; + } +.marker-cluster div { + width: 30px; + height: 30px; + margin-left: 5px; + margin-top: 5px; + + text-align: center; + border-radius: 15px; + font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; + } +.marker-cluster span { + line-height: 30px; + } \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet.markercluster/MarkerCluster.css b/includes/services/Leaflet/leaflet.markercluster/MarkerCluster.css new file mode 100644 index 000000000..c60d71b7a --- /dev/null +++ b/includes/services/Leaflet/leaflet.markercluster/MarkerCluster.css @@ -0,0 +1,14 @@ +.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { + -webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in; + -moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in; + -o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in; + transition: transform 0.3s ease-out, opacity 0.3s ease-in; +} + +.leaflet-cluster-spider-leg { + /* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */ + -webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in; + -moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in; + -o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in; + transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in; +} diff --git a/includes/services/Leaflet/leaflet.markercluster/leaflet.markercluster-src.js b/includes/services/Leaflet/leaflet.markercluster/leaflet.markercluster-src.js new file mode 100644 index 000000000..9a61450d7 --- /dev/null +++ b/includes/services/Leaflet/leaflet.markercluster/leaflet.markercluster-src.js @@ -0,0 +1,2632 @@ +/* + Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps. + https://github.com/Leaflet/Leaflet.markercluster + (c) 2012-2013, Dave Leaver, smartrak +*/ +(function (window, document, undefined) {/* + * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within + */ + +L.MarkerClusterGroup = L.FeatureGroup.extend({ + + options: { + maxClusterRadius: 80, //A cluster will cover at most this many pixels from its center + iconCreateFunction: null, + + spiderfyOnMaxZoom: true, + showCoverageOnHover: true, + zoomToBoundsOnClick: true, + singleMarkerMode: false, + + disableClusteringAtZoom: null, + + // Setting this to false prevents the removal of any clusters outside of the viewpoint, which + // is the default behaviour for performance reasons. + removeOutsideVisibleBounds: true, + + // Set to false to disable all animations (zoom and spiderfy). + // If false, option animateAddingMarkers below has no effect. + // If L.DomUtil.TRANSITION is falsy, this option has no effect. + animate: true, + + //Whether to animate adding markers after adding the MarkerClusterGroup to the map + // If you are adding individual markers set to true, if adding bulk markers leave false for massive performance gains. + animateAddingMarkers: false, + + //Increase to increase the distance away that spiderfied markers appear from the center + spiderfyDistanceMultiplier: 1, + + // Make it possible to specify a polyline options on a spider leg + spiderLegPolylineOptions: { weight: 1.5, color: '#222', opacity: 0.5 }, + + // When bulk adding layers, adds markers in chunks. Means addLayers may not add all the layers in the call, others will be loaded during setTimeouts + chunkedLoading: false, + chunkInterval: 200, // process markers for a maximum of ~ n milliseconds (then trigger the chunkProgress callback) + chunkDelay: 50, // at the end of each interval, give n milliseconds back to system/browser + chunkProgress: null, // progress callback: function(processed, total, elapsed) (e.g. for a progress indicator) + + //Options to pass to the L.Polygon constructor + polygonOptions: {} + }, + + initialize: function (options) { + L.Util.setOptions(this, options); + if (!this.options.iconCreateFunction) { + this.options.iconCreateFunction = this._defaultIconCreateFunction; + } + + this._featureGroup = L.featureGroup(); + this._featureGroup.addEventParent(this); + + this._nonPointGroup = L.featureGroup(); + this._nonPointGroup.addEventParent(this); + + this._inZoomAnimation = 0; + this._needsClustering = []; + this._needsRemoving = []; //Markers removed while we aren't on the map need to be kept track of + //The bounds of the currently shown area (from _getExpandedVisibleBounds) Updated on zoom/move + this._currentShownBounds = null; + + this._queue = []; + + // Hook the appropriate animation methods. + var animate = L.DomUtil.TRANSITION && this.options.animate; + L.extend(this, animate ? this._withAnimation : this._noAnimation); + // Remember which MarkerCluster class to instantiate (animated or not). + this._markerCluster = animate ? L.MarkerCluster : L.MarkerClusterNonAnimated; + }, + + addLayer: function (layer) { + + if (layer instanceof L.LayerGroup) { + return this.addLayers([layer]); + } + + //Don't cluster non point data + if (!layer.getLatLng) { + this._nonPointGroup.addLayer(layer); + return this; + } + + if (!this._map) { + this._needsClustering.push(layer); + return this; + } + + if (this.hasLayer(layer)) { + return this; + } + + + //If we have already clustered we'll need to add this one to a cluster + + if (this._unspiderfy) { + this._unspiderfy(); + } + + this._addLayer(layer, this._maxZoom); + + // Refresh bounds and weighted positions. + this._topClusterLevel._recalculateBounds(); + + //Work out what is visible + var visibleLayer = layer, + currentZoom = this._map.getZoom(); + if (layer.__parent) { + while (visibleLayer.__parent._zoom >= currentZoom) { + visibleLayer = visibleLayer.__parent; + } + } + + if (this._currentShownBounds.contains(visibleLayer.getLatLng())) { + if (this.options.animateAddingMarkers) { + this._animationAddLayer(layer, visibleLayer); + } else { + this._animationAddLayerNonAnimated(layer, visibleLayer); + } + } + return this; + }, + + removeLayer: function (layer) { + + if (layer instanceof L.LayerGroup) { + return this.removeLayers([layer]); + } + + //Non point layers + if (!layer.getLatLng) { + this._nonPointGroup.removeLayer(layer); + return this; + } + + if (!this._map) { + if (!this._arraySplice(this._needsClustering, layer) && this.hasLayer(layer)) { + this._needsRemoving.push(layer); + } + return this; + } + + if (!layer.__parent) { + return this; + } + + if (this._unspiderfy) { + this._unspiderfy(); + this._unspiderfyLayer(layer); + } + + //Remove the marker from clusters + this._removeLayer(layer, true); + + // Refresh bounds and weighted positions. + this._topClusterLevel._recalculateBounds(); + + layer.off('move', this._childMarkerMoved, this); + + if (this._featureGroup.hasLayer(layer)) { + this._featureGroup.removeLayer(layer); + if (layer.clusterShow) { + layer.clusterShow(); + } + } + + return this; + }, + + //Takes an array of markers and adds them in bulk + addLayers: function (layersArray) { + if (!L.Util.isArray(layersArray)) { + return this.addLayer(layersArray); + } + + var fg = this._featureGroup, + npg = this._nonPointGroup, + chunked = this.options.chunkedLoading, + chunkInterval = this.options.chunkInterval, + chunkProgress = this.options.chunkProgress, + l = layersArray.length, + offset = 0, + originalArray = true, + m; + + if (this._map) { + var started = (new Date()).getTime(); + var process = L.bind(function () { + var start = (new Date()).getTime(); + for (; offset < l; offset++) { + if (chunked && offset % 200 === 0) { + // every couple hundred markers, instrument the time elapsed since processing started: + var elapsed = (new Date()).getTime() - start; + if (elapsed > chunkInterval) { + break; // been working too hard, time to take a break :-) + } + } + + m = layersArray[offset]; + + // Group of layers, append children to layersArray and skip. + // Side effects: + // - Total increases, so chunkProgress ratio jumps backward. + // - Groups are not included in this group, only their non-group child layers (hasLayer). + // Changing array length while looping does not affect performance in current browsers: + // http://jsperf.com/for-loop-changing-length/6 + if (m instanceof L.LayerGroup) { + if (originalArray) { + layersArray = layersArray.slice(); + originalArray = false; + } + this._extractNonGroupLayers(m, layersArray); + l = layersArray.length; + continue; + } + + //Not point data, can't be clustered + if (!m.getLatLng) { + npg.addLayer(m); + continue; + } + + if (this.hasLayer(m)) { + continue; + } + + this._addLayer(m, this._maxZoom); + + //If we just made a cluster of size 2 then we need to remove the other marker from the map (if it is) or we never will + if (m.__parent) { + if (m.__parent.getChildCount() === 2) { + var markers = m.__parent.getAllChildMarkers(), + otherMarker = markers[0] === m ? markers[1] : markers[0]; + fg.removeLayer(otherMarker); + } + } + } + + if (chunkProgress) { + // report progress and time elapsed: + chunkProgress(offset, l, (new Date()).getTime() - started); + } + + // Completed processing all markers. + if (offset === l) { + + // Refresh bounds and weighted positions. + this._topClusterLevel._recalculateBounds(); + + //Update the icons of all those visible clusters that were affected + this._featureGroup.eachLayer(function (c) { + if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) { + c._updateIcon(); + } + }); + + this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds); + } else { + setTimeout(process, this.options.chunkDelay); + } + }, this); + + process(); + } else { + var needsClustering = this._needsClustering; + + for (; offset < l; offset++) { + m = layersArray[offset]; + + // Group of layers, append children to layersArray and skip. + if (m instanceof L.LayerGroup) { + if (originalArray) { + layersArray = layersArray.slice(); + originalArray = false; + } + this._extractNonGroupLayers(m, layersArray); + l = layersArray.length; + continue; + } + + //Not point data, can't be clustered + if (!m.getLatLng) { + npg.addLayer(m); + continue; + } + + if (this.hasLayer(m)) { + continue; + } + + needsClustering.push(m); + } + } + return this; + }, + + //Takes an array of markers and removes them in bulk + removeLayers: function (layersArray) { + var i, m, + l = layersArray.length, + fg = this._featureGroup, + npg = this._nonPointGroup, + originalArray = true; + + if (!this._map) { + for (i = 0; i < l; i++) { + m = layersArray[i]; + + // Group of layers, append children to layersArray and skip. + if (m instanceof L.LayerGroup) { + if (originalArray) { + layersArray = layersArray.slice(); + originalArray = false; + } + this._extractNonGroupLayers(m, layersArray); + l = layersArray.length; + continue; + } + + this._arraySplice(this._needsClustering, m); + npg.removeLayer(m); + if (this.hasLayer(m)) { + this._needsRemoving.push(m); + } + } + return this; + } + + if (this._unspiderfy) { + this._unspiderfy(); + + // Work on a copy of the array, so that next loop is not affected. + var layersArray2 = layersArray.slice(), + l2 = l; + for (i = 0; i < l2; i++) { + m = layersArray2[i]; + + // Group of layers, append children to layersArray and skip. + if (m instanceof L.LayerGroup) { + this._extractNonGroupLayers(m, layersArray2); + l2 = layersArray2.length; + continue; + } + + this._unspiderfyLayer(m); + } + } + + for (i = 0; i < l; i++) { + m = layersArray[i]; + + // Group of layers, append children to layersArray and skip. + if (m instanceof L.LayerGroup) { + if (originalArray) { + layersArray = layersArray.slice(); + originalArray = false; + } + this._extractNonGroupLayers(m, layersArray); + l = layersArray.length; + continue; + } + + if (!m.__parent) { + npg.removeLayer(m); + continue; + } + + this._removeLayer(m, true, true); + + if (fg.hasLayer(m)) { + fg.removeLayer(m); + if (m.clusterShow) { + m.clusterShow(); + } + } + } + + // Refresh bounds and weighted positions. + this._topClusterLevel._recalculateBounds(); + + //Fix up the clusters and markers on the map + this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds); + + fg.eachLayer(function (c) { + if (c instanceof L.MarkerCluster) { + c._updateIcon(); + } + }); + + return this; + }, + + //Removes all layers from the MarkerClusterGroup + clearLayers: function () { + //Need our own special implementation as the LayerGroup one doesn't work for us + + //If we aren't on the map (yet), blow away the markers we know of + if (!this._map) { + this._needsClustering = []; + delete this._gridClusters; + delete this._gridUnclustered; + } + + if (this._noanimationUnspiderfy) { + this._noanimationUnspiderfy(); + } + + //Remove all the visible layers + this._featureGroup.clearLayers(); + this._nonPointGroup.clearLayers(); + + this.eachLayer(function (marker) { + marker.off('move', this._childMarkerMoved, this); + delete marker.__parent; + }); + + if (this._map) { + //Reset _topClusterLevel and the DistanceGrids + this._generateInitialClusters(); + } + + return this; + }, + + //Override FeatureGroup.getBounds as it doesn't work + getBounds: function () { + var bounds = new L.LatLngBounds(); + + if (this._topClusterLevel) { + bounds.extend(this._topClusterLevel._bounds); + } + + for (var i = this._needsClustering.length - 1; i >= 0; i--) { + bounds.extend(this._needsClustering[i].getLatLng()); + } + + bounds.extend(this._nonPointGroup.getBounds()); + + return bounds; + }, + + //Overrides LayerGroup.eachLayer + eachLayer: function (method, context) { + var markers = this._needsClustering.slice(), + needsRemoving = this._needsRemoving, + i; + + if (this._topClusterLevel) { + this._topClusterLevel.getAllChildMarkers(markers); + } + + for (i = markers.length - 1; i >= 0; i--) { + if (needsRemoving.indexOf(markers[i]) === -1) { + method.call(context, markers[i]); + } + } + + this._nonPointGroup.eachLayer(method, context); + }, + + //Overrides LayerGroup.getLayers + getLayers: function () { + var layers = []; + this.eachLayer(function (l) { + layers.push(l); + }); + return layers; + }, + + //Overrides LayerGroup.getLayer, WARNING: Really bad performance + getLayer: function (id) { + var result = null; + + id = parseInt(id, 10); + + this.eachLayer(function (l) { + if (L.stamp(l) === id) { + result = l; + } + }); + + return result; + }, + + //Returns true if the given layer is in this MarkerClusterGroup + hasLayer: function (layer) { + if (!layer) { + return false; + } + + var i, anArray = this._needsClustering; + + for (i = anArray.length - 1; i >= 0; i--) { + if (anArray[i] === layer) { + return true; + } + } + + anArray = this._needsRemoving; + for (i = anArray.length - 1; i >= 0; i--) { + if (anArray[i] === layer) { + return false; + } + } + + return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer); + }, + + //Zoom down to show the given layer (spiderfying if necessary) then calls the callback + zoomToShowLayer: function (layer, callback) { + + if (typeof callback !== 'function') { + callback = function () {}; + } + + var showMarker = function () { + if ((layer._icon || layer.__parent._icon) && !this._inZoomAnimation) { + this._map.off('moveend', showMarker, this); + this.off('animationend', showMarker, this); + + if (layer._icon) { + callback(); + } else if (layer.__parent._icon) { + this.once('spiderfied', callback, this); + layer.__parent.spiderfy(); + } + } + }; + + if (layer._icon && this._map.getBounds().contains(layer.getLatLng())) { + //Layer is visible ond on screen, immediate return + callback(); + } else if (layer.__parent._zoom < this._map.getZoom()) { + //Layer should be visible at this zoom level. It must not be on screen so just pan over to it + this._map.on('moveend', showMarker, this); + this._map.panTo(layer.getLatLng()); + } else { + var moveStart = function () { + this._map.off('movestart', moveStart, this); + moveStart = null; + }; + + this._map.on('movestart', moveStart, this); + this._map.on('moveend', showMarker, this); + this.on('animationend', showMarker, this); + layer.__parent.zoomToBounds(); + + if (moveStart) { + //Never started moving, must already be there, probably need clustering however + showMarker.call(this); + } + } + }, + + //Overrides FeatureGroup.onAdd + onAdd: function (map) { + this._map = map; + var i, l, layer; + + if (!isFinite(this._map.getMaxZoom())) { + throw "Map has no maxZoom specified"; + } + + this._featureGroup.addTo(map); + this._nonPointGroup.addTo(map); + + if (!this._gridClusters) { + this._generateInitialClusters(); + } + + this._maxLat = map.options.crs.projection.MAX_LATITUDE; + + for (i = 0, l = this._needsRemoving.length; i < l; i++) { + layer = this._needsRemoving[i]; + this._removeLayer(layer, true); + } + this._needsRemoving = []; + + //Remember the current zoom level and bounds + this._zoom = this._map.getZoom(); + this._currentShownBounds = this._getExpandedVisibleBounds(); + + this._map.on('zoomend', this._zoomEnd, this); + this._map.on('moveend', this._moveEnd, this); + + if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely + this._spiderfierOnAdd(); + } + + this._bindEvents(); + + //Actually add our markers to the map: + l = this._needsClustering; + this._needsClustering = []; + this.addLayers(l); + }, + + //Overrides FeatureGroup.onRemove + onRemove: function (map) { + map.off('zoomend', this._zoomEnd, this); + map.off('moveend', this._moveEnd, this); + + this._unbindEvents(); + + //In case we are in a cluster animation + this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', ''); + + if (this._spiderfierOnRemove) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely + this._spiderfierOnRemove(); + } + + delete this._maxLat; + + //Clean up all the layers we added to the map + this._hideCoverage(); + this._featureGroup.remove(); + this._nonPointGroup.remove(); + + this._featureGroup.clearLayers(); + + this._map = null; + }, + + getVisibleParent: function (marker) { + var vMarker = marker; + while (vMarker && !vMarker._icon) { + vMarker = vMarker.__parent; + } + return vMarker || null; + }, + + //Remove the given object from the given array + _arraySplice: function (anArray, obj) { + for (var i = anArray.length - 1; i >= 0; i--) { + if (anArray[i] === obj) { + anArray.splice(i, 1); + return true; + } + } + }, + + /** + * Removes a marker from all _gridUnclustered zoom levels, starting at the supplied zoom. + * @param marker to be removed from _gridUnclustered. + * @param z integer bottom start zoom level (included) + * @private + */ + _removeFromGridUnclustered: function (marker, z) { + var map = this._map, + gridUnclustered = this._gridUnclustered; + + for (; z >= 0; z--) { + if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) { + break; + } + } + }, + + _childMarkerMoved: function (e) { + if (!this._ignoreMove) { + e.target._latlng = e.oldLatLng; + this.removeLayer(e.target); + + e.target._latlng = e.latlng; + this.addLayer(e.target); + } + }, + + //Internal function for removing a marker from everything. + //dontUpdateMap: set to true if you will handle updating the map manually (for bulk functions) + _removeLayer: function (marker, removeFromDistanceGrid, dontUpdateMap) { + var gridClusters = this._gridClusters, + gridUnclustered = this._gridUnclustered, + fg = this._featureGroup, + map = this._map; + + //Remove the marker from distance clusters it might be in + if (removeFromDistanceGrid) { + this._removeFromGridUnclustered(marker, this._maxZoom); + } + + //Work our way up the clusters removing them as we go if required + var cluster = marker.__parent, + markers = cluster._markers, + otherMarker; + + //Remove the marker from the immediate parents marker list + this._arraySplice(markers, marker); + + while (cluster) { + cluster._childCount--; + cluster._boundsNeedUpdate = true; + + if (cluster._zoom < 0) { + //Top level, do nothing + break; + } else if (removeFromDistanceGrid && cluster._childCount <= 1) { //Cluster no longer required + //We need to push the other marker up to the parent + otherMarker = cluster._markers[0] === marker ? cluster._markers[1] : cluster._markers[0]; + + //Update distance grid + gridClusters[cluster._zoom].removeObject(cluster, map.project(cluster._cLatLng, cluster._zoom)); + gridUnclustered[cluster._zoom].addObject(otherMarker, map.project(otherMarker.getLatLng(), cluster._zoom)); + + //Move otherMarker up to parent + this._arraySplice(cluster.__parent._childClusters, cluster); + cluster.__parent._markers.push(otherMarker); + otherMarker.__parent = cluster.__parent; + + if (cluster._icon) { + //Cluster is currently on the map, need to put the marker on the map instead + fg.removeLayer(cluster); + if (!dontUpdateMap) { + fg.addLayer(otherMarker); + } + } + } else { + if (!dontUpdateMap || !cluster._icon) { + cluster._updateIcon(); + } + } + + cluster = cluster.__parent; + } + + delete marker.__parent; + }, + + _isOrIsParent: function (el, oel) { + while (oel) { + if (el === oel) { + return true; + } + oel = oel.parentNode; + } + return false; + }, + + //Override L.Evented.fire + fire: function (type, data, propagate) { + if (data && data.layer instanceof L.MarkerCluster) { + //Prevent multiple clustermouseover/off events if the icon is made up of stacked divs (Doesn't work in ie <= 8, no relatedTarget) + if (data.originalEvent && this._isOrIsParent(data.layer._icon, data.originalEvent.relatedTarget)) { + return; + } + type = 'cluster' + type; + } + + L.FeatureGroup.prototype.fire.call(this, type, data, propagate); + }, + + //Override L.Evented.listens + listens: function (type, propagate) { + return L.FeatureGroup.prototype.listens.call(this, type, propagate) || L.FeatureGroup.prototype.listens.call(this, 'cluster' + type, propagate); + }, + + //Default functionality + _defaultIconCreateFunction: function (cluster) { + var childCount = cluster.getChildCount(); + + var c = ' marker-cluster-'; + if (childCount < 10) { + c += 'small'; + } else if (childCount < 100) { + c += 'medium'; + } else { + c += 'large'; + } + + return new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); + }, + + _bindEvents: function () { + var map = this._map, + spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom, + showCoverageOnHover = this.options.showCoverageOnHover, + zoomToBoundsOnClick = this.options.zoomToBoundsOnClick; + + //Zoom on cluster click or spiderfy if we are at the lowest level + if (spiderfyOnMaxZoom || zoomToBoundsOnClick) { + this.on('clusterclick', this._zoomOrSpiderfy, this); + } + + //Show convex hull (boundary) polygon on mouse over + if (showCoverageOnHover) { + this.on('clustermouseover', this._showCoverage, this); + this.on('clustermouseout', this._hideCoverage, this); + map.on('zoomend', this._hideCoverage, this); + } + }, + + _zoomOrSpiderfy: function (e) { + var cluster = e.layer, + bottomCluster = cluster; + + while (bottomCluster._childClusters.length === 1) { + bottomCluster = bottomCluster._childClusters[0]; + } + + if (bottomCluster._zoom === this._maxZoom && + bottomCluster._childCount === cluster._childCount && + this.options.spiderfyOnMaxZoom) { + + // All child markers are contained in a single cluster from this._maxZoom to this cluster. + cluster.spiderfy(); + } else if (this.options.zoomToBoundsOnClick) { + cluster.zoomToBounds(); + } + + // Focus the map again for keyboard users. + if (e.originalEvent && e.originalEvent.keyCode === 13) { + this._map._container.focus(); + } + }, + + _showCoverage: function (e) { + var map = this._map; + if (this._inZoomAnimation) { + return; + } + if (this._shownPolygon) { + map.removeLayer(this._shownPolygon); + } + if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) { + this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions); + map.addLayer(this._shownPolygon); + } + }, + + _hideCoverage: function () { + if (this._shownPolygon) { + this._map.removeLayer(this._shownPolygon); + this._shownPolygon = null; + } + }, + + _unbindEvents: function () { + var spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom, + showCoverageOnHover = this.options.showCoverageOnHover, + zoomToBoundsOnClick = this.options.zoomToBoundsOnClick, + map = this._map; + + if (spiderfyOnMaxZoom || zoomToBoundsOnClick) { + this.off('clusterclick', this._zoomOrSpiderfy, this); + } + if (showCoverageOnHover) { + this.off('clustermouseover', this._showCoverage, this); + this.off('clustermouseout', this._hideCoverage, this); + map.off('zoomend', this._hideCoverage, this); + } + }, + + _zoomEnd: function () { + if (!this._map) { //May have been removed from the map by a zoomEnd handler + return; + } + this._mergeSplitClusters(); + + this._zoom = Math.round(this._map._zoom); + this._currentShownBounds = this._getExpandedVisibleBounds(); + }, + + _moveEnd: function () { + if (this._inZoomAnimation) { + return; + } + + var newBounds = this._getExpandedVisibleBounds(); + + this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom, newBounds); + this._topClusterLevel._recursivelyAddChildrenToMap(null, Math.round(this._map._zoom), newBounds); + + this._currentShownBounds = newBounds; + return; + }, + + _generateInitialClusters: function () { + var maxZoom = this._map.getMaxZoom(), + radius = this.options.maxClusterRadius, + radiusFn = radius; + + //If we just set maxClusterRadius to a single number, we need to create + //a simple function to return that number. Otherwise, we just have to + //use the function we've passed in. + if (typeof radius !== "function") { + radiusFn = function () { return radius; }; + } + + if (this.options.disableClusteringAtZoom) { + maxZoom = this.options.disableClusteringAtZoom - 1; + } + this._maxZoom = maxZoom; + this._gridClusters = {}; + this._gridUnclustered = {}; + + //Set up DistanceGrids for each zoom + for (var zoom = maxZoom; zoom >= 0; zoom--) { + this._gridClusters[zoom] = new L.DistanceGrid(radiusFn(zoom)); + this._gridUnclustered[zoom] = new L.DistanceGrid(radiusFn(zoom)); + } + + // Instantiate the appropriate L.MarkerCluster class (animated or not). + this._topClusterLevel = new this._markerCluster(this, -1); + }, + + //Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom) + _addLayer: function (layer, zoom) { + var gridClusters = this._gridClusters, + gridUnclustered = this._gridUnclustered, + markerPoint, z; + + if (this.options.singleMarkerMode) { + this._overrideMarkerIcon(layer); + } + + layer.on('move', this._childMarkerMoved, this); + + //Find the lowest zoom level to slot this one in + for (; zoom >= 0; zoom--) { + markerPoint = this._map.project(layer.getLatLng(), zoom); // calculate pixel position + + //Try find a cluster close by + var closest = gridClusters[zoom].getNearObject(markerPoint); + if (closest) { + closest._addChild(layer); + layer.__parent = closest; + return; + } + + //Try find a marker close by to form a new cluster with + closest = gridUnclustered[zoom].getNearObject(markerPoint); + if (closest) { + var parent = closest.__parent; + if (parent) { + this._removeLayer(closest, false); + } + + //Create new cluster with these 2 in it + + var newCluster = new this._markerCluster(this, zoom, closest, layer); + gridClusters[zoom].addObject(newCluster, this._map.project(newCluster._cLatLng, zoom)); + closest.__parent = newCluster; + layer.__parent = newCluster; + + //First create any new intermediate parent clusters that don't exist + var lastParent = newCluster; + for (z = zoom - 1; z > parent._zoom; z--) { + lastParent = new this._markerCluster(this, z, lastParent); + gridClusters[z].addObject(lastParent, this._map.project(closest.getLatLng(), z)); + } + parent._addChild(lastParent); + + //Remove closest from this zoom level and any above that it is in, replace with newCluster + this._removeFromGridUnclustered(closest, zoom); + + return; + } + + //Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards + gridUnclustered[zoom].addObject(layer, markerPoint); + } + + //Didn't get in anything, add us to the top + this._topClusterLevel._addChild(layer); + layer.__parent = this._topClusterLevel; + return; + }, + + //Enqueue code to fire after the marker expand/contract has happened + _enqueue: function (fn) { + this._queue.push(fn); + if (!this._queueTimeout) { + this._queueTimeout = setTimeout(L.bind(this._processQueue, this), 300); + } + }, + _processQueue: function () { + for (var i = 0; i < this._queue.length; i++) { + this._queue[i].call(this); + } + this._queue.length = 0; + clearTimeout(this._queueTimeout); + this._queueTimeout = null; + }, + + //Merge and split any existing clusters that are too big or small + _mergeSplitClusters: function () { + var mapZoom = Math.round(this._map._zoom); + + //In case we are starting to split before the animation finished + this._processQueue(); + + if (this._zoom < mapZoom && this._currentShownBounds.intersects(this._getExpandedVisibleBounds())) { //Zoom in, split + this._animationStart(); + //Remove clusters now off screen + this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom, this._getExpandedVisibleBounds()); + + this._animationZoomIn(this._zoom, mapZoom); + + } else if (this._zoom > mapZoom) { //Zoom out, merge + this._animationStart(); + + this._animationZoomOut(this._zoom, mapZoom); + } else { + this._moveEnd(); + } + }, + + //Gets the maps visible bounds expanded in each direction by the size of the screen (so the user cannot see an area we do not cover in one pan) + _getExpandedVisibleBounds: function () { + if (!this.options.removeOutsideVisibleBounds) { + return this._mapBoundsInfinite; + } else if (L.Browser.mobile) { + return this._checkBoundsMaxLat(this._map.getBounds()); + } + + return this._checkBoundsMaxLat(this._map.getBounds().pad(1)); // Padding expands the bounds by its own dimensions but scaled with the given factor. + }, + + /** + * Expands the latitude to Infinity (or -Infinity) if the input bounds reach the map projection maximum defined latitude + * (in the case of Web/Spherical Mercator, it is 85.0511287798 / see https://en.wikipedia.org/wiki/Web_Mercator#Formulas). + * Otherwise, the removeOutsideVisibleBounds option will remove markers beyond that limit, whereas the same markers without + * this option (or outside MCG) will have their position floored (ceiled) by the projection and rendered at that limit, + * making the user think that MCG "eats" them and never displays them again. + * @param bounds L.LatLngBounds + * @returns {L.LatLngBounds} + * @private + */ + _checkBoundsMaxLat: function (bounds) { + var maxLat = this._maxLat; + + if (maxLat !== undefined) { + if (bounds.getNorth() >= maxLat) { + bounds._northEast.lat = Infinity; + } + if (bounds.getSouth() <= -maxLat) { + bounds._southWest.lat = -Infinity; + } + } + + return bounds; + }, + + //Shared animation code + _animationAddLayerNonAnimated: function (layer, newCluster) { + if (newCluster === layer) { + this._featureGroup.addLayer(layer); + } else if (newCluster._childCount === 2) { + newCluster._addToMap(); + + var markers = newCluster.getAllChildMarkers(); + this._featureGroup.removeLayer(markers[0]); + this._featureGroup.removeLayer(markers[1]); + } else { + newCluster._updateIcon(); + } + }, + + /** + * Extracts individual (i.e. non-group) layers from a Layer Group. + * @param group to extract layers from. + * @param output {Array} in which to store the extracted layers. + * @returns {*|Array} + * @private + */ + _extractNonGroupLayers: function (group, output) { + var layers = group.getLayers(), + i = 0, + layer; + + output = output || []; + + for (; i < layers.length; i++) { + layer = layers[i]; + + if (layer instanceof L.LayerGroup) { + this._extractNonGroupLayers(layer, output); + continue; + } + + output.push(layer); + } + + return output; + }, + + /** + * Implements the singleMarkerMode option. + * @param layer Marker to re-style using the Clusters iconCreateFunction. + * @returns {L.Icon} The newly created icon. + * @private + */ + _overrideMarkerIcon: function (layer) { + var icon = layer.options.icon = this.options.iconCreateFunction({ + getChildCount: function () { + return 1; + }, + getAllChildMarkers: function () { + return [layer]; + } + }); + + return icon; + } +}); + +// Constant bounds used in case option "removeOutsideVisibleBounds" is set to false. +L.MarkerClusterGroup.include({ + _mapBoundsInfinite: new L.LatLngBounds(new L.LatLng(-Infinity, -Infinity), new L.LatLng(Infinity, Infinity)) +}); + +L.MarkerClusterGroup.include({ + _noAnimation: { + //Non Animated versions of everything + _animationStart: function () { + //Do nothing... + }, + _animationZoomIn: function (previousZoomLevel, newZoomLevel) { + this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel); + this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds()); + + //We didn't actually animate, but we use this event to mean "clustering animations have finished" + this.fire('animationend'); + }, + _animationZoomOut: function (previousZoomLevel, newZoomLevel) { + this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel); + this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds()); + + //We didn't actually animate, but we use this event to mean "clustering animations have finished" + this.fire('animationend'); + }, + _animationAddLayer: function (layer, newCluster) { + this._animationAddLayerNonAnimated(layer, newCluster); + } + }, + + _withAnimation: { + //Animated versions here + _animationStart: function () { + this._map._mapPane.className += ' leaflet-cluster-anim'; + this._inZoomAnimation++; + }, + + _animationZoomIn: function (previousZoomLevel, newZoomLevel) { + var bounds = this._getExpandedVisibleBounds(), + fg = this._featureGroup, + i; + + this._ignoreMove = true; + + //Add all children of current clusters to map and remove those clusters from map + this._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) { + var startPos = c._latlng, + markers = c._markers, + m; + + if (!bounds.contains(startPos)) { + startPos = null; + } + + if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { //Immediately add the new child and remove us + fg.removeLayer(c); + c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds); + } else { + //Fade out old cluster + c.clusterHide(); + c._recursivelyAddChildrenToMap(startPos, newZoomLevel, bounds); + } + + //Remove all markers that aren't visible any more + //TODO: Do we actually need to do this on the higher levels too? + for (i = markers.length - 1; i >= 0; i--) { + m = markers[i]; + if (!bounds.contains(m._latlng)) { + fg.removeLayer(m); + } + } + + }); + + this._forceLayout(); + + //Update opacities + this._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel); + //TODO Maybe? Update markers in _recursivelyBecomeVisible + fg.eachLayer(function (n) { + if (!(n instanceof L.MarkerCluster) && n._icon) { + n.clusterShow(); + } + }); + + //update the positions of the just added clusters/markers + this._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) { + c._recursivelyRestoreChildPositions(newZoomLevel); + }); + + this._ignoreMove = false; + + //Remove the old clusters and close the zoom animation + this._enqueue(function () { + //update the positions of the just added clusters/markers + this._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) { + fg.removeLayer(c); + c.clusterShow(); + }); + + this._animationEnd(); + }); + }, + + _animationZoomOut: function (previousZoomLevel, newZoomLevel) { + this._animationZoomOutSingle(this._topClusterLevel, previousZoomLevel - 1, newZoomLevel); + + //Need to add markers for those that weren't on the map before but are now + this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds()); + //Remove markers that were on the map before but won't be now + this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel, this._getExpandedVisibleBounds()); + }, + + _animationAddLayer: function (layer, newCluster) { + var me = this, + fg = this._featureGroup; + + fg.addLayer(layer); + if (newCluster !== layer) { + if (newCluster._childCount > 2) { //Was already a cluster + + newCluster._updateIcon(); + this._forceLayout(); + this._animationStart(); + + layer._setPos(this._map.latLngToLayerPoint(newCluster.getLatLng())); + layer.clusterHide(); + + this._enqueue(function () { + fg.removeLayer(layer); + layer.clusterShow(); + + me._animationEnd(); + }); + + } else { //Just became a cluster + this._forceLayout(); + + me._animationStart(); + me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._map.getZoom()); + } + } + } + }, + + // Private methods for animated versions. + _animationZoomOutSingle: function (cluster, previousZoomLevel, newZoomLevel) { + var bounds = this._getExpandedVisibleBounds(); + + //Animate all of the markers in the clusters to move to their cluster center point + cluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, previousZoomLevel + 1, newZoomLevel); + + var me = this; + + //Update the opacity (If we immediately set it they won't animate) + this._forceLayout(); + cluster._recursivelyBecomeVisible(bounds, newZoomLevel); + + //TODO: Maybe use the transition timing stuff to make this more reliable + //When the animations are done, tidy up + this._enqueue(function () { + + //This cluster stopped being a cluster before the timeout fired + if (cluster._childCount === 1) { + var m = cluster._markers[0]; + //If we were in a cluster animation at the time then the opacity and position of our child could be wrong now, so fix it + this._ignoreMove = true; + m.setLatLng(m.getLatLng()); + this._ignoreMove = false; + if (m.clusterShow) { + m.clusterShow(); + } + } else { + cluster._recursively(bounds, newZoomLevel, 0, function (c) { + c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel + 1); + }); + } + me._animationEnd(); + }); + }, + + _animationEnd: function () { + if (this._map) { + this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', ''); + } + this._inZoomAnimation--; + this.fire('animationend'); + }, + + //Force a browser layout of stuff in the map + // Should apply the current opacity and location to all elements so we can update them again for an animation + _forceLayout: function () { + //In my testing this works, infact offsetWidth of any element seems to work. + //Could loop all this._layers and do this for each _icon if it stops working + + L.Util.falseFn(document.body.offsetWidth); + } +}); + +L.markerClusterGroup = function (options) { + return new L.MarkerClusterGroup(options); +}; + + +L.MarkerCluster = L.Marker.extend({ + initialize: function (group, zoom, a, b) { + + L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0), { icon: this }); + + + this._group = group; + this._zoom = zoom; + + this._markers = []; + this._childClusters = []; + this._childCount = 0; + this._iconNeedsUpdate = true; + this._boundsNeedUpdate = true; + + this._bounds = new L.LatLngBounds(); + + if (a) { + this._addChild(a); + } + if (b) { + this._addChild(b); + } + }, + + //Recursively retrieve all child markers of this cluster + getAllChildMarkers: function (storageArray) { + storageArray = storageArray || []; + + for (var i = this._childClusters.length - 1; i >= 0; i--) { + this._childClusters[i].getAllChildMarkers(storageArray); + } + + for (var j = this._markers.length - 1; j >= 0; j--) { + storageArray.push(this._markers[j]); + } + + return storageArray; + }, + + //Returns the count of how many child markers we have + getChildCount: function () { + return this._childCount; + }, + + //Zoom to the minimum of showing all of the child markers, or the extents of this cluster + zoomToBounds: function () { + var childClusters = this._childClusters.slice(), + map = this._group._map, + boundsZoom = map.getBoundsZoom(this._bounds), + zoom = this._zoom + 1, + mapZoom = map.getZoom(), + i; + + //calculate how far we need to zoom down to see all of the markers + while (childClusters.length > 0 && boundsZoom > zoom) { + zoom++; + var newClusters = []; + for (i = 0; i < childClusters.length; i++) { + newClusters = newClusters.concat(childClusters[i]._childClusters); + } + childClusters = newClusters; + } + + if (boundsZoom > zoom) { + this._group._map.setView(this._latlng, zoom); + } else if (boundsZoom <= mapZoom) { //If fitBounds wouldn't zoom us down, zoom us down instead + this._group._map.setView(this._latlng, mapZoom + 1); + } else { + this._group._map.fitBounds(this._bounds); + } + }, + + getBounds: function () { + var bounds = new L.LatLngBounds(); + bounds.extend(this._bounds); + return bounds; + }, + + _updateIcon: function () { + this._iconNeedsUpdate = true; + if (this._icon) { + this.setIcon(this); + } + }, + + //Cludge for Icon, we pretend to be an icon for performance + createIcon: function () { + if (this._iconNeedsUpdate) { + this._iconObj = this._group.options.iconCreateFunction(this); + this._iconNeedsUpdate = false; + } + return this._iconObj.createIcon(); + }, + createShadow: function () { + return this._iconObj.createShadow(); + }, + + + _addChild: function (new1, isNotificationFromChild) { + + this._iconNeedsUpdate = true; + + this._boundsNeedUpdate = true; + this._setClusterCenter(new1); + + if (new1 instanceof L.MarkerCluster) { + if (!isNotificationFromChild) { + this._childClusters.push(new1); + new1.__parent = this; + } + this._childCount += new1._childCount; + } else { + if (!isNotificationFromChild) { + this._markers.push(new1); + } + this._childCount++; + } + + if (this.__parent) { + this.__parent._addChild(new1, true); + } + }, + + /** + * Makes sure the cluster center is set. If not, uses the child center if it is a cluster, or the marker position. + * @param child L.MarkerCluster|L.Marker that will be used as cluster center if not defined yet. + * @private + */ + _setClusterCenter: function (child) { + if (!this._cLatLng) { + // when clustering, take position of the first point as the cluster center + this._cLatLng = child._cLatLng || child._latlng; + } + }, + + /** + * Assigns impossible bounding values so that the next extend entirely determines the new bounds. + * This method avoids having to trash the previous L.LatLngBounds object and to create a new one, which is much slower for this class. + * As long as the bounds are not extended, most other methods would probably fail, as they would with bounds initialized but not extended. + * @private + */ + _resetBounds: function () { + var bounds = this._bounds; + + if (bounds._southWest) { + bounds._southWest.lat = Infinity; + bounds._southWest.lng = Infinity; + } + if (bounds._northEast) { + bounds._northEast.lat = -Infinity; + bounds._northEast.lng = -Infinity; + } + }, + + _recalculateBounds: function () { + var markers = this._markers, + childClusters = this._childClusters, + latSum = 0, + lngSum = 0, + totalCount = this._childCount, + i, child, childLatLng, childCount; + + // Case where all markers are removed from the map and we are left with just an empty _topClusterLevel. + if (totalCount === 0) { + return; + } + + // Reset rather than creating a new object, for performance. + this._resetBounds(); + + // Child markers. + for (i = 0; i < markers.length; i++) { + childLatLng = markers[i]._latlng; + + this._bounds.extend(childLatLng); + + latSum += childLatLng.lat; + lngSum += childLatLng.lng; + } + + // Child clusters. + for (i = 0; i < childClusters.length; i++) { + child = childClusters[i]; + + // Re-compute child bounds and weighted position first if necessary. + if (child._boundsNeedUpdate) { + child._recalculateBounds(); + } + + this._bounds.extend(child._bounds); + + childLatLng = child._wLatLng; + childCount = child._childCount; + + latSum += childLatLng.lat * childCount; + lngSum += childLatLng.lng * childCount; + } + + this._latlng = this._wLatLng = new L.LatLng(latSum / totalCount, lngSum / totalCount); + + // Reset dirty flag. + this._boundsNeedUpdate = false; + }, + + //Set our markers position as given and add it to the map + _addToMap: function (startPos) { + if (startPos) { + this._backupLatlng = this._latlng; + this.setLatLng(startPos); + } + this._group._featureGroup.addLayer(this); + }, + + _recursivelyAnimateChildrenIn: function (bounds, center, maxZoom) { + this._recursively(bounds, 0, maxZoom - 1, + function (c) { + var markers = c._markers, + i, m; + for (i = markers.length - 1; i >= 0; i--) { + m = markers[i]; + + //Only do it if the icon is still on the map + if (m._icon) { + m._setPos(center); + m.clusterHide(); + } + } + }, + function (c) { + var childClusters = c._childClusters, + j, cm; + for (j = childClusters.length - 1; j >= 0; j--) { + cm = childClusters[j]; + if (cm._icon) { + cm._setPos(center); + cm.clusterHide(); + } + } + } + ); + }, + + _recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, previousZoomLevel, newZoomLevel) { + this._recursively(bounds, newZoomLevel, 0, + function (c) { + c._recursivelyAnimateChildrenIn(bounds, c._group._map.latLngToLayerPoint(c.getLatLng()).round(), previousZoomLevel); + + //TODO: depthToAnimateIn affects _isSingleParent, if there is a multizoom we may/may not be. + //As a hack we only do a animation free zoom on a single level zoom, if someone does multiple levels then we always animate + if (c._isSingleParent() && previousZoomLevel - 1 === newZoomLevel) { + c.clusterShow(); + c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel); //Immediately remove our children as we are replacing them. TODO previousBounds not bounds + } else { + c.clusterHide(); + } + + c._addToMap(); + } + ); + }, + + _recursivelyBecomeVisible: function (bounds, zoomLevel) { + this._recursively(bounds, 0, zoomLevel, null, function (c) { + c.clusterShow(); + }); + }, + + _recursivelyAddChildrenToMap: function (startPos, zoomLevel, bounds) { + this._recursively(bounds, -1, zoomLevel, + function (c) { + if (zoomLevel === c._zoom) { + return; + } + + //Add our child markers at startPos (so they can be animated out) + for (var i = c._markers.length - 1; i >= 0; i--) { + var nm = c._markers[i]; + + if (!bounds.contains(nm._latlng)) { + continue; + } + + if (startPos) { + nm._backupLatlng = nm.getLatLng(); + + nm.setLatLng(startPos); + if (nm.clusterHide) { + nm.clusterHide(); + } + } + + c._group._featureGroup.addLayer(nm); + } + }, + function (c) { + c._addToMap(startPos); + } + ); + }, + + _recursivelyRestoreChildPositions: function (zoomLevel) { + //Fix positions of child markers + for (var i = this._markers.length - 1; i >= 0; i--) { + var nm = this._markers[i]; + if (nm._backupLatlng) { + nm.setLatLng(nm._backupLatlng); + delete nm._backupLatlng; + } + } + + if (zoomLevel - 1 === this._zoom) { + //Reposition child clusters + for (var j = this._childClusters.length - 1; j >= 0; j--) { + this._childClusters[j]._restorePosition(); + } + } else { + for (var k = this._childClusters.length - 1; k >= 0; k--) { + this._childClusters[k]._recursivelyRestoreChildPositions(zoomLevel); + } + } + }, + + _restorePosition: function () { + if (this._backupLatlng) { + this.setLatLng(this._backupLatlng); + delete this._backupLatlng; + } + }, + + //exceptBounds: If set, don't remove any markers/clusters in it + _recursivelyRemoveChildrenFromMap: function (previousBounds, zoomLevel, exceptBounds) { + var m, i; + this._recursively(previousBounds, -1, zoomLevel - 1, + function (c) { + //Remove markers at every level + for (i = c._markers.length - 1; i >= 0; i--) { + m = c._markers[i]; + if (!exceptBounds || !exceptBounds.contains(m._latlng)) { + c._group._featureGroup.removeLayer(m); + if (m.clusterShow) { + m.clusterShow(); + } + } + } + }, + function (c) { + //Remove child clusters at just the bottom level + for (i = c._childClusters.length - 1; i >= 0; i--) { + m = c._childClusters[i]; + if (!exceptBounds || !exceptBounds.contains(m._latlng)) { + c._group._featureGroup.removeLayer(m); + if (m.clusterShow) { + m.clusterShow(); + } + } + } + } + ); + }, + + //Run the given functions recursively to this and child clusters + // boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to + // zoomLevelToStart: zoom level to start running functions (inclusive) + // zoomLevelToStop: zoom level to stop running functions (inclusive) + // runAtEveryLevel: function that takes an L.MarkerCluster as an argument that should be applied on every level + // runAtBottomLevel: function that takes an L.MarkerCluster as an argument that should be applied at only the bottom level + _recursively: function (boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) { + var childClusters = this._childClusters, + zoom = this._zoom, + i, c; + + if (zoomLevelToStart > zoom) { //Still going down to required depth, just recurse to child clusters + for (i = childClusters.length - 1; i >= 0; i--) { + c = childClusters[i]; + if (boundsToApplyTo.intersects(c._bounds)) { + c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel); + } + } + } else { //In required depth + + if (runAtEveryLevel) { + runAtEveryLevel(this); + } + if (runAtBottomLevel && this._zoom === zoomLevelToStop) { + runAtBottomLevel(this); + } + + //TODO: This loop is almost the same as above + if (zoomLevelToStop > zoom) { + for (i = childClusters.length - 1; i >= 0; i--) { + c = childClusters[i]; + if (boundsToApplyTo.intersects(c._bounds)) { + c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel); + } + } + } + } + }, + + //Returns true if we are the parent of only one cluster and that cluster is the same as us + _isSingleParent: function () { + //Don't need to check this._markers as the rest won't work if there are any + return this._childClusters.length > 0 && this._childClusters[0]._childCount === this._childCount; + } +}); + + + +/* +* Extends L.Marker to include two extra methods: clusterHide and clusterShow. +* +* They work as setOpacity(0) and setOpacity(1) respectively, but +* they will remember the marker's opacity when hiding and showing it again. +* +*/ + + +L.Marker.include({ + + clusterHide: function () { + this.options.opacityWhenUnclustered = this.options.opacity || 1; + return this.setOpacity(0); + }, + + clusterShow: function () { + var ret = this.setOpacity(this.options.opacity || this.options.opacityWhenUnclustered); + delete this.options.opacityWhenUnclustered; + return ret; + } + +}); + + + + + +L.DistanceGrid = function (cellSize) { + this._cellSize = cellSize; + this._sqCellSize = cellSize * cellSize; + this._grid = {}; + this._objectPoint = { }; +}; + +L.DistanceGrid.prototype = { + + addObject: function (obj, point) { + var x = this._getCoord(point.x), + y = this._getCoord(point.y), + grid = this._grid, + row = grid[y] = grid[y] || {}, + cell = row[x] = row[x] || [], + stamp = L.Util.stamp(obj); + + this._objectPoint[stamp] = point; + + cell.push(obj); + }, + + updateObject: function (obj, point) { + this.removeObject(obj); + this.addObject(obj, point); + }, + + //Returns true if the object was found + removeObject: function (obj, point) { + var x = this._getCoord(point.x), + y = this._getCoord(point.y), + grid = this._grid, + row = grid[y] = grid[y] || {}, + cell = row[x] = row[x] || [], + i, len; + + delete this._objectPoint[L.Util.stamp(obj)]; + + for (i = 0, len = cell.length; i < len; i++) { + if (cell[i] === obj) { + + cell.splice(i, 1); + + if (len === 1) { + delete row[x]; + } + + return true; + } + } + + }, + + eachObject: function (fn, context) { + var i, j, k, len, row, cell, removed, + grid = this._grid; + + for (i in grid) { + row = grid[i]; + + for (j in row) { + cell = row[j]; + + for (k = 0, len = cell.length; k < len; k++) { + removed = fn.call(context, cell[k]); + if (removed) { + k--; + len--; + } + } + } + } + }, + + getNearObject: function (point) { + var x = this._getCoord(point.x), + y = this._getCoord(point.y), + i, j, k, row, cell, len, obj, dist, + objectPoint = this._objectPoint, + closestDistSq = this._sqCellSize, + closest = null; + + for (i = y - 1; i <= y + 1; i++) { + row = this._grid[i]; + if (row) { + + for (j = x - 1; j <= x + 1; j++) { + cell = row[j]; + if (cell) { + + for (k = 0, len = cell.length; k < len; k++) { + obj = cell[k]; + dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point); + if (dist < closestDistSq) { + closestDistSq = dist; + closest = obj; + } + } + } + } + } + } + return closest; + }, + + _getCoord: function (x) { + return Math.floor(x / this._cellSize); + }, + + _sqDist: function (p, p2) { + var dx = p2.x - p.x, + dy = p2.y - p.y; + return dx * dx + dy * dy; + } +}; + + +/* Copyright (c) 2012 the authors listed at the following URL, and/or +the authors of referenced articles or incorporated external code: +http://en.literateprograms.org/Quickhull_(Javascript)?action=history&offset=20120410175256 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Retrieved from: http://en.literateprograms.org/Quickhull_(Javascript)?oldid=18434 +*/ + +(function () { + L.QuickHull = { + + /* + * @param {Object} cpt a point to be measured from the baseline + * @param {Array} bl the baseline, as represented by a two-element + * array of latlng objects. + * @returns {Number} an approximate distance measure + */ + getDistant: function (cpt, bl) { + var vY = bl[1].lat - bl[0].lat, + vX = bl[0].lng - bl[1].lng; + return (vX * (cpt.lat - bl[0].lat) + vY * (cpt.lng - bl[0].lng)); + }, + + /* + * @param {Array} baseLine a two-element array of latlng objects + * representing the baseline to project from + * @param {Array} latLngs an array of latlng objects + * @returns {Object} the maximum point and all new points to stay + * in consideration for the hull. + */ + findMostDistantPointFromBaseLine: function (baseLine, latLngs) { + var maxD = 0, + maxPt = null, + newPoints = [], + i, pt, d; + + for (i = latLngs.length - 1; i >= 0; i--) { + pt = latLngs[i]; + d = this.getDistant(pt, baseLine); + + if (d > 0) { + newPoints.push(pt); + } else { + continue; + } + + if (d > maxD) { + maxD = d; + maxPt = pt; + } + } + + return { maxPoint: maxPt, newPoints: newPoints }; + }, + + + /* + * Given a baseline, compute the convex hull of latLngs as an array + * of latLngs. + * + * @param {Array} latLngs + * @returns {Array} + */ + buildConvexHull: function (baseLine, latLngs) { + var convexHullBaseLines = [], + t = this.findMostDistantPointFromBaseLine(baseLine, latLngs); + + if (t.maxPoint) { // if there is still a point "outside" the base line + convexHullBaseLines = + convexHullBaseLines.concat( + this.buildConvexHull([baseLine[0], t.maxPoint], t.newPoints) + ); + convexHullBaseLines = + convexHullBaseLines.concat( + this.buildConvexHull([t.maxPoint, baseLine[1]], t.newPoints) + ); + return convexHullBaseLines; + } else { // if there is no more point "outside" the base line, the current base line is part of the convex hull + return [baseLine[0]]; + } + }, + + /* + * Given an array of latlngs, compute a convex hull as an array + * of latlngs + * + * @param {Array} latLngs + * @returns {Array} + */ + getConvexHull: function (latLngs) { + // find first baseline + var maxLat = false, minLat = false, + maxLng = false, minLng = false, + maxLatPt = null, minLatPt = null, + maxLngPt = null, minLngPt = null, + maxPt = null, minPt = null, + i; + + for (i = latLngs.length - 1; i >= 0; i--) { + var pt = latLngs[i]; + if (maxLat === false || pt.lat > maxLat) { + maxLatPt = pt; + maxLat = pt.lat; + } + if (minLat === false || pt.lat < minLat) { + minLatPt = pt; + minLat = pt.lat; + } + if (maxLng === false || pt.lng > maxLng) { + maxLngPt = pt; + maxLng = pt.lng; + } + if (minLng === false || pt.lng < minLng) { + minLngPt = pt; + minLng = pt.lng; + } + } + + if (minLat !== maxLat) { + minPt = minLatPt; + maxPt = maxLatPt; + } else { + minPt = minLngPt; + maxPt = maxLngPt; + } + + var ch = [].concat(this.buildConvexHull([minPt, maxPt], latLngs), + this.buildConvexHull([maxPt, minPt], latLngs)); + return ch; + } + }; +}()); + +L.MarkerCluster.include({ + getConvexHull: function () { + var childMarkers = this.getAllChildMarkers(), + points = [], + p, i; + + for (i = childMarkers.length - 1; i >= 0; i--) { + p = childMarkers[i].getLatLng(); + points.push(p); + } + + return L.QuickHull.getConvexHull(points); + } +}); + + +//This code is 100% based on https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet +//Huge thanks to jawj for implementing it first to make my job easy :-) + +L.MarkerCluster.include({ + + _2PI: Math.PI * 2, + _circleFootSeparation: 25, //related to circumference of circle + _circleStartAngle: Math.PI / 6, + + _spiralFootSeparation: 28, //related to size of spiral (experiment!) + _spiralLengthStart: 11, + _spiralLengthFactor: 5, + + _circleSpiralSwitchover: 9, //show spiral instead of circle from this marker count upwards. + // 0 -> always spiral; Infinity -> always circle + + spiderfy: function () { + if (this._group._spiderfied === this || this._group._inZoomAnimation) { + return; + } + + var childMarkers = this.getAllChildMarkers(), + group = this._group, + map = group._map, + center = map.latLngToLayerPoint(this._latlng), + positions; + + this._group._unspiderfy(); + this._group._spiderfied = this; + + //TODO Maybe: childMarkers order by distance to center + + if (childMarkers.length >= this._circleSpiralSwitchover) { + positions = this._generatePointsSpiral(childMarkers.length, center); + } else { + center.y += 10; // Otherwise circles look wrong => hack for standard blue icon, renders differently for other icons. + positions = this._generatePointsCircle(childMarkers.length, center); + } + + this._animationSpiderfy(childMarkers, positions); + }, + + unspiderfy: function (zoomDetails) { + /// Argument from zoomanim if being called in a zoom animation or null otherwise + if (this._group._inZoomAnimation) { + return; + } + this._animationUnspiderfy(zoomDetails); + + this._group._spiderfied = null; + }, + + _generatePointsCircle: function (count, centerPt) { + var circumference = this._group.options.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count), + legLength = circumference / this._2PI, //radius from circumference + angleStep = this._2PI / count, + res = [], + i, angle; + + res.length = count; + + for (i = count - 1; i >= 0; i--) { + angle = this._circleStartAngle + i * angleStep; + res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round(); + } + + return res; + }, + + _generatePointsSpiral: function (count, centerPt) { + var spiderfyDistanceMultiplier = this._group.options.spiderfyDistanceMultiplier, + legLength = spiderfyDistanceMultiplier * this._spiralLengthStart, + separation = spiderfyDistanceMultiplier * this._spiralFootSeparation, + lengthFactor = spiderfyDistanceMultiplier * this._spiralLengthFactor * this._2PI, + angle = 0, + res = [], + i; + + res.length = count; + + // Higher index, closer position to cluster center. + for (i = count - 1; i >= 0; i--) { + angle += separation / legLength + i * 0.0005; + res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round(); + legLength += lengthFactor / angle; + } + return res; + }, + + _noanimationUnspiderfy: function () { + var group = this._group, + map = group._map, + fg = group._featureGroup, + childMarkers = this.getAllChildMarkers(), + m, i; + + group._ignoreMove = true; + + this.setOpacity(1); + for (i = childMarkers.length - 1; i >= 0; i--) { + m = childMarkers[i]; + + fg.removeLayer(m); + + if (m._preSpiderfyLatlng) { + m.setLatLng(m._preSpiderfyLatlng); + delete m._preSpiderfyLatlng; + } + if (m.setZIndexOffset) { + m.setZIndexOffset(0); + } + + if (m._spiderLeg) { + map.removeLayer(m._spiderLeg); + delete m._spiderLeg; + } + } + + group.fire('unspiderfied', { + cluster: this, + markers: childMarkers + }); + group._ignoreMove = false; + group._spiderfied = null; + } +}); + +//Non Animated versions of everything +L.MarkerClusterNonAnimated = L.MarkerCluster.extend({ + _animationSpiderfy: function (childMarkers, positions) { + var group = this._group, + map = group._map, + fg = group._featureGroup, + legOptions = this._group.options.spiderLegPolylineOptions, + i, m, leg, newPos; + + group._ignoreMove = true; + + // Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition. + // The reverse order trick no longer improves performance on modern browsers. + for (i = 0; i < childMarkers.length; i++) { + newPos = map.layerPointToLatLng(positions[i]); + m = childMarkers[i]; + + // Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it. + leg = new L.Polyline([this._latlng, newPos], legOptions); + map.addLayer(leg); + m._spiderLeg = leg; + + // Now add the marker. + m._preSpiderfyLatlng = m._latlng; + m.setLatLng(newPos); + if (m.setZIndexOffset) { + m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING + } + + fg.addLayer(m); + } + this.setOpacity(0.3); + + group._ignoreMove = false; + group.fire('spiderfied', { + cluster: this, + markers: childMarkers + }); + }, + + _animationUnspiderfy: function () { + this._noanimationUnspiderfy(); + } +}); + +//Animated versions here +L.MarkerCluster.include({ + + _animationSpiderfy: function (childMarkers, positions) { + var me = this, + group = this._group, + map = group._map, + fg = group._featureGroup, + thisLayerLatLng = this._latlng, + thisLayerPos = map.latLngToLayerPoint(thisLayerLatLng), + svg = L.Path.SVG, + legOptions = L.extend({}, this._group.options.spiderLegPolylineOptions), // Copy the options so that we can modify them for animation. + finalLegOpacity = legOptions.opacity, + i, m, leg, legPath, legLength, newPos; + + if (finalLegOpacity === undefined) { + finalLegOpacity = L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity; + } + + if (svg) { + // If the initial opacity of the spider leg is not 0 then it appears before the animation starts. + legOptions.opacity = 0; + + // Add the class for CSS transitions. + legOptions.className = (legOptions.className || '') + ' leaflet-cluster-spider-leg'; + } else { + // Make sure we have a defined opacity. + legOptions.opacity = finalLegOpacity; + } + + group._ignoreMove = true; + + // Add markers and spider legs to map, hidden at our center point. + // Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition. + // The reverse order trick no longer improves performance on modern browsers. + for (i = 0; i < childMarkers.length; i++) { + m = childMarkers[i]; + + newPos = map.layerPointToLatLng(positions[i]); + + // Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it. + leg = new L.Polyline([thisLayerLatLng, newPos], legOptions); + map.addLayer(leg); + m._spiderLeg = leg; + + // Explanations: https://jakearchibald.com/2013/animated-line-drawing-svg/ + // In our case the transition property is declared in the CSS file. + if (svg) { + legPath = leg._path; + legLength = legPath.getTotalLength() + 0.1; // Need a small extra length to avoid remaining dot in Firefox. + legPath.style.strokeDasharray = legLength; // Just 1 length is enough, it will be duplicated. + legPath.style.strokeDashoffset = legLength; + } + + // If it is a marker, add it now and we'll animate it out + if (m.setZIndexOffset) { + m.setZIndexOffset(1000000); // Make normal markers appear on top of EVERYTHING + } + if (m.clusterHide) { + m.clusterHide(); + } + + // Vectors just get immediately added + fg.addLayer(m); + + if (m._setPos) { + m._setPos(thisLayerPos); + } + } + + group._forceLayout(); + group._animationStart(); + + // Reveal markers and spider legs. + for (i = childMarkers.length - 1; i >= 0; i--) { + newPos = map.layerPointToLatLng(positions[i]); + m = childMarkers[i]; + + //Move marker to new position + m._preSpiderfyLatlng = m._latlng; + m.setLatLng(newPos); + + if (m.clusterShow) { + m.clusterShow(); + } + + // Animate leg (animation is actually delegated to CSS transition). + if (svg) { + leg = m._spiderLeg; + legPath = leg._path; + legPath.style.strokeDashoffset = 0; + //legPath.style.strokeOpacity = finalLegOpacity; + leg.setStyle({opacity: finalLegOpacity}); + } + } + this.setOpacity(0.3); + + group._ignoreMove = false; + + setTimeout(function () { + group._animationEnd(); + group.fire('spiderfied', { + cluster: me, + markers: childMarkers + }); + }, 200); + }, + + _animationUnspiderfy: function (zoomDetails) { + var me = this, + group = this._group, + map = group._map, + fg = group._featureGroup, + thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng), + childMarkers = this.getAllChildMarkers(), + svg = L.Path.SVG, + m, i, leg, legPath, legLength, nonAnimatable; + + group._ignoreMove = true; + group._animationStart(); + + //Make us visible and bring the child markers back in + this.setOpacity(1); + for (i = childMarkers.length - 1; i >= 0; i--) { + m = childMarkers[i]; + + //Marker was added to us after we were spiderfied + if (!m._preSpiderfyLatlng) { + continue; + } + + //Fix up the location to the real one + m.setLatLng(m._preSpiderfyLatlng); + delete m._preSpiderfyLatlng; + + //Hack override the location to be our center + nonAnimatable = true; + if (m._setPos) { + m._setPos(thisLayerPos); + nonAnimatable = false; + } + if (m.clusterHide) { + m.clusterHide(); + nonAnimatable = false; + } + if (nonAnimatable) { + fg.removeLayer(m); + } + + // Animate the spider leg back in (animation is actually delegated to CSS transition). + if (svg) { + leg = m._spiderLeg; + legPath = leg._path; + legLength = legPath.getTotalLength() + 0.1; + legPath.style.strokeDashoffset = legLength; + leg.setStyle({opacity: 0}); + } + } + + group._ignoreMove = false; + + setTimeout(function () { + //If we have only <= one child left then that marker will be shown on the map so don't remove it! + var stillThereChildCount = 0; + for (i = childMarkers.length - 1; i >= 0; i--) { + m = childMarkers[i]; + if (m._spiderLeg) { + stillThereChildCount++; + } + } + + + for (i = childMarkers.length - 1; i >= 0; i--) { + m = childMarkers[i]; + + if (!m._spiderLeg) { //Has already been unspiderfied + continue; + } + + if (m.clusterShow) { + m.clusterShow(); + } + if (m.setZIndexOffset) { + m.setZIndexOffset(0); + } + + if (stillThereChildCount > 1) { + fg.removeLayer(m); + } + + map.removeLayer(m._spiderLeg); + delete m._spiderLeg; + } + group._animationEnd(); + group.fire('unspiderfied', { + cluster: me, + markers: childMarkers + }); + }, 200); + } +}); + + +L.MarkerClusterGroup.include({ + //The MarkerCluster currently spiderfied (if any) + _spiderfied: null, + + unspiderfy: function () { + this._unspiderfy.apply(this, arguments); + }, + + _spiderfierOnAdd: function () { + this._map.on('click', this._unspiderfyWrapper, this); + + if (this._map.options.zoomAnimation) { + this._map.on('zoomstart', this._unspiderfyZoomStart, this); + } + //Browsers without zoomAnimation or a big zoom don't fire zoomstart + this._map.on('zoomend', this._noanimationUnspiderfy, this); + + if (!L.Browser.touch) { + this._map.getRenderer(this); + //Needs to happen in the pageload, not after, or animations don't work in webkit + // http://stackoverflow.com/questions/8455200/svg-animate-with-dynamically-added-elements + //Disable on touch browsers as the animation messes up on a touch zoom and isn't very noticable + } + }, + + _spiderfierOnRemove: function () { + this._map.off('click', this._unspiderfyWrapper, this); + this._map.off('zoomstart', this._unspiderfyZoomStart, this); + this._map.off('zoomanim', this._unspiderfyZoomAnim, this); + this._map.off('zoomend', this._noanimationUnspiderfy, this); + + //Ensure that markers are back where they should be + // Use no animation to avoid a sticky leaflet-cluster-anim class on mapPane + this._noanimationUnspiderfy(); + }, + + //On zoom start we add a zoomanim handler so that we are guaranteed to be last (after markers are animated) + //This means we can define the animation they do rather than Markers doing an animation to their actual location + _unspiderfyZoomStart: function () { + if (!this._map) { //May have been removed from the map by a zoomEnd handler + return; + } + + this._map.on('zoomanim', this._unspiderfyZoomAnim, this); + }, + + _unspiderfyZoomAnim: function (zoomDetails) { + //Wait until the first zoomanim after the user has finished touch-zooming before running the animation + if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) { + return; + } + + this._map.off('zoomanim', this._unspiderfyZoomAnim, this); + this._unspiderfy(zoomDetails); + }, + + _unspiderfyWrapper: function () { + /// _unspiderfy but passes no arguments + this._unspiderfy(); + }, + + _unspiderfy: function (zoomDetails) { + if (this._spiderfied) { + this._spiderfied.unspiderfy(zoomDetails); + } + }, + + _noanimationUnspiderfy: function () { + if (this._spiderfied) { + this._spiderfied._noanimationUnspiderfy(); + } + }, + + //If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc + _unspiderfyLayer: function (layer) { + if (layer._spiderLeg) { + this._featureGroup.removeLayer(layer); + + if (layer.clusterShow) { + layer.clusterShow(); + } + //Position will be fixed up immediately in _animationUnspiderfy + if (layer.setZIndexOffset) { + layer.setZIndexOffset(0); + } + + this._map.removeLayer(layer._spiderLeg); + delete layer._spiderLeg; + } + } +}); + + +/** + * Adds 1 public method to MCG and 1 to L.Marker to facilitate changing + * markers' icon options and refreshing their icon and their parent clusters + * accordingly (case where their iconCreateFunction uses data of childMarkers + * to make up the cluster icon). + */ + + +L.MarkerClusterGroup.include({ + /** + * Updates the icon of all clusters which are parents of the given marker(s). + * In singleMarkerMode, also updates the given marker(s) icon. + * @param layers L.MarkerClusterGroup|L.LayerGroup|Array(L.Marker)|Map(L.Marker)| + * L.MarkerCluster|L.Marker (optional) list of markers (or single marker) whose parent + * clusters need to be updated. If not provided, retrieves all child markers of this. + * @returns {L.MarkerClusterGroup} + */ + refreshClusters: function (layers) { + if (!layers) { + layers = this._topClusterLevel.getAllChildMarkers(); + } else if (layers instanceof L.MarkerClusterGroup) { + layers = layers._topClusterLevel.getAllChildMarkers(); + } else if (layers instanceof L.LayerGroup) { + layers = layers._layers; + } else if (layers instanceof L.MarkerCluster) { + layers = layers.getAllChildMarkers(); + } else if (layers instanceof L.Marker) { + layers = [layers]; + } // else: must be an Array(L.Marker)|Map(L.Marker) + this._flagParentsIconsNeedUpdate(layers); + this._refreshClustersIcons(); + + // In case of singleMarkerMode, also re-draw the markers. + if (this.options.singleMarkerMode) { + this._refreshSingleMarkerModeMarkers(layers); + } + + return this; + }, + + /** + * Simply flags all parent clusters of the given markers as having a "dirty" icon. + * @param layers Array(L.Marker)|Map(L.Marker) list of markers. + * @private + */ + _flagParentsIconsNeedUpdate: function (layers) { + var id, parent; + + // Assumes layers is an Array or an Object whose prototype is non-enumerable. + for (id in layers) { + // Flag parent clusters' icon as "dirty", all the way up. + // Dumb process that flags multiple times upper parents, but still + // much more efficient than trying to be smart and make short lists, + // at least in the case of a hierarchy following a power law: + // http://jsperf.com/flag-nodes-in-power-hierarchy/2 + parent = layers[id].__parent; + while (parent) { + parent._iconNeedsUpdate = true; + parent = parent.__parent; + } + } + }, + + /** + * Refreshes the icon of all "dirty" visible clusters. + * Non-visible "dirty" clusters will be updated when they are added to the map. + * @private + */ + _refreshClustersIcons: function () { + this._featureGroup.eachLayer(function (c) { + if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) { + c._updateIcon(); + } + }); + }, + + /** + * Re-draws the icon of the supplied markers. + * To be used in singleMarkerMode only. + * @param layers Array(L.Marker)|Map(L.Marker) list of markers. + * @private + */ + _refreshSingleMarkerModeMarkers: function (layers) { + var id, layer; + + for (id in layers) { + layer = layers[id]; + + // Make sure we do not override markers that do not belong to THIS group. + if (this.hasLayer(layer)) { + // Need to re-create the icon first, then re-draw the marker. + layer.setIcon(this._overrideMarkerIcon(layer)); + } + } + } +}); + +L.Marker.include({ + /** + * Updates the given options in the marker's icon and refreshes the marker. + * @param options map object of icon options. + * @param directlyRefreshClusters boolean (optional) true to trigger + * MCG.refreshClustersOf() right away with this single marker. + * @returns {L.Marker} + */ + refreshIconOptions: function (options, directlyRefreshClusters) { + var icon = this.options.icon; + + L.setOptions(icon, options); + + this.setIcon(icon); + + // Shortcut to refresh the associated MCG clusters right away. + // To be used when refreshing a single marker. + // Otherwise, better use MCG.refreshClusters() once at the end with + // the list of modified markers. + if (directlyRefreshClusters && this.__parent) { + this.__parent._group.refreshClusters(this); + } + + return this; + } +}); + + +}(window, document)); \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet.markercluster/leaflet.markercluster.js b/includes/services/Leaflet/leaflet.markercluster/leaflet.markercluster.js new file mode 100644 index 000000000..020abe678 --- /dev/null +++ b/includes/services/Leaflet/leaflet.markercluster/leaflet.markercluster.js @@ -0,0 +1,6 @@ +/* + Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps. + https://github.com/Leaflet/Leaflet.markercluster + (c) 2012-2013, Dave Leaver, smartrak +*/ +!function(e,t,i){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,removeOutsideVisibleBounds:!0,animate:!0,animateAddingMarkers:!1,spiderfyDistanceMultiplier:1,spiderLegPolylineOptions:{weight:1.5,color:"#222",opacity:.5},chunkedLoading:!1,chunkInterval:200,chunkDelay:50,chunkProgress:null,polygonOptions:{}},initialize:function(e){L.Util.setOptions(this,e),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),this._featureGroup=L.featureGroup(),this._featureGroup.addEventParent(this),this._nonPointGroup=L.featureGroup(),this._nonPointGroup.addEventParent(this),this._inZoomAnimation=0,this._needsClustering=[],this._needsRemoving=[],this._currentShownBounds=null,this._queue=[];var t=L.DomUtil.TRANSITION&&this.options.animate;L.extend(this,t?this._withAnimation:this._noAnimation),this._markerCluster=t?L.MarkerCluster:L.MarkerClusterNonAnimated},addLayer:function(e){if(e instanceof L.LayerGroup)return this.addLayers([e]);if(!e.getLatLng)return this._nonPointGroup.addLayer(e),this;if(!this._map)return this._needsClustering.push(e),this;if(this.hasLayer(e))return this;this._unspiderfy&&this._unspiderfy(),this._addLayer(e,this._maxZoom),this._topClusterLevel._recalculateBounds();var t=e,i=this._map.getZoom();if(e.__parent)for(;t.__parent._zoom>=i;)t=t.__parent;return this._currentShownBounds.contains(t.getLatLng())&&(this.options.animateAddingMarkers?this._animationAddLayer(e,t):this._animationAddLayerNonAnimated(e,t)),this},removeLayer:function(e){return e instanceof L.LayerGroup?this.removeLayers([e]):e.getLatLng?this._map?e.__parent?(this._unspiderfy&&(this._unspiderfy(),this._unspiderfyLayer(e)),this._removeLayer(e,!0),this._topClusterLevel._recalculateBounds(),e.off("move",this._childMarkerMoved,this),this._featureGroup.hasLayer(e)&&(this._featureGroup.removeLayer(e),e.clusterShow&&e.clusterShow()),this):this:(!this._arraySplice(this._needsClustering,e)&&this.hasLayer(e)&&this._needsRemoving.push(e),this):(this._nonPointGroup.removeLayer(e),this)},addLayers:function(e){if(!L.Util.isArray(e))return this.addLayer(e);var t,i=this._featureGroup,n=this._nonPointGroup,s=this.options.chunkedLoading,r=this.options.chunkInterval,o=this.options.chunkProgress,a=e.length,h=0,u=!0;if(this._map){var l=(new Date).getTime(),_=L.bind(function(){for(var d=(new Date).getTime();a>h;h++){if(s&&0===h%200){var c=(new Date).getTime()-d;if(c>r)break}if(t=e[h],t instanceof L.LayerGroup)u&&(e=e.slice(),u=!1),this._extractNonGroupLayers(t,e),a=e.length;else if(t.getLatLng){if(!this.hasLayer(t)&&(this._addLayer(t,this._maxZoom),t.__parent&&2===t.__parent.getChildCount())){var p=t.__parent.getAllChildMarkers(),f=p[0]===t?p[1]:p[0];i.removeLayer(f)}}else n.addLayer(t)}o&&o(h,a,(new Date).getTime()-l),h===a?(this._topClusterLevel._recalculateBounds(),this._featureGroup.eachLayer(function(e){e instanceof L.MarkerCluster&&e._iconNeedsUpdate&&e._updateIcon()}),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds)):setTimeout(_,this.options.chunkDelay)},this);_()}else for(var d=this._needsClustering;a>h;h++)t=e[h],t instanceof L.LayerGroup?(u&&(e=e.slice(),u=!1),this._extractNonGroupLayers(t,e),a=e.length):t.getLatLng?this.hasLayer(t)||d.push(t):n.addLayer(t);return this},removeLayers:function(e){var t,i,n=e.length,s=this._featureGroup,r=this._nonPointGroup,o=!0;if(!this._map){for(t=0;n>t;t++)i=e[t],i instanceof L.LayerGroup?(o&&(e=e.slice(),o=!1),this._extractNonGroupLayers(i,e),n=e.length):(this._arraySplice(this._needsClustering,i),r.removeLayer(i),this.hasLayer(i)&&this._needsRemoving.push(i));return this}if(this._unspiderfy){this._unspiderfy();var a=e.slice(),h=n;for(t=0;h>t;t++)i=a[t],i instanceof L.LayerGroup?(this._extractNonGroupLayers(i,a),h=a.length):this._unspiderfyLayer(i)}for(t=0;n>t;t++)i=e[t],i instanceof L.LayerGroup?(o&&(e=e.slice(),o=!1),this._extractNonGroupLayers(i,e),n=e.length):i.__parent?(this._removeLayer(i,!0,!0),s.hasLayer(i)&&(s.removeLayer(i),i.clusterShow&&i.clusterShow())):r.removeLayer(i);return this._topClusterLevel._recalculateBounds(),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds),s.eachLayer(function(e){e instanceof L.MarkerCluster&&e._updateIcon()}),this},clearLayers:function(){return this._map||(this._needsClustering=[],delete this._gridClusters,delete this._gridUnclustered),this._noanimationUnspiderfy&&this._noanimationUnspiderfy(),this._featureGroup.clearLayers(),this._nonPointGroup.clearLayers(),this.eachLayer(function(e){e.off("move",this._childMarkerMoved,this),delete e.__parent}),this._map&&this._generateInitialClusters(),this},getBounds:function(){var e=new L.LatLngBounds;this._topClusterLevel&&e.extend(this._topClusterLevel._bounds);for(var t=this._needsClustering.length-1;t>=0;t--)e.extend(this._needsClustering[t].getLatLng());return e.extend(this._nonPointGroup.getBounds()),e},eachLayer:function(e,t){var i,n=this._needsClustering.slice(),s=this._needsRemoving;for(this._topClusterLevel&&this._topClusterLevel.getAllChildMarkers(n),i=n.length-1;i>=0;i--)-1===s.indexOf(n[i])&&e.call(t,n[i]);this._nonPointGroup.eachLayer(e,t)},getLayers:function(){var e=[];return this.eachLayer(function(t){e.push(t)}),e},getLayer:function(e){var t=null;return e=parseInt(e,10),this.eachLayer(function(i){L.stamp(i)===e&&(t=i)}),t},hasLayer:function(e){if(!e)return!1;var t,i=this._needsClustering;for(t=i.length-1;t>=0;t--)if(i[t]===e)return!0;for(i=this._needsRemoving,t=i.length-1;t>=0;t--)if(i[t]===e)return!1;return!(!e.__parent||e.__parent._group!==this)||this._nonPointGroup.hasLayer(e)},zoomToShowLayer:function(e,t){"function"!=typeof t&&(t=function(){});var i=function(){!e._icon&&!e.__parent._icon||this._inZoomAnimation||(this._map.off("moveend",i,this),this.off("animationend",i,this),e._icon?t():e.__parent._icon&&(this.once("spiderfied",t,this),e.__parent.spiderfy()))};if(e._icon&&this._map.getBounds().contains(e.getLatLng()))t();else if(e.__parent._zoomt;t++)n=this._needsRemoving[t],this._removeLayer(n,!0);this._needsRemoving=[],this._zoom=this._map.getZoom(),this._currentShownBounds=this._getExpandedVisibleBounds(),this._map.on("zoomend",this._zoomEnd,this),this._map.on("moveend",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd(),this._bindEvents(),i=this._needsClustering,this._needsClustering=[],this.addLayers(i)},onRemove:function(e){e.off("zoomend",this._zoomEnd,this),e.off("moveend",this._moveEnd,this),this._unbindEvents(),this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim",""),this._spiderfierOnRemove&&this._spiderfierOnRemove(),delete this._maxLat,this._hideCoverage(),this._featureGroup.remove(),this._nonPointGroup.remove(),this._featureGroup.clearLayers(),this._map=null},getVisibleParent:function(e){for(var t=e;t&&!t._icon;)t=t.__parent;return t||null},_arraySplice:function(e,t){for(var i=e.length-1;i>=0;i--)if(e[i]===t)return e.splice(i,1),!0},_removeFromGridUnclustered:function(e,t){for(var i=this._map,n=this._gridUnclustered;t>=0&&n[t].removeObject(e,i.project(e.getLatLng(),t));t--);},_childMarkerMoved:function(e){this._ignoreMove||(e.target._latlng=e.oldLatLng,this.removeLayer(e.target),e.target._latlng=e.latlng,this.addLayer(e.target))},_removeLayer:function(e,t,i){var n=this._gridClusters,s=this._gridUnclustered,r=this._featureGroup,o=this._map;t&&this._removeFromGridUnclustered(e,this._maxZoom);var a,h=e.__parent,u=h._markers;for(this._arraySplice(u,e);h&&(h._childCount--,h._boundsNeedUpdate=!0,!(h._zoom<0));)t&&h._childCount<=1?(a=h._markers[0]===e?h._markers[1]:h._markers[0],n[h._zoom].removeObject(h,o.project(h._cLatLng,h._zoom)),s[h._zoom].addObject(a,o.project(a.getLatLng(),h._zoom)),this._arraySplice(h.__parent._childClusters,h),h.__parent._markers.push(a),a.__parent=h.__parent,h._icon&&(r.removeLayer(h),i||r.addLayer(a))):i&&h._icon||h._updateIcon(),h=h.__parent;delete e.__parent},_isOrIsParent:function(e,t){for(;t;){if(e===t)return!0;t=t.parentNode}return!1},fire:function(e,t,i){if(t&&t.layer instanceof L.MarkerCluster){if(t.originalEvent&&this._isOrIsParent(t.layer._icon,t.originalEvent.relatedTarget))return;e="cluster"+e}L.FeatureGroup.prototype.fire.call(this,e,t,i)},listens:function(e,t){return L.FeatureGroup.prototype.listens.call(this,e,t)||L.FeatureGroup.prototype.listens.call(this,"cluster"+e,t)},_defaultIconCreateFunction:function(e){var t=e.getChildCount(),i=" marker-cluster-";return i+=10>t?"small":100>t?"medium":"large",new L.DivIcon({html:"
"+t+"
",className:"marker-cluster"+i,iconSize:new L.Point(40,40)})},_bindEvents:function(){var e=this._map,t=this.options.spiderfyOnMaxZoom,i=this.options.showCoverageOnHover,n=this.options.zoomToBoundsOnClick;(t||n)&&this.on("clusterclick",this._zoomOrSpiderfy,this),i&&(this.on("clustermouseover",this._showCoverage,this),this.on("clustermouseout",this._hideCoverage,this),e.on("zoomend",this._hideCoverage,this))},_zoomOrSpiderfy:function(e){for(var t=e.layer,i=t;1===i._childClusters.length;)i=i._childClusters[0];i._zoom===this._maxZoom&&i._childCount===t._childCount&&this.options.spiderfyOnMaxZoom?t.spiderfy():this.options.zoomToBoundsOnClick&&t.zoomToBounds(),e.originalEvent&&13===e.originalEvent.keyCode&&this._map._container.focus()},_showCoverage:function(e){var t=this._map;this._inZoomAnimation||(this._shownPolygon&&t.removeLayer(this._shownPolygon),e.layer.getChildCount()>2&&e.layer!==this._spiderfied&&(this._shownPolygon=new L.Polygon(e.layer.getConvexHull(),this.options.polygonOptions),t.addLayer(this._shownPolygon)))},_hideCoverage:function(){this._shownPolygon&&(this._map.removeLayer(this._shownPolygon),this._shownPolygon=null)},_unbindEvents:function(){var e=this.options.spiderfyOnMaxZoom,t=this.options.showCoverageOnHover,i=this.options.zoomToBoundsOnClick,n=this._map;(e||i)&&this.off("clusterclick",this._zoomOrSpiderfy,this),t&&(this.off("clustermouseover",this._showCoverage,this),this.off("clustermouseout",this._hideCoverage,this),n.off("zoomend",this._hideCoverage,this))},_zoomEnd:function(){this._map&&(this._mergeSplitClusters(),this._zoom=Math.round(this._map._zoom),this._currentShownBounds=this._getExpandedVisibleBounds())},_moveEnd:function(){if(!this._inZoomAnimation){var e=this._getExpandedVisibleBounds();this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,this._zoom,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,Math.round(this._map._zoom),e),this._currentShownBounds=e}},_generateInitialClusters:function(){var e=this._map.getMaxZoom(),t=this.options.maxClusterRadius,i=t;"function"!=typeof t&&(i=function(){return t}),this.options.disableClusteringAtZoom&&(e=this.options.disableClusteringAtZoom-1),this._maxZoom=e,this._gridClusters={},this._gridUnclustered={};for(var n=e;n>=0;n--)this._gridClusters[n]=new L.DistanceGrid(i(n)),this._gridUnclustered[n]=new L.DistanceGrid(i(n));this._topClusterLevel=new this._markerCluster(this,-1)},_addLayer:function(e,t){var i,n,s=this._gridClusters,r=this._gridUnclustered;for(this.options.singleMarkerMode&&this._overrideMarkerIcon(e),e.on("move",this._childMarkerMoved,this);t>=0;t--){i=this._map.project(e.getLatLng(),t);var o=s[t].getNearObject(i);if(o)return o._addChild(e),e.__parent=o,void 0;if(o=r[t].getNearObject(i)){var a=o.__parent;a&&this._removeLayer(o,!1);var h=new this._markerCluster(this,t,o,e);s[t].addObject(h,this._map.project(h._cLatLng,t)),o.__parent=h,e.__parent=h;var u=h;for(n=t-1;n>a._zoom;n--)u=new this._markerCluster(this,n,u),s[n].addObject(u,this._map.project(o.getLatLng(),n));return a._addChild(u),this._removeFromGridUnclustered(o,t),void 0}r[t].addObject(e,i)}this._topClusterLevel._addChild(e),e.__parent=this._topClusterLevel},_enqueue:function(e){this._queue.push(e),this._queueTimeout||(this._queueTimeout=setTimeout(L.bind(this._processQueue,this),300))},_processQueue:function(){for(var e=0;ee?(this._animationStart(),this._animationZoomOut(this._zoom,e)):this._moveEnd()},_getExpandedVisibleBounds:function(){return this.options.removeOutsideVisibleBounds?L.Browser.mobile?this._checkBoundsMaxLat(this._map.getBounds()):this._checkBoundsMaxLat(this._map.getBounds().pad(1)):this._mapBoundsInfinite},_checkBoundsMaxLat:function(e){var t=this._maxLat;return t!==i&&(e.getNorth()>=t&&(e._northEast.lat=1/0),e.getSouth()<=-t&&(e._southWest.lat=-1/0)),e},_animationAddLayerNonAnimated:function(e,t){if(t===e)this._featureGroup.addLayer(e);else if(2===t._childCount){t._addToMap();var i=t.getAllChildMarkers();this._featureGroup.removeLayer(i[0]),this._featureGroup.removeLayer(i[1])}else t._updateIcon()},_extractNonGroupLayers:function(e,t){var i,n=e.getLayers(),s=0;for(t=t||[];s=0;i--)o=h[i],n.contains(o._latlng)||s.removeLayer(o)}),this._forceLayout(),this._topClusterLevel._recursivelyBecomeVisible(n,t),s.eachLayer(function(e){e instanceof L.MarkerCluster||!e._icon||e.clusterShow()}),this._topClusterLevel._recursively(n,e,t,function(e){e._recursivelyRestoreChildPositions(t)}),this._ignoreMove=!1,this._enqueue(function(){this._topClusterLevel._recursively(n,e,0,function(e){s.removeLayer(e),e.clusterShow()}),this._animationEnd()})},_animationZoomOut:function(e,t){this._animationZoomOutSingle(this._topClusterLevel,e-1,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,t,this._getExpandedVisibleBounds()),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,e,this._getExpandedVisibleBounds())},_animationAddLayer:function(e,t){var i=this,n=this._featureGroup;n.addLayer(e),t!==e&&(t._childCount>2?(t._updateIcon(),this._forceLayout(),this._animationStart(),e._setPos(this._map.latLngToLayerPoint(t.getLatLng())),e.clusterHide(),this._enqueue(function(){n.removeLayer(e),e.clusterShow(),i._animationEnd()})):(this._forceLayout(),i._animationStart(),i._animationZoomOutSingle(t,this._map.getMaxZoom(),this._map.getZoom())))}},_animationZoomOutSingle:function(e,t,i){var n=this._getExpandedVisibleBounds();e._recursivelyAnimateChildrenInAndAddSelfToMap(n,t+1,i);var s=this;this._forceLayout(),e._recursivelyBecomeVisible(n,i),this._enqueue(function(){if(1===e._childCount){var r=e._markers[0];this._ignoreMove=!0,r.setLatLng(r.getLatLng()),this._ignoreMove=!1,r.clusterShow&&r.clusterShow()}else e._recursively(n,i,0,function(e){e._recursivelyRemoveChildrenFromMap(n,t+1)});s._animationEnd()})},_animationEnd:function(){this._map&&(this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim","")),this._inZoomAnimation--,this.fire("animationend")},_forceLayout:function(){L.Util.falseFn(t.body.offsetWidth)}}),L.markerClusterGroup=function(e){return new L.MarkerClusterGroup(e)},L.MarkerCluster=L.Marker.extend({initialize:function(e,t,i,n){L.Marker.prototype.initialize.call(this,i?i._cLatLng||i.getLatLng():new L.LatLng(0,0),{icon:this}),this._group=e,this._zoom=t,this._markers=[],this._childClusters=[],this._childCount=0,this._iconNeedsUpdate=!0,this._boundsNeedUpdate=!0,this._bounds=new L.LatLngBounds,i&&this._addChild(i),n&&this._addChild(n)},getAllChildMarkers:function(e){e=e||[];for(var t=this._childClusters.length-1;t>=0;t--)this._childClusters[t].getAllChildMarkers(e);for(var i=this._markers.length-1;i>=0;i--)e.push(this._markers[i]);return e},getChildCount:function(){return this._childCount},zoomToBounds:function(){for(var e,t=this._childClusters.slice(),i=this._group._map,n=i.getBoundsZoom(this._bounds),s=this._zoom+1,r=i.getZoom();t.length>0&&n>s;){s++;var o=[];for(e=0;es?this._group._map.setView(this._latlng,s):r>=n?this._group._map.setView(this._latlng,r+1):this._group._map.fitBounds(this._bounds)},getBounds:function(){var e=new L.LatLngBounds;return e.extend(this._bounds),e},_updateIcon:function(){this._iconNeedsUpdate=!0,this._icon&&this.setIcon(this)},createIcon:function(){return this._iconNeedsUpdate&&(this._iconObj=this._group.options.iconCreateFunction(this),this._iconNeedsUpdate=!1),this._iconObj.createIcon()},createShadow:function(){return this._iconObj.createShadow()},_addChild:function(e,t){this._iconNeedsUpdate=!0,this._boundsNeedUpdate=!0,this._setClusterCenter(e),e instanceof L.MarkerCluster?(t||(this._childClusters.push(e),e.__parent=this),this._childCount+=e._childCount):(t||this._markers.push(e),this._childCount++),this.__parent&&this.__parent._addChild(e,!0)},_setClusterCenter:function(e){this._cLatLng||(this._cLatLng=e._cLatLng||e._latlng)},_resetBounds:function(){var e=this._bounds;e._southWest&&(e._southWest.lat=1/0,e._southWest.lng=1/0),e._northEast&&(e._northEast.lat=-1/0,e._northEast.lng=-1/0)},_recalculateBounds:function(){var e,t,i,n,s=this._markers,r=this._childClusters,o=0,a=0,h=this._childCount;if(0!==h){for(this._resetBounds(),e=0;e=0;i--)n=s[i],n._icon&&(n._setPos(t),n.clusterHide())},function(e){var i,n,s=e._childClusters;for(i=s.length-1;i>=0;i--)n=s[i],n._icon&&(n._setPos(t),n.clusterHide())})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(e,t,i){this._recursively(e,i,0,function(n){n._recursivelyAnimateChildrenIn(e,n._group._map.latLngToLayerPoint(n.getLatLng()).round(),t),n._isSingleParent()&&t-1===i?(n.clusterShow(),n._recursivelyRemoveChildrenFromMap(e,t)):n.clusterHide(),n._addToMap()})},_recursivelyBecomeVisible:function(e,t){this._recursively(e,0,t,null,function(e){e.clusterShow()})},_recursivelyAddChildrenToMap:function(e,t,i){this._recursively(i,-1,t,function(n){if(t!==n._zoom)for(var s=n._markers.length-1;s>=0;s--){var r=n._markers[s];i.contains(r._latlng)&&(e&&(r._backupLatlng=r.getLatLng(),r.setLatLng(e),r.clusterHide&&r.clusterHide()),n._group._featureGroup.addLayer(r))}},function(t){t._addToMap(e)})},_recursivelyRestoreChildPositions:function(e){for(var t=this._markers.length-1;t>=0;t--){var i=this._markers[t];i._backupLatlng&&(i.setLatLng(i._backupLatlng),delete i._backupLatlng)}if(e-1===this._zoom)for(var n=this._childClusters.length-1;n>=0;n--)this._childClusters[n]._restorePosition();else for(var s=this._childClusters.length-1;s>=0;s--)this._childClusters[s]._recursivelyRestoreChildPositions(e)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(e,t,i){var n,s;this._recursively(e,-1,t-1,function(e){for(s=e._markers.length-1;s>=0;s--)n=e._markers[s],i&&i.contains(n._latlng)||(e._group._featureGroup.removeLayer(n),n.clusterShow&&n.clusterShow())},function(e){for(s=e._childClusters.length-1;s>=0;s--)n=e._childClusters[s],i&&i.contains(n._latlng)||(e._group._featureGroup.removeLayer(n),n.clusterShow&&n.clusterShow())})},_recursively:function(e,t,i,n,s){var r,o,a=this._childClusters,h=this._zoom;if(t>h)for(r=a.length-1;r>=0;r--)o=a[r],e.intersects(o._bounds)&&o._recursively(e,t,i,n,s);else if(n&&n(this),s&&this._zoom===i&&s(this),i>h)for(r=a.length-1;r>=0;r--)o=a[r],e.intersects(o._bounds)&&o._recursively(e,t,i,n,s)},_isSingleParent:function(){return this._childClusters.length>0&&this._childClusters[0]._childCount===this._childCount}}),L.Marker.include({clusterHide:function(){return this.options.opacityWhenUnclustered=this.options.opacity||1,this.setOpacity(0)},clusterShow:function(){var e=this.setOpacity(this.options.opacity||this.options.opacityWhenUnclustered);return delete this.options.opacityWhenUnclustered,e}}),L.DistanceGrid=function(e){this._cellSize=e,this._sqCellSize=e*e,this._grid={},this._objectPoint={}},L.DistanceGrid.prototype={addObject:function(e,t){var i=this._getCoord(t.x),n=this._getCoord(t.y),s=this._grid,r=s[n]=s[n]||{},o=r[i]=r[i]||[],a=L.Util.stamp(e);this._objectPoint[a]=t,o.push(e)},updateObject:function(e,t){this.removeObject(e),this.addObject(e,t)},removeObject:function(e,t){var i,n,s=this._getCoord(t.x),r=this._getCoord(t.y),o=this._grid,a=o[r]=o[r]||{},h=a[s]=a[s]||[];for(delete this._objectPoint[L.Util.stamp(e)],i=0,n=h.length;n>i;i++)if(h[i]===e)return h.splice(i,1),1===n&&delete a[s],!0},eachObject:function(e,t){var i,n,s,r,o,a,h,u=this._grid;for(i in u){o=u[i];for(n in o)for(a=o[n],s=0,r=a.length;r>s;s++)h=e.call(t,a[s]),h&&(s--,r--)}},getNearObject:function(e){var t,i,n,s,r,o,a,h,u=this._getCoord(e.x),l=this._getCoord(e.y),_=this._objectPoint,d=this._sqCellSize,c=null;for(t=l-1;l+1>=t;t++)if(s=this._grid[t])for(i=u-1;u+1>=i;i++)if(r=s[i])for(n=0,o=r.length;o>n;n++)a=r[n],h=this._sqDist(_[L.Util.stamp(a)],e),d>h&&(d=h,c=a);return c},_getCoord:function(e){return Math.floor(e/this._cellSize)},_sqDist:function(e,t){var i=t.x-e.x,n=t.y-e.y;return i*i+n*n}},function(){L.QuickHull={getDistant:function(e,t){var i=t[1].lat-t[0].lat,n=t[0].lng-t[1].lng;return n*(e.lat-t[0].lat)+i*(e.lng-t[0].lng)},findMostDistantPointFromBaseLine:function(e,t){var i,n,s,r=0,o=null,a=[];for(i=t.length-1;i>=0;i--)n=t[i],s=this.getDistant(n,e),s>0&&(a.push(n),s>r&&(r=s,o=n));return{maxPoint:o,newPoints:a}},buildConvexHull:function(e,t){var i=[],n=this.findMostDistantPointFromBaseLine(e,t);return n.maxPoint?(i=i.concat(this.buildConvexHull([e[0],n.maxPoint],n.newPoints)),i=i.concat(this.buildConvexHull([n.maxPoint,e[1]],n.newPoints))):[e[0]]},getConvexHull:function(e){var t,i=!1,n=!1,s=!1,r=!1,o=null,a=null,h=null,u=null,l=null,_=null;for(t=e.length-1;t>=0;t--){var d=e[t];(i===!1||d.lat>i)&&(o=d,i=d.lat),(n===!1||d.lats)&&(h=d,s=d.lng),(r===!1||d.lng=0;t--)e=i[t].getLatLng(),n.push(e);return L.QuickHull.getConvexHull(n)}}),L.MarkerCluster.include({_2PI:2*Math.PI,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied!==this&&!this._group._inZoomAnimation){var e,t=this.getAllChildMarkers(),i=this._group,n=i._map,s=n.latLngToLayerPoint(this._latlng);this._group._unspiderfy(),this._group._spiderfied=this,t.length>=this._circleSpiralSwitchover?e=this._generatePointsSpiral(t.length,s):(s.y+=10,e=this._generatePointsCircle(t.length,s)),this._animationSpiderfy(t,e)}},unspiderfy:function(e){this._group._inZoomAnimation||(this._animationUnspiderfy(e),this._group._spiderfied=null)},_generatePointsCircle:function(e,t){var i,n,s=this._group.options.spiderfyDistanceMultiplier*this._circleFootSeparation*(2+e),r=s/this._2PI,o=this._2PI/e,a=[];for(a.length=e,i=e-1;i>=0;i--)n=this._circleStartAngle+i*o,a[i]=new L.Point(t.x+r*Math.cos(n),t.y+r*Math.sin(n))._round();return a},_generatePointsSpiral:function(e,t){var i,n=this._group.options.spiderfyDistanceMultiplier,s=n*this._spiralLengthStart,r=n*this._spiralFootSeparation,o=n*this._spiralLengthFactor*this._2PI,a=0,h=[];for(h.length=e,i=e-1;i>=0;i--)a+=r/s+5e-4*i,h[i]=new L.Point(t.x+s*Math.cos(a),t.y+s*Math.sin(a))._round(),s+=o/a;return h},_noanimationUnspiderfy:function(){var e,t,i=this._group,n=i._map,s=i._featureGroup,r=this.getAllChildMarkers();for(i._ignoreMove=!0,this.setOpacity(1),t=r.length-1;t>=0;t--)e=r[t],s.removeLayer(e),e._preSpiderfyLatlng&&(e.setLatLng(e._preSpiderfyLatlng),delete e._preSpiderfyLatlng),e.setZIndexOffset&&e.setZIndexOffset(0),e._spiderLeg&&(n.removeLayer(e._spiderLeg),delete e._spiderLeg);i.fire("unspiderfied",{cluster:this,markers:r}),i._ignoreMove=!1,i._spiderfied=null}}),L.MarkerClusterNonAnimated=L.MarkerCluster.extend({_animationSpiderfy:function(e,t){var i,n,s,r,o=this._group,a=o._map,h=o._featureGroup,u=this._group.options.spiderLegPolylineOptions;for(o._ignoreMove=!0,i=0;i=0;n--)h=_.layerPointToLatLng(t[n]),s=e[n],s._preSpiderfyLatlng=s._latlng,s.setLatLng(h),s.clusterShow&&s.clusterShow(),f&&(r=s._spiderLeg,o=r._path,o.style.strokeDashoffset=0,r.setStyle({opacity:g}));this.setOpacity(.3),l._ignoreMove=!1,setTimeout(function(){l._animationEnd(),l.fire("spiderfied",{cluster:u,markers:e})},200)},_animationUnspiderfy:function(e){var t,i,n,s,r,o,a=this,h=this._group,u=h._map,l=h._featureGroup,_=e?u._latLngToNewLayerPoint(this._latlng,e.zoom,e.center):u.latLngToLayerPoint(this._latlng),d=this.getAllChildMarkers(),c=L.Path.SVG;for(h._ignoreMove=!0,h._animationStart(),this.setOpacity(1),i=d.length-1;i>=0;i--)t=d[i],t._preSpiderfyLatlng&&(t.setLatLng(t._preSpiderfyLatlng),delete t._preSpiderfyLatlng,o=!0,t._setPos&&(t._setPos(_),o=!1),t.clusterHide&&(t.clusterHide(),o=!1),o&&l.removeLayer(t),c&&(n=t._spiderLeg,s=n._path,r=s.getTotalLength()+.1,s.style.strokeDashoffset=r,n.setStyle({opacity:0})));h._ignoreMove=!1,setTimeout(function(){var e=0;for(i=d.length-1;i>=0;i--)t=d[i],t._spiderLeg&&e++;for(i=d.length-1;i>=0;i--)t=d[i],t._spiderLeg&&(t.clusterShow&&t.clusterShow(),t.setZIndexOffset&&t.setZIndexOffset(0),e>1&&l.removeLayer(t),u.removeLayer(t._spiderLeg),delete t._spiderLeg);h._animationEnd(),h.fire("unspiderfied",{cluster:a,markers:d})},200)}}),L.MarkerClusterGroup.include({_spiderfied:null,unspiderfy:function(){this._unspiderfy.apply(this,arguments)},_spiderfierOnAdd:function(){this._map.on("click",this._unspiderfyWrapper,this),this._map.options.zoomAnimation&&this._map.on("zoomstart",this._unspiderfyZoomStart,this),this._map.on("zoomend",this._noanimationUnspiderfy,this),L.Browser.touch||this._map.getRenderer(this)},_spiderfierOnRemove:function(){this._map.off("click",this._unspiderfyWrapper,this),this._map.off("zoomstart",this._unspiderfyZoomStart,this),this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._map.off("zoomend",this._noanimationUnspiderfy,this),this._noanimationUnspiderfy()},_unspiderfyZoomStart:function(){this._map&&this._map.on("zoomanim",this._unspiderfyZoomAnim,this)},_unspiderfyZoomAnim:function(e){L.DomUtil.hasClass(this._map._mapPane,"leaflet-touching")||(this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._unspiderfy(e))},_unspiderfyWrapper:function(){this._unspiderfy()},_unspiderfy:function(e){this._spiderfied&&this._spiderfied.unspiderfy(e)},_noanimationUnspiderfy:function(){this._spiderfied&&this._spiderfied._noanimationUnspiderfy()},_unspiderfyLayer:function(e){e._spiderLeg&&(this._featureGroup.removeLayer(e),e.clusterShow&&e.clusterShow(),e.setZIndexOffset&&e.setZIndexOffset(0),this._map.removeLayer(e._spiderLeg),delete e._spiderLeg)}}),L.MarkerClusterGroup.include({refreshClusters:function(e){return e?e instanceof L.MarkerClusterGroup?e=e._topClusterLevel.getAllChildMarkers():e instanceof L.LayerGroup?e=e._layers:e instanceof L.MarkerCluster?e=e.getAllChildMarkers():e instanceof L.Marker&&(e=[e]):e=this._topClusterLevel.getAllChildMarkers(),this._flagParentsIconsNeedUpdate(e),this._refreshClustersIcons(),this.options.singleMarkerMode&&this._refreshSingleMarkerModeMarkers(e),this},_flagParentsIconsNeedUpdate:function(e){var t,i;for(t in e)for(i=e[t].__parent;i;)i._iconNeedsUpdate=!0,i=i.__parent},_refreshClustersIcons:function(){this._featureGroup.eachLayer(function(e){e instanceof L.MarkerCluster&&e._iconNeedsUpdate&&e._updateIcon()})},_refreshSingleMarkerModeMarkers:function(e){var t,i;for(t in e)i=e[t],this.hasLayer(i)&&i.setIcon(this._overrideMarkerIcon(i))}}),L.Marker.include({refreshIconOptions:function(e,t){var i=this.options.icon;return L.setOptions(i,e),this.setIcon(i),t&&this.__parent&&this.__parent._group.refreshClusters(this),this}})}(window,document); \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet/images/layers-2x.png b/includes/services/Leaflet/leaflet/images/layers-2x.png new file mode 100644 index 000000000..200c333dc Binary files /dev/null and b/includes/services/Leaflet/leaflet/images/layers-2x.png differ diff --git a/includes/services/Leaflet/leaflet/images/layers.png b/includes/services/Leaflet/leaflet/images/layers.png index d25f9c70e..1a72e5784 100644 Binary files a/includes/services/Leaflet/leaflet/images/layers.png and b/includes/services/Leaflet/leaflet/images/layers.png differ diff --git a/includes/services/Leaflet/leaflet/images/marker-icon-2x.png b/includes/services/Leaflet/leaflet/images/marker-icon-2x.png new file mode 100644 index 000000000..e4abba3b5 Binary files /dev/null and b/includes/services/Leaflet/leaflet/images/marker-icon-2x.png differ diff --git a/includes/services/Leaflet/leaflet/images/marker-icon.png b/includes/services/Leaflet/leaflet/images/marker-icon.png index 1a5cde674..950edf246 100644 Binary files a/includes/services/Leaflet/leaflet/images/marker-icon.png and b/includes/services/Leaflet/leaflet/images/marker-icon.png differ diff --git a/includes/services/Leaflet/leaflet/images/marker-shadow.png b/includes/services/Leaflet/leaflet/images/marker-shadow.png index 86a382bca..9fd297953 100644 Binary files a/includes/services/Leaflet/leaflet/images/marker-shadow.png and b/includes/services/Leaflet/leaflet/images/marker-shadow.png differ diff --git a/includes/services/Leaflet/leaflet/images/zoom-in.png b/includes/services/Leaflet/leaflet/images/zoom-in.png deleted file mode 100644 index f165c2e90..000000000 Binary files a/includes/services/Leaflet/leaflet/images/zoom-in.png and /dev/null differ diff --git a/includes/services/Leaflet/leaflet/images/zoom-out.png b/includes/services/Leaflet/leaflet/images/zoom-out.png deleted file mode 100644 index 94bfc4221..000000000 Binary files a/includes/services/Leaflet/leaflet/images/zoom-out.png and /dev/null differ diff --git a/includes/services/Leaflet/leaflet/leaflet.css b/includes/services/Leaflet/leaflet/leaflet.css index c76c54a68..c6d920a0b 100644 --- a/includes/services/Leaflet/leaflet/leaflet.css +++ b/includes/services/Leaflet/leaflet/leaflet.css @@ -1,75 +1,113 @@ /* required styles */ -.leaflet-map-pane, +.leaflet-pane, .leaflet-tile, .leaflet-marker-icon, .leaflet-marker-shadow, -.leaflet-tile-pane, -.leaflet-overlay-pane, -.leaflet-shadow-pane, -.leaflet-marker-pane, -.leaflet-popup-pane, -.leaflet-overlay-pane svg, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, .leaflet-zoom-box, .leaflet-image-layer, -.leaflet-layer { /* TODO optimize classes */ +.leaflet-layer { position: absolute; + left: 0; + top: 0; } .leaflet-container { overflow: hidden; - outline: 0; } .leaflet-tile, .leaflet-marker-icon, .leaflet-marker-shadow { - -moz-user-select: none; -webkit-user-select: none; - user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; } .leaflet-marker-icon, .leaflet-marker-shadow { display: block; } -.leaflet-clickable { - cursor: pointer; - } -.leaflet-dragging, .leaflet-dragging .leaflet-clickable { - cursor: move; - } -.leaflet-container img { - /* map is broken in FF if you have max-width: 100% on tiles */ +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg, +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer { max-width: none !important; } -.leaflet-container img.leaflet-image-layer { - /* stupid Android 2 doesn't understand "max-width: none" properly */ - max-width: 15000px !important; - } - -.leaflet-tile-pane { z-index: 2; } -.leaflet-objects-pane { z-index: 3; } -.leaflet-overlay-pane { z-index: 4; } -.leaflet-shadow-pane { z-index: 5; } -.leaflet-marker-pane { z-index: 6; } -.leaflet-popup-pane { z-index: 7; } +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + } +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} .leaflet-tile { - filter: inherit; - visibility: hidden; + filter: inherit; + visibility: hidden; } .leaflet-tile-loaded { visibility: inherit; } - .leaflet-zoom-box { - width: 0; - height: 0; - } + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } -/* Leaflet controls */ + +/* control positioning */ .leaflet-control { position: relative; - z-index: 7; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ pointer-events: auto; } .leaflet-top, @@ -110,58 +148,199 @@ margin-right: 10px; } -.leaflet-control-zoom { - -moz-border-radius: 7px; - -webkit-border-radius: 7px; - border-radius: 7px; + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-tile { + will-change: opacity; + } +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; } -.leaflet-control-zoom { - padding: 5px; - background: rgba(0, 0, 0, 0.25); +.leaflet-zoom-anim .leaflet-zoom-animated { + will-change: transform; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); } -.leaflet-control-zoom a { - background-color: rgba(255, 255, 255, 0.75); +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; } -.leaflet-control-zoom a, .leaflet-control-layers a { +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline: 0; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-container a.leaflet-active { + outline: 2px solid orange; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a, +.leaflet-bar a:hover { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { background-position: 50% 50%; background-repeat: no-repeat; display: block; } -.leaflet-control-zoom a { - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - border-radius: 4px; - width: 19px; - height: 19px; +.leaflet-bar a:hover { + background-color: #f4f4f4; } -.leaflet-control-zoom a:hover { - background-color: #fff; +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; } -.leaflet-touch .leaflet-control-zoom a { - width: 27px; - height: 27px; +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; } -.leaflet-control-zoom-in { - background-image: url(images/zoom-in.png); - margin-bottom: 5px; + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; } + + +/* zoom control */ + +.leaflet-control-zoom-in, .leaflet-control-zoom-out { - background-image: url(images/zoom-out.png); + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } +.leaflet-control-zoom-out { + font-size: 20px; } +.leaflet-touch .leaflet-control-zoom-in { + font-size: 22px; + } +.leaflet-touch .leaflet-control-zoom-out { + font-size: 24px; + } + + +/* layers control */ + .leaflet-control-layers { - box-shadow: 0 1px 7px #999; - background: #f8f8f9; - -moz-border-radius: 8px; - -webkit-border-radius: 8px; - border-radius: 8px; + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; } -.leaflet-control-layers a { +.leaflet-control-layers-toggle { background-image: url(images/layers.png); width: 36px; height: 36px; } -.leaflet-touch .leaflet-control-layers a { +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { width: 44px; height: 44px; } @@ -175,11 +354,14 @@ } .leaflet-control-layers-expanded { padding: 6px 10px 6px 6px; - font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; color: #333; background: #fff; } -.leaflet-control-layers input { +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + padding-right: 5px; + } +.leaflet-control-layers-selector { margin-top: 2px; position: relative; top: 1px; @@ -193,43 +375,56 @@ margin: 5px -10px 5px -6px; } +/* Default icon URLs */ +.leaflet-default-icon-path { + background-image: url(images/marker-icon.png); + } + + +/* attribution and scale controls */ + .leaflet-container .leaflet-control-attribution { - background-color: rgba(255, 255, 255, 0.7); - box-shadow: 0 0 5px #bbb; + background: #fff; + background: rgba(255, 255, 255, 0.7); margin: 0; - } - + } .leaflet-control-attribution, .leaflet-control-scale-line { padding: 0 5px; color: #333; } - +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover { + text-decoration: underline; + } .leaflet-container .leaflet-control-attribution, .leaflet-container .leaflet-control-scale { - font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + font-size: 11px; } - .leaflet-left .leaflet-control-scale { margin-left: 5px; } .leaflet-bottom .leaflet-control-scale { margin-bottom: 5px; } - .leaflet-control-scale-line { border: 2px solid #777; border-top: none; - color: black; - line-height: 1; - font-size: 10px; - padding-bottom: 2px; - text-shadow: 1px 1px 1px #fff; - background-color: rgba(255, 255, 255, 0.5); + line-height: 1.1; + padding: 2px 5px 1px; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + -moz-box-sizing: border-box; + box-sizing: border-box; + + background: #fff; + background: rgba(255, 255, 255, 0.5); } .leaflet-control-scale-line:not(:first-child) { border-top: 2px solid #777; - padding-top: 1px; border-bottom: none; margin-top: -2px; } @@ -237,87 +432,71 @@ border-bottom: 2px solid #777; } -.leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-layers { +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { box-shadow: none; } -.leaflet-touch .leaflet-control-layers { - border: 5px solid #bbb; +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; } -/* Zoom and fade animations */ - -.leaflet-fade-anim .leaflet-tile, .leaflet-fade-anim .leaflet-popup { - opacity: 0; - - -webkit-transition: opacity 0.2s linear; - -moz-transition: opacity 0.2s linear; - -o-transition: opacity 0.2s linear; - transition: opacity 0.2s linear; - } -.leaflet-fade-anim .leaflet-tile-loaded, .leaflet-fade-anim .leaflet-map-pane .leaflet-popup { - opacity: 1; - } - -.leaflet-zoom-anim .leaflet-zoom-animated { - -webkit-transition: -webkit-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); - -moz-transition: -moz-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); - -o-transition: -o-transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); - transition: transform 0.25s cubic-bezier(0.25,0.1,0.25,0.75); - } - -.leaflet-zoom-anim .leaflet-tile, -.leaflet-pan-anim .leaflet-tile, -.leaflet-touching .leaflet-zoom-animated { - -webkit-transition: none; - -moz-transition: none; - -o-transition: none; - transition: none; - } - -.leaflet-zoom-anim .leaflet-zoom-hide { - visibility: hidden; - } - - -/* Popup layout */ +/* popup */ .leaflet-popup { position: absolute; text-align: center; + margin-bottom: 20px; } .leaflet-popup-content-wrapper { padding: 1px; text-align: left; + border-radius: 12px; } .leaflet-popup-content { - margin: 14px 20px; + margin: 13px 19px; + line-height: 1.4; + } +.leaflet-popup-content p { + margin: 18px 0; } .leaflet-popup-tip-container { - margin: 0 auto; width: 40px; height: 20px; - position: relative; + position: absolute; + left: 50%; + margin-left: -20px; overflow: hidden; + pointer-events: none; } .leaflet-popup-tip { - width: 15px; - height: 15px; + width: 17px; + height: 17px; padding: 1px; - margin: -8px auto 0; + margin: -10px auto 0; - -moz-transform: rotate(45deg); -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); } .leaflet-container a.leaflet-popup-close-button { position: absolute; top: 0; right: 0; - padding: 4px 5px 0 0; + padding: 4px 4px 0 0; + border: none; text-align: center; width: 18px; height: 14px; @@ -325,55 +504,121 @@ color: #c3c3c3; text-decoration: none; font-weight: bold; + background: transparent; } .leaflet-container a.leaflet-popup-close-button:hover { color: #999; } -.leaflet-popup-content p { - margin: 18px 0; - } .leaflet-popup-scrolled { overflow: auto; border-bottom: 1px solid #ddd; border-top: 1px solid #ddd; } +.leaflet-oldie .leaflet-popup-content-wrapper { + zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; -/* Visual appearance */ - -.leaflet-container { - background: #ddd; + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); } -.leaflet-container a { - color: #0078A8; +.leaflet-oldie .leaflet-popup-tip-container { + margin-top: -1px; } -.leaflet-container a.leaflet-active { - outline: 2px solid orange; - } -.leaflet-zoom-box { - border: 2px dotted #05f; - background: white; - opacity: 0.5; + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; } + + +/* div icon */ + .leaflet-div-icon { - background: #fff; - border: 1px solid #666; - } -.leaflet-editing-icon { - border-radius: 2px; - } -.leaflet-popup-content-wrapper, .leaflet-popup-tip { - background: white; + background: #fff; + border: 1px solid #666; + } + - box-shadow: 0 3px 10px #888; - -moz-box-shadow: 0 3px 10px #888; - -webkit-box-shadow: 0 3px 14px #999; +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); } -.leaflet-popup-content-wrapper { - -moz-border-radius: 20px; - -webkit-border-radius: 20px; - border-radius: 20px; +.leaflet-tooltip.leaflet-clickable { + cursor: pointer; + pointer-events: auto; } -.leaflet-popup-content { - font: 12px/1.4 "Helvetica Neue", Arial, Helvetica, sans-serif; +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; } diff --git a/includes/services/Leaflet/leaflet/leaflet.ie.css b/includes/services/Leaflet/leaflet/leaflet.ie.css deleted file mode 100644 index 9d2a52fba..000000000 --- a/includes/services/Leaflet/leaflet/leaflet.ie.css +++ /dev/null @@ -1,44 +0,0 @@ -.leaflet-vml-shape { - width: 1px; - height: 1px; - } -.lvml { - behavior: url(#default#VML); - display: inline-block; - position: absolute; - } - -.leaflet-control { - display: inline; - } - -.leaflet-popup-tip { - width: 21px; - _width: 27px; - margin: 0 auto; - _margin-top: -3px; - - filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); - -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; - } -.leaflet-popup-tip-container { - margin-top: -1px; - } -.leaflet-popup-content-wrapper, .leaflet-popup-tip { - border: 1px solid #bbb; - } - -.leaflet-control-zoom { - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#3F000000',EndColorStr='#3F000000'); - } -.leaflet-control-zoom a { - background-color: #eee; - } -.leaflet-control-zoom a:hover { - background-color: #fff; - } -.leaflet-control-layers-toggle { - } -.leaflet-control-attribution, .leaflet-control-layers { - background: white; - } \ No newline at end of file diff --git a/includes/services/Leaflet/leaflet/leaflet.js b/includes/services/Leaflet/leaflet/leaflet.js index b24900b06..24042d125 100644 --- a/includes/services/Leaflet/leaflet/leaflet.js +++ b/includes/services/Leaflet/leaflet/leaflet.js @@ -1,6 +1,9 @@ /* - Copyright (c) 2010-2012, CloudMade, Vladimir Agafonkin - Leaflet is an open-source JavaScript library for mobile-friendly interactive maps. - http://leaflet.cloudmade.com + Leaflet 1.0.3+ed36a04, a JS library for interactive maps. http://leafletjs.com + (c) 2010-2016 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ -(function(e,t){var n,r;typeof exports!=t+""?n=exports:(r=e.L,n={},n.noConflict=function(){return e.L=r,this},e.L=n),n.version="0.4.5",n.Util={extend:function(e){var t=Array.prototype.slice.call(arguments,1);for(var n=0,r=t.length,i;n2?Array.prototype.slice.call(arguments,2):null;return function(){return e.apply(t,n||arguments)}},stamp:function(){var e=0,t="_leaflet_id";return function(n){return n[t]=n[t]||++e,n[t]}}(),limitExecByInterval:function(e,t,n){var r,i;return function s(){var o=arguments;if(r){i=!0;return}r=!0,setTimeout(function(){r=!1,i&&(s.apply(n,o),i=!1)},t),e.apply(n,o)}},falseFn:function(){return!1},formatNum:function(e,t){var n=Math.pow(10,t||5);return Math.round(e*n)/n},splitWords:function(e){return e.replace(/^\s+|\s+$/g,"").split(/\s+/)},setOptions:function(e,t){return e.options=n.Util.extend({},e.options,t),e.options},getParamString:function(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n+"="+e[n]);return"?"+t.join("&")},template:function(e,t){return e.replace(/\{ *([\w_]+) *\}/g,function(e,n){var r=t[n];if(!t.hasOwnProperty(n))throw Error("No value provided for variable "+e);return r})},emptyImageUrl:"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="},function(){function t(t){var n,r,i=["webkit","moz","o","ms"];for(n=0;n0},removeEventListener:function(e,t,r){var s=this[i],o,u,a,f,l;if(typeof e=="object"){for(o in e)e.hasOwnProperty(o)&&this.removeEventListener(o,e[o],t);return this}e=n.Util.splitWords(e);for(u=0,a=e.length;u=0;l--)(!t||f[l].action===t)&&(!r||f[l].context===r)&&f.splice(l,1)}return this},fireEvent:function(e,t){if(!this.hasEventListeners(e))return this;var r=n.Util.extend({type:e,target:this},t),s=this[i][e].slice();for(var o=0,u=s.length;o1||"matchMedia"in e&&e.matchMedia("(min-resolution:144dpi)").matches;n.Browser={ua:r,ie:i,ie6:s,webkit:o,gecko:u,opera:f,android:l,android23:c,chrome:a,ie3d:d,webkit3d:v,gecko3d:m,opera3d:g,any3d:!e.L_DISABLE_3D&&(d||v||m||g),mobile:h,mobileWebkit:h&&o,mobileWebkit3d:h&&v,mobileOpera:h&&f,touch:y,retina:b}}(),n.Point=function(e,t,n){this.x=n?Math.round(e):e,this.y=n?Math.round(t):t},n.Point.prototype={add:function(e){return this.clone()._add(n.point(e))},_add:function(e){return this.x+=e.x,this.y+=e.y,this},subtract:function(e){return this.clone()._subtract(n.point(e))},_subtract:function(e){return this.x-=e.x,this.y-=e.y,this},divideBy:function(e,t){return new n.Point(this.x/e,this.y/e,t)},multiplyBy:function(e,t){return new n.Point(this.x*e,this.y*e,t)},distanceTo:function(e){e=n.point(e);var t=e.x-this.x,r=e.y-this.y;return Math.sqrt(t*t+r*r)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},clone:function(){return new n.Point(this.x,this.y)},toString:function(){return"Point("+n.Util.formatNum(this.x)+", "+n.Util.formatNum(this.y)+")"}},n.point=function(e,t,r){return e instanceof n.Point?e:e instanceof Array?new n.Point(e[0],e[1]):isNaN(e)?e:new n.Point(e,t,r)},n.Bounds=n.Class.extend({initialize:function(e,t){if(!e)return;var n=t?[e,t]:e;for(var r=0,i=n.length;r=this.min.x&&r.x<=this.max.x&&t.y>=this.min.y&&r.y<=this.max.y},intersects:function(e){e=n.bounds(e);var t=this.min,r=this.max,i=e.min,s=e.max,o=s.x>=t.x&&i.x<=r.x,u=s.y>=t.y&&i.y<=r.y;return o&&u}}),n.bounds=function(e,t){return!e||e instanceof n.Bounds?e:new n.Bounds(e,t)},n.Transformation=n.Class.extend({initialize:function(e,t,n,r){this._a=e,this._b=t,this._c=n,this._d=r},transform:function(e,t){return this._transform(e.clone(),t)},_transform:function(e,t){return t=t||1,e.x=t*(this._a*e.x+this._b),e.y=t*(this._c*e.y+this._d),e},untransform:function(e,t){return t=t||1,new n.Point((e.x/t-this._b)/this._a,(e.y/t-this._d)/this._c)}}),n.DomUtil={get:function(e){return typeof e=="string"?document.getElementById(e):e},getStyle:function(e,t){var n=e.style[t];!n&&e.currentStyle&&(n=e.currentStyle[t]);if(!n||n==="auto"){var r=document.defaultView.getComputedStyle(e,null);n=r?r[t]:null}return n==="auto"?null:n},getViewportOffset:function(e){var t=0,r=0,i=e,s=document.body;do{t+=i.offsetTop||0,r+=i.offsetLeft||0;if(i.offsetParent===s&&n.DomUtil.getStyle(i,"position")==="absolute")break;if(n.DomUtil.getStyle(i,"position")==="fixed"){t+=s.scrollTop||0,r+=s.scrollLeft||0;break}i=i.offsetParent}while(i);i=e;do{if(i===s)break;t-=i.scrollTop||0,r-=i.scrollLeft||0,i=i.parentNode}while(i);return new n.Point(r,t)},create:function(e,t,n){var r=document.createElement(e);return r.className=t,n&&n.appendChild(r),r},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty(),this._onselectstart||(this._onselectstart=document.onselectstart,document.onselectstart=n.Util.falseFn)},enableTextSelection:function(){document.onselectstart=this._onselectstart,this._onselectstart=null},hasClass:function(e,t){return e.className.length>0&&RegExp("(^|\\s)"+t+"(\\s|$)").test(e.className)},addClass:function(e,t){n.DomUtil.hasClass(e,t)||(e.className+=(e.className?" ":"")+t)},removeClass:function(e,t){function n(e,n){return n===t?"":e}e.className=e.className.replace(/(\S+)\s*/g,n).replace(/(^\s+|\s+$)/,"")},setOpacity:function(e,t){if("opacity"in e.style)e.style.opacity=t;else if(n.Browser.ie){var r=!1,i="DXImageTransform.Microsoft.Alpha";try{r=e.filters.item(i)}catch(s){}t=Math.round(t*100),r?(r.Enabled=t!==100,r.Opacity=t):e.style.filter+=" progid:"+i+"(opacity="+t+")"}},testProp:function(e){var t=document.documentElement.style;for(var n=0;n=t.lat&&s.lat<=r.lat&&i.lng>=t.lng&&s.lng<=r.lng},intersects:function(e){e=n.latLngBounds(e);var t=this._southWest,r=this._northEast,i=e.getSouthWest(),s=e.getNorthEast(),o=s.lat>=t.lat&&i.lat<=r.lat,u=s.lng>=t.lng&&i.lng<=r.lng;return o&&u},toBBoxString:function(){var e=this._southWest,t=this._northEast;return[e.lng,e.lat,t.lng,t.lat].join(",")},equals:function(e){return e?(e=n.latLngBounds(e),this._southWest.equals(e.getSouthWest())&&this._northEast.equals(e.getNorthEast())):!1}}),n.latLngBounds=function(e,t){return!e||e instanceof n.LatLngBounds?e:new n.LatLngBounds(e,t)},n.Projection={},n.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(e){var t=n.LatLng.DEG_TO_RAD,r=this.MAX_LATITUDE,i=Math.max(Math.min(r,e.lat),-r),s=e.lng*t,o=i*t;return o=Math.log(Math.tan(Math.PI/4+o/2)),new n.Point(s,o)},unproject:function(e){var t=n.LatLng.RAD_TO_DEG,r=e.x*t,i=(2*Math.atan(Math.exp(e.y))-Math.PI/2)*t;return new n.LatLng(i,r,!0)}},n.Projection.LonLat={project:function(e){return new n.Point(e.lng,e.lat)},unproject:function(e){return new n.LatLng(e.y,e.x,!0)}},n.CRS={latLngToPoint:function(e,t){var n=this.projection.project(e),r=this.scale(t);return this.transformation._transform(n,r)},pointToLatLng:function(e,t){var n=this.scale(t),r=this.transformation.untransform(e,n);return this.projection.unproject(r)},project:function(e){return this.projection.project(e)},scale:function(e){return 256*Math.pow(2,e)}},n.CRS.EPSG3857=n.Util.extend({},n.CRS,{code:"EPSG:3857",projection:n.Projection.SphericalMercator,transformation:new n.Transformation(.5/Math.PI,.5,-0.5/Math.PI,.5),project:function(e){var t=this.projection.project(e),n=6378137;return t.multiplyBy(n)}}),n.CRS.EPSG900913=n.Util.extend({},n.CRS.EPSG3857,{code:"EPSG:900913"}),n.CRS.EPSG4326=n.Util.extend({},n.CRS,{code:"EPSG:4326",projection:n.Projection.LonLat,transformation:new n.Transformation(1/360,.5,-1/360,.5)}),n.Map=n.Class.extend({includes:n.Mixin.Events,options:{crs:n.CRS.EPSG3857,fadeAnimation:n.DomUtil.TRANSITION&&!n.Browser.android23,trackResize:!0,markerZoomAnimation:n.DomUtil.TRANSITION&&n.Browser.any3d},initialize:function(e,r){r=n.Util.setOptions(this,r),this._initContainer(e),this._initLayout(),this._initHooks(),this._initEvents(),r.maxBounds&&this.setMaxBounds(r.maxBounds),r.center&&r.zoom!==t&&this.setView(n.latLng(r.center),r.zoom,!0),this._initLayers(r.layers)},setView:function(e,t){return this._resetView(n.latLng(e),this._limitZoom(t)),this},setZoom:function(e){return this.setView(this.getCenter(),e)},zoomIn:function(){return this.setZoom(this._zoom+1)},zoomOut:function(){return this.setZoom(this._zoom-1)},fitBounds:function(e){var t=this.getBoundsZoom(e);return this.setView(n.latLngBounds(e).getCenter(),t)},fitWorld:function(){var e=new n.LatLng(-60,-170),t=new n.LatLng(85,179);return this.fitBounds(new n.LatLngBounds(e,t))},panTo:function(e){return this.setView(e,this._zoom)},panBy:function(e){return this.fire("movestart"),this._rawPanBy(n.point(e)),this.fire("move"),this.fire("moveend")},setMaxBounds:function(e){e=n.latLngBounds(e),this.options.maxBounds=e;if(!e)return this._boundsMinZoom=null,this;var t=this.getBoundsZoom(e,!0);return this._boundsMinZoom=t,this._loaded&&(this._zoomo.x&&(u=o.x-i.x),r.y>s.y&&(a=s.y-r.y),r.xc&&--h>0)d=u*Math.sin(f),p=Math.PI/2-2*Math.atan(a*Math.pow((1-d)/(1+d),.5*u))-f,f+=p;return new n.LatLng(f*t,s,!0)}},n.CRS.EPSG3395=n.Util.extend({},n.CRS,{code:"EPSG:3395",projection:n.Projection.Mercator,transformation:function(){var e=n.Projection.Mercator,t=e.R_MAJOR,r=e.R_MINOR;return new n.Transformation(.5/(Math.PI*t),.5,-0.5/(Math.PI*r),.5)}()}),n.TileLayer=n.Class.extend({includes:n.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",zoomOffset:0,opacity:1,unloadInvisibleTiles:n.Browser.mobile,updateWhenIdle:n.Browser.mobile},initialize:function(e,t){t=n.Util.setOptions(this,t),t.detectRetina&&n.Browser.retina&&t.maxZoom>0&&(t.tileSize=Math.floor(t.tileSize/2),t.zoomOffset++,t.minZoom>0&&t.minZoom--,this.options.maxZoom--),this._url=e;var r=this.options.subdomains;typeof r=="string"&&(this.options.subdomains=r.split(""))},onAdd:function(e){this._map=e,this._initContainer(),this._createTileProto(),e.on({viewreset:this._resetCallback,moveend:this._update},this),this.options.updateWhenIdle||(this._limitedUpdate=n.Util.limitExecByInterval(this._update,150,this),e.on("move",this._limitedUpdate,this)),this._reset(),this._update()},addTo:function(e){return e.addLayer(this),this},onRemove:function(e){e._panes.tilePane.removeChild(this._container),e.off({viewreset:this._resetCallback,moveend:this._update},this),this.options.updateWhenIdle||e.off("move",this._limitedUpdate,this),this._container=null,this._map=null},bringToFront:function(){var e=this._map._panes.tilePane;return this._container&&(e.appendChild(this._container),this._setAutoZIndex(e,Math.max)),this},bringToBack:function(){var e=this._map._panes.tilePane;return this._container&&(e.insertBefore(this._container,e.firstChild),this._setAutoZIndex(e,Math.min)),this},getAttribution:function(){return this.options.attribution},setOpacity:function(e){return this.options.opacity=e,this._map&&this._updateOpacity(),this},setZIndex:function(e){return this.options.zIndex=e,this._updateZIndex(),this},setUrl:function(e,t){return this._url=e,t||this.redraw(),this},redraw:function(){return this._map&&(this._map._panes.tilePane.empty=!1,this._reset(!0),this._update()),this},_updateZIndex:function(){this._container&&this.options.zIndex!==t&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(e,t){var n=e.getElementsByClassName("leaflet-layer"),r=-t(Infinity,-Infinity),i;for(var s=0,o=n.length;sthis.options.maxZoom||r=t)||e.y<0||e.y>=t)return!1}return!0},_removeOtherTiles:function(e){var t,n,r,i;for(i in this._tiles)this._tiles.hasOwnProperty(i)&&(t=i.split(":"),n=parseInt(t[0],10),r=parseInt(t[1],10),(ne.max.x||re.max.y)&&this._removeTile(i))},_removeTile:function(e){var t=this._tiles[e];this.fire("tileunload",{tile:t,url:t.src}),this.options.reuseTiles?(n.DomUtil.removeClass(t,"leaflet-tile-loaded"),this._unusedTiles.push(t)):t.parentNode===this._container&&this._container.removeChild(t),n.Browser.android||(t.src=n.Util.emptyImageUrl),delete this._tiles[e]},_addTile:function(e,t){var r=this._getTilePos(e),i=this._getTile();n.DomUtil.setPosition(i,r,n.Browser.chrome||n.Browser.android23),this._tiles[e.x+":"+e.y]=i,this._loadTile(i,e),i.parentNode!==this._container&&t.appendChild(i)},_getZoomForUrl:function(){var e=this.options,t=this._map.getZoom();return e.zoomReverse&&(t=e.maxZoom-t),t+e.zoomOffset},_getTilePos:function(e){var t=this._map.getPixelOrigin(),n=this.options.tileSize;return e.multiplyBy(n).subtract(t)},getTileUrl:function(e){return this._adjustTilePoint(e),n.Util.template(this._url,n.Util.extend({s:this._getSubdomain(e),z:this._getZoomForUrl(),x:e.x,y:e.y},this.options))},_getWrapTileNum:function(){return Math.pow(2,this._getZoomForUrl())},_adjustTilePoint:function(e){var t=this._getWrapTileNum();!this.options.continuousWorld&&!this.options.noWrap&&(e.x=(e.x%t+t)%t),this.options.tms&&(e.y=t-e.y-1)},_getSubdomain:function(e){var t=(e.x+e.y)%this.options.subdomains.length;return this.options.subdomains[t]},_createTileProto:function(){var e=this._tileImg=n.DomUtil.create("img","leaflet-tile");e.galleryimg="no";var t=this.options.tileSize;e.style.width=t+"px",e.style.height=t+"px"},_getTile:function(){if(this.options.reuseTiles&&this._unusedTiles.length>0){var e=this._unusedTiles.pop();return this._resetTile(e),e}return this._createTile()},_resetTile:function(e){},_createTile:function(){var e=this._tileImg.cloneNode(!1);return e.onselectstart=e.onmousemove=n.Util.falseFn,e},_loadTile:function(e,t){e._layer=this,e.onload=this._tileOnLoad,e.onerror=this._tileOnError,e.src=this.getTileUrl(t)},_tileLoaded:function(){this._tilesToLoad--,this._tilesToLoad||this.fire("load")},_tileOnLoad:function(e){var t=this._layer;this.src!==n.Util.emptyImageUrl&&(n.DomUtil.addClass(this,"leaflet-tile-loaded"),t.fire("tileload",{tile:this,url:this.src})),t._tileLoaded()},_tileOnError:function(e){var t=this._layer;t.fire("tileerror",{tile:this,url:this.src});var n=t.options.errorTileUrl;n&&(this.src=n),t._tileLoaded()}}),n.tileLayer=function(e,t){return new n.TileLayer(e,t)},n.TileLayer.WMS=n.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(e,t){this._url=e;var r=n.Util.extend({},this.defaultWmsParams);t.detectRetina&&n.Browser.retina?r.width=r.height=this.options.tileSize*2:r.width=r.height=this.options.tileSize;for(var i in t)this.options.hasOwnProperty(i)||(r[i]=t[i]);this.wmsParams=r,n.Util.setOptions(this,t)},onAdd:function(e){var t=parseFloat(this.wmsParams.version)>=1.3?"crs":"srs";this.wmsParams[t]=e.options.crs.code,n.TileLayer.prototype.onAdd.call(this,e)},getTileUrl:function(e,t){var r=this._map,i=r.options.crs,s=this.options.tileSize,o=e.multiplyBy(s),u=o.add(new n.Point(s,s)),a=i.project(r.unproject(o,t)),f=i.project(r.unproject(u,t)),l=[a.x,f.y,f.x,a.y].join(","),c=n.Util.template(this._url,{s:this._getSubdomain(e)});return c+n.Util.getParamString(this.wmsParams)+"&bbox="+l},setParams:function(e,t){return n.Util.extend(this.wmsParams,e),t||this.redraw(),this}}),n.tileLayer.wms=function(e,t){return new n.TileLayer.WMS(e,t)},n.TileLayer.Canvas=n.TileLayer.extend({options:{async:!1},initialize:function(e){n.Util.setOptions(this,e)},redraw:function(){var e,t=this._tiles;for(e in t)t.hasOwnProperty(e)&&this._redrawTile(t[e])},_redrawTile:function(e){this.drawTile(e,e._tilePoint,e._zoom)},_createTileProto:function(){var e=this._canvasProto=n.DomUtil.create("canvas","leaflet-tile"),t=this.options.tileSize;e.width=t,e.height=t},_createTile:function(){var e=this._canvasProto.cloneNode(!1);return e.onselectstart=e.onmousemove=n.Util.falseFn,e},_loadTile:function(e,t,n){e._layer=this,e._tilePoint=t,e._zoom=n,this.drawTile(e,t,n),this.options.async||this.tileDrawn(e)},drawTile:function(e,t,n){},tileDrawn:function(e){this._tileOnLoad.call(e)}}),n.tileLayer.canvas=function(e){return new n.TileLayer.Canvas(e)},n.ImageOverlay=n.Class.extend({includes:n.Mixin.Events,options:{opacity:1},initialize:function(e,t,r){this._url=e,this._bounds=n.latLngBounds(t),n.Util.setOptions(this,r)},onAdd:function(e){this._map=e,this._image||this._initImage(),e._panes.overlayPane.appendChild(this._image),e.on("viewreset",this._reset,this),e.options.zoomAnimation&&n.Browser.any3d&&e.on("zoomanim",this._animateZoom,this),this._reset()},onRemove:function(e){e.getPanes().overlayPane.removeChild(this._image),e.off("viewreset",this._reset,this),e.options.zoomAnimation&&e.off("zoomanim",this._animateZoom,this)},addTo:function(e){return e.addLayer(this),this},setOpacity:function(e){return this.options.opacity=e,this._updateOpacity(),this},bringToFront:function(){return this._image&&this._map._panes.overlayPane.appendChild(this._image),this},bringToBack:function(){var e=this._map._panes.overlayPane;return this._image&&e.insertBefore(this._image,e.firstChild),this},_initImage:function(){this._image=n.DomUtil.create("img","leaflet-image-layer"),this._map.options.zoomAnimation&&n.Browser.any3d?n.DomUtil.addClass(this._image,"leaflet-zoom-animated"):n.DomUtil.addClass(this._image,"leaflet-zoom-hide"),this._updateOpacity(),n.Util.extend(this._image,{galleryimg:"no",onselectstart:n.Util.falseFn,onmousemove:n.Util.falseFn,onload:n.Util.bind(this._onImageLoad,this),src:this._url})},_animateZoom:function(e){var t=this._map,r=this._image,i=t.getZoomScale(e.zoom),s=this._bounds.getNorthWest(),o=this._bounds.getSouthEast(),u=t._latLngToNewLayerPoint(s,e.zoom,e.center),a=t._latLngToNewLayerPoint(o,e.zoom,e.center).subtract(u),f=t.latLngToLayerPoint(o).subtract(t.latLngToLayerPoint(s)),l=u.add(a.subtract(f).divideBy(2));r.style[n.DomUtil.TRANSFORM]=n.DomUtil.getTranslateString(l)+" scale("+i+") "},_reset:function(){var e=this._image,t=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),r=this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(t);n.DomUtil.setPosition(e,t),e.style.width=r.x+"px",e.style.height=r.y+"px"},_onImageLoad:function(){this.fire("load")},_updateOpacity:function(){n.DomUtil.setOpacity(this._image,this.options.opacity)}}),n.imageOverlay=function(e,t,r){return new n.ImageOverlay(e,t,r)},n.Icon=n.Class.extend({options:{className:""},initialize:function(e){n.Util.setOptions(this,e)},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(e){var t=this._getIconUrl(e);if(!t){if(e==="icon")throw Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(t);return this._setIconStyles(n,e),n},_setIconStyles:function(e,t){var r=this.options,i=n.point(r[t+"Size"]),s;t==="shadow"?s=n.point(r.shadowAnchor||r.iconAnchor):s=n.point(r.iconAnchor),!s&&i&&(s=i.divideBy(2,!0)),e.className="leaflet-marker-"+t+" "+r.className,s&&(e.style.marginLeft=-s.x+"px",e.style.marginTop=-s.y+"px"),i&&(e.style.width=i.x+"px",e.style.height=i.y+"px")},_createImg:function(e){var t;return n.Browser.ie6?(t=document.createElement("div"),t.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+e+'")'):(t=document.createElement("img"),t.src=e),t},_getIconUrl:function(e){return this.options[e+"Url"]}}),n.icon=function(e){return new n.Icon(e)},n.Icon.Default=n.Icon.extend({options:{iconSize:new n.Point(25,41),iconAnchor:new n.Point(13,41),popupAnchor:new n.Point(1,-34),shadowSize:new n.Point(41,41)},_getIconUrl:function(e){var t=e+"Url";if(this.options[t])return this.options[t];var r=n.Icon.Default.imagePath;if(!r)throw Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");return r+"/marker-"+e+".png"}}),n.Icon.Default.imagePath=function(){var e=document.getElementsByTagName("script"),t=/\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/,n,r,i,s;for(n=0,r=e.length;ns?(t.height=s+"px",n.DomUtil.addClass(e,o)):n.DomUtil.removeClass(e,o),this._containerWidth=this._container.offsetWidth},_updatePosition:function(){var e=this._map.latLngToLayerPoint(this._latlng),t=n.Browser.any3d,r=this.options.offset;t&&n.DomUtil.setPosition(this._container,e),this._containerBottom=-r.y-(t?0:e.y),this._containerLeft=-Math.round(this._containerWidth/2)+r.x+(t?0:e.x),this._container.style.bottom=this._containerBottom+"px",this._container.style.left=this._containerLeft+"px"},_zoomAnimation:function(e){var t=this._map._latLngToNewLayerPoint(this._latlng,e.zoom,e.center);n.DomUtil.setPosition(this._container,t)},_adjustPan:function(){if(!this.options.autoPan)return;var e=this._map,t=this._container.offsetHeight,r=this._containerWidth,i=new n.Point(this._containerLeft,-t-this._containerBottom);n.Browser.any3d&&i._add(n.DomUtil.getPosition(this._container));var s=e.layerPointToContainerPoint(i),o=this.options.autoPanPadding,u=e.getSize(),a=0,f=0;s.x<0&&(a=s.x-o.x),s.x+r>u.x&&(a=s.x+r-u.x+o.x),s.y<0&&(f=s.y-o.y),s.y+t>u.y&&(f=s.y+t-u.y+o.y),(a||f)&&e.panBy(new n.Point(a,f))},_onCloseButtonClick:function(e){this._close(),n.DomEvent.stop(e)}}),n.popup=function(e,t){return new n.Popup(e,t)},n.Marker.include({openPopup:function(){return this._popup&&this._map&&(this._popup.setLatLng(this._latlng),this._map.openPopup(this._popup)),this},closePopup:function(){return this._popup&&this._popup._close(),this},bindPopup:function(e,t){var r=n.point(this.options.icon.options.popupAnchor)||new n.Point(0,0);return r=r.add(n.Popup.prototype.options.offset),t&&t.offset&&(r=r.add(t.offset)),t=n.Util.extend({offset:r},t),this._popup||this.on("click",this.openPopup,this),this._popup=(new n.Popup(t,this)).setContent(e),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this.openPopup)),this}}),n.Map.include({openPopup:function(e){return this.closePopup(),this._popup=e,this.addLayer(e).fire("popupopen",{popup:this._popup})},closePopup:function(){return this._popup&&this._popup._close(),this}}),n.LayerGroup=n.Class.extend({initialize:function(e){this._layers={};var t,n;if(e)for(t=0,n=e.length;t';var t=e.firstChild;return t.style.behavior="url(#default#VML)",t&&typeof t.adj=="object"}catch(n){return!1}}(),n.Path=n.Browser.svg||!n.Browser.vml?n.Path:n.Path.extend({statics:{VML:!0,CLIP_PADDING:.02},_createElement:function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(e){return document.createElement("')}}catch(e){return function(e){return document.createElement("<"+e+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_initPath:function(){var e=this._container=this._createElement("shape");n.DomUtil.addClass(e,"leaflet-vml-shape"),this.options.clickable&&n.DomUtil.addClass(e,"leaflet-clickable"),e.coordsize="1 1",this._path=this._createElement("path"),e.appendChild(this._path),this._map._pathRoot.appendChild(e)},_initStyle:function(){this._updateStyle()},_updateStyle:function(){var e=this._stroke,t=this._fill,n=this.options,r=this._container;r.stroked=n.stroke,r.filled=n.fill,n.stroke?(e||(e=this._stroke=this._createElement("stroke"),e.endcap="round",r.appendChild(e)),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=n.dashArray.replace(/ *, */g," "):e.dashStyle=""):e&&(r.removeChild(e),this._stroke=null),n.fill?(t||(t=this._fill=this._createElement("fill"),r.appendChild(t)),t.color=n.fillColor||n.color,t.opacity=n.fillOpacity):t&&(r.removeChild(t),this._fill=null)},_updatePath:function(){var e=this._container.style;e.display="none",this._path.v=this.getPathString()+" ",e.display=""}}),n.Map.include(n.Browser.svg||!n.Browser.vml?{}:{_initPathRoot:function(){if(this._pathRoot)return;var e=this._pathRoot=document.createElement("div");e.className="leaflet-vml-container",this._panes.overlayPane.appendChild(e),this.on("moveend",this._updatePathViewport),this._updatePathViewport()}}),n.Browser.canvas=function(){return!!document.createElement("canvas").getContext}(),n.Path=n.Path.SVG&&!e.L_PREFER_CANVAS||!n.Browser.canvas?n.Path:n.Path.extend({statics:{CANVAS:!0,SVG:!1},redraw:function(){return this._map&&(this.projectLatlngs(),this._requestUpdate()),this},setStyle:function(e){return n.Util.setOptions(this,e),this._map&&(this._updateStyle(),this._requestUpdate()),this},onRemove:function(e){e.off("viewreset",this.projectLatlngs,this).off("moveend",this._updatePath,this),this._requestUpdate(),this._map=null},_requestUpdate:function(){this._map&&(n.Util.cancelAnimFrame(this._fireMapMoveEnd),this._updateRequest=n.Util.requestAnimFrame(this._fireMapMoveEnd,this._map))},_fireMapMoveEnd:function(){this.fire("moveend")},_initElements:function(){this._map._initPathRoot(),this._ctx=this._map._canvasCtx},_updateStyle:function(){var e=this.options;e.stroke&&(this._ctx.lineWidth=e.weight,this._ctx.strokeStyle=e.color),e.fill&&(this._ctx.fillStyle=e.fillColor||e.color)},_drawPath:function(){var e,t,r,i,s,o;this._ctx.beginPath();for(e=0,r=this._parts.length;es&&(o=u,s=a);s>n&&(t[o]=1,this._simplifyDPStep(e,t,n,r,o),this._simplifyDPStep(e,t,n,o,i))},_reducePoints:function(e,t){var n=[e[0]];for(var r=1,i=0,s=e.length;rt&&(n.push(e[r]),i=r);return it.max.x&&(n|=2),e.yt.max.y&&(n|=8),n},_sqDist:function(e,t){var n=t.x-e.x,r=t.y-e.y;return n*n+r*r},_sqClosestPointOnSegment:function(e,t,r,i){var s=t.x,o=t.y,u=r.x-s,a=r.y-o,f=u*u+a*a,l;return f>0&&(l=((e.x-s)*u+(e.y-o)*a)/f,l>1?(s=r.x,o=r.y):l>0&&(s+=u*l,o+=a*l)),u=e.x-s,a=e.y-o,i?u*u+a*a:new n.Point(s,o)}},n.Polyline=n.Path.extend({initialize:function(e,t){n.Path.prototype.initialize.call(this,t),this._latlngs=this._convertLatLngs(e),n.Handler.PolyEdit&&(this.editing=new n.Handler.PolyEdit(this),this.options.editable&&this.editing.enable())},options:{smoothFactor:1,noClip:!1},projectLatlngs:function(){this._originalPoints=[];for(var e=0,t=this._latlngs.length;ee.max.x||n.y-t>e.max.y||n.x+te.y!=s.y>e.y&&e.x<(s.x-i.x)*(e.y-i.y)/(s.y-i.y)+i.x&&(t=!t)}return t}}:{}),n.Circle.include(n.Path.CANVAS?{_drawPath:function(){var e=this._point;this._ctx.beginPath(),this._ctx.arc(e.x,e.y,this._radius,0,Math.PI*2,!1)},_containsPoint:function(e){var t=this._point,n=this.options.stroke?this.options.weight/2:0;return e.distanceTo(t)<=this._radius+n}}:{}),n.GeoJSON=n.FeatureGroup.extend({initialize:function(e,t){n.Util.setOptions(this,t),this._layers={},e&&this.addData(e)},addData:function(e){var t=e instanceof Array?e:e.features,r,i;if(t){for(r=0,i=t.length;r1){this._simulateClick=!1;return}var t=e.touches&&e.touches.length===1?e.touches[0]:e,r=t.target;n.DomEvent.preventDefault(e),n.Browser.touch&&r.tagName.toLowerCase()==="a"&&n.DomUtil.addClass(r,"leaflet-active"),this._moved=!1;if(this._moving)return;this._startPos=this._newPos=n.DomUtil.getPosition(this._element),this._startPoint=new n.Point(t.clientX,t.clientY),n.DomEvent.on(document,n.Draggable.MOVE,this._onMove,this),n.DomEvent.on(document,n.Draggable.END,this._onUp,this)},_onMove:function(e){if(e.touches&&e.touches.length>1)return;var t=e.touches&&e.touches.length===1?e.touches[0]:e,r=new n.Point(t.clientX,t.clientY),i=r.subtract(this._startPoint);if(!i.x&&!i.y)return;n.DomEvent.preventDefault(e),this._moved||(this.fire("dragstart"),this._moved=!0,n.Browser.touch||(n.DomUtil.disableTextSelection(),this._setMovingCursor())),this._newPos=this._startPos.add(i),this._moving=!0,n.Util.cancelAnimFrame(this._animRequest),this._animRequest=n.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget)},_updatePosition:function(){this.fire("predrag"),n.DomUtil.setPosition(this._element,this._newPos),this.fire("drag")},_onUp:function(e){if(this._simulateClick&&e.changedTouches){var t=e.changedTouches[0],r=t.target,i=this._newPos&&this._newPos.distanceTo(this._startPos)||0;r.tagName.toLowerCase()==="a"&&n.DomUtil.removeClass(r,"leaflet-active"),i200&&(this._positions.shift(),this._times.shift())}this._map.fire("move").fire("drag")},_onViewReset:function(){var e=this._map.getSize().divideBy(2),t=this._map.latLngToLayerPoint(new n.LatLng(0,0));this._initialWorldOffset=t.subtract(e).x,this._worldWidth=this._map.project(new n.LatLng(0,180)).x},_onPreDrag:function(){var e=this._map,t=this._worldWidth,n=Math.round(t/2),r=this._initialWorldOffset,i=this._draggable._newPos.x,s=(i-n+r)%t+n-r,o=(i+n+r)%t-n-r,u=Math.abs(s+r)r.inertiaThreshold||this._positions[0]===t;if(s)e.fire("moveend");else{var o=this._lastPos.subtract(this._positions[0]),u=(this._lastTime+i-this._times[0])/1e3,a=o.multiplyBy(.58/u),f=a.distanceTo(new n.Point(0,0)),l=Math.min(r.inertiaMaxSpeed,f),c=a.multiplyBy(l/f),h=l/r.inertiaDeceleration,p=c.multiplyBy(-h/2).round(),d={duration:h,easing:"ease-out"};n.Util.requestAnimFrame(n.Util.bind(function(){this._map.panBy(p,d)},this))}e.fire("dragend"),r.maxBounds&&n.Util.requestAnimFrame(this._panInsideMaxBounds,e,!0,e._container)},_panInsideMaxBounds:function(){this.panInsideBounds(this.options.maxBounds)}}),n.Map.addInitHook("addHandler","dragging",n.Map.Drag),n.Map.mergeOptions({doubleClickZoom:!0}),n.Map.DoubleClickZoom=n.Handler.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick)},_onDoubleClick:function(e){this.setView(e.latlng,this._zoom+1)}}),n.Map.addInitHook("addHandler","doubleClickZoom",n.Map.DoubleClickZoom),n.Map.mergeOptions({scrollWheelZoom:!n.Browser.touch}),n.Map.ScrollWheelZoom=n.Handler.extend({addHooks:function(){n.DomEvent.on(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0},removeHooks:function(){n.DomEvent.off(this._map._container,"mousewheel",this._onWheelScroll)},_onWheelScroll:function(e){var t=n.DomEvent.getWheelDelta(e);this._delta+=t,this._lastMousePos=this._map.mouseEventToContainerPoint(e),clearTimeout(this._timer),this._timer=setTimeout(n.Util.bind(this._performZoom,this),40),n.DomEvent.preventDefault(e)},_performZoom:function(){var e=this._map,t=Math.round(this._delta),n=e.getZoom();t=Math.max(Math.min(t,4),-4),t=e._limitZoom(n+t)-n,this._delta=0;if(!t)return;var r=n+t,i=this._getCenterForScrollWheelZoom(this._lastMousePos,r);e.setView(i,r)},_getCenterForScrollWheelZoom:function(e,t){var n=this._map,r=n.getZoomScale(t),i=n.getSize().divideBy(2),s=e.subtract(i).multiplyBy(1-1/r),o=n._getTopLeftPoint().add(i).add(s);return n.unproject(o)}}),n.Map.addInitHook("addHandler","scrollWheelZoom",n.Map.ScrollWheelZoom),n.Util.extend(n.DomEvent,{addDoubleTapListener:function(e,t,n){function l(e){if(e.touches.length!==1)return;var t=Date.now(),n=t-(r||t);o=e.touches[0],i=n>0&&n<=s,r=t}function c(e){i&&(o.type="dblclick",t(o),r=null)}var r,i=!1,s=250,o,u="_leaflet_",a="touchstart",f="touchend";return e[u+a+n]=l,e[u+f+n]=c,e.addEventListener(a,l,!1),e.addEventListener(f,c,!1),this},removeDoubleTapListener:function(e,t){var n="_leaflet_";return e.removeEventListener(e,e[n+"touchstart"+t],!1),e.removeEventListener(e,e[n+"touchend"+t],!1),this}}),n.Map.mergeOptions({touchZoom:n.Browser.touch&&!n.Browser.android23}),n.Map.TouchZoom=n.Handler.extend({addHooks:function(){n.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){n.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(e){var t=this._map;if(!e.touches||e.touches.length!==2||t._animatingZoom||this._zooming)return;var r=t.mouseEventToLayerPoint(e.touches[0]),i=t.mouseEventToLayerPoint(e.touches[1]),s=t._getCenterLayerPoint();this._startCenter=r.add(i).divideBy(2,!0),this._startDist=r.distanceTo(i),this._moved=!1,this._zooming=!0,this._centerOffset=s.subtract(this._startCenter),n.DomEvent.on(document,"touchmove",this._onTouchMove,this).on(document,"touchend",this._onTouchEnd,this),n.DomEvent.preventDefault(e)},_onTouchMove:function(e){if(!e.touches||e.touches.length!==2)return;var t=this._map,r=t.mouseEventToLayerPoint(e.touches[0]),i=t.mouseEventToLayerPoint(e.touches[1]);this._scale=r.distanceTo(i)/this._startDist,this._delta=r.add(i).divideBy(2,!0).subtract(this._startCenter);if(this._scale===1)return;this._moved||(n.DomUtil.addClass(t._mapPane,"leaflet-zoom-anim leaflet-touching"),t.fire("movestart").fire("zoomstart")._prepareTileBg(),this._moved=!0),n.Util.cancelAnimFrame(this._animRequest),this._animRequest=n.Util.requestAnimFrame(this._updateOnMove,this,!0,this._map._container),n.DomEvent.preventDefault(e)},_updateOnMove:function(){var e=this._map,t=this._getScaleOrigin(),r=e.layerPointToLatLng(t);e.fire("zoomanim",{center:r,zoom:e.getScaleZoom(this._scale)}),e._tileBg.style[n.DomUtil.TRANSFORM]=n.DomUtil.getTranslateString(this._delta)+" "+n.DomUtil.getScaleString(this._scale,this._startCenter)},_onTouchEnd:function(e){if(!this._moved||!this._zooming)return;var t=this._map;this._zooming=!1,n.DomUtil.removeClass(t._mapPane,"leaflet-touching"),n.DomEvent.off(document,"touchmove",this._onTouchMove).off(document,"touchend",this._onTouchEnd);var r=this._getScaleOrigin(),i=t.layerPointToLatLng(r),s=t.getZoom(),o=t.getScaleZoom(this._scale)-s,u=o>0?Math.ceil(o):Math.floor(o),a=t._limitZoom(s+u);t.fire("zoomanim",{center:i,zoom:a}),t._runAnimation(i,a,t.getZoomScale(a)/this._scale,r,!0)},_getScaleOrigin:function(){var e=this._centerOffset.subtract(this._delta).divideBy(this._scale);return this._startCenter.add(e)}}),n.Map.addInitHook("addHandler","touchZoom",n.Map.TouchZoom),n.Map.mergeOptions({boxZoom:!0}),n.Map.BoxZoom=n.Handler.extend({initialize:function(e){this._map=e,this._container=e._container,this._pane=e._panes.overlayPane},addHooks:function(){n.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){n.DomEvent.off(this._container,"mousedown",this._onMouseDown)},_onMouseDown:function(e){if(!e.shiftKey||e.which!==1&&e.button!==1)return!1;n.DomUtil.disableTextSelection(),this._startLayerPoint=this._map.mouseEventToLayerPoint(e),this._box=n.DomUtil.create("div","leaflet-zoom-box",this._pane),n.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor="crosshair",n.DomEvent.on(document,"mousemove",this._onMouseMove,this).on(document,"mouseup",this._onMouseUp,this).preventDefault(e),this._map.fire("boxzoomstart")},_onMouseMove:function(e){var t=this._startLayerPoint,r=this._box,i=this._map.mouseEventToLayerPoint(e),s=i.subtract(t),o=new n.Point(Math.min(i.x,t.x),Math.min(i.y,t.y));n.DomUtil.setPosition(r,o),r.style.width=Math.abs(s.x)-4+"px",r.style.height=Math.abs(s.y)-4+"px"},_onMouseUp:function(e){this._pane.removeChild(this._box),this._container.style.cursor="",n.DomUtil.enableTextSelection(),n.DomEvent.off(document,"mousemove",this._onMouseMove).off(document,"mouseup",this._onMouseUp);var t=this._map,r=t.mouseEventToLayerPoint(e),i=new n.LatLngBounds(t.layerPointToLatLng(this._startLayerPoint),t.layerPointToLatLng(r));t.fitBounds(i),t.fire("boxzoomend",{boxZoomBounds:i})}}),n.Map.addInitHook("addHandler","boxZoom",n.Map.BoxZoom),n.Map.mergeOptions({keyboard:!0,keyboardPanOffset:80,keyboardZoomOffset:1}),n.Map.Keyboard=n.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61],zoomOut:[189,109]},initialize:function(e){this._map=e,this._setPanOffset(e.options.keyboardPanOffset),this._setZoomOffset(e.options.keyboardZoomOffset)},addHooks:function(){var e=this._map._container;e.tabIndex===-1&&(e.tabIndex="0"),n.DomEvent.addListener(e,"focus",this._onFocus,this).addListener(e,"blur",this._onBlur,this).addListener(e,"mousedown",this._onMouseDown,this),this._map.on("focus",this._addHooks,this).on("blur",this._removeHooks,this)},removeHooks:function(){this._removeHooks();var e=this._map._container;n.DomEvent.removeListener(e,"focus",this._onFocus,this).removeListener(e,"blur",this._onBlur,this).removeListener(e,"mousedown",this._onMouseDown,this),this._map.off("focus",this._addHooks,this).off("blur",this._removeHooks,this)},_onMouseDown:function(){this._focused||this._map._container.focus()},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanOffset:function(e){var t=this._panKeys={},n=this.keyCodes,r,i;for(r=0,i=n.left.length;re&&(n._index+=t)})},_createMiddleMarker:function(e,t){var n=this._getMiddleLatLng(e,t),r=this._createMarker(n),i,s,o;r.setOpacity(.6),e._middleRight=t._middleLeft=r,s=function(){var s=t._index;r._index=s,r.off("click",i).on("click",this._onMarkerClick,this),n.lat=r.getLatLng().lat,n.lng=r.getLatLng().lng,this._poly.spliceLatLngs(s,0,n),this._markers.splice(s,0,r),r.setOpacity(1),this._updateIndexes(s,1),t._index++,this._updatePrevNext(e,r),this._updatePrevNext(r,t)},o=function(){r.off("dragstart",s,this),r.off("dragend",o,this),this._createMiddleMarker(e,r),this._createMiddleMarker(r,t)},i=function(){s.call(this),o.call(this),this._poly.fire("edit")},r.on("click",i,this).on("dragstart",s,this).on("dragend",o,this),this._markerGroup.addLayer(r)},_updatePrevNext:function(e,t){e._next=t,t._prev=e},_getMiddleLatLng:function(e,t){var n=this._poly._map,r=n.latLngToLayerPoint(e.getLatLng()),i=n.latLngToLayerPoint(t.getLatLng());return n.layerPointToLatLng(r._add(i).divideBy(2))}}),n.Control=n.Class.extend({options:{position:"topright"},initialize:function(e){n.Util.setOptions(this,e)},getPosition:function(){return this.options.position},setPosition:function(e){var t=this._map;return t&&t.removeControl(this),this.options.position=e,t&&t.addControl(this),this},addTo:function(e){this._map=e;var t=this._container=this.onAdd(e),r=this.getPosition(),i=e._controlCorners[r];return n.DomUtil.addClass(t,"leaflet-control"),r.indexOf("bottom")!==-1?i.insertBefore(t,i.firstChild):i.appendChild(t),this},removeFrom:function(e){var t=this.getPosition(),n=e._controlCorners[t];return n.removeChild(this._container),this._map=null,this.onRemove&&this.onRemove(e),this}}),n.control=function(e){return new n.Control(e)},n.Map.include({addControl:function(e){return e.addTo(this),this},removeControl:function(e){return e.removeFrom(this),this},_initControlPos:function(){function i(i,s){var o=t+i+" "+t+s;e[i+s]=n.DomUtil.create("div",o,r)}var e=this._controlCorners={},t="leaflet-",r=this._controlContainer=n.DomUtil.create("div",t+"control-container",this._container);i("top","left"),i("top","right"),i("bottom","left"),i("bottom","right")}}),n.Control.Zoom=n.Control.extend({options:{position:"topleft"},onAdd:function(e){var t="leaflet-control-zoom",r=n.DomUtil.create("div",t);return this._createButton("Zoom in",t+"-in",r,e.zoomIn,e),this._createButton("Zoom out",t+"-out",r,e.zoomOut,e),r},_createButton:function(e,t,r,i,s){var o=n.DomUtil.create("a",t,r);return o.href="#",o.title=e,n.DomEvent.on(o,"click",n.DomEvent.stopPropagation).on(o,"click",n.DomEvent.preventDefault).on(o,"click",i,s).on(o,"dblclick",n.DomEvent.stopPropagation),o}}),n.Map.mergeOptions({zoomControl:!0}),n.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new n.Control.Zoom,this.addControl(this.zoomControl))}),n.control.zoom=function(e){return new n.Control.Zoom(e)},n.Control.Attribution=n.Control.extend({options:{position:"bottomright",prefix:'Powered by Leaflet'},initialize:function(e){n.Util.setOptions(this,e),this._attributions={}},onAdd:function(e){return this._container=n.DomUtil.create("div","leaflet-control-attribution"),n.DomEvent.disableClickPropagation(this._container),e.on("layeradd",this._onLayerAdd,this).on("layerremove",this._onLayerRemove,this),this._update(),this._container},onRemove:function(e){e.off("layeradd",this._onLayerAdd).off("layerremove",this._onLayerRemove)},setPrefix:function(e){return this.options.prefix=e,this._update(),this},addAttribution:function(e){if(!e)return;return this._attributions[e]||(this._attributions[e]=0),this._attributions[e]++,this._update(),this},removeAttribution:function(e){if(!e)return;return this._attributions[e]--,this._update(),this},_update:function(){if(!this._map)return;var e=[];for(var t in this._attributions)this._attributions.hasOwnProperty(t)&&this._attributions[t]&&e.push(t);var n=[];this.options.prefix&&n.push(this.options.prefix),e.length&&n.push(e.join(", ")),this._container.innerHTML=n.join(" — ")},_onLayerAdd:function(e){e.layer.getAttribution&&this.addAttribution(e.layer.getAttribution())},_onLayerRemove:function(e){e.layer.getAttribution&&this.removeAttribution(e.layer.getAttribution())}}),n.Map.mergeOptions({attributionControl:!0}),n.Map.addInitHook(function(){this.options.attributionControl&&(this.attributionControl=(new n.Control.Attribution).addTo(this))}),n.control.attribution=function(e){return new n.Control.Attribution(e)},n.Control.Scale=n.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0,updateWhenIdle:!1},onAdd:function(e){this._map=e;var t="leaflet-control-scale",r=n.DomUtil.create("div",t),i=this.options;return this._addScales(i,t,r),e.on(i.updateWhenIdle?"moveend":"move",this._update,this),this._update(),r},onRemove:function(e){e.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(e,t,r){e.metric&&(this._mScale=n.DomUtil.create("div",t+"-line",r)),e.imperial&&(this._iScale=n.DomUtil.create("div",t+"-line",r))},_update:function(){var e=this._map.getBounds(),t=e.getCenter().lat,n=6378137*Math.PI*Math.cos(t*Math.PI/180),r=n*(e.getNorthEast().lng-e.getSouthWest().lng)/180,i=this._map.getSize(),s=this.options,o=0;i.x>0&&(o=r*(s.maxWidth/i.x)),this._updateScales(s,o)},_updateScales:function(e,t){e.metric&&t&&this._updateMetric(t),e.imperial&&t&&this._updateImperial(t)},_updateMetric:function(e){var t=this._getRoundNum(e);this._mScale.style.width=this._getScaleWidth(t/e)+"px",this._mScale.innerHTML=t<1e3?t+" m":t/1e3+" km"},_updateImperial:function(e){var t=e*3.2808399,n=this._iScale,r,i,s;t>5280?(r=t/5280,i=this._getRoundNum(r),n.style.width=this._getScaleWidth(i/r)+"px",n.innerHTML=i+" mi"):(s=this._getRoundNum(t),n.style.width=this._getScaleWidth(s/t)+"px",n.innerHTML=s+" ft")},_getScaleWidth:function(e){return Math.round(this.options.maxWidth*e)-10},_getRoundNum:function(e){var t=Math.pow(10,(Math.floor(e)+"").length-1),n=e/t;return n=n>=10?10:n>=5?5:n>=3?3:n>=2?2:1,t*n}}),n.control.scale=function(e){return new n.Control.Scale(e)},n.Control.Layers=n.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0},initialize:function(e,t,r){n.Util.setOptions(this,r),this._layers={},this._lastZIndex=0;for(var i in e)e.hasOwnProperty(i)&&this._addLayer(e[i],i);for(i in t)t.hasOwnProperty(i)&&this._addLayer(t[i],i,!0)},onAdd:function(e){return this._initLayout(),this._update(),this._container},addBaseLayer:function(e,t){return this._addLayer(e,t),this._update(),this},addOverlay:function(e,t){return this._addLayer(e,t,!0),this._update(),this},removeLayer:function(e){var t=n.Util.stamp(e);return delete this._layers[t],this._update(),this},_initLayout:function(){var e="leaflet-control-layers",t=this._container=n.DomUtil.create("div",e);n.Browser.touch?n.DomEvent.on(t,"click",n.DomEvent.stopPropagation):n.DomEvent.disableClickPropagation(t);var r=this._form=n.DomUtil.create("form",e+"-list");if(this.options.collapsed){n.DomEvent.on(t,"mouseover",this._expand,this).on(t,"mouseout",this._collapse,this);var i=this._layersLink=n.DomUtil.create("a",e+"-toggle",t);i.href="#",i.title="Layers",n.Browser.touch?n.DomEvent.on(i,"click",n.DomEvent.stopPropagation).on(i,"click",n.DomEvent.preventDefault).on(i,"click",this._expand,this):n.DomEvent.on(i,"focus",this._expand,this),this._map.on("movestart",this._collapse,this)}else this._expand();this._baseLayersList=n.DomUtil.create("div",e+"-base",r),this._separator=n.DomUtil.create("div",e+"-separator",r),this._overlaysList=n.DomUtil.create("div",e+"-overlays",r),t.appendChild(r)},_addLayer:function(e,t,r){var i=n.Util.stamp(e);this._layers[i]={layer:e,name:t,overlay:r},this.options.autoZIndex&&e.setZIndex&&(this._lastZIndex++,e.setZIndex(this._lastZIndex))},_update:function(){if(!this._container)return;this._baseLayersList.innerHTML="",this._overlaysList.innerHTML="";var e=!1,t=!1;for(var n in this._layers)if(this._layers.hasOwnProperty(n)){var r=this._layers[n];this._addItem(r),t=t||r.overlay,e=e||!r.overlay}this._separator.style.display=t&&e?"":"none"},_createRadioElement:function(e,t){var n='.5&&this._getLoadedTilesPercentage(e)<.5){e.style.visibility="hidden",e.empty=!0,this._stopLoadingImages(e);return}t||(t=this._tileBg=this._createPane("leaflet-tile-pane",this._mapPane),t.style.zIndex=1),t.style[n.DomUtil.TRANSFORM]="",t.style.visibility="hidden",t.empty=!0,e.empty=!1,this._tilePane=this._panes.tilePane=t;var r=this._tileBg=e;n.DomUtil.addClass(r,"leaflet-zoom-animated"),this._stopLoadingImages(r)},_getLoadedTilesPercentage:function(e){var t=e.getElementsByTagName("img"),n,r,i=0;for(n=0,r=t.length;n1}}(),o.Point=function(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},o.Point.prototype={clone:function(){return new o.Point(this.x,this.y)},add:function(t){return this.clone()._add(o.point(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(o.point(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new o.Point(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new o.Point(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},distanceTo:function(t){t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},equals:function(t){return t=o.point(t),t.x===this.x&&t.y===this.y},contains:function(t){return t=o.point(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+o.Util.formatNum(this.x)+", "+o.Util.formatNum(this.y)+")"}},o.point=function(t,e,n){return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:"object"==typeof t&&"x"in t&&"y"in t?new o.Point(t.x,t.y):new o.Point(t,e,n)},o.Bounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;n=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,r=s.x>=e.x&&n.x<=i.x,a=s.y>=e.y&&n.y<=i.y;return r&&a},overlaps:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,r=s.x>e.x&&n.xe.y&&n.y0&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(n)},addClass:function(t,e){if(t.classList!==i)for(var n=o.Util.splitWords(e),s=0,r=n.length;s=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng},intersects:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),r=s.lat>=e.lat&&n.lat<=i.lat,a=s.lng>=e.lng&&n.lng<=i.lng;return r&&a},overlaps:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),r=s.lat>e.lat&&n.late.lng&&n.lngthis.options.maxZoom?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),n=this._limitCenter(i,this._zoom,o.latLngBounds(t));return i.equals(n)||this.panTo(n,e),this._enforcingBounds=!1,this},invalidateSize:function(t){if(!this._loaded)return this;t=o.extend({animate:!1,pan:!0},t===!0?{animate:!0}:t);var e=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var i=this.getSize(),n=e.divideBy(2).round(),s=i.divideBy(2).round(),r=n.subtract(s);return r.x||r.y?(t.animate&&t.pan?this.panBy(r):(t.pan&&this._rawPanBy(r),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(o.bind(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=o.extend({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var e=o.bind(this._handleGeolocationResponse,this),i=o.bind(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e=t.code,i=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+i+"."})},_handleGeolocationResponse:function(t){var e=t.coords.latitude,i=t.coords.longitude,n=new o.LatLng(e,i),s=n.toBounds(t.coords.accuracy),r=this._locateOptions;if(r.setView){var a=this.getBoundsZoom(s);this.setView(n,r.maxZoom?Math.min(a,r.maxZoom):a)}var h={latlng:n,bounds:s,timestamp:t.timestamp};for(var l in t.coords)"number"==typeof t.coords[l]&&(h[l]=t.coords[l]);this.fire("locationfound",h)},addHandler:function(t,e){if(!e)return this;var i=this[t]=new e(this);return this._handlers.push(i),this.options[t]&&i.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=i,this._containerId=i}o.DomUtil.remove(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this._loaded&&this.fire("unload");for(var t in this._layers)this._layers[t].remove();return this},createPane:function(t,e){var i="leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),n=o.DomUtil.create("div",i,e||this._mapPane);return t&&(this._panes[t]=n),n},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds(),e=this.unproject(t.getBottomLeft()),i=this.unproject(t.getTopRight());return new o.LatLngBounds(e,i)},getMinZoom:function(){return this.options.minZoom===i?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===i?this._layersMaxZoom===i?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=o.latLngBounds(t),i=o.point(i||[0,0]);var n=this.getZoom()||0,s=this.getMinZoom(),r=this.getMaxZoom(),a=t.getNorthWest(),h=t.getSouthEast(),l=this.getSize().subtract(i),u=o.bounds(this.project(h,n),this.project(a,n)).getSize(),c=o.Browser.any3d?this.options.zoomSnap:1,d=Math.min(l.x/u.x,l.y/u.y);return n=this.getScaleZoom(d,n),c&&(n=Math.round(n/(c/100))*(c/100),n=e?Math.ceil(n/c)*c:Math.floor(n/c)*c),Math.max(s,Math.min(r,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new o.Point(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){var i=this._getTopLeftPoint(t,e);return new o.Bounds(i,i.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(t===i?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var n=this.options.crs;return e=e===i?this._zoom:e,n.scale(t)/n.scale(e)},getScaleZoom:function(t,e){var n=this.options.crs;e=e===i?this._zoom:e;var o=n.zoom(t*n.scale(e));return isNaN(o)?1/0:o},project:function(t,e){return e=e===i?this._zoom:e,this.options.crs.latLngToPoint(o.latLng(t),e)},unproject:function(t,e){return e=e===i?this._zoom:e,this.options.crs.pointToLatLng(o.point(t),e)},layerPointToLatLng:function(t){var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e)},latLngToLayerPoint:function(t){var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(o.latLng(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(o.latLngBounds(t))},distance:function(t,e){return this.options.crs.distance(o.latLng(t),o.latLng(e))},containerPointToLayerPoint:function(t){return o.point(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return o.point(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)))},mouseEventToContainerPoint:function(t){return o.DomEvent.getMousePosition(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var e=this._container=o.DomUtil.get(t);if(!e)throw new Error("Map container not found.");if(e._leaflet_id)throw new Error("Map container is already initialized.");o.DomEvent.addListener(e,"scroll",this._onScroll,this),this._containerId=o.Util.stamp(e)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&o.Browser.any3d, +o.DomUtil.addClass(t,"leaflet-container"+(o.Browser.touch?" leaflet-touch":"")+(o.Browser.retina?" leaflet-retina":"")+(o.Browser.ielt9?" leaflet-oldie":"")+(o.Browser.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var e=o.DomUtil.getStyle(t,"position");"absolute"!==e&&"relative"!==e&&"fixed"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,"leaflet-zoom-hide"),o.DomUtil.addClass(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e){o.DomUtil.setPosition(this._mapPane,new o.Point(0,0));var i=!this._loaded;this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset");var n=this._zoom!==e;this._moveStart(n)._move(t,e)._moveEnd(n),this.fire("viewreset"),i&&this.fire("load")},_moveStart:function(t){return t&&this.fire("zoomstart"),this.fire("movestart")},_move:function(t,e,n){e===i&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(o||n&&n.pinch)&&this.fire("zoom",n),this.fire("move",n)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return o.Util.cancelAnimFrame(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(e){if(o.DomEvent){this._targets={},this._targets[o.stamp(this._container)]=this;var i=e?"off":"on";o.DomEvent[i](this._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress",this._handleDOMEvent,this),this.options.trackResize&&o.DomEvent[i](t,"resize",this._onResize,this),o.Browser.any3d&&this.options.transform3DLimit&&this[i]("moveend",this._onMoveEnd)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],s="mouseout"===e||"mouseover"===e,r=t.target||t.srcElement,a=!1;r;){if(i=this._targets[o.stamp(r)],i&&("click"===e||"preclick"===e)&&!t._simulated&&this._draggableMoved(i)){a=!0;break}if(i&&i.listens(e,!0)){if(s&&!o.DomEvent._isExternalTarget(r,t))break;if(n.push(i),s)break}if(r===this._container)break;r=r.parentNode}return n.length||a||s||!o.DomEvent._isExternalTarget(r,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!o.DomEvent._skipped(t)){var e="keypress"===t.type&&13===t.keyCode?"click":t.type;"mousedown"===e&&o.DomUtil.preventOutline(t.target||t.srcElement),this._fireDOMEvent(t,e)}},_fireDOMEvent:function(t,e,i){if("click"===t.type){var n=o.Util.extend({},t);n.type="preclick",this._fireDOMEvent(n,n.type,i)}if(!t._stopped&&(i=(i||[]).concat(this._findEventTargets(t,e)),i.length)){var s=i[0];"contextmenu"===e&&s.listens(e,!0)&&o.DomEvent.preventDefault(t);var r={originalEvent:t};if("keypress"!==t.type){var a=s instanceof o.Marker;r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h0?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e))},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom(),n=o.Browser.any3d?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(e,Math.min(i,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return!((e&&e.animate)!==!0&&!this.getSize().contains(i))&&(this.panBy(i,e),!0)},_createAnimProxy:function(){var t=this._proxy=o.DomUtil.create("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(e){var i=o.DomUtil.TRANSFORM,n=t.style[i];o.DomUtil.setTransform(t,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1)),n===t.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var e=this.getCenter(),i=this.getZoom();o.DomUtil.setTransform(t,this.project(e,i),this.getZoomScale(i,1))},this)},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),s=this._getCenterOffset(t)._divideBy(1-1/n);return!(i.animate!==!0&&!this.getSize().contains(s))&&(o.Util.requestAnimFrame(function(){this._moveStart(!0)._animateZoom(t,e,!0)},this),!0)},_animateZoom:function(t,e,i,n){i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),setTimeout(o.bind(this._onZoomTransitionEnd,this),250)},_onZoomTransitionEnd:function(){this._animatingZoom&&(o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),o.Util.requestAnimFrame(function(){this._moveEnd(!0)},this))}}),o.map=function(t,e){return new o.Map(t,e)},o.Layer=o.Evented.extend({options:{pane:"overlayPane",nonBubblingEvents:[],attribution:null},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[o.stamp(t)]=this,this},removeInteractiveTarget:function(t){return delete this._map._targets[o.stamp(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var e=t.target;if(e.hasLayer(this)){if(this._map=e,this._zoomAnimated=e._zoomAnimated,this.getEvents){var i=this.getEvents();e.on(i,this),this.once("remove",function(){e.off(i,this)},this)}this.onAdd(e),this.getAttribution&&e.attributionControl&&e.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),e.fire("layeradd",{layer:this})}}}),o.Map.include({addLayer:function(t){var e=o.stamp(t);return this._layers[e]?this:(this._layers[e]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var e=o.stamp(t);return this._layers[e]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[e],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&o.stamp(t)in this._layers},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},_addLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;ethis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),this.options.minZoom===i&&this._layersMinZoom&&this.getZoom()100&&n<500||t.target._simulatedClick&&!t._simulated?void o.DomEvent.stop(t):(o.DomEvent._lastClick=i,void e(t))}},o.DomEvent.addListener=o.DomEvent.on,o.DomEvent.removeListener=o.DomEvent.off,o.PosAnimation=o.Evented.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(t){var e=+new Date-this._startTime,i=1e3*this._duration;e1e-7;l++)e=r*Math.sin(h),e=Math.pow((1-e)/(1+e),r/2),u=Math.PI/2-2*Math.atan(a*e)-h,h+=u;return new o.LatLng(h*i,t.x*i/n)}},o.CRS.EPSG3395=o.extend({},o.CRS.Earth,{code:"EPSG:3395",projection:o.Projection.Mercator,transformation:function(){var t=.5/(Math.PI*o.Projection.Mercator.R);return new o.Transformation(t,.5,-t,.5)}()}),o.GridLayer=o.Layer.extend({options:{tileSize:256,opacity:1,updateWhenIdle:o.Browser.mobile,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:i,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){o.setOptions(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),o.DomUtil.remove(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=null},bringToFront:function(){return this._map&&(o.DomUtil.toFront(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(o.DomUtil.toBack(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o.Util.throttle(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return e.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof o.Point?t:new o.Point(t,t)},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var e,i=this.getPane().children,n=-t(-(1/0),1/0),o=0,s=i.length;othis.options.maxZoom||in&&this._retainParent(s,r,a,n))},_retainChildren:function(t,e,i,n){for(var s=2*t;s<2*t+2;s++)for(var r=2*e;r<2*e+2;r++){var a=new o.Point(s,r);a.z=i+1;var h=this._tileCoordsToKey(a),l=this._tiles[h];l&&l.active?l.retain=!0:(l&&l.loaded&&(l.retain=!0),i+1this.options.maxZoom||this.options.minZoom!==i&&s1)return void this._setView(t,s);for(var m=a.min.y;m<=a.max.y;m++)for(var p=a.min.x;p<=a.max.x;p++){var f=new o.Point(p,m);if(f.z=this._tileZoom,this._isValidTile(f)){var g=this._tiles[this._tileCoordsToKey(f)];g?g.current=!0:l.push(f)}}if(l.sort(function(t,e){return t.distanceTo(h)-e.distanceTo(h)}),0!==l.length){this._loading||(this._loading=!0,this.fire("loading"));var v=e.createDocumentFragment();for(p=0;pi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return o.latLngBounds(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToBounds:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),s=n.add(i),r=e.unproject(n,t.z),a=e.unproject(s,t.z),h=new o.LatLngBounds(r,a);return this.options.noWrap||e.wrapLatLngBounds(h),h},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var e=t.split(":"),i=new o.Point(+e[0],+e[1]);return i.z=+e[2],i},_removeTile:function(t){var e=this._tiles[t];e&&(o.DomUtil.remove(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){o.DomUtil.addClass(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity<1&&o.DomUtil.setOpacity(t,this.options.opacity),o.Browser.android&&!o.Browser.android23&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),o.bind(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&o.Util.requestAnimFrame(o.bind(this._tileReady,this,t,null,s)),o.DomUtil.setPosition(s,i),this._tiles[n]={el:s,coords:t,current:!0},e.appendChild(s),this.fire("tileloadstart",{tile:s,coords:t})},_tileReady:function(t,e,i){if(this._map){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);i=this._tiles[n],i&&(i.loaded=+new Date,this._map._fadeAnimated?(o.DomUtil.setOpacity(i.el,0),o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(o.DomUtil.addClass(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),o.Browser.ielt9||!this._map._fadeAnimated?o.Util.requestAnimFrame(this._pruneTiles,this):setTimeout(o.bind(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new o.Point(this._wrapX?o.Util.wrapNum(t.x,this._wrapX):t.x,this._wrapY?o.Util.wrapNum(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new o.Bounds(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),o.gridLayer=function(t){return new o.GridLayer(t)},o.TileLayer=o.GridLayer.extend({options:{minZoom:0,maxZoom:18,maxNativeZoom:null,minNativeZoom:null,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,e){this._url=t,e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomReverse?(e.zoomOffset--,e.minZoom++):(e.zoomOffset++,e.maxZoom--),e.minZoom=Math.max(0,e.minZoom)),"string"==typeof e.subdomains&&(e.subdomains=e.subdomains.split("")),o.Browser.android||this.on("tileunload",this._onTileRemove)},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},createTile:function(t,i){var n=e.createElement("img");return o.DomEvent.on(n,"load",o.bind(this._tileOnLoad,this,i,n)),o.DomEvent.on(n,"error",o.bind(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=""),n.alt="",n.setAttribute("role","presentation"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:o.Browser.retina?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var i=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=i),e["-y"]=i}return o.Util.template(this._url,o.extend(e,this.options))},_tileOnLoad:function(t,e){o.Browser.ielt9?setTimeout(o.bind(t,this,null,e),0):t(null,e)},_tileOnError:function(t,e,i){var n=this.options.errorTileUrl;n&&e.src!==n&&(e.src=n),t(i,e)},getTileSize:function(){var t=this._map,e=o.GridLayer.prototype.getTileSize.call(this),i=this._tileZoom+this.options.zoomOffset,n=this.options.minNativeZoom,s=this.options.maxNativeZoom;return null!==n&&is?e.divideBy(t.getZoomScale(s,i)).round():e},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,e=this.options.maxZoom,i=this.options.zoomReverse,n=this.options.zoomOffset,o=this.options.minNativeZoom,s=this.options.maxNativeZoom;return i&&(t=e-t),t+=n,null!==o&&ts?s:t},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_abortLoading:function(){var t,e;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&(e=this._tiles[t].el,e.onload=o.Util.falseFn,e.onerror=o.Util.falseFn,e.complete||(e.src=o.Util.emptyImageUrl,o.DomUtil.remove(e)))}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams);for(var n in e)n in this.options||(i[n]=e[n]);e=o.setOptions(this,e),i.width=i.height=e.tileSize*(e.detectRetina&&o.Browser.retina?2:1),this.wmsParams=i},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var e=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[e]=this._crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._tileCoordsToBounds(t),i=this._crs.project(e.getNorthWest()),n=this._crs.project(e.getSouthEast()),s=(this._wmsVersion>=1.3&&this._crs===o.CRS.EPSG4326?[n.y,i.x,i.y,n.x]:[i.x,n.y,n.x,i.y]).join(","),r=o.TileLayer.prototype.getTileUrl.call(this,t);return r+o.Util.getParamString(this.wmsParams,r,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+s},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.ImageOverlay=o.Layer.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(o.DomUtil.addClass(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){o.DomUtil.remove(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._image),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=t,this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t=this._image=o.DomUtil.create("img","leaflet-image-layer "+(this._zoomAnimated?"leaflet-zoom-animated":""));t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,t.onload=o.bind(this.fire,this,"load"),this.options.crossOrigin&&(t.crossOrigin=""),t.src=this._url,t.alt=this.options.alt},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),i=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min; +o.DomUtil.setTransform(this._image,i,e)},_reset:function(){var t=this._image,e=new o.Bounds(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),i=e.getSize();o.DomUtil.setPosition(t,e.min),t.style.width=i.x+"px",t.style.height=i.y+"px"},_updateOpacity:function(){o.DomUtil.setOpacity(this._image,this.options.opacity)}}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(i,e&&"IMG"===e.tagName?e:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i=this.options,n=i[e+"Size"];"number"==typeof n&&(n=[n,n]);var s=o.point(n),r=o.point("shadow"===e&&i.shadowAnchor||i.iconAnchor||s&&s.divideBy(2,!0));t.className="leaflet-marker-"+e+" "+(i.className||""),r&&(t.style.marginLeft=-r.x+"px",t.style.marginTop=-r.y+"px"),s&&(t.style.width=s.x+"px",t.style.height=s.y+"px")},_createImg:function(t,i){return i=i||e.createElement("img"),i.src=t,i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return o.Icon.Default.imagePath||(o.Icon.Default.imagePath=this._detectIconPath()),(this.options.imagePath||o.Icon.Default.imagePath)+o.Icon.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=o.DomUtil.create("div","leaflet-default-icon-path",e.body),i=o.DomUtil.getStyle(t,"background-image")||o.DomUtil.getStyle(t,"backgroundImage");return e.body.removeChild(t),0===i.indexOf("url")?i.replace(/^url\([\"\']?/,"").replace(/marker-icon\.png[\"\']?\)$/,""):""}}),o.Marker=o.Layer.extend({options:{icon:new o.Icon.Default,interactive:!0,draggable:!1,keyboard:!0,title:"",alt:"",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",nonBubblingEvents:["click","dblclick","mouseover","mouseout","contextmenu"]},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var e=this._latlng;return this._latlng=o.latLng(t),this.update(),this.fire("move",{oldLatLng:e,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),i=t.icon.createIcon(this._icon),n=!1;i!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(i.title=t.title),t.alt&&(i.alt=t.alt)),o.DomUtil.addClass(i,e),t.keyboard&&(i.tabIndex="0"),this._icon=i,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var s=t.icon.createShadow(this._shadow),r=!1;s!==this._shadow&&(this._removeShadow(),r=!0),s&&(o.DomUtil.addClass(s,e),s.alt=""),this._shadow=s,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),s&&r&&this.getPane("shadowPane").appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),o.DomUtil.remove(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&o.DomUtil.remove(this._shadow),this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(e)},_initInteraction:function(){if(this.options.interactive&&(o.DomUtil.addClass(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),o.Handler.MarkerDrag)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new o.Handler.MarkerDrag(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;o.DomUtil.setOpacity(this._icon,t),this._shadow&&o.DomUtil.setOpacity(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor||[0,0]},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor||[0,0]}}),o.marker=function(t,e){return new o.Marker(t,e)},o.DivIcon=o.Icon.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:e.createElement("div"),n=this.options;if(i.innerHTML=n.html!==!1?n.html:"",n.bgPos){var s=o.point(n.bgPos);i.style.backgroundPosition=-s.x+"px "+-s.y+"px"}return this._setIconStyles(i,"icon"),i},createShadow:function(){return null}}),o.divIcon=function(t){return new o.DivIcon(t)},o.DivOverlay=o.Layer.extend({options:{offset:[0,7],className:"",pane:"popupPane"},initialize:function(t,e){o.setOptions(this,t),this._source=e},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(o.DomUtil.setOpacity(this._container,0),this._removeTimeout=setTimeout(o.bind(o.DomUtil.remove,o.DomUtil,this._container),200)):o.DomUtil.remove(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._container),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._container),this},_updateContent:function(){if(this._content){var t=this._contentNode,e="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof e)t.innerHTML=e;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(e)}this.fire("contentupdate")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=o.point(this.options.offset),i=this._getAnchor();this._zoomAnimated?o.DomUtil.setPosition(this._container,t.add(i)):e=e.add(t).add(i);var n=this._containerBottom=-e.y,s=this._containerLeft=-Math.round(this._containerWidth/2)+e.x;this._container.style.bottom=n+"px",this._container.style.left=s+"px"}},_getAnchor:function(){return[0,0]}}),o.Popup=o.DivOverlay.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,className:""},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof o.Path||this._source.on("preclick",o.DomEvent.stopPropagation))},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof o.Path||this._source.off("preclick",o.DomEvent.stopPropagation))},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return("closeOnClick"in this.options?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t="leaflet-popup",e=this._container=o.DomUtil.create("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated");if(this.options.closeButton){var i=this._closeButton=o.DomUtil.create("a",t+"-close-button",e);i.href="#close",i.innerHTML="×",o.DomEvent.on(i,"click",this._onCloseButtonClick,this)}var n=this._wrapper=o.DomUtil.create("div",t+"-content-wrapper",e);this._contentNode=o.DomUtil.create("div",t+"-content",n),o.DomEvent.disableClickPropagation(n).disableScrollPropagation(this._contentNode).on(n,"contextmenu",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create("div",t+"-tip-container",e),this._tip=o.DomUtil.create("div",t+"-tip",this._tipContainer)},_updateLayout:function(){var t=this._contentNode,e=t.style;e.width="",e.whiteSpace="nowrap";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="";var n=t.offsetHeight,s=this.options.maxHeight,r="leaflet-popup-scrolled";s&&n>s?(e.height=s+"px",o.DomUtil.addClass(t,r)):o.DomUtil.removeClass(t,r),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),i=this._getAnchor();o.DomUtil.setPosition(this._container,e.add(i))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,e=parseInt(o.DomUtil.getStyle(this._container,"marginBottom"),10)||0,i=this._container.offsetHeight+e,n=this._containerWidth,s=new o.Point(this._containerLeft,-i-this._containerBottom);s._add(o.DomUtil.getPosition(this._container));var r=t.layerPointToContainerPoint(s),a=o.point(this.options.autoPanPadding),h=o.point(this.options.autoPanPaddingTopLeft||a),l=o.point(this.options.autoPanPaddingBottomRight||a),u=t.getSize(),c=0,d=0;r.x+n+l.x>u.x&&(c=r.x+n-u.x+l.x),r.x-c-h.x<0&&(c=r.x-h.x),r.y+i+l.y>u.y&&(d=r.y+i-u.y+l.y),r.y-d-h.y<0&&(d=r.y-h.y),(c||d)&&t.fire("autopanstart").panBy([c,d])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)},_getAnchor:function(){return o.point(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.mergeOptions({closePopupOnClick:!0}),o.Map.include({openPopup:function(t,e,i){return t instanceof o.Popup||(t=new o.Popup(i).setContent(t)),e&&t.setLatLng(e),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),o.Layer.include({bindPopup:function(t,e){return t instanceof o.Popup?(o.setOptions(t,e),this._popup=t,t._source=this):(this._popup&&!e||(this._popup=new o.Popup(e,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,e){if(t instanceof o.Layer||(e=t,t=this),t instanceof o.FeatureGroup)for(var i in this._layers){t=this._layers[i];break}return e||(e=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,e)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e=t.layer||t.target;if(this._popup&&this._map)return o.DomEvent.stop(t),e instanceof o.Path?void this.openPopup(t.layer||t.target,t.latlng):void(this._map.hasLayer(this._popup)&&this._popup._source===e?this.closePopup():this.openPopup(e,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.Tooltip=o.DivOverlay.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return o.Browser.touch&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip",e=t+" "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=o.DomUtil.create("div",e)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e=this._map,i=this._container,n=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=i.offsetWidth,h=i.offsetHeight,l=o.point(this.options.offset),u=this._getAnchor();"top"===r?t=t.add(o.point(-a/2+l.x,-h+l.y+u.y,!0)):"bottom"===r?t=t.subtract(o.point(a/2-l.x,-l.y,!0)):"center"===r?t=t.subtract(o.point(a/2+l.x,h/2-u.y+l.y,!0)):"right"===r||"auto"===r&&s.xh&&(s=r,h=a);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;ne&&(i.push(t[n]),o=n);return oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,r=e.x,a=e.y,h=i.x-r,l=i.y-a,u=h*h+l*l;return u>0&&(s=((t.x-r)*h+(t.y-a)*l)/u,s>1?(r=i.x,a=i.y):s>0&&(r+=h*s,a+=l*s)),h=t.x-r,l=t.y-a,n?h*h+l*l:new o.Point(r,a)}},o.Polyline=o.Path.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,e){o.setOptions(this,e),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var e,i,n=1/0,s=null,r=o.LineUtil._sqClosestPointOnSegment,a=0,h=this._parts.length;ae)return r=(n-e)/i,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,e){return e=e||this._defaultShape(),t=o.latLng(t),e.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new o.LatLngBounds,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return o.Polyline._flat(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var e=[],i=o.Polyline._flat(t),n=0,s=t.length;n=2&&e[0]instanceof o.LatLng&&e[0].equals(e[i-1])&&e.pop(),e},_setLatLngs:function(t){o.Polyline.prototype._setLatLngs.call(this,t),o.Polyline._flat(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return o.Polyline._flat(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,e=this.options.weight,i=new o.Point(e,e);if(t=new o.Bounds(t.min.subtract(i),t.max.add(i)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);for(var n,s=0,r=this._rings.length;s';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}(),o.SVG.include(o.Browser.vml?{_initContainer:function(){this._container=o.DomUtil.create("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(o.Renderer.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=o.SVG.create("shape");o.DomUtil.addClass(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=o.SVG.create("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[o.stamp(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;o.DomUtil.remove(e),t.removeInteractiveTarget(e),delete this._layers[o.stamp(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,s=t._container;s.stroked=!!n.stroke,s.filled=!!n.fill,n.stroke?(e||(e=t._stroke=o.SVG.create("stroke")),s.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=o.Util.isArray(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(s.removeChild(e),t._stroke=null),n.fill?(i||(i=t._fill=o.SVG.create("fill")),s.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(s.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){o.DomUtil.toFront(t._container)},_bringToBack:function(t){o.DomUtil.toBack(t._container)}}:{}),o.Browser.vml&&(o.SVG.create=function(){try{return e.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return e.createElement("')}}catch(t){return function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()),o.Canvas=o.Renderer.extend({getEvents:function(){var t=o.Renderer.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){o.Renderer.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=e.createElement("canvas");o.DomEvent.on(t,"mousemove",o.Util.throttle(this._onMouseMove,32,this),this).on(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this).on(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_updatePaths:function(){if(!this._postponeUpdatePaths){var t;this._redrawBounds=null;for(var e in this._layers)t=this._layers[e],t._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},o.Renderer.prototype._update.call(this);var t=this._bounds,e=this._container,i=t.getSize(),n=o.Browser.retina?2:1;o.DomUtil.setPosition(e,t.min),e.width=n*i.x,e.height=n*i.y,e.style.width=i.x+"px",e.style.height=i.y+"px",o.Browser.retina&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_reset:function(){o.Renderer.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t),this._layers[o.stamp(t)]=t;var e=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=e),this._drawLast=e,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var e=t._order,i=e.next,n=e.prev;i?i.prev=n:this._drawLast=n,n?n.next=i:this._drawFirst=i,delete t._order,delete this._layers[o.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var e,i=t.options.dashArray.split(","),n=[];for(e=0;et.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u||o.Polyline.prototype._containsPoint.call(this,t,!0)},o.CircleMarker.prototype._containsPoint=function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()},o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,s=o.Util.isArray(t)?t:t.features;if(s){for(e=0,i=s.length;e1)return void(this._moved=!0);var n=i.touches&&1===i.touches.length?i.touches[0]:i,s=new o.Point(n.clientX,n.clientY),r=s.subtract(this._startPoint);(r.x||r.y)&&(Math.abs(r.x)+Math.abs(r.y)50&&(this._positions.shift(),this._times.shift())}this._map.fire("move",t).fire("drag",t)},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,e){return t-(t-e)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),e=this._offsetLimit;t.xe.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,r=Math.abs(o+i)0?s:-s))-e;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(e+r):t.setZoomAround(this._lastMousePos,e+r))}}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msPointer?"MSPointerDown":o.Browser.pointer?"pointerdown":"touchstart",_touchend:o.Browser.msPointer?"MSPointerUp":o.Browser.pointer?"pointerup":"touchend",addDoubleTapListener:function(t,e,i){function n(t){var e;if(o.Browser.pointer){if(!o.Browser.edge||"mouse"===t.pointerType)return;e=o.DomEvent._pointersCount}else e=t.touches.length;if(!(e>1)){var i=Date.now(),n=i-(r||i);a=t.touches?t.touches[0]:t,h=n>0&&n<=l,r=i}}function s(t){if(h&&!a.cancelBubble){if(o.Browser.pointer){if(!o.Browser.edge||"mouse"===t.pointerType)return;var i,n,s={};for(n in a)i=a[n],s[n]=i&&i.bind?i.bind(a):i;a=s}a.type="dblclick",e(a),r=null}}var r,a,h=!1,l=250,u="_leaflet_",c=this._touchstart,d=this._touchend;return t[u+c+i]=n,t[u+d+i]=s,t[u+"dblclick"+i]=e,t.addEventListener(c,n,!1),t.addEventListener(d,s,!1),t.addEventListener("dblclick",e,!1),this},removeDoubleTapListener:function(t,e){var i="_leaflet_",n=t[i+this._touchstart+e],s=t[i+this._touchend+e],r=t[i+"dblclick"+e];return t.removeEventListener(this._touchstart,n,!1),t.removeEventListener(this._touchend,s,!1),o.Browser.edge||t.removeEventListener("dblclick",r,!1),this}}),o.extend(o.DomEvent,{POINTER_DOWN:o.Browser.msPointer?"MSPointerDown":"pointerdown",POINTER_MOVE:o.Browser.msPointer?"MSPointerMove":"pointermove",POINTER_UP:o.Browser.msPointer?"MSPointerUp":"pointerup",POINTER_CANCEL:o.Browser.msPointer?"MSPointerCancel":"pointercancel",TAG_WHITE_LIST:["INPUT","SELECT","OPTION"],_pointers:{},_pointersCount:0,addPointerListener:function(t,e,i,n){return"touchstart"===e?this._addPointerStart(t,i,n):"touchmove"===e?this._addPointerMove(t,i,n):"touchend"===e&&this._addPointerEnd(t,i,n),this},removePointerListener:function(t,e,i){var n=t["_leaflet_"+e+i];return"touchstart"===e?t.removeEventListener(this.POINTER_DOWN,n,!1):"touchmove"===e?t.removeEventListener(this.POINTER_MOVE,n,!1):"touchend"===e&&(t.removeEventListener(this.POINTER_UP,n,!1),t.removeEventListener(this.POINTER_CANCEL,n,!1)),this},_addPointerStart:function(t,i,n){var s=o.bind(function(t){if("mouse"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(this.TAG_WHITE_LIST.indexOf(t.target.tagName)<0))return;o.DomEvent.preventDefault(t)}this._handlePointer(t,i)},this);if(t["_leaflet_touchstart"+n]=s,t.addEventListener(this.POINTER_DOWN,s,!1),!this._pointerDocListener){var r=o.bind(this._globalPointerUp,this);e.documentElement.addEventListener(this.POINTER_DOWN,o.bind(this._globalPointerDown,this),!0),e.documentElement.addEventListener(this.POINTER_MOVE,o.bind(this._globalPointerMove,this),!0),e.documentElement.addEventListener(this.POINTER_UP,r,!0),e.documentElement.addEventListener(this.POINTER_CANCEL,r,!0),this._pointerDocListener=!0}},_globalPointerDown:function(t){this._pointers[t.pointerId]=t,this._pointersCount++},_globalPointerMove:function(t){this._pointers[t.pointerId]&&(this._pointers[t.pointerId]=t)},_globalPointerUp:function(t){delete this._pointers[t.pointerId],this._pointersCount--},_handlePointer:function(t,e){t.touches=[];for(var i in this._pointers)t.touches.push(this._pointers[i]);t.changedTouches=[t],e(t)},_addPointerMove:function(t,e,i){var n=o.bind(function(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&this._handlePointer(t,e)},this);t["_leaflet_touchmove"+i]=n,t.addEventListener(this.POINTER_MOVE,n,!1)},_addPointerEnd:function(t,e,i){var n=o.bind(function(t){this._handlePointer(t,e)},this);t["_leaflet_touchend"+i]=n,t.addEventListener(this.POINTER_UP,n,!1),t.addEventListener(this.POINTER_CANCEL,n,!1)}}),o.Map.mergeOptions({touchZoom:o.Browser.touch&&!o.Browser.android23,bounceAtZoomLimits:!0}),o.Map.TouchZoom=o.Handler.extend({addHooks:function(){o.DomUtil.addClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){o.DomUtil.removeClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var n=i.mouseEventToContainerPoint(t.touches[0]),s=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(n.add(s)._divideBy(2))),this._startDist=n.distanceTo(s),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),o.DomEvent.on(e,"touchmove",this._onTouchMove,this).on(e,"touchend",this._onTouchEnd,this),o.DomEvent.preventDefault(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var e=this._map,i=e.mouseEventToContainerPoint(t.touches[0]),n=e.mouseEventToContainerPoint(t.touches[1]),s=i.distanceTo(n)/this._startDist;if(this._zoom=e.getScaleZoom(s,this._startZoom),!e.options.bounceAtZoomLimits&&(this._zoome.getMaxZoom()&&s>1)&&(this._zoom=e._limitZoom(this._zoom)),"center"===e.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=i._add(n)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=e.unproject(e.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(e._moveStart(!0),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest);var a=o.bind(e._move,e,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=o.Util.requestAnimFrame(a,this,!0),o.DomEvent.preventDefault(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,"touchmove",this._onTouchMove).off(e,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({tap:!0,tapTolerance:15}),o.Map.Tap=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){o.DomEvent.off(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,"leaflet-active"),this._holdTimeout=setTimeout(o.bind(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),o.DomEvent.on(e,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],n=i.target;n&&n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),this._simulateEvent("mouseup",i), +this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY),this._simulateEvent("mousemove",e)},_simulateEvent:function(i,n){var o=e.createEvent("MouseEvents");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o)}}),o.Browser.touch&&!o.Browser.pointer&&o.Map.addInitHook("addHandler","tap",o.Map.Tap),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane},addHooks:function(){o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_resetState:function(){this._moved=!1},_onMouseDown:function(t){return!(!t.shiftKey||1!==t.which&&1!==t.button)&&(this._resetState(),o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startPoint=this._map.mouseEventToContainerPoint(t),void o.DomEvent.on(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this))},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=o.DomUtil.create("div","leaflet-zoom-box",this._container),o.DomUtil.addClass(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var e=new o.Bounds(this._point,this._startPoint),i=e.getSize();o.DomUtil.setPosition(this._box,e.min),this._box.style.width=i.x+"px",this._box.style.height=i.y+"px"},_finish:function(){this._moved&&(o.DomUtil.remove(this._box),o.DomUtil.removeClass(this._container,"leaflet-crosshair")),o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){setTimeout(o.bind(this._resetState,this),0);var e=new o.LatLngBounds(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(e).fire("boxzoomend",{boxZoomBounds:e})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanDelta:80}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),o.DomEvent.on(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),o.DomEvent.off(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;e0&&t.screenY>0&&this._map.getContainer().focus()}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,s){var r=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",r,n)}var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){o.DomUtil.remove(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"-",zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,s){var r=o.DomUtil.create("a",i,n);return r.innerHTML=t,r.href="#",r.title=e,r.setAttribute("role","button"),r.setAttribute("aria-label",e),o.DomEvent.on(r,"mousedown dblclick",o.DomEvent.stopPropagation).on(r,"click",o.DomEvent.stop).on(r,"click",s,this).on(r,"click",this._refocusOnMap,this),r},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMinZoom())&&o.DomUtil.addClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMaxZoom())&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:"bottomright",prefix:'Leaflet'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent&&o.DomEvent.disableClickPropagation(this._container);for(var e in t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ")}}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(new o.Control.Attribution).addTo(this)}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create("div",e,i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,i=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(i)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t),i=e<1e3?e+" m":e/1e3+" km";this._updateScale(this._mScale,i,e/t)},_updateImperial:function(t){var e,i,n,o=3.2808399*t;o>5280?(e=o/5280,i=this._getRoundNum(e),this._updateScale(this._iScale,i+" mi",i/e)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,e,i){t.style.width=Math.round(this.options.maxWidth*i)+"px",t.innerHTML=e},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,e,i,n){return i1,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=e&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var e=this._getLayer(o.stamp(t.target)),i=e.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;i&&this._map.fire(i,e)},_createRadioElement:function(t,i){var n='",o=e.createElement("div");return o.innerHTML=n,o.firstChild},_addItem:function(t){var i,n=e.createElement("label"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=s):i=this._createRadioElement("leaflet-base-layers",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,"click",this._onInputClick,this);var r=e.createElement("span");r.innerHTML=" "+t.name;var a=e.createElement("div");n.appendChild(a),a.appendChild(i),a.appendChild(r);var h=t.overlay?this._overlaysList:this._baseLayersList;return h.appendChild(n),this._checkDisabledLayers(),n},_onInputClick:function(){var t,e,i,n=this._form.getElementsByTagName("input"),o=[],s=[];this._handlingClick=!0;for(var r=n.length-1;r>=0;r--)t=n[r],e=this._getLayer(t.layerId).layer,i=this._map.hasLayer(e),t.checked&&!i?o.push(e):!t.checked&&i&&s.push(e);for(r=0;r=0;s--)t=n[s],e=this._getLayer(t.layerId).layer,t.disabled=e.options.minZoom!==i&&oe.options.maxZoom},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)}}(window,document); \ No newline at end of file diff --git a/includes/services/OpenLayers/Maps_OpenLayers.php b/includes/services/OpenLayers/Maps_OpenLayers.php index 6c3e0a3a5..70eb075ae 100644 --- a/includes/services/OpenLayers/Maps_OpenLayers.php +++ b/includes/services/OpenLayers/Maps_OpenLayers.php @@ -3,131 +3,122 @@ /** * Class holding information and functionality specific to OpenLayers. * This information and features can be used by any mapping feature. - * + * * @since 0.1 - * + * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class MapsOpenLayers extends MapsMappingService { - - /** - * Constructor. - * - * @since 0.6.6 - */ + public function __construct( $serviceName ) { parent::__construct( $serviceName, - array( 'layers', 'openlayer' ) + [ 'layers', 'openlayer' ] ); - } - + } + /** * @see MapsMappingService::addParameterInfo - * - * @since 0.7 - */ + */ public function addParameterInfo( array &$params ) { global $egMapsOLLayers, $egMapsOLControls, $egMapsResizableByDefault; - $params['zoom'] = array( + $params['zoom'] = [ 'type' => 'integer', - 'range' => array( 0, 19 ), + 'range' => [ 0, 19 ], 'default' => self::getDefaultZoom(), - 'message' => 'maps-openlayers-par-zoom', - ); + 'message' => 'maps-par-zoom', + ]; - $params['controls'] = array( + $params['controls'] = [ 'default' => $egMapsOLControls, 'values' => self::getControlNames(), 'message' =>'maps-openlayers-par-controls', 'islist' => true, 'tolower' => true, - ); + ]; - $params['layers'] = array( + $params['layers'] = [ 'default' => $egMapsOLLayers, 'message' =>'maps-openlayers-par-layers', 'manipulatedefault' => true, 'islist' => true, 'tolower' => true, // TODO-customMaps: addCriteria( new CriterionOLLayer() ); - ); - - $params['resizable'] = array( + ]; + + $params['resizable'] = [ 'type' => 'boolean', 'default' => false, 'manipulatedefault' => false, 'message' => 'maps-par-resizable', - ); - - $params['overlays'] = array( + ]; + + $params['overlays'] = [ // Default empty array will end up in JS just right without manipulation. - 'default' => array(), + 'default' => [], 'manipulatedefault' => false, 'message' => 'maps-openlayers-par-overlays', // NOTE: code has moved into @see MapsDisplayMapRenderer // TODO-customMaps: addCriteria( new CriterionOLLayer( ';' ) ); // TODO-customMaps: addManipulations( new MapsParamOLLayers() ); - ); + ]; - $params['resizable'] = array( + $params['resizable'] = [ 'type' => 'boolean', 'default' => $egMapsResizableByDefault, 'message' => 'maps-par-resizable', - ); + ]; - $params['searchmarkers'] = array( + $params['searchmarkers'] = [ 'default' => '', - 'message' => 'maps-openlayers-par-searchmarkers', - 'values' => array( 'title', 'all', '' ), + 'message' => 'maps-par-searchmarkers', + 'values' => [ 'title', 'all', '' ], 'tolower' => true, - ); + ]; - $params['kml'] = array( - 'default' => array(), - 'message' => 'maps-openlayers-par-kml', + $params['kml'] = [ + 'default' => [], + 'message' => 'maps-par-kml', 'islist' => true, // new MapsParamFile() FIXME - ); + ]; } - + /** - * @see iMappingService::getDefaultZoom - * * @since 0.6.5 - */ + */ public function getDefaultZoom() { global $egMapsOpenLayersZoom; return $egMapsOpenLayersZoom; - } - + } + /** * @see MapsMappingService::getMapId - * + * * @since 0.6.5 */ public function getMapId( $increment = true ) { static $mapsOnThisPage = 0; - + if ( $increment ) { $mapsOnThisPage++; } - + return 'open_layer_' . $mapsOnThisPage; - } - + } + /** - * Returns the names of all supported controls. + * Returns the names of all supported controls. * This data is a copy of the one used to actually translate the names - * into the controls, since this resides client side, in OpenLayerFunctions.js. - * + * into the controls, since this resides client side, in OpenLayerFunctions.js. + * * @return array */ public static function getControlNames() { - return array( + return [ 'argparser', 'attribution', 'button', 'dragfeature', 'dragpan', 'drawfeature', 'editingtoolbar', 'getfeature', 'keyboarddefaults', 'layerswitcher', 'measure', 'modifyfeature', 'mousedefaults', 'mouseposition', 'mousetoolbar', @@ -136,7 +127,7 @@ public static function getControlNames() { 'scale', 'scaleline', 'selectfeature', 'snapping', 'split', 'wmsgetfeatureinfo', 'zoombox', 'zoomin', 'zoomout', 'zoompanel', 'zoomtomaxextent' - ); + ]; } /** @@ -148,40 +139,27 @@ public static function getControlNames() { */ public static function getLayerNames( $includeGroups = false ) { global $egMapsOLAvailableLayers, $egMapsOLLayerGroups; - + $keys = array_keys( $egMapsOLAvailableLayers ); - + if ( $includeGroups ) { $keys = array_merge( $keys, array_keys( $egMapsOLLayerGroups ) ); } - + return $keys; } - - /** - * Adds the layer dependencies. - * - * @since 0.7.1 - * - * @param array $dependencies - */ - public function addLayerDependencies( array $dependencies ) { - foreach ( $dependencies as $dependency ) { - $this->addDependency( $dependency ); - } - } - + /** * @see MapsMappingService::getResourceModules - * + * * @since 0.7.3 - * + * * @return array of string */ public function getResourceModules() { return array_merge( parent::getResourceModules(), - array( 'ext.maps.openlayers' ) + [ 'ext.maps.openlayers' ] ); } @@ -195,8 +173,8 @@ public function getResourceModules() { public function getConfigVariables() { return array_merge( parent::getConfigVariables(), - array( 'egMapsScriptPath' => $GLOBALS['wgScriptPath'] . '/extensions/Maps/' ) + [ 'egMapsScriptPath' => $GLOBALS['wgScriptPath'] . '/extensions/Maps/' ] ); } - + } diff --git a/includes/services/OpenLayers/Maps_ParamOLLayers.php b/includes/services/OpenLayers/Maps_ParamOLLayers.php deleted file mode 100644 index 08ce54860..000000000 --- a/includes/services/OpenLayers/Maps_ParamOLLayers.php +++ /dev/null @@ -1,170 +0,0 @@ - - * @author Daniel Werner - */ -class MapsParamOLLayers extends ListParameterManipulation { - - /** - * @since 3.0 - * - * @var string - */ - protected $groupNameSep; - - /** - * Constructor. - * - * @param string $groupNameSeparator Separator between layer group and the - * layers name within the group. - * - * @since 0.7 - */ - public function __construct( $groupNameSeparator = ';' ) { - parent::__construct(); - $this->groupNameSep = $groupNameSeparator; - } - - /** - * @see ParameterManipulation::manipulate - * - * @since 0.7 - */ - public function manipulate( Parameter &$parameter, array &$parameters ) { - global $egMapsOLLayerGroups, $egMapsOLAvailableLayers; - - $layerDefs = array(); - $usedLayers = array(); - - foreach ( $parameter->getValue() as $layerOrGroup ) { - $lcLayerOrGroup = strtolower( $layerOrGroup ); - - // Layer groups. Loop over all items and add them if not present yet. - if ( array_key_exists( $lcLayerOrGroup, $egMapsOLLayerGroups ) ) { - foreach ( $egMapsOLLayerGroups[$lcLayerOrGroup] as $layerName ) { - if ( !in_array( $layerName, $usedLayers ) ) { - if ( is_array( $egMapsOLAvailableLayers[$layerName] ) ) { - $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName][0]; - } - else { - $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName]; - } - $usedLayers[] = $layerName; - } - } - } - // Single layers. Add them if not present yet. - elseif ( array_key_exists( $lcLayerOrGroup, $egMapsOLAvailableLayers ) ) { - if ( !in_array( $lcLayerOrGroup, $usedLayers ) ) { - if ( is_array( $egMapsOLAvailableLayers[$lcLayerOrGroup] ) ) { - $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup][0]; - } - else { - $layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup]; - } - - $usedLayers[] = $lcLayerOrGroup; - } - } - // Image layers. Check validity and add if not present yet. - else { - $layerParts = explode( $this->groupNameSep, $layerOrGroup, 2 ); - $layerGroup = $layerParts[0]; - $layerName = count( $layerParts ) > 1 ? $layerParts[1] : null; - - $title = Title::newFromText( $layerGroup, Maps_NS_LAYER ); - - if ( $title !== null && $title->getNamespace() == Maps_NS_LAYER ) { - /** - * TODO/FIXME: This shouldn't be here and using $wgParser, instead it should - * be somewhere around MapsBaseMap::renderMap. But since we do a lot more than - * 'parameter manipulation' in here, we already diminish the information needed - * for this which will never arrive there. Perhaps the whole - * MapsLayer::getJavaScriptDefinition() shouldn't be done here. - */ - global $wgParser; - // add dependency to the layer page so if the layer definition gets updated, - // the page where it is used will be updated as well: - $rev = Revision::newFromTitle( $title ); - $wgParser->getOutput()->addTemplate( $title, $title->getArticleID(), $rev->getId() ); - - // if the whole layer group is not yet loaded into the map and the group exists: - if( ! in_array( $layerGroup, $usedLayers ) - && $title->exists() - ) { - $layerPage = new MapsLayerPage( $title ); - - if( $layerName !== null ) { - // load specific layer with name: - $layer = MapsLayers::loadLayer( $title, $layerName ); - $layers = new MapsLayerGroup( $layer ); - $usedLayer = $layerOrGroup; - } - else { - // load all layers from group: - $layers = MapsLayers::loadLayerGroup( $title ); - $usedLayer = $layerGroup; - } - - foreach( $layers->getLayers() as $layer ) { - if( ( // make sure named layer is only taken once (in case it was requested on its own before) - $layer->getName() === null - || ! in_array( $layerGroup . $this->groupNameSep . $layer->getName(), $usedLayers ) - ) - && $layer->isOk() - ) { - $layerDefs[] = $layer->getJavaScriptDefinition(); - } - } - $usedLayers[] = $usedLayer; // have to add this after loop of course! - } - } - else { - wfWarn( "Invalid layer ($layerOrGroup) encountered after validation." ); - } - } - } - - $parameter->setValue( $layerDefs ); - - MapsMappingServices::getServiceInstance( 'openlayers' )->addLayerDependencies( $this->getDependencies( $usedLayers ) ); - } - - /** - * Returns the depencies for the provided layers. - * - * @since 0.7.1 - * - * @param array $layerNames - * - * @return array - */ - protected function getDependencies( array $layerNames ) { - global $egMapsOLLayerDependencies, $egMapsOLAvailableLayers; - - $layerDependencies = array(); - - foreach ( $layerNames as $layerName ) { - if ( array_key_exists( $layerName, $egMapsOLAvailableLayers ) // The layer must be defined in php - && is_array( $egMapsOLAvailableLayers[$layerName] ) // The layer must be an array... - && count( $egMapsOLAvailableLayers[$layerName] ) > 1 // ...with a second element... - && array_key_exists( $egMapsOLAvailableLayers[$layerName][1], $egMapsOLLayerDependencies ) ) { //...that is a dependency. - $layerDependencies[] = $egMapsOLLayerDependencies[$egMapsOLAvailableLayers[$layerName][1]]; - } - } - - return array_unique( $layerDependencies ); - } - -} diff --git a/includes/services/OpenLayers/OSM/OpenStreetMap.js b/includes/services/OpenLayers/OSM/OpenStreetMap.js index 36cb437ad..a768b7183 100644 --- a/includes/services/OpenLayers/OSM/OpenStreetMap.js +++ b/includes/services/OpenLayers/OSM/OpenStreetMap.js @@ -60,38 +60,6 @@ OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, { CLASS_NAME: "OpenLayers.Layer.OSM.Mapnik" }); -/** - * Class: OpenLayers.Layer.OSM.Osmarender - * - * Inherits from: - * - - */ -OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, { - /** - * Constructor: OpenLayers.Layer.OSM.Osmarender - * - * Parameters: - * name - {String} - * options - {Object} Hashtable of extra options to tag onto the layer - */ - initialize: function(name, options) { - var url = [ - "http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png", - "http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png", - "http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png" - ]; - options = OpenLayers.Util.extend({ - numZoomLevels: 18, - buffer: 0, - transitionEffect: "resize" - }, options); - var newArguments = [name, url, options]; - OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments); - }, - - CLASS_NAME: "OpenLayers.Layer.OSM.Osmarender" -}); - /** * Class: OpenLayers.Layer.OSM.CycleMap * diff --git a/includes/services/OpenLayers/OpenLayers.php b/includes/services/OpenLayers/OpenLayers.php index bf6916c81..1ecfaa3f3 100644 --- a/includes/services/OpenLayers/OpenLayers.php +++ b/includes/services/OpenLayers/OpenLayers.php @@ -2,12 +2,12 @@ /** * This group contains all OpenLayers related files of the Maps extension. - * + * * @defgroup MapsOpenLayers OpenLayers */ /** - * This file holds the hook and initialization for the OpenLayers service. + * This file holds the hook and initialization for the OpenLayers service. * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > @@ -18,46 +18,32 @@ } call_user_func( function() { - global $wgHooks, $wgResourceModules, $wgAutoloadClasses; + global $wgResourceModules; $pathParts = ( explode( DIRECTORY_SEPARATOR . 'extensions' . DIRECTORY_SEPARATOR, __DIR__, 2 ) ); - $wgResourceModules['ext.maps.openlayers'] = array( - 'dependencies' => array( 'ext.maps.common' ), + $wgResourceModules['ext.maps.openlayers'] = [ + 'dependencies' => [ 'ext.maps.common' ], 'localBasePath' => __DIR__, 'remoteExtPath' => end( $pathParts ), 'group' => 'ext.maps', - 'targets' => array( + 'targets' => [ 'mobile', 'desktop' - ), - 'scripts' => array( + ], + 'scripts' => [ 'OpenLayers/OpenLayers.js', 'OSM/OpenStreetMap.js', 'jquery.openlayers.js', 'ext.maps.openlayers.js' - ), - 'styles' => array( + ], + 'styles' => [ 'OpenLayers/theme/default/style.css' - ), - 'messages' => array( + ], + 'messages' => [ 'maps-markers', 'maps-copycoords-prompt', 'maps-searchmarkers-text', - ) - ); - - $wgAutoloadClasses['MapsOpenLayers'] = __DIR__ . '/Maps_OpenLayers.php'; - - $wgHooks['MappingServiceLoad'][] = 'efMapsInitOpenLayers'; + ] + ]; } ); - -function efMapsInitOpenLayers() { - MapsMappingServices::registerService( - 'openlayers', - 'MapsOpenLayers', - array( 'display_map' => 'MapsDisplayMapRenderer' ) - ); - - return true; -} \ No newline at end of file diff --git a/includes/services/OpenLayers/ext.maps.openlayers.js b/includes/services/OpenLayers/ext.maps.openlayers.js index b4c13cae9..3244277ff 100644 --- a/includes/services/OpenLayers/ext.maps.openlayers.js +++ b/includes/services/OpenLayers/ext.maps.openlayers.js @@ -27,7 +27,8 @@ var $this = $( this), mapData = $.parseJSON( $this.find( 'div').text() ); - $this.openlayers( $this.attr( 'id' ), mapData ); + var map = $this.openlayers( $this.attr( 'id' ), mapData ); + window.maps.openlayersList.push(map); } ); } ); diff --git a/includes/services/OpenLayers/jquery.openlayers.js b/includes/services/OpenLayers/jquery.openlayers.js index 8216f064e..232790007 100644 --- a/includes/services/OpenLayers/jquery.openlayers.js +++ b/includes/services/OpenLayers/jquery.openlayers.js @@ -4,21 +4,26 @@ * * @author Jeroen De Dauw * @author Daniel Werner + * @author Peter Grassberger < petertheone@gmail.com > * * @todo This whole JS is very blown up and could use some quality refactoring. */ -(function ($) { +(function ($, mw, OpenLayers) { $.fn.openlayers = function (mapElementId, options) { + this.map = null; + this.options = options; + this.bounds = null; + OpenLayers._getScriptLocation = function() { return mw.config.get('wgScriptPath') + '/extensions/Maps/includes/services/OpenLayers/OpenLayers/'; - } + }; this.getOLMarker = function (markerLayer, markerData) { var marker; - if (markerData.icon !== "") { + if (markerData.hasOwnProperty('icon') && markerData.icon !== "") { marker = new OpenLayers.Marker(markerData.lonlat, new OpenLayers.Icon(markerData.icon)); } else { marker = new OpenLayers.Marker(markerData.lonlat, new OpenLayers.Icon(markerLayer.defaultIcon)); @@ -56,51 +61,62 @@ } var locations = options.locations; - var bounds = null; if (locations.length > 1 && ( options.centre === false || options.zoom === false )) { - bounds = new OpenLayers.Bounds(); + this.bounds = new OpenLayers.Bounds(); } - var groupLayers = new Object(); - var groups = 0; + this.groupLayers = new Object(); + this.groups = 0; for (var i = locations.length - 1; i >= 0; i--) { + this.addMarker( locations[i] ); + } - var location = locations[i]; - - // Create a own marker-layer for the marker group: - if (!groupLayers[ location.group ]) { - // in case no group is specified, use default marker layer: - var layerName = location.group != '' ? location.group : mediaWiki.msg('maps-markers'); - var curLayer = new OpenLayers.Layer.Markers(layerName); - groups++; - curLayer.id = 'markerLayer' + groups; - // define default icon, one of ten in different colors, if more than ten layers, colors will repeat: - curLayer.defaultIcon = mw.config.get( 'egMapsScriptPath' ) + '/includes/services/OpenLayers/OpenLayers/img/marker' + ( ( groups + 10 ) % 10 ) + '.png'; - map.addLayer(curLayer); - groupLayers[ location.group ] = curLayer; - } else { - // if markers of this group exist already, they have an own layer already - var curLayer = groupLayers[ location.group ]; - } + if (this.bounds != null) map.zoomToExtent(this.bounds); // If a bounds object has been created, use it to set the zoom and center. + }; - location.lonlat = new OpenLayers.LonLat(location.lon, location.lat); + this.addMarker = function (markerData) { + markerData.group = !markerData.hasOwnProperty('group') ? '' : markerData.group; + // Create a own marker-layer for the marker group: + if (!this.groupLayers[ markerData.group ]) { + // in case no group is specified, use default marker layer: + var layerName = markerData.group != '' ? markerData.group : mw.msg('maps-markers'); + var curLayer = new OpenLayers.Layer.Markers(layerName); + this.groups++; + curLayer.id = 'markerLayer' + this.groups; + // define default icon, one of ten in different colors, if more than ten layers, colors will repeat: + curLayer.defaultIcon = mw.config.get( 'egMapsScriptPath' ) + '/includes/services/OpenLayers/OpenLayers/img/marker' + ( ( this.groups + 10 ) % 10 ) + '.png'; + map.addLayer(curLayer); + this.groupLayers[ markerData.group ] = curLayer; + } else { + // if markers of this group exist already, they have an own layer already + var curLayer = this.groupLayers[ markerData.group ]; + } - if (!hasImageLayer) { - location.lonlat.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); - } + markerData.lonlat = new OpenLayers.LonLat(markerData.lon, markerData.lat); - if (bounds != null) bounds.extend(location.lonlat); // Extend the bounds when no center is set. - var marker = this.getOLMarker(curLayer, location); - this.markers.push({ - target:marker, - data:location - }); - curLayer.addMarker(marker); // Create and add the marker. + if (!hasImageLayer) { + markerData.lonlat.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); } - if (bounds != null) map.zoomToExtent(bounds); // If a bounds object has been created, use it to set the zoom and center. + if (this.bounds != null) this.bounds.extend(markerData.lonlat); // Extend the bounds when no center is set. + var marker = this.getOLMarker(curLayer, markerData); + this.markers.push({ + target:marker, + data:markerData + }); + curLayer.addMarker(marker); // Create and add the marker. + }; + + this.removeMarkers = function () { + var map = this.map; + $.each(this.groupLayers, function(index, layer) { + map.removeLayer(layer); + }); + this.groupLayers = new Object(); + this.groups = 0; + this.markers = []; }; this.addControls = function (map, controls, mapElement) { @@ -125,6 +141,18 @@ } map.addControl(new OpenLayers.Control.Attribution()); + map.addControl(new OpenLayers.Control.MousePosition({ + formatOutput: function(lonLat) { + var digits = parseInt(this.numDigits); + var newHtml = + this.prefix + + lonLat.lat.toFixed(digits) + + this.separator + + lonLat.lon.toFixed(digits) + + this.suffix; + return newHtml; + } + })); }; this.addLine = function (properties) { @@ -233,7 +261,7 @@ var OLControls = [ 'ArgParser', 'Attribution', 'Button', 'DragFeature', 'DragPan', 'DrawFeature', 'EditingToolbar', 'GetFeature', 'KeyboardDefaults', 'LayerSwitcher', - 'Measure', 'ModifyFeature', 'MouseDefaults', 'MousePosition', 'MouseToolbar', + 'Measure', 'ModifyFeature', 'MouseDefaults', 'MouseToolbar', 'Navigation', 'NavigationHistory', 'NavToolbar', 'OverviewMap', 'Pan', 'Panel', 'PanPanel', 'PanZoom', 'PanZoomBar', 'Permalink', 'Scale', 'ScaleLine', 'SelectFeature', 'Snapping', 'Split', @@ -265,7 +293,7 @@ this.text( '' ); /** - * ToDo: That layers being created by 'eval' will deny us the possiblity to + * ToDo: That layers being created by 'eval' will deny us the possibility to * set certain options. It's possible to set properties of course but they will * show no effect since they are not passed as options to the constructor. * With this working we could adjust max/minScale to display overlays independent @@ -330,6 +358,7 @@ map.addLayers( layers ); // Add the base layers + //Add markers this.addMarkers( map, options ); var centre = false; @@ -340,8 +369,7 @@ else if ( options.locations.length == 0 ) { centre = new OpenLayers.LonLat( 0, 0 ); } - } - else { // When the center is provided, set it. + } else { // When the center is provided, set it. centre = new OpenLayers.LonLat( options.centre.lon, options.centre.lat ); } @@ -351,8 +379,10 @@ new OpenLayers.Projection( "EPSG:4326" ), new OpenLayers.Projection( "EPSG:900913" ) ); + map.setCenter( centre ); + } else { + map.zoomToMaxExtent(); } - map.setCenter( centre ); } if ( options.zoom !== false ) { @@ -394,10 +424,6 @@ } } - //Add markers - this.addMarkers(map, options); - var centre = false; - //Add line layer if applicable if (options.lines && options.lines.length > 0) { this.lineLayer = new OpenLayers.Layer.Vector("Line Layer"); @@ -445,7 +471,7 @@ 'strokeOpacity':feature.attributes.strokeOpacity, 'fillColor':feature.attributes.fillColor, 'fillOpacity':feature.attributes.fillOpacity - } + }; _this.polygonLayer.drawFeature(feature, style); } }, @@ -457,7 +483,7 @@ 'strokeOpacity':0, 'fillColor':feature.attributes.fillColor, 'fillOpacity':0 - } + }; _this.polygonLayer.drawFeature(feature, style); } }, @@ -548,35 +574,6 @@ map.zoomTo(options.zoom); } - if (options.centre === false) { - if (options.locations.length == 1) { - centre = new OpenLayers.LonLat(options.locations[0].lon, options.locations[0].lat); - } - else if (options.locations.length == 0) { - centre = new OpenLayers.LonLat(0, 0); - } - } - else { // When the center is provided, set it. - centre = new OpenLayers.LonLat(options.centre.lon, options.centre.lat); - } - - if (centre !== false) { - if (!hasImageLayer) { - centre.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")); - map.setCenter(centre); - } else { - map.zoomToMaxExtent(); - } - } - - if (options.resizable) { - mw.loader.using('ext.maps.resizable', function () { - _this.resizable(); - }); - } - - - if (options.copycoords) { map.div.oncontextmenu = function () { return false; @@ -603,7 +600,7 @@ ); } - }) + }); var click = new OpenLayers.Control.Click({ eventMethods:{ 'rightclick':function (e) { @@ -611,7 +608,7 @@ if (!hasImageLayer) { lonlat = lonlat.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326")); } - prompt(mediaWiki.msg('maps-copycoords-prompt'), lonlat.lat + ',' + lonlat.lon); + prompt(mw.msg('maps-copycoords-prompt'), lonlat.lat + ',' + lonlat.lon); } } }); @@ -623,7 +620,7 @@ OpenLayers.Control.SearchField = OpenLayers.Class(OpenLayers.Control, { draw:function (px) { OpenLayers.Control.prototype.draw.apply(this, arguments); - var searchBoxValue = mediaWiki.msg('maps-searchmarkers-text'); + var searchBoxValue = mw.msg('maps-searchmarkers-text'); var searchBoxContainer = document.createElement('div'); this.div.style.top = "5px"; this.div.style.right = "5px"; @@ -675,16 +672,16 @@ } function openBubble(properties) { - var mousePos = map.getControlsByClass("OpenLayers.Control.MousePosition")[0].lastXy + var mousePos = map.getControlsByClass("OpenLayers.Control.MousePosition")[0].lastXy; var lonlat = map.getLonLatFromPixel(mousePos); var popup = new OpenLayers.Popup(null, lonlat, null, properties.text, true, function () { map.getControlsByClass('OpenLayers.Control.SelectFeature')[0].unselectAll(); map.removePopup(this); - }) + }); _this.map.addPopup(popup); } return this; }; -})(jQuery); +})(jQuery, window.mediaWiki, OpenLayers); diff --git a/includes/specials/SpecialMapEditor.php b/includes/specials/SpecialMapEditor.php index 13b08642d..dc71cfacf 100644 --- a/includes/specials/SpecialMapEditor.php +++ b/includes/specials/SpecialMapEditor.php @@ -34,7 +34,7 @@ public function execute( $subPage ) { $outputPage->addHtml( MapsGoogleMaps3::getApiScript( $this->getLanguage()->getCode(), - array( 'libraries' => 'drawing' ) + [ 'libraries' => 'drawing' ] ) ); $outputPage->addModules( 'mapeditor' ); @@ -49,10 +49,10 @@ public function execute( $subPage ) { * @return array */ protected function getAttribs(){ - return array( + return [ 'id' => 'map-canvas', 'context' => 'SpecialMapEditor' - ); + ]; } protected function getGroupName() { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 2bd804b36..9e44be414 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,5 +1,6 @@ + stopOnSkipped="false"> - tests/phpunit + tests + SemanticMaps/tests includes src + SemanticMaps/src diff --git a/schema/MapsLayers-postgres.sql b/schema/MapsLayers-postgres.sql deleted file mode 100644 index 271d4aaaf..000000000 --- a/schema/MapsLayers-postgres.sql +++ /dev/null @@ -1,10 +0,0 @@ -BEGIN; - -CREATE TABLE maps_layers ( - layer_page_id INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, - layer_name VARCHAR(64) DEFAULT NULL, - layer_type VARCHAR(32) NOT NULL, - layer_data TEXT NOT NULL -) /*$wgDBTableOptions*/; - -COMMIT; \ No newline at end of file diff --git a/schema/MapsLayers.sql b/schema/MapsLayers.sql deleted file mode 100644 index b544291e7..000000000 --- a/schema/MapsLayers.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE IF NOT EXISTS /*_*/maps_layers ( - layer_page_id int REFERENCES /*_*/page(page_id) ON DELETE CASCADE, - layer_name varchar(64) binary default NULL, - layer_type varchar(32) binary NOT NULL, - layer_data text NOT NULL -) /*$wgDBTableOptions*/; \ No newline at end of file diff --git a/src/Maps/Elements/BaseElement.php b/src/Elements/BaseElement.php similarity index 95% rename from src/Maps/Elements/BaseElement.php rename to src/Elements/BaseElement.php index 5e7935f8f..01f489b17 100644 --- a/src/Maps/Elements/BaseElement.php +++ b/src/Elements/BaseElement.php @@ -15,7 +15,7 @@ * @author Kim Eik < kim@heldig.org > * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ -abstract class BaseElement implements Element, \iBubbleMapElement, \iLinkableMapElement { +abstract class BaseElement implements Element { /** * @since 3.0 @@ -93,7 +93,7 @@ public function setLink( $link ) { * @return array */ public function getJSONObject( $defText = '' , $defTitle = '' ) { - $array = array(); + $array = []; $array['text'] = $this->options->hasOption( 'text' ) ? $this->getText() : $defText; $array['title'] = $this->options->hasOption( 'title' ) ? $this->getTitle() : $defTitle; diff --git a/src/Maps/Elements/Circle.php b/src/Elements/Circle.php similarity index 94% rename from src/Maps/Elements/Circle.php rename to src/Elements/Circle.php index 7c5383ab6..364d2a13b 100644 --- a/src/Maps/Elements/Circle.php +++ b/src/Elements/Circle.php @@ -18,12 +18,12 @@ class Circle extends \MapsBaseFillableElement { /** * @var LatLongValue */ - protected $circleCentre; + private $circleCentre; /** * @var integer|float */ - protected $circleRadius; + private $circleRadius; /** * @param LatLongValue $circleCentre @@ -77,13 +77,13 @@ public function setCircleRadius( $circleRadius ) { public function getJSONObject( $defText = '' , $defTitle = '' ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $array = array( - 'centre' => array( + $array = [ + 'centre' => [ 'lon' => $this->getCircleCentre()->getLongitude(), 'lat' => $this->getCircleCentre()->getLatitude() - ) , + ], 'radius' => intval( $this->getCircleRadius() ), - ); + ]; return array_merge( $parentArray, $array ); } diff --git a/src/Maps/Elements/ImageOverlay.php b/src/Elements/ImageOverlay.php similarity index 96% rename from src/Maps/Elements/ImageOverlay.php rename to src/Elements/ImageOverlay.php index e1466d8e1..f7b53cec7 100644 --- a/src/Maps/Elements/ImageOverlay.php +++ b/src/Elements/ImageOverlay.php @@ -21,10 +21,6 @@ class ImageOverlay extends Rectangle { private $imageUrl; /** - * Constructor. - * - * @since 3.0 - * * @param LatLongValue $boundsNorthEast * @param LatLongValue $boundsSouthWest * @param string $image diff --git a/src/Maps/Elements/Line.php b/src/Elements/Line.php similarity index 89% rename from src/Maps/Elements/Line.php rename to src/Elements/Line.php index 26b7ba507..bf07ccff7 100644 --- a/src/Maps/Elements/Line.php +++ b/src/Elements/Line.php @@ -31,7 +31,7 @@ class Line extends \MapsBaseStrokableElement { * * @throws InvalidArgumentException */ - public function __construct( array $coordinates = array() ) { + public function __construct( array $coordinates = [] ) { foreach ( $coordinates as $coordinate ) { if ( !( $coordinate instanceof LatLongValue ) ) { throw new InvalidArgumentException( 'Can only construct Line with LatLongValue objects' ); @@ -62,16 +62,16 @@ public function getLineCoordinates() { */ public function getJSONObject( $defText = '' , $defTitle = '' ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $posArray = array(); + $posArray = []; foreach ( $this->coordinates as $mapLocation ) { - $posArray[] = array( + $posArray[] = [ 'lat' => $mapLocation->getLatitude() , 'lon' => $mapLocation->getLongitude() - ); + ]; } - $posArray = array( 'pos' => $posArray ); + $posArray = [ 'pos' => $posArray ]; return array_merge( $parentArray , $posArray ); } diff --git a/src/Maps/Elements/Location.php b/src/Elements/Location.php similarity index 83% rename from src/Maps/Elements/Location.php rename to src/Elements/Location.php index 1b9012bfd..df4c5cdfd 100644 --- a/src/Maps/Elements/Location.php +++ b/src/Elements/Location.php @@ -20,44 +20,34 @@ class Location extends BaseElement { /** - * @since 3.0 - * * @var LatLongValue */ - protected $coordinates; + private $coordinates; /** - * @since 0.7.1 - * * @var string */ - protected $address; + private $address; /** - * @since 0.7.2 - * * @var string */ - protected $icon = ''; + private $icon = ''; /** - * @since 2.0 - * * @var string */ - protected $group = ''; + private $group = ''; /** * @var string - * @since 2.0 */ - protected $inlineLabel = ''; + private $inlineLabel = ''; /** * @var string - * @since 2.0 */ - protected $visitedIcon = ''; + private $visitedIcon = ''; /** * Creates and returns a new instance of a Location from a latitude and longitude. @@ -73,6 +63,23 @@ public static function newFromLatLon( $lat, $lon ) { return new self( new LatLongValue( $lat, $lon ) ); } + + /** + * Creates and returns a new instance of a Location with title from a latitude and longitude. + * + * @since 3.7 + * + * @param float $lat + * @param float $lon + * + * @return Location + */ + public static function newTitledFromLatLon( $lat, $lon ) { + $location = new self( new LatLongValue( $lat, $lon ) ); + $location->setTitle( $lat . ',' . $lon ); + return $location; + } + /** * Creates and returns a new instance of a Location from an address. * @@ -94,13 +101,6 @@ public static function newFromAddress( $address ) { return new static( $address ); } - /** - * Constructor. - * - * @param LatLongValue $coordinates - * - * @since 3.0 - */ public function __construct( LatLongValue $coordinates ) { parent::__construct(); $this->coordinates = $coordinates; @@ -228,7 +228,7 @@ public function getGroup() { } /** - * Returns whether Location is asigned to a group. + * Returns whether Location is assigned to a group. * * @since 2.0 * @@ -305,16 +305,27 @@ public function hasVisitedIcon(){ public function getJSONObject( $defText = '', $defTitle = '', $defIconUrl = '', $defGroup = '', $defInlineLabel = '', $defVisitedIcon = '' ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $array = array( + $array = [ 'lat' => $this->coordinates->getLatitude(), 'lon' => $this->coordinates->getLongitude(), - 'alt' => 0, - 'address' => $this->getAddress( false ), 'icon' => $this->hasIcon() ? \MapsMapper::getFileUrl( $this->getIcon() ) : $defIconUrl, - 'group' => $this->hasGroup() ? $this->getGroup() : $defGroup, - 'inlineLabel' => $this->hasInlineLabel() ? $this->getInlineLabel() : $defInlineLabel, - 'visitedicon' => $this->hasVisitedIcon() ? $this->getVisitedIcon() : $defVisitedIcon, - ); + ]; + $val = $this->getAddress(); + if( $val !== '' ) { + $array['address'] = $val; + } + $val = $this->hasGroup() ? $this->getGroup() : $defGroup; + if( !empty( $val ) ) { + $array['group'] = $val; + } + $val = $this->hasInlineLabel() ? $this->getInlineLabel() : $defInlineLabel; + if( !empty( $val ) ) { + $array['inlineLabel'] = $val; + } + $val = $this->hasVisitedIcon() ? $this->getVisitedIcon() : $defVisitedIcon; + if( !empty( $val ) ) { + $array['visitedicon'] = $val; + } return array_merge( $parentArray , $array ); } diff --git a/src/Maps/Elements/Polygon.php b/src/Elements/Polygon.php similarity index 88% rename from src/Maps/Elements/Polygon.php rename to src/Elements/Polygon.php index df2ee1d38..d6d5b41eb 100644 --- a/src/Maps/Elements/Polygon.php +++ b/src/Elements/Polygon.php @@ -11,11 +11,11 @@ * @author Kim Eik < kim@heldig.org > * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ -class Polygon extends Line implements \iHoverableMapElement { +class Polygon extends Line { - protected $onlyVisibleOnHover = false; - protected $fillOpacity = '0.5'; - protected $fillColor = '#FF0000'; + private $onlyVisibleOnHover = false; + private $fillOpacity = '0.5'; + private $fillColor = '#FF0000'; /** * @since 3.0 diff --git a/src/Maps/Elements/Rectangle.php b/src/Elements/Rectangle.php similarity index 97% rename from src/Maps/Elements/Rectangle.php rename to src/Elements/Rectangle.php index 9d772756a..d055f7971 100644 --- a/src/Maps/Elements/Rectangle.php +++ b/src/Elements/Rectangle.php @@ -93,16 +93,16 @@ public function setRectangleNorthEast( LatLongValue $rectangleNorthEast ) { */ public function getJSONObject( $defText = '' , $defTitle = '' ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $array = array( - 'ne' => array( + $array = [ + 'ne' => [ 'lon' => $this->getRectangleNorthEast()->getLongitude(), 'lat' => $this->getRectangleNorthEast()->getLatitude() - ), - 'sw' => array( + ], + 'sw' => [ 'lon' => $this->getRectangleSouthWest()->getLongitude(), 'lat' => $this->getRectangleSouthWest()->getLatitude() - ), - ); + ], + ]; return array_merge( $parentArray , $array ); } diff --git a/src/Maps/Elements/WmsOverlay.php b/src/Elements/WmsOverlay.php similarity index 95% rename from src/Maps/Elements/WmsOverlay.php rename to src/Elements/WmsOverlay.php index 8ac1ecc8b..3c96283c2 100644 --- a/src/Maps/Elements/WmsOverlay.php +++ b/src/Elements/WmsOverlay.php @@ -23,7 +23,7 @@ class WmsOverlay extends BaseElement { private $wmsLayerName; /** - * @var String WMS Stype name (default value: 'default') + * @var String WMS Style name (default value: 'default') */ private $wmsStyleName; @@ -96,11 +96,11 @@ public function getWmsStyleName() { public function getJSONObject ( $defText = "", $defTitle = "" ) { $parentArray = parent::getJSONObject( $defText , $defTitle ); - $array = array ( + $array = [ 'wmsServerUrl' => $this->getWmsServerUrl() , 'wmsLayerName' => $this->getWmsLayerName() , 'wmsStyleName' => $this->getWmsStyleName() - ); + ]; return array_merge( $parentArray, $array ); } diff --git a/src/Geocoders/Geocoder.php b/src/Geocoders/Geocoder.php new file mode 100644 index 000000000..ad1708e62 --- /dev/null +++ b/src/Geocoders/Geocoder.php @@ -0,0 +1,24 @@ + + */ +interface Geocoder { + + /** + * @param string $address + * + * @return LatLongValue|null + * + * TODO: specify failure behaviour. Exception or null? + */ + public function geocode( $address ); + +} \ No newline at end of file diff --git a/src/Geocoders/InMemoryGeocoder.php b/src/Geocoders/InMemoryGeocoder.php new file mode 100644 index 000000000..02303140d --- /dev/null +++ b/src/Geocoders/InMemoryGeocoder.php @@ -0,0 +1,37 @@ + + */ +class InMemoryGeocoder implements Geocoder { + + private $locations; + + /** + * @param LatLongValue[] $locations + */ + public function __construct( array $locations ) { + $this->locations = $locations; + } + + /** + * @param string $address + * + * @return LatLongValue|null + */ + public function geocode( $address ) { + if ( array_key_exists( $address, $this->locations ) ) { + return $this->locations[$address]; + } + + return null; + } + +} diff --git a/src/Geocoders/NominatimGeocoder.php b/src/Geocoders/NominatimGeocoder.php new file mode 100644 index 000000000..2a183399b --- /dev/null +++ b/src/Geocoders/NominatimGeocoder.php @@ -0,0 +1,63 @@ + + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +class NominatimGeocoder implements Geocoder { + + private $fileFetcher; + + public function __construct( FileFetcher $fileFetcher ) { + $this->fileFetcher = $fileFetcher; + } + + /** + * @param string $address + * + * @return LatLongValue|null + */ + public function geocode( $address ) { + try { + $response = $this->fileFetcher->fetchFile( $this->getRequestUrl( $address ) ); + } + catch ( FileFetchingException $ex ) { + return null; + } + + $jsonResponse = json_decode( $response ); + + if ( !is_array( $jsonResponse ) || count( $jsonResponse ) < 1 ) { + return null; + } + + $location = $jsonResponse[0]; + + if ( !isset( $location->lat ) || ! isset( $location->lon ) ) { + return null; + } + + return new LatLongValue( (float)$location->lat, (float)$location->lon ); + } + + /** + * @param string $address + * + * @return string + */ + private function getRequestUrl( $address ) { + return 'https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&q=' . urlencode( $address ); + } + +} diff --git a/src/Semantic/DataValues/CoordinateValue.php b/src/Semantic/DataValues/CoordinateValue.php new file mode 100644 index 000000000..d7f26d398 --- /dev/null +++ b/src/Semantic/DataValues/CoordinateValue.php @@ -0,0 +1,259 @@ + + * @author Markus Krötzsch + */ +class CoordinateValue extends SMWDataValue { + + private $wikiValue; + + /** + * @see SMWDataValue::setDataItem + * + * @param SMWDataItem $dataItem + * + * @return boolean + */ + protected function loadDataItem( SMWDataItem $dataItem ) { + if ( $dataItem instanceof SMWDIGeoCoord ) { + $formattedValue = $this->getFormattedCoord( $dataItem ); + + if ( $formattedValue !== null ) { + $this->wikiValue = $formattedValue; + $this->m_dataitem = $dataItem; + return true; + } + } + + return false; + } + + /** + * @param SMWDIGeoCoord $dataItem + * @param string|null $format + * + * @return string|null + */ + private function getFormattedCoord( SMWDIGeoCoord $dataItem, $format = null ) { + global $smgQPCoodFormat; + + $options = new \ValueFormatters\FormatterOptions( [ + GeoCoordinateFormatter::OPT_FORMAT => $format === null ? $smgQPCoodFormat : $format, // TODO + ] ); + + // TODO: $smgQPCoodDirectional + + $coordinateFormatter = new GeoCoordinateFormatter( $options ); + + $value = new LatLongValue( + $dataItem->getLatitude(), + $dataItem->getLongitude() + ); + + return $coordinateFormatter->format( $value ); + } + + /** + * Overwrite SMWDataValue::getQueryDescription() to be able to process + * comparators between all values. + * + * @param string $value + * + * @return Description + * @throws InvalidArgumentException + */ + public function getQueryDescription( $value ) { + if ( !is_string( $value ) ) { + throw new InvalidArgumentException( '$value needs to be a string' ); + } + + list( $distance, $comparator ) = $this->parseUserValue( $value ); + $distance = $this->parserDistance( $distance ); + + $this->setUserValue( $value ); + + switch ( true ) { + case !$this->isValid(): + return new ThingDescription(); + case $distance !== false: + return new \Maps\Semantic\ValueDescriptions\AreaDescription( $this->getDataItem(), $comparator, $distance ); + default: + return new \Maps\Semantic\ValueDescriptions\CoordinateDescription( $this->getDataItem(), null, $comparator ); + } + } + + private function parserDistance( $distance ) { + if ( $distance !== false ) { + $distance = substr( trim( $distance ), 0, -1 ); + + if ( !MapsDistanceParser::isDistance( $distance ) ) { + $this->addError( wfMessage( 'semanticmaps-unrecognizeddistance', $distance )->text() ); + $distance = false; + } + } + + return $distance; + } + + /** + * @see SMWDataValue::parseUserValue + */ + protected function parseUserValue( $value ) { + if ( !is_string( $value ) ) { + throw new InvalidArgumentException( '$value needs to be a string' ); + } + + $this->wikiValue = $value; + + $comparator = SMW_CMP_EQ; + $distance = false; + + if ( $value === '' ) { + $this->addError( wfMessage( 'smw_novalues' )->text() ); + } else { + SMWDataValue::prepareValue( $value, $comparator ); + + list( $coordinates, $distance ) = $this->findValueParts( $value ); + + $this->tryParseAndSetDataItem( $coordinates ); + } + + return [ $distance, $comparator ]; + } + + private function findValueParts( $value ) { + $parts = explode( '(', $value ); + + $coordinates = trim( array_shift( $parts ) ); + $distance = count( $parts ) > 0 ? trim( array_shift( $parts ) ) : false; + + return [ $coordinates, $distance ]; + } + + /** + * @param string $coordinates + */ + private function tryParseAndSetDataItem( $coordinates ) { + $parser = new GeoCoordinateParser(); + + try { + $value = $parser->parse( $coordinates ); + $this->m_dataitem = new SMWDIGeoCoord( $value->getLatitude(), $value->getLongitude() ); + } + catch ( ParseException $parseException ) { + $this->addError( wfMessage( 'maps_unrecognized_coords', $coordinates, 1 )->text() ); + + // Make sure this is always set + // TODO: Why is this needed?! + $this->m_dataitem = new SMWDIGeoCoord( [ 'lat' => 0, 'lon' => 0 ] ); + } + } + + /** + * @see SMWDataValue::getShortWikiText + */ + public function getShortWikiText( $linked = null ) { + if ( $this->isValid() ) { + if ( $this->m_caption === false ) { + return $this->getFormattedCoord( $this->m_dataitem ); + } + + return $this->m_caption; + } + + return $this->getErrorText(); + } + + /** + * @see SMWDataValue::getShortHTMLText + * + * @since 0.6 + */ + public function getShortHTMLText( $linker = null ) { + return $this->getShortWikiText( $linker ); + } + + /** + * @see SMWDataValue::getLongWikiText + * + * @since 0.6 + */ + public function getLongWikiText( $linked = null ) { + if ( $this->isValid() ) { + SMWOutputs::requireHeadItem( SMW_HEADER_TOOLTIP ); + + // TODO: fix lang keys so they include the space and coordinates. + $coordinateSet = $this->m_dataitem->getCoordinateSet(); + + $text = $this->getFormattedCoord( $this->m_dataitem ); + + $lines = [ + wfMessage( 'semanticmaps-latitude', $coordinateSet['lat'] )->inContentLanguage()->escaped(), + wfMessage( 'semanticmaps-longitude', $coordinateSet['lon'] )->inContentLanguage()->escaped(), + ]; + + if ( array_key_exists( 'alt', $coordinateSet ) ) { + $lines[] = wfMessage( 'semanticmaps-altitude', $coordinateSet['alt'] )->inContentLanguage()->escaped(); + } + + return '' . htmlspecialchars( $text ) . '' . + implode( '
', $lines ) . + '
'; + } else { + return $this->getErrorText(); + } + } + + /** + * @see SMWDataValue::getLongHTMLText + */ + public function getLongHTMLText( $linker = null ) { + return $this->getLongWikiText( $linker ); + } + + /** + * @see SMWDataValue::getWikiValue + */ + public function getWikiValue() { + return $this->wikiValue; + } + + /** + * Create links to mapping services based on a wiki-editable message. The parameters + * available to the message are: + * + * $1: The location in non-directional float notation. + * $2: The location in directional DMS notation. + * $3: The latitude in non-directional float notation. + * $4 The longitude in non-directional float notation. + * + * @return array + */ + protected function getServiceLinkParams() { + $coordinateSet = $this->m_dataitem->getCoordinateSet(); + return [ + $this->getFormattedCoord( $this->m_dataitem, 'float' ), // TODO + $this->getFormattedCoord( $this->m_dataitem, 'dms' ), // TODO + $coordinateSet['lat'], + $coordinateSet['lon'] + ]; + } + +} diff --git a/src/Semantic/DataValues/GeoPolygonValue.php b/src/Semantic/DataValues/GeoPolygonValue.php new file mode 100644 index 000000000..ed553297f --- /dev/null +++ b/src/Semantic/DataValues/GeoPolygonValue.php @@ -0,0 +1,109 @@ +m_dataitem = $dataItem; + return true; + } + + return false; + } + + /** + * NOTE: Do param validation. + * TODO: Stores as a Blob, use better data structure + * @see SMWDataValue::parseUserValue + * + * @since 2.0 + */ + protected function parseUserValue( $value ) { + if ( $value === '' ) { + $this->addError( wfMessage( 'smw_emptystring' )->inContentLanguage()->text() ); + } + + foreach( ( new PolygonHandler( $value ) )->getValidationErrors() as $errMsg ) { + $this->addError( $errMsg ); + } + + $this->m_dataitem = new SMWDIBlob( $value, $this->m_typeid ); + } + + /** + * @see SMWDataValue::getShortWikiText + * + * @since 2.0 + */ + public function getShortWikiText( $linked = null ) { + if ( $this->isValid() ) { + return $this->m_dataitem->getString(); + } + + return $this->getErrorText(); + } + + /** + * @see SMWDataValue::getShortHTMLText + * + * @since 2.0 + */ + public function getShortHTMLText( $linker = null ) { + return $this->getShortWikiText( $linker ); + } + + /** + * @see SMWDataValue::getLongWikiText + * + * @since 2.0 + */ + public function getLongWikiText( $linker = null ) { + return $this->getShortWikiText( $linker ); + } + + /** + * @see SMWDataValue::getLongHTMLText + * + * @since 2.0 + */ + public function getLongHTMLText( $linker = null ) { + return $this->getLongWikiText( $linker ); + } + + /** + * @see SMWDataValue::getWikiValue + * + * @since 2.0 + */ + public function getWikiValue() { + return $this->m_dataitem->getString(); + } + + /** + * @see SMWDataValue::getExportData + * + * @since 2.0 + */ + public function getExportData() { + return null; + } +} diff --git a/src/Semantic/ValueDescriptions/AreaDescription.php b/src/Semantic/ValueDescriptions/AreaDescription.php new file mode 100644 index 000000000..b29688c90 --- /dev/null +++ b/src/Semantic/ValueDescriptions/AreaDescription.php @@ -0,0 +1,160 @@ + + */ +class AreaDescription extends ValueDescription { + + /** + * @var SMWDIGeoCoord + */ + private $center; + + /** + * @var string + */ + private $radius; + + /** + * @param SMWDataItem $areaCenter + * @param string $comparator + * @param string $radius + * @param DIProperty|null $property + * + * @throws InvalidArgumentException + */ + public function __construct( SMWDataItem $areaCenter, $comparator, $radius, DIProperty $property = null ) { + if ( !( $areaCenter instanceof SMWDIGeoCoord ) ) { + throw new InvalidArgumentException( '$areaCenter needs to be a SMWDIGeoCoord' ); + } + + parent::__construct( $areaCenter, $property, $comparator ); + + $this->center = $areaCenter; + $this->radius = $radius; + } + + /** + * @see \SMW\Query\Language\Description::getQueryString + * + * @param boolean $asValue + * @return string + */ + public function getQueryString( $asValue = false ) { + $centerString = DataValueFactory::newDataItemValue( $this->center, $this->getProperty() )->getWikiValue(); + + $queryString = "$centerString ({$this->radius})"; + + return $asValue ? $queryString : "[[$queryString]]"; + } + + /** + * @see \SMW\Query\Language\Description::prune + */ + public function prune( &$maxsize, &$maxdepth, &$log ) { + if ( ( $maxsize < $this->getSize() ) || ( $maxdepth < $this->getDepth() ) ) { + $log[] = $this->getQueryString(); + + $result = new SMWThingDescription(); + $result->setPrintRequests( $this->getPrintRequests() ); + + return $result; + } + + $maxsize = $maxsize - $this->getSize(); + $maxdepth = $maxdepth - $this->getDepth(); + + return $this; + } + + /** + * @see \SMW\Query\Language\Description::getSQLCondition + * + * FIXME: store specific code should be in the store component + * + * @param string $tableName + * @param array $fieldNames + * @param DatabaseBase $dbs + * + * @return string|false + */ + public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) { + if ( $this->center->getDIType() != SMWDataItem::TYPE_GEO ) { + throw new \LogicException( 'Constructor should have prevented this' ); + } + + if ( !$this->comparatorIsSupported() ) { + return false; + } + + $bounds = $this->getBoundingBox(); + + $north = $dbs->addQuotes( $bounds['north'] ); + $east = $dbs->addQuotes( $bounds['east'] ); + $south = $dbs->addQuotes( $bounds['south'] ); + $west = $dbs->addQuotes( $bounds['west'] ); + + $isEq = $this->getComparator() == SMW_CMP_EQ; + + $smallerThen = $isEq ? '<' : '>='; + $biggerThen = $isEq ? '>' : '<='; + $joinCond = $isEq ? 'AND' : 'OR'; + + $conditions = []; + + $conditions[] = "{$tableName}.$fieldNames[1] $smallerThen $north"; + $conditions[] = "{$tableName}.$fieldNames[1] $biggerThen $south"; + $conditions[] = "{$tableName}.$fieldNames[2] $smallerThen $east"; + $conditions[] = "{$tableName}.$fieldNames[2] $biggerThen $west"; + + return implode( " $joinCond ", $conditions ); + } + + private function comparatorIsSupported() { + return $this->getComparator() === SMW_CMP_EQ || $this->getComparator() === SMW_CMP_NEQ; + } + + /** + * @return float[] An associative array containing the limits with keys north, east, south and west. + */ + public function getBoundingBox() { + $center = new LatLongValue( + $this->center->getLatitude(), + $this->center->getLongitude() + ); + + $radiusInMeters = MapsDistanceParser::parseDistance( $this->radius ); // TODO: this can return false + + $north = MapsGeoFunctions::findDestination( $center, 0, $radiusInMeters ); + $east = MapsGeoFunctions::findDestination( $center, 90, $radiusInMeters ); + $south = MapsGeoFunctions::findDestination( $center, 180, $radiusInMeters ); + $west = MapsGeoFunctions::findDestination( $center, 270, $radiusInMeters ); + + return [ + 'north' => $north['lat'], + 'east' => $east['lon'], + 'south' => $south['lat'], + 'west' => $west['lon'], + ]; + } + +} \ No newline at end of file diff --git a/src/Semantic/ValueDescriptions/CoordinateDescription.php b/src/Semantic/ValueDescriptions/CoordinateDescription.php new file mode 100644 index 000000000..fc778cabb --- /dev/null +++ b/src/Semantic/ValueDescriptions/CoordinateDescription.php @@ -0,0 +1,71 @@ +getDataItem(), $this->getProperty() )->getWikiValue(); + return $asValue ? $queryString : "[[$queryString]]"; + } + + /** + * @see SMWDescription::getSQLCondition + * + * FIXME: store specific code should be in the store component + * + * @since 0.6 + * + * @param string $tableName + * @param array $fieldNames + * @param DatabaseBase $dbs + * + * @return string|false + */ + public function getSQLCondition( $tableName, array $fieldNames, DatabaseBase $dbs ) { + $dataItem = $this->getDataItem(); + + // Only execute the query when the description's type is geographical coordinates, + // the description is valid, and the near comparator is used. + if ( $dataItem instanceof SMWDIGeoCoord ) { + switch ( $this->getComparator() ) { + case SMW_CMP_EQ: $comparator = '='; break; + case SMW_CMP_LEQ: $comparator = '<='; break; + case SMW_CMP_GEQ: $comparator = '>='; break; + case SMW_CMP_NEQ: $comparator = '!='; break; + default: return false; + } + + $lat = $dbs->addQuotes( $dataItem->getLatitude() ); + $lon = $dbs->addQuotes( $dataItem->getLongitude() ); + + $conditions = []; + + $conditions[] = "{$tableName}.$fieldNames[1] $comparator $lat"; + $conditions[] = "{$tableName}.$fieldNames[2] $comparator $lon"; + + return implode( ' AND ', $conditions ); + } + + return false; + } + +} \ No newline at end of file diff --git a/src/SemanticMaps.php b/src/SemanticMaps.php new file mode 100644 index 000000000..f650597ca --- /dev/null +++ b/src/SemanticMaps.php @@ -0,0 +1,138 @@ + + */ +class SemanticMaps { + + private $mwGlobals; + + public static function newFromMediaWikiGlobals( array &$mwGlobals ) { + return new self( $mwGlobals ); + } + + private function __construct( array &$mwGlobals ) { + $this->mwGlobals =& $mwGlobals; + } + + public function initExtension() { + // Hook for initializing the Geographical Data types. + $this->mwGlobals['wgHooks']['SMW::DataType::initTypes'][] = 'SemanticMapsHooks::initGeoDataTypes'; + + // Hook for defining the default query printer for queries that ask for geographical coordinates. + $this->mwGlobals['wgHooks']['SMWResultFormat'][] = 'SemanticMapsHooks::addGeoCoordsDefaultFormat'; + + // Hook for adding a Semantic Maps links to the Admin Links extension. + $this->mwGlobals['wgHooks']['AdminLinks'][] = 'SemanticMapsHooks::addToAdminLinks'; + + $this->registerResourceModules(); + + $this->registerGoogleMaps(); + $this->registerLeaflet(); + $this->registerOpenLayers(); + + $this->mwGlobals['smwgResultFormats']['kml'] = SMKMLPrinter::class; + + $this->mwGlobals['smwgResultAliases'][$this->mwGlobals['egMapsDefaultServices']['qp']][] = 'map'; + SMMapPrinter::registerDefaultService( $this->mwGlobals['egMapsDefaultServices']['qp'] ); + + // Internationalization + $this->mwGlobals['wgMessagesDirs']['SemanticMaps'] = __DIR__ . '/i18n'; + } + + private function registerResourceModules() { + $moduleTemplate = [ + 'position' => 'bottom', + 'group' => 'ext.semanticmaps', + ]; + + $this->mwGlobals['wgResourceModules']['ext.sm.common'] = $moduleTemplate + [ + 'localBasePath' => __DIR__ . '/../SemanticMaps/src', + 'remoteExtPath' => 'Maps/SemanticMaps/src', + 'scripts' => [ + 'ext.sm.common.js' + ] + ]; + } + + private function registerGoogleMaps() { + $this->mwGlobals['wgResourceModules']['ext.sm.googlemaps3ajax'] = [ + 'localBasePath' => __DIR__ . '/../SemanticMaps/src/services/GoogleMaps3', + 'remoteExtPath' => 'Maps/SemanticMaps/src/services/GoogleMaps3', + 'group' => 'ext.semanticmaps', + 'dependencies' => [ + 'ext.maps.googlemaps3', + 'ext.sm.common' + ], + 'scripts' => [ + 'ext.sm.googlemaps3ajax.js' + ] + ]; + + /* @var MapsMappingService $googleMaps */ + $googleMaps = MapsMappingServices::getServiceInstance( 'googlemaps3' ); + $googleMaps->addResourceModules( [ 'ext.sm.googlemaps3ajax' ] ); + + SMMapPrinter::registerService( $googleMaps ); + + $this->mwGlobals['smwgResultFormats'][$googleMaps->getName()] = SMMapPrinter::class; + $this->mwGlobals['smwgResultAliases'][$googleMaps->getName()] = $googleMaps->getAliases(); + } + + private function registerLeaflet() { + $this->mwGlobals['wgResourceModules']['ext.sm.fi.leafletajax'] = [ + 'localBasePath' => __DIR__ . '/../SemanticMaps/src/services/Leaflet', + 'remoteExtPath' => 'Maps/SemanticMaps/src/services/Leaflet', + 'group' => 'ext.semanticmaps', + 'dependencies' => [ + 'ext.maps.leaflet', + 'ext.sm.common' + ], + 'scripts' => [ + 'ext.sm.leafletajax.js' + ] + ]; + + /* @var MapsMappingService $leaflet */ + $leaflet = MapsMappingServices::getServiceInstance( 'leaflet' ); + $leaflet->addResourceModules( [ 'ext.sm.fi.leafletajax' ] ); + + SMMapPrinter::registerService( $leaflet ); + + $this->mwGlobals['smwgResultFormats'][$leaflet->getName()] = SMMapPrinter::class; + $this->mwGlobals['smwgResultAliases'][$leaflet->getName()] = $leaflet->getAliases(); + } + + private function registerOpenLayers() { + $this->mwGlobals['wgResourceModules']['ext.sm.fi.openlayersajax'] = [ + 'localBasePath' => __DIR__ . '/../SemanticMaps/src/services/OpenLayers', + 'remoteExtPath' => 'Maps/SemanticMaps/src/services/OpenLayers', + 'group' => 'ext.semanticmaps', + 'dependencies' => [ + 'ext.maps.openlayers', + 'ext.sm.common' + ], + 'scripts' => [ + 'ext.sm.openlayersajax.js' + ] + ]; + + /* @var MapsMappingService $openLayers */ + $openLayers = MapsMappingServices::getServiceInstance( 'openlayers' ); + $openLayers->addResourceModules( [ 'ext.sm.fi.openlayersajax' ] ); + + SMMapPrinter::registerService( $openLayers ); + + $this->mwGlobals['smwgResultFormats'][$openLayers->getName()] = SMMapPrinter::class; + $this->mwGlobals['smwgResultAliases'][$openLayers->getName()] = $openLayers->getAliases(); + } + +} diff --git a/tests/phpunit/MapsDistanceParserTest.php b/tests/Integration/MapsDistanceParserTest.php similarity index 88% rename from tests/phpunit/MapsDistanceParserTest.php rename to tests/Integration/MapsDistanceParserTest.php index b9c5a94d2..e2ca03acb 100644 --- a/tests/phpunit/MapsDistanceParserTest.php +++ b/tests/Integration/MapsDistanceParserTest.php @@ -5,18 +5,20 @@ use MapsDistanceParser; /** - * @covers MapsCoordinates - * - * @since 0.6.5 - * - * @group Maps + * @covers MapsDistanceParser * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ -class MapsDistanceParserTest extends \MediaWikiTestCase { - - public static $distances = array( +class MapsDistanceParserTest extends \PHPUnit_Framework_TestCase { + + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + + public static $distances = [ '1' => 1, '1m' => 1, '1 m' => 1, @@ -30,33 +32,33 @@ class MapsDistanceParserTest extends \MediaWikiTestCase { '1 mile' => 1609.344, '10 nauticalmiles' => 18520, '1.0nautical mile' => 1852, - ); + ]; - public static $formatTests = array( - 'm' => array( + public static $formatTests = [ + 'm' => [ '1 m' => 1, '1000 m' => 1000.00, '42.42 m' => 42.42, '42.4242 m' => 42.4242, - ), - 'km' => array( + ], + 'km' => [ //'0.001 km' => 1, '1 km' => 1000, '4.24 km' => 4242, - ), - 'kilometers' => array( + ], + 'kilometers' => [ '0.001 kilometers' => 1, '1 kilometers' => 1000, '4.24 kilometers' => 4242, - ), - ); + ], + ]; /** * Invalid distances. * * @var array */ - public static $fakeDistances = array( + public static $fakeDistances = [ 'IN YOUR CODE, BEING TOTALLY RIDICULOUS', '0x20 km', 'km 42', @@ -64,7 +66,7 @@ class MapsDistanceParserTest extends \MediaWikiTestCase { '42 km km', '42 foo', '3.4.2 km' - ); + ]; /** * Tests MapsDistanceParser::parseDistance() @@ -92,9 +94,9 @@ public function testFormatDistance() { * Tests MapsDistanceParser::parseAndFormat() */ public function testParseAndFormat() { - $conversions = array( + $conversions = [ '42 km' => '42000 m' - ); + ]; foreach( array_merge( $conversions, array_reverse( $conversions ) ) as $source => $target ) { global $wgContLang; @@ -138,7 +140,7 @@ public function testGetValidUnit() { global $egMapsDistanceUnit; - foreach ( array( '0', 'swfwdffdhy', 'dxwgdrfh' ) as $unit ) { + foreach ( [ '0', 'swfwdffdhy', 'dxwgdrfh' ] as $unit ) { $u = MapsDistanceParser::getValidUnit( $unit ); $this->assertEquals( $egMapsDistanceUnit, $u, "The valid unit for '$unit' should be '$egMapsDistanceUnit' but was '$u'" ); } diff --git a/tests/Integration/MapsMapperTest.php b/tests/Integration/MapsMapperTest.php new file mode 100644 index 000000000..3b3e521b3 --- /dev/null +++ b/tests/Integration/MapsMapperTest.php @@ -0,0 +1,47 @@ + + */ +class MapsMapperTest extends \PHPUnit_Framework_TestCase { + + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + + public function imageUrlProvider() { + return [ + ['markerImage.png', 'markerImage.png'], + ['/w/images/c/ce/Green_marker.png', '/w/images/c/ce/Green_marker.png'], + ['//semantic-mediawiki.org/w/images/c/ce/Green_marker.png', '//semantic-mediawiki.org/w/images/c/ce/Green_marker.png'], + ['Cat2.jpg', 'Cat2.jpg'], + ]; + } + + /** + * Tests MapsMapperTest::getFileUrl() + * + * @dataProvider imageUrlProvider + */ + public function testGetFileUrl($file, $expected) { + $this->assertSame( $expected, MapsMapper::getFileUrl($file) ); + } + + /** + * Tests MapsMapperTest::getFileUrl() + */ + public function testGivenNull_getFileUrlReturnsNull() { + $this->assertNull( MapsMapper::getFileUrl(null)); + } + + // TODO test with existing imagePage +} diff --git a/tests/Integration/Semantic/ValueDescriptions/AreaDescriptionTest.php b/tests/Integration/Semantic/ValueDescriptions/AreaDescriptionTest.php new file mode 100644 index 000000000..58ca376fb --- /dev/null +++ b/tests/Integration/Semantic/ValueDescriptions/AreaDescriptionTest.php @@ -0,0 +1,83 @@ + + */ +class AreaDescriptionTest extends \PHPUnit_Framework_TestCase { + + public function setUp() { + if ( !defined( 'SMW_VERSION' ) ) { + $this->markTestSkipped( 'SMW is not available' ); + } + } + + public function testGetBoundingBox() { + $area = new AreaDescription( + new SMWDIGeoCoord( 0, 5 ), + SMW_CMP_EQ, + '10 km' + ); + + $this->assertEquals( + [ + 'north' => 0.089932160591873, + 'east' => 5.089932160591873, + 'south' => -0.089932160591873, + 'west' => 4.9100678394081 + ], + $area->getBoundingBox() + ); + } + + public function testGetSQLCondition() { + $area = new AreaDescription( + new SMWDIGeoCoord( 0, 5 ), + SMW_CMP_EQ, + '10 km' + ); + + $this->assertSame( + 'geo_table.lat_field < \'0.089932160591873\' AND geo_table.lat_field > \'-0.089932160591873\' ' + . 'AND geo_table.long_field < \'5.0899321605919\' AND geo_table.long_field > \'4.9100678394081\'', + $area->getSQLCondition( 'geo_table', ['id_field', 'lat_field', 'long_field'], wfGetDB( DB_MASTER ) ) + ); + } + + public function testWhenComparatorIsNotSupported_getSQLConditionReturnsFalse() { + $area = new AreaDescription( + new SMWDIGeoCoord( 0, 5 ), + SMW_CMP_LIKE, + '10 km' + ); + + $this->assertFalse( + $area->getSQLCondition( 'geo_table', ['id_field', 'lat_field', 'long_field'], wfGetDB( DB_MASTER ) ) + ); + } + + public function testGetQueryString() { + $area = new AreaDescription( + new SMWDIGeoCoord( 1, 5 ), + SMW_CMP_EQ, + '10 km' + ); + + $this->assertSame( + '[[1° 0\' 0", 5° 0\' 0" (10 km)]]', + $area->getQueryString() + ); + } + +} diff --git a/tests/phpunit/parserhooks/CoordinatesTest.php b/tests/Integration/parserhooks/CoordinatesTest.php similarity index 71% rename from tests/phpunit/parserhooks/CoordinatesTest.php rename to tests/Integration/parserhooks/CoordinatesTest.php index b07541164..20bd5be64 100644 --- a/tests/phpunit/parserhooks/CoordinatesTest.php +++ b/tests/Integration/parserhooks/CoordinatesTest.php @@ -8,10 +8,6 @@ /** * @covers MapsCoordinates * - * @group Maps - * @group ParserHook - * @group CoordinatesTest - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -19,8 +15,6 @@ class CoordinatesTest extends ParserHookTest { /** * @see ParserHookTest::getInstance - * @since 2.0 - * @return \ParserHook */ protected function getInstance() { return new \MapsCoordinates(); @@ -28,105 +22,101 @@ protected function getInstance() { /** * @see ParserHookTest::parametersProvider - * @since 2.0 - * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; - $paramLists[] = array( - array( + $paramLists[] = [ + [ 'location' => '4,2', 'format' => 'dms', 'directional' => 'no', - ), + ], '4° 0\' 0.00", 2° 0\' 0.00"' - ); + ]; - $paramLists[] = array( - array( + $paramLists[] = [ + [ 'location' => '55 S, 37.6176330 W', 'format' => 'dms', 'directional' => 'no', - ), + ], '-55° 0\' 0.00", -37° 37\' 3.48"' - ); + ]; - $paramLists[] = array( - array( + $paramLists[] = [ + [ 'location' => '4,2', 'format' => 'float', 'directional' => 'no', - ), + ], '4, 2' - ); + ]; - $paramLists[] = array( - array( + $paramLists[] = [ + [ 'location' => '-4,-2', 'format' => 'float', 'directional' => 'yes', - ), + ], '4 S, 2 W' - ); + ]; - $paramLists[] = array( - array( + $paramLists[] = [ + [ 'location' => '55 S, 37.6176330 W', 'directional' => 'yes', - ), + ], '55° 0\' 0.00" S, 37° 37\' 3.48" W' - ); + ]; return $paramLists; } /** * @see ParserHookTest::processingProvider - * @since 3.0 - * @return array */ public function processingProvider() { $definitions = ParamDefinition::getCleanDefinitions( $this->getInstance()->getParamDefinitions() ); - $argLists = array(); + $argLists = []; - $values = array( + $values = [ 'location' => '4,2', - ); + ]; - $expected = array( + $expected = [ 'location' => new LatLongValue( 4, 2 ), - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; - $values = array( + $values = [ 'location' => '4,2', 'directional' => $definitions['directional']->getDefault() ? 'no' : 'yes', 'format' => 'dd', - ); + ]; - $expected = array( + $expected = [ 'location' => new LatLongValue( 4, 2 ), 'directional' => !$definitions['directional']->getDefault(), 'format' => Maps_COORDS_DD, - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; - $values = array( + $values = [ 'location' => '4,2', 'directional' => $definitions['directional']->getDefault() ? 'NO' : 'YES', 'format' => ' DD ', - ); + ]; - $expected = array( + $expected = [ 'location' => new LatLongValue( 4, 2 ), 'directional' => !$definitions['directional']->getDefault(), 'format' => Maps_COORDS_DD, - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; return $argLists; } diff --git a/tests/phpunit/parserhooks/DisplayMapTest.php b/tests/Integration/parserhooks/DisplayMapTest.php similarity index 61% rename from tests/phpunit/parserhooks/DisplayMapTest.php rename to tests/Integration/parserhooks/DisplayMapTest.php index c74d067a6..0ea625f84 100644 --- a/tests/phpunit/parserhooks/DisplayMapTest.php +++ b/tests/Integration/parserhooks/DisplayMapTest.php @@ -2,15 +2,12 @@ namespace Maps\Test; +use DataValues\Geo\Values\LatLongValue; use Maps\Elements\Location; /** * @covers MapsDisplayMap * - * @group Maps - * @group ParserHook - * @group DisplayMapTest - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -31,54 +28,50 @@ protected function getInstance() { * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; // TODO - $paramLists[] = array( 'coordinates' => '4,2' ); + $paramLists[] = [ 'coordinates' => '4,2' ]; - $paramLists[] = array( 'location' => '4,2' ); + $paramLists[] = [ 'location' => '4,2' ]; - $paramLists[] = array( 'location' => 'new york city' ); + $paramLists[] = [ 'location' => 'new york city' ]; - $paramLists[] = array( + $paramLists[] = [ 'service' => 'googlemaps', 'location' => 'new york city', 'zoom' => '10', 'minzoom' => '5', 'maxzoom' => '7', 'autozoom' => 'off', - ); + ]; return $this->arrayWrap( $paramLists ); } - public function testForSomeReasonPhpSegfaultsIfThereIsOneMethodLess() { - $this->assertTrue( (bool)'This is fucking weird' ); - } - /** * @see ParserHookTest::processingProvider * @since 3.0 * @return array */ public function processingProvider() { - $argLists = array(); + $argLists = []; - $values = array( - 'locations' => '4,2', + $values = [ + 'locations' => '4,2; New York City; 13,37', 'width' => '420', 'height' => '420', 'service' => 'openlayers', - ); + ]; - $expected = array( - 'coordinates' => array( new Location( new \DataValues\LatLongValue( 4, 2 ) ) ), + $expected = [ + 'coordinates' => [ '4,2', 'New York City', '13,37' ], 'width' => '420px', 'height' => '420px', 'mappingservice' => 'openlayers', - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; return $argLists; } diff --git a/tests/phpunit/parserhooks/DistanceTest.php b/tests/Integration/parserhooks/DistanceTest.php similarity index 62% rename from tests/phpunit/parserhooks/DistanceTest.php rename to tests/Integration/parserhooks/DistanceTest.php index 3f25b02ea..4b4ed0e9f 100644 --- a/tests/phpunit/parserhooks/DistanceTest.php +++ b/tests/Integration/parserhooks/DistanceTest.php @@ -5,47 +5,35 @@ /** * @covers MapsDistance * - * @group Maps - * @group ParserHook - * @group MapsDistanceTest - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class DistanceTest extends ParserHookTest { - /** - * @see ParserHookTest::getInstance - * @since 2.0 - * @return \ParserHook - */ - protected function getInstance() { - return new \MapsDistance(); - } - - /** - * @since 3.0 - * @var array - */ - protected $distances = array( + private $distances = [ '42' => 42, '42m' => 42, '42 m' => 42, '42 km' => 42000, '4.2 km' => 4200, '4.2 m' => 4.2, - ); + ]; + + /** + * @see ParserHookTest::getInstance + */ + protected function getInstance() { + return new \MapsDistance(); + } /** * @see ParserHookTest::parametersProvider - * @since 2.0 - * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; foreach ( array_keys( $this->distances ) as $distance ) { - $paramLists[] = array( 'distance' => (string)$distance ); + $paramLists[] = [ 'distance' => (string)$distance ]; } return $this->arrayWrap( $paramLists ); @@ -53,49 +41,47 @@ public function parametersProvider() { /** * @see ParserHookTest::processingProvider - * @since 3.0 - * @return array */ public function processingProvider() { - $argLists = array(); + $argLists = []; foreach ( $this->distances as $input => $output ) { - $values = array( + $values = [ 'distance' => (string)$input, - ); + ]; - $expected = array( + $expected = [ 'distance' => $output, - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; } - $values = array( + $values = [ 'distance' => '42m', 'unit' => 'km', 'decimals' => '1', - ); + ]; - $expected = array( + $expected = [ 'distance' => 42, 'unit' => 'km', 'decimals' => 1, - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; - $values = array( + $values = [ 'distance' => '42m', 'unit' => '~=[,,_,,]:3', 'decimals' => 'foobar', - ); + ]; - $expected = array( + $expected = [ 'distance' => 42, - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; return $argLists; } diff --git a/tests/phpunit/parserhooks/FinddestinationTest.php b/tests/Integration/parserhooks/FinddestinationTest.php similarity index 66% rename from tests/phpunit/parserhooks/FinddestinationTest.php rename to tests/Integration/parserhooks/FinddestinationTest.php index 67009e180..1ac170636 100644 --- a/tests/phpunit/parserhooks/FinddestinationTest.php +++ b/tests/Integration/parserhooks/FinddestinationTest.php @@ -8,52 +8,37 @@ /** * @covers MapsFinddestination * - * @group Maps - * @group ParserHook - * @group MapsFinddestinationTest - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class FinddestinationTest extends ParserHookTest { /** - * @since 3.0 * @var string[] */ - protected $locations = array( + private $locations = [ '4,2', '4.2,-42', - ); + ]; - /** - * @since 3.0 - * @var array - */ - protected $bearings = array( + private $bearings = [ 1, 42, -42, 0, 4.2, - ); + ]; - /** - * @since 3.0 - * @var string[] - */ - protected $distances = array( + private $distances = [ '42' => 42, '0' => 0, '42 m' => 42, '42 km' => 42000, '4.2 km' => 4200, - ); + ]; /** * @see ParserHookTest::getInstance - * @since 2.0 - * @return \ParserHook */ protected function getInstance() { return new \MapsFinddestination(); @@ -61,47 +46,43 @@ protected function getInstance() { /** * @see ParserHookTest::parametersProvider - * @since 2.0 - * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; - $paramLists[] = array( + $paramLists[] = [ 'location' => '4,2', 'bearing' => '1', 'distance' => '42 km' - ); + ]; return $this->arrayWrap( $paramLists ); } /** * @see ParserHookTest::processingProvider - * @since 3.0 - * @return array */ public function processingProvider() { - $argLists = array(); + $argLists = []; $coordinateParser = new GeoCoordinateParser( new \ValueParsers\ParserOptions() ); foreach ( $this->distances as $distance => $expectedDistance ) { foreach ( $this->bearings as $bearing ) { - foreach ( $this->locations as $location ) { - $values = array( + foreach ( $this->locations as $locationString ) { + $values = [ 'distance' => (string)$distance, 'bearing' => (string)$bearing, - 'location' => (string)$location, - ); + 'location' => (string)$locationString, + ]; - $expected = array( + $expected = [ 'distance' => $expectedDistance, 'bearing' => (float)$bearing, - 'location' => new Location( $coordinateParser->parse( $location )->getValue() ), - ); + 'location' => new Location( $coordinateParser->parse( $locationString )->getValue() ), + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; } } } diff --git a/tests/phpunit/parserhooks/GeocodeTest.php b/tests/Integration/parserhooks/GeocodeTest.php similarity index 53% rename from tests/phpunit/parserhooks/GeocodeTest.php rename to tests/Integration/parserhooks/GeocodeTest.php index c3bb0878f..62fdaebed 100644 --- a/tests/phpunit/parserhooks/GeocodeTest.php +++ b/tests/Integration/parserhooks/GeocodeTest.php @@ -2,14 +2,12 @@ namespace Maps\Test; +use DataValues\Geo\Values\LatLongValue; use Maps\Elements\Location; /** * @covers MapsGeocode * - * @group Maps - * @group ParserHook - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -17,8 +15,6 @@ class GeocodeTest extends ParserHookTest { /** * @see ParserHookTest::getInstance - * @since 2.0 - * @return \ParserHook */ protected function getInstance() { return new \MapsGeocode(); @@ -26,36 +22,31 @@ protected function getInstance() { /** * @see ParserHookTest::parametersProvider - * @since 2.0 - * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; - $paramLists[] = array( 'location' => 'new york city' ); + $paramLists[] = [ 'location' => 'new york city' ]; return $this->arrayWrap( $paramLists ); } /** * @see ParserHookTest::processingProvider - * @since 3.0 - * @return array */ public function processingProvider() { - $argLists = array(); - - $values = array( - 'location' => '4,2', - 'allowcoordinates' => 'yes', - ); - - $expected = array( - 'location' => new Location( new \DataValues\LatLongValue( 4, 2 ) ), - 'allowcoordinates' => true, - ); - - $argLists[] = array( $values, $expected ); + $argLists = []; + + $argLists[] = [ + [ + 'location' => '4,2', + 'allowcoordinates' => 'yes', + ], + [ + 'location' => '4,2', + 'allowcoordinates' => true, + ] + ]; return $argLists; } diff --git a/tests/phpunit/parserhooks/GeodistanceTest.php b/tests/Integration/parserhooks/GeodistanceTest.php similarity index 72% rename from tests/phpunit/parserhooks/GeodistanceTest.php rename to tests/Integration/parserhooks/GeodistanceTest.php index 3d7e21a79..232187c84 100644 --- a/tests/phpunit/parserhooks/GeodistanceTest.php +++ b/tests/Integration/parserhooks/GeodistanceTest.php @@ -3,15 +3,12 @@ namespace Maps\Test; use DataValues\Geo\Values\LatLongValue; +use Maps\ElementOptions; use Maps\Elements\Location; /** * @covers MapsGeodistance * - * @group Maps - * @group ParserHook - * @group GeodistanceTest - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -19,8 +16,6 @@ class GeodistanceTest extends ParserHookTest { /** * @see ParserHookTest::getInstance - * @since 2.0 - * @return \ParserHook */ protected function getInstance() { return new \MapsGeodistance(); @@ -28,21 +23,19 @@ protected function getInstance() { /** * @see ParserHookTest::parametersProvider - * @since 2.0 - * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; - $paramLists[] = array( + $paramLists[] = [ 'location1' => '4,2', 'location2' => '42,0', - ); + ]; - $paramLists[] = array( + $paramLists[] = [ '4,2', '42,0', - ); + ]; return $this->arrayWrap( $paramLists ); } @@ -53,34 +46,34 @@ public function parametersProvider() { * @return array */ public function processingProvider() { - $argLists = array(); + $argLists = []; - $values = array( + $values = [ 'location1' => '4,2', 'location2' => '42,0', - ); + ]; - $expected = array( + $expected = [ 'location1' => new Location( new LatLongValue( 4, 2 ) ), 'location2' => new Location( new LatLongValue( 42, 0 ) ), - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; - $values = array( + $values = [ 'location1' => '4,2', 'location2' => '42,0', 'unit' => '~=[,,_,,]:3', 'decimals' => '1', - ); + ]; - $expected = array( + $expected = [ 'location1' => new Location( new LatLongValue( 4, 2 ) ), 'location2' => new Location( new LatLongValue( 42, 0 ) ), 'decimals' => 1, - ); + ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; return $argLists; } diff --git a/tests/phpunit/parserhooks/MapsDocTest.php b/tests/Integration/parserhooks/MapsDocTest.php similarity index 52% rename from tests/phpunit/parserhooks/MapsDocTest.php rename to tests/Integration/parserhooks/MapsDocTest.php index 77151bacf..bbe760a28 100644 --- a/tests/phpunit/parserhooks/MapsDocTest.php +++ b/tests/Integration/parserhooks/MapsDocTest.php @@ -5,9 +5,6 @@ /** * @covers MapsMapsDoc * - * @group Maps - * @group ParserHook - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -15,8 +12,6 @@ class MapsDocTest extends ParserHookTest { /** * @see ParserHookTest::getInstance - * @since 2.0 - * @return \ParserHook */ protected function getInstance() { return new \MapsMapsDoc(); @@ -24,37 +19,33 @@ protected function getInstance() { /** * @see ParserHookTest::parametersProvider - * @since 2.0 - * @return array */ public function parametersProvider() { - $paramLists = array(); + $paramLists = []; - $paramLists[] = array(); + $paramLists[] = []; return $this->arrayWrap( $paramLists ); } /** * @see ParserHookTest::processingProvider - * @since 3.0 - * @return array */ public function processingProvider() { - $argLists = array(); + $argLists = []; - $values = array( 'service' => 'googlemaps3' ); + $values = [ 'service' => 'googlemaps3' ]; - $expected = array( 'service' => 'googlemaps3' ); + $expected = [ 'service' => 'googlemaps3' ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; - $values = array( 'service' => 'GOOGLEmaps3' ); + $values = [ 'service' => 'GOOGLEmaps3' ]; - $expected = array( 'service' => 'googlemaps3' ); + $expected = [ 'service' => 'googlemaps3' ]; - $argLists[] = array( $values, $expected ); + $argLists[] = [ $values, $expected ]; return $argLists; } diff --git a/tests/phpunit/parserhooks/ParserHookTest.php b/tests/Integration/parserhooks/ParserHookTest.php similarity index 89% rename from tests/phpunit/parserhooks/ParserHookTest.php rename to tests/Integration/parserhooks/ParserHookTest.php index f8a274182..473de3ea0 100644 --- a/tests/phpunit/parserhooks/ParserHookTest.php +++ b/tests/Integration/parserhooks/ParserHookTest.php @@ -6,14 +6,17 @@ use ParamProcessor\Processor; /** - * @group Maps - * @group ParserHook - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ abstract class ParserHookTest extends \PHPUnit_Framework_TestCase { + public static function setUpBeforeClass() { + if ( !defined( 'MEDIAWIKI' ) ) { + self::markTestSkipped( 'MediaWiki is not available' ); + } + } + /** * @since 2.0 * @return \ParserHook @@ -44,8 +47,8 @@ public function testRender( array $parameters, $expected = null ) { $parser->setTitle( \Title::newMainPage() ); $renderResult = call_user_func_array( - array( $parserHook, 'renderFunction' ), - array_merge( array( &$parser ), $parameters ) + [ $parserHook, 'renderFunction' ], + array_merge( [ &$parser ], $parameters ) ); if ( is_string( $renderResult ) ) { @@ -62,7 +65,7 @@ public function testRender( array $parameters, $expected = null ) { } public function processingProvider() { - return array(); + return []; } /** @@ -100,15 +103,11 @@ public function testParamProcessing( array $parameters, array $expectedValues ) /** * Returns an array with the default values of the parameters. - * - * @since 3.0 - * - * @return array */ - protected function getDefaultValues() { + private function getDefaultValues() { $definitions = ParamDefinition::getCleanDefinitions( $this->getInstance()->getParamDefinitions() ); - $defaults = array(); + $defaults = []; foreach ( $definitions as $definition ) { if ( !$definition->isRequired() ) { @@ -122,7 +121,7 @@ protected function getDefaultValues() { protected function arrayWrap( array $elements ) { return array_map( function ( $element ) { - return array( $element ); + return [ $element ]; }, $elements ); diff --git a/tests/phpunit/parsers/CircleParserTest.php b/tests/Integration/parsers/CircleParserTest.php similarity index 66% rename from tests/phpunit/parsers/CircleParserTest.php rename to tests/Integration/parsers/CircleParserTest.php index a656442c4..1546b99c7 100644 --- a/tests/phpunit/parsers/CircleParserTest.php +++ b/tests/Integration/parsers/CircleParserTest.php @@ -4,6 +4,7 @@ use DataValues\Geo\Values\LatLongValue; use Maps\CircleParser; +use Maps\Elements\Circle; /** * @covers Maps\CircleParser @@ -12,6 +13,12 @@ */ class CircleParserTest extends \PHPUnit_Framework_TestCase { + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + public function testCanConstruct() { new CircleParser(); $this->assertTrue( true ); @@ -22,12 +29,12 @@ public function testGivenCoordinateAndRadius_parserReturnsCircle() { $circle = $parser->parse( '57.421,23.90625:32684.605182' ); - $this->assertInstanceOf( 'Maps\Elements\Circle', $circle ); + $this->assertInstanceOf( Circle::class, $circle ); $expectedLatLong = new LatLongValue( 57.421, 23.90625 ); $this->assertTrue( $expectedLatLong->equals( $circle->getCircleCentre() ) ); - $this->assertEquals( 32684.605182, $circle->getCircleRadius() ); + $this->assertSame( 32684.605182, $circle->getCircleRadius() ); } public function testGivenTitleAndText_circleHasProvidedMetaData() { @@ -35,10 +42,10 @@ public function testGivenTitleAndText_circleHasProvidedMetaData() { $circle = $parser->parse( '57.421,23.90625:32684.605182~title~text' ); - $this->assertInstanceOf( 'Maps\Elements\Circle', $circle ); + $this->assertInstanceOf( Circle::class, $circle ); - $this->assertEquals( 'title', $circle->getTitle() ); - $this->assertEquals( 'text', $circle->getText() ); + $this->assertSame( 'title', $circle->getTitle() ); + $this->assertSame( 'text', $circle->getText() ); } } diff --git a/tests/Integration/parsers/DistanceParserTest.php b/tests/Integration/parsers/DistanceParserTest.php new file mode 100644 index 000000000..35fb983db --- /dev/null +++ b/tests/Integration/parsers/DistanceParserTest.php @@ -0,0 +1,69 @@ + + */ +class DistanceParserTest extends \PHPUnit_Framework_TestCase { + + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + + /** + * @dataProvider validInputProvider + */ + public function testValidInputs( $input, $expected ) { + $this->assertSame( + $expected, + ( new DistanceParser() )->parse( $input ) + ); + } + + public function validInputProvider() { + return [ + [ '1', 1.0 ], + [ '1m', 1.0 ], + [ '42 km', 42000.0 ], + [ '4.2 km', 4200.0 ], + [ '4.2 m', 4.2 ], + [ '4.02 m', 4.02 ], + [ '4.02 km', 4020.0 ], + [ '0.001 km', 1.0 ], + ]; + } + + /** + * @dataProvider invalidInputProvider + */ + public function testGivenInvalidInput_exceptionIsThrown( $input ) { + $parser = new DistanceParser(); + + $this->setExpectedException( ParseException::class ); + $parser->parse( $input ); + } + + public function invalidInputProvider() { + return [ + [ '' ], + [ 'kittens' ], + [ '1 kittens' ], + [ '-1m' ], + [ 'foo m' ], + [ '1m foo' ], + [ 'foo 1m' ], + [ 'm1' ], + [ '4. m' ], + [ '4.2.1 m' ], + ]; + } + +} diff --git a/tests/phpunit/parsers/LineParserTest.php b/tests/Integration/parsers/LineParserTest.php similarity index 66% rename from tests/phpunit/parsers/LineParserTest.php rename to tests/Integration/parsers/LineParserTest.php index 2cfdd430f..3e20a7b3b 100644 --- a/tests/phpunit/parsers/LineParserTest.php +++ b/tests/Integration/parsers/LineParserTest.php @@ -4,6 +4,8 @@ use DataValues\Geo\Values\LatLongValue; use Maps\Elements\Line; +use Maps\LineParser; +use ValueParsers\ValueParser; /** * @covers Maps\LineParser @@ -12,6 +14,19 @@ */ class LineParserTest extends \ValueParsers\Test\StringValueParserTest { + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + + /** + * @return string + */ + protected function getParserClass() { + return LineParser::class; + } + /** * @see ValueParserTestBase::validInputProvider * @@ -20,39 +35,39 @@ class LineParserTest extends \ValueParsers\Test\StringValueParserTest { * @return array */ public function validInputProvider() { - $argLists = array(); + $argLists = []; - $valid = array(); + $valid = []; - $valid[] = array( - array( + $valid[] = [ + [ 42, 4.2 - ), - ); + ], + ]; - $valid[] = array( - array( + $valid[] = [ + [ 49.83798245308486, 2.724609375 - ), - array( + ], + [ 52.05249047600102, 8.26171875 - ), - array( + ], + [ 46.37725420510031, 6.15234375 - ), - array( + ], + [ 49.83798245308486, 2.724609375 - ), - ); + ], + ]; foreach ( $valid as $values ) { - $input = array(); - $output = array(); + $input = []; + $output = []; foreach ( $values as $value ) { $input[] = implode( ',', $value ); @@ -61,32 +76,30 @@ public function validInputProvider() { $input = implode( ':', $input ); - $argLists[] = array( $input, new Line( $output ) ); + $argLists[] = [ $input, new Line( $output ) ]; } return $argLists; } /** - * @see ValueParserTestBase::getParserClass + * @see ValueParserTestBase::requireDataValue * * @since 3.0 * - * @return string + * @return boolean */ - protected function getParserClass() { - return 'Maps\LineParser'; + protected function requireDataValue() { + return false; } /** - * @see ValueParserTestBase::requireDataValue + * @since 0.1 * - * @since 3.0 - * - * @return boolean + * @return ValueParser */ - protected function requireDataValue() { - return false; + protected function getInstance() { + return new LineParser(); } } diff --git a/tests/phpunit/parsers/LocationParserTest.php b/tests/Integration/parsers/LocationParserTest.php similarity index 56% rename from tests/phpunit/parsers/LocationParserTest.php rename to tests/Integration/parsers/LocationParserTest.php index 39255bc31..51b93bdf4 100644 --- a/tests/phpunit/parsers/LocationParserTest.php +++ b/tests/Integration/parsers/LocationParserTest.php @@ -6,6 +6,8 @@ use Maps\Elements\Location; use Maps\LocationParser; use Title; +use ValueParsers\ParserOptions; +use ValueParsers\ValueParser; /** * @covers Maps\LocationParser @@ -14,6 +16,19 @@ */ class LocationParserTest extends \ValueParsers\Test\StringValueParserTest { + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + + /** + * @return string + */ + protected function getParserClass() { + return LocationParser::class; + } + /** * @see ValueParserTestBase::validInputProvider * @@ -22,42 +37,31 @@ class LocationParserTest extends \ValueParsers\Test\StringValueParserTest { * @return array */ public function validInputProvider() { - $argLists = array(); - - $valid = array( - '55.7557860 N, 37.6176330 W' => array( 55.7557860, -37.6176330 ), - '55.7557860, -37.6176330' => array( 55.7557860, -37.6176330 ), - '55 S, 37.6176330 W' => array( -55, -37.6176330 ), - '-55, -37.6176330' => array( -55, -37.6176330 ), - '5.5S,37W ' => array( -5.5, -37 ), - '-5.5,-37 ' => array( -5.5, -37 ), - '4,2' => array( 4, 2 ), - ); + $argLists = []; + + $valid = [ + '55.7557860 N, 37.6176330 W' => [ 55.7557860, -37.6176330 ], + '55.7557860, -37.6176330' => [ 55.7557860, -37.6176330 ], + '55 S, 37.6176330 W' => [ -55, -37.6176330 ], + '-55, -37.6176330' => [ -55, -37.6176330 ], + '5.5S,37W ' => [ -5.5, -37 ], + '-5.5,-37 ' => [ -5.5, -37 ], + '4,2' => [ 4, 2 ], + ]; foreach ( $valid as $value => $expected ) { $expected = new Location( new LatLongValue( $expected[0], $expected[1] ) ); - $argLists[] = array( (string)$value, $expected ); + $argLists[] = [ (string)$value, $expected ]; } $location = new Location( new LatLongValue( 4, 2 ) ); $location->setTitle( 'Title' ); $location->setText( 'some description' ); - $argLists[] = array( '4,2~Title~some description', $location ); + $argLists[] = [ '4,2~Title~some description', $location ]; return $argLists; } - /** - * @see ValueParserTestBase::getParserClass - * - * @since 3.0 - * - * @return string - */ - protected function getParserClass() { - return 'Maps\LocationParser'; - } - /** * @see ValueParserTestBase::requireDataValue * @@ -80,13 +84,13 @@ public function testGivenTitleThatIsNotLink_titleIsSetAndLinkIsNot( $title ) { } public function titleProvider() { - return array( - array( '' ), - array( 'Title' ), - array( 'Some title' ), - array( 'link' ), - array( 'links:foo' ), - ); + return [ + [ '' ], + [ 'Title' ], + [ 'Some title' ], + [ 'link' ], + [ 'links:foo' ], + ]; } protected function assertTitleAndLinkAre( Location $location, $title, $link ) { @@ -115,11 +119,11 @@ public function testGivenTitleThatIsLink_linkIsSetAndTitleIsNot( $link ) { } public function linkProvider() { - return array( - array( 'https://semantic-mediawiki.org' ), - array( 'http://www.semantic-mediawiki.org' ), - array( 'irc://freenode.net' ), - ); + return [ + [ 'https://semantic-mediawiki.org' ], + [ 'http://www.semantic-mediawiki.org' ], + [ 'irc://freenode.net' ], + ]; } /** @@ -140,4 +144,32 @@ public function linkProvider() { // ); // } + protected function getInstance() { + return new LocationParser(); + } + + public function testGivenAddressAndNoTitle_addressIsSetAsTitle() { + $options = new ParserOptions( ['useaddressastitle' => true] ); + $parser = new LocationParser( $options ); + $location = $parser->parse( 'Tempelhofer Ufer 42' ); + + $this->assertSame( 'Tempelhofer Ufer 42', $location->getTitle() ); + } + + public function testGivenAddressAndTitle_addressIsNotUsedAsTitle() { + $options = new ParserOptions( ['useaddressastitle' => true] ); + $parser = new LocationParser( $options ); + $location = $parser->parse( 'Tempelhofer Ufer 42~Great title of doom' ); + + $this->assertSame( 'Great title of doom', $location->getTitle() ); + } + + public function testGivenCoordinatesAndNoTitle_noTitleIsSet() { + $options = new ParserOptions( ['useaddressastitle' => true] ); + $parser = new LocationParser( $options ); + $location = $parser->parse( '4,2' ); + + $this->assertFalse( $location->getOptions()->hasOption( 'title' ) ); + } + } diff --git a/tests/phpunit/parsers/RectlangleParserTest.php b/tests/Integration/parsers/RectlangleParserTest.php similarity index 72% rename from tests/phpunit/parsers/RectlangleParserTest.php rename to tests/Integration/parsers/RectlangleParserTest.php index 8c8072d12..1e7d2cd26 100644 --- a/tests/phpunit/parsers/RectlangleParserTest.php +++ b/tests/Integration/parsers/RectlangleParserTest.php @@ -3,6 +3,7 @@ namespace Maps\Test; use DataValues\Geo\Values\LatLongValue; +use Maps\Elements\Rectangle; use Maps\RectangleParser; /** @@ -12,6 +13,12 @@ */ class RectangleParserTest extends \PHPUnit_Framework_TestCase { + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + public function testCanConstruct() { new RectangleParser(); $this->assertTrue( true ); @@ -22,7 +29,7 @@ public function testGivenBoundingBox_parserReturnsRectangle() { $rectangle = $parser->parse( '51.8357775,33.83789:46,23.37890625' ); - $this->assertInstanceOf( 'Maps\Elements\Rectangle', $rectangle ); + $this->assertInstanceOf( Rectangle::class, $rectangle ); $expectedNorthEast = new LatLongValue( 51.8357775, 33.83789 ); $this->assertTrue( $expectedNorthEast->equals( $rectangle->getRectangleNorthEast() ) ); @@ -36,10 +43,10 @@ public function testGivenTitleAndText_rectangleHasProvidedMetaData() { $rectangle = $parser->parse( "51.8357775,33.83789:46,23.37890625~I'm a square~of doom" ); - $this->assertInstanceOf( 'Maps\Elements\Rectangle', $rectangle ); + $this->assertInstanceOf( Rectangle::class, $rectangle ); - $this->assertEquals( "I'm a square", $rectangle->getTitle() ); - $this->assertEquals( 'of doom', $rectangle->getText() ); + $this->assertSame( "I'm a square", $rectangle->getTitle() ); + $this->assertSame( 'of doom', $rectangle->getText() ); } } diff --git a/tests/phpunit/parsers/WmsOverlayParserTest.php b/tests/Integration/parsers/WmsOverlayParserTest.php similarity index 65% rename from tests/phpunit/parsers/WmsOverlayParserTest.php rename to tests/Integration/parsers/WmsOverlayParserTest.php index 1b141af7b..cc02dce64 100644 --- a/tests/phpunit/parsers/WmsOverlayParserTest.php +++ b/tests/Integration/parsers/WmsOverlayParserTest.php @@ -3,6 +3,7 @@ namespace Maps\Test; use Maps\Elements\WmsOverlay; +use Maps\WmsOverlayParser; /** * @covers Maps\WmsOverlayParser @@ -11,22 +12,33 @@ */ class WmsOverlayParserTest extends \ValueParsers\Test\StringValueParserTest { + public function setUp() { + if ( !defined( 'MEDIAWIKI' ) ) { + $this->markTestSkipped( 'MediaWiki is not available' ); + } + } + + /** + * @return string + */ + protected function getParserClass() { + return WmsOverlayParser::class; + } + /** * @see ValueParserTestBase::validInputProvider * - * @since 3.0 - * * @return array */ public function validInputProvider() { - $argLists = array(); + $argLists = []; - $valid = array( + $valid = [ "http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi? Foundation.GTOPO30" => - array( "http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?", "Foundation.GTOPO30" ), + [ "http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?", "Foundation.GTOPO30" ], "http://maps.imr.no:80/geoserver/wms? vulnerable_areas:Identified_coral_area coral_identified_areas" => - array( "http://maps.imr.no:80/geoserver/wms?", "vulnerable_areas:Identified_coral_area", "coral_identified_areas" ) - ); + [ "http://maps.imr.no:80/geoserver/wms?", "vulnerable_areas:Identified_coral_area", "coral_identified_areas" ] + ]; foreach ( $valid as $value => $expected ) { $expectedOverlay = new WmsOverlay( $expected[0], $expected[1] ); @@ -35,33 +47,23 @@ public function validInputProvider() { $expectedOverlay->setWmsStyleName( $expected[2] ); } - $argLists[] = array( (string)$value, $expectedOverlay ); + $argLists[] = [ (string)$value, $expectedOverlay ]; } return $argLists; } - - /** - * @see ValueParserTestBase::getParserClass - * - * @since 3.0 - * - * @return string - */ - protected function getParserClass() { - return 'Maps\WmsOverlayParser'; - } - /** * @see ValueParserTestBase::requireDataValue * - * @since 3.0 - * * @return boolean */ protected function requireDataValue() { return false; } + protected function getInstance() { + return new WmsOverlayParser(); + } + } diff --git a/tests/phpunit/ElementTest.php b/tests/Unit/ElementTest.php similarity index 76% rename from tests/phpunit/ElementTest.php rename to tests/Unit/ElementTest.php index f5ba5f816..2e93cbf16 100644 --- a/tests/phpunit/ElementTest.php +++ b/tests/Unit/ElementTest.php @@ -2,6 +2,7 @@ use DataValues\Geo\Values\LatLongValue; use Maps\Element; +use Maps\ElementOptions; use Maps\Elements\Circle; use Maps\Elements\ImageOverlay; use Maps\Elements\Line; @@ -10,21 +11,18 @@ /** * @covers Maps\Elements\BaseElement * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ - class ElementTest extends \PHPUnit_Framework_TestCase { public function elementProvider() { - $elements = array(); + $elements = []; - $elements[] = array( new Rectangle( new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ) ) ); - $elements[] = array( new ImageOverlay( new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ), 'foo' ) ); - $elements[] = array( new Circle( new LatLongValue( 4, 2 ), 42 ) ); - $elements[] = array( new Line( array( new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ) ) ) ); + $elements[] = [ new Rectangle( new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ) ) ]; + $elements[] = [ new ImageOverlay( new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ), 'foo' ) ]; + $elements[] = [ new Circle( new LatLongValue( 4, 2 ), 42 ) ]; + $elements[] = [ new Line( [ new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ) ] ) ]; //$elements[] = new \Maps\Polygon( array( new LatLongValue( 4, 2 ), new LatLongValue( 5, 6 ) ) ); // TODO: location @@ -67,7 +65,7 @@ public function testSetOptions( Element $element ) { * @param Element $element */ public function testGetOptions( Element $element ) { - $this->assertInstanceOf( '\Maps\ElementOptions', $element->getOptions() ); + $this->assertInstanceOf( ElementOptions::class , $element->getOptions() ); } } diff --git a/tests/phpunit/elements/BaseElementTest.php b/tests/Unit/Elements/BaseElementTest.php similarity index 77% rename from tests/phpunit/elements/BaseElementTest.php rename to tests/Unit/Elements/BaseElementTest.php index 772b2d557..4f3d43a07 100644 --- a/tests/phpunit/elements/BaseElementTest.php +++ b/tests/Unit/Elements/BaseElementTest.php @@ -2,7 +2,9 @@ namespace Maps\Tests\Elements; +use InvalidArgumentException; use Maps\Element; +use Maps\ElementOptions; /** * Base class for unit tests classes for the Maps\BaseElement deriving objects. @@ -26,7 +28,7 @@ public abstract function getClass(); public abstract function validConstructorProvider(); public function invalidConstructorProvider() { - return array(); + return []; } /** @@ -49,11 +51,11 @@ public function newInstance() { * @return array [instance, constructor args] */ public function instanceProvider() { - $phpFails = array( $this, 'newInstance' ); + $phpFails = [ $this, 'newInstance' ]; return array_map( function( array $args ) use ( $phpFails ) { - return array( call_user_func_array( $phpFails, $args ), $args ); + return [ call_user_func_array( $phpFails, $args ), $args ]; }, $this->validConstructorProvider() ); @@ -65,7 +67,7 @@ function( array $args ) use ( $phpFails ) { * @since 3.0 */ public function testGivenValidArguments_constructorDoesNotThrowException() { - $instance = call_user_func_array( array( $this, 'newInstance' ), func_get_args() ); + $instance = call_user_func_array( [ $this, 'newInstance' ], func_get_args() ); $this->assertInstanceOf( $this->getClass(), $instance ); } @@ -75,8 +77,8 @@ public function testGivenValidArguments_constructorDoesNotThrowException() { * @since 3.0 */ public function testGivenInvalidArguments_constructorThrowsException() { - $this->setExpectedException( 'InvalidArgumentException' ); - call_user_func_array( array( $this, 'newInstance' ), func_get_args() ); + $this->setExpectedException( InvalidArgumentException::class ); + call_user_func_array( [ $this, 'newInstance' ], func_get_args() ); } /** @@ -84,7 +86,7 @@ public function testGivenInvalidArguments_constructorThrowsException() { * @param Element $element */ public function testGetOptions( Element $element ) { - $this->assertInstanceOf( '\Maps\ElementOptions', $element->getOptions() ); + $this->assertInstanceOf( ElementOptions::class, $element->getOptions() ); } } diff --git a/tests/phpunit/elements/CircleTest.php b/tests/Unit/Elements/CircleTest.php similarity index 67% rename from tests/phpunit/elements/CircleTest.php rename to tests/Unit/Elements/CircleTest.php index 68772a734..7a5317de7 100644 --- a/tests/phpunit/elements/CircleTest.php +++ b/tests/Unit/Elements/CircleTest.php @@ -8,8 +8,6 @@ /** * @covers Maps\Elements\Circle * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -23,27 +21,27 @@ class CircleTest extends BaseElementTest { * @return string */ public function getClass() { - return 'Maps\Elements\Circle'; + return Circle::class; } public function validConstructorProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( new LatLongValue( 4, 2 ), 42 ); - $argLists[] = array( new LatLongValue( 42, 2.2 ), 9000.1 ); - $argLists[] = array( new LatLongValue( 4, 2 ), 1 ); - $argLists[] = array( new LatLongValue( 4, 2 ), 0.1 ); + $argLists[] = [ new LatLongValue( 4, 2 ), 42 ]; + $argLists[] = [ new LatLongValue( 42, 2.2 ), 9000.1 ]; + $argLists[] = [ new LatLongValue( 4, 2 ), 1 ]; + $argLists[] = [ new LatLongValue( 4, 2 ), 0.1 ]; return $argLists; } public function invalidConstructorProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( new LatLongValue( 4, 2 ), 'foo' ); + $argLists[] = [ new LatLongValue( 4, 2 ), 'foo' ]; - $argLists[] = array( new LatLongValue( 4, 2 ), 0 ); - $argLists[] = array( new LatLongValue( 4, 2 ), -42 ); + $argLists[] = [ new LatLongValue( 4, 2 ), 0 ]; + $argLists[] = [ new LatLongValue( 4, 2 ), -42 ]; return $argLists; } diff --git a/tests/phpunit/elements/ImageOverlayTest.php b/tests/Unit/Elements/ImageOverlayTest.php similarity index 94% rename from tests/phpunit/elements/ImageOverlayTest.php rename to tests/Unit/Elements/ImageOverlayTest.php index 419991efe..f2ca72cd6 100644 --- a/tests/phpunit/elements/ImageOverlayTest.php +++ b/tests/Unit/Elements/ImageOverlayTest.php @@ -7,8 +7,6 @@ /** * @covers Maps\Elements\ImageOverlay * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -22,7 +20,7 @@ class ImageOverlayTest extends RectangleTest { * @return string */ public function getClass() { - return 'Maps\Elements\ImageOverlay'; + return ImageOverlay::class; } public function validConstructorProvider() { diff --git a/tests/phpunit/elements/LineTest.php b/tests/Unit/Elements/LineTest.php similarity index 67% rename from tests/phpunit/elements/LineTest.php rename to tests/Unit/Elements/LineTest.php index 908ccdb63..0d87df20e 100644 --- a/tests/phpunit/elements/LineTest.php +++ b/tests/Unit/Elements/LineTest.php @@ -8,8 +8,6 @@ /** * @covers Maps\Elements\Line * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -23,32 +21,32 @@ class LineTest extends BaseElementTest { * @return string */ public function getClass() { - return 'Maps\Elements\Line'; + return Line::class; } public function validConstructorProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( array() ); - $argLists[] = array( array( new LatLongValue( 4, 2 ) ) ); + $argLists[] = [ [] ]; + $argLists[] = [ [ new LatLongValue( 4, 2 ) ] ]; - $argLists[] = array( - array( + $argLists[] = [ + [ new LatLongValue( 4, 2 ), new LatLongValue( 2, 4 ), new LatLongValue( 42, 42 ), - ) - ); + ] + ]; return $argLists; } public function invalidConstructorProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( array( '~=[,,_,,]:3' ) ); - $argLists[] = array( array( new LatLongValue( 4, 2 ), '~=[,,_,,]:3' ) ); - $argLists[] = array( array( '~=[,,_,,]:3', new LatLongValue( 4, 2 ) ) ); + $argLists[] = [ [ '~=[,,_,,]:3' ] ]; + $argLists[] = [ [ new LatLongValue( 4, 2 ), '~=[,,_,,]:3' ] ]; + $argLists[] = [ [ '~=[,,_,,]:3', new LatLongValue( 4, 2 ) ] ]; return $argLists; } @@ -65,7 +63,7 @@ public function testGetLineCoordinates( Line $line, array $arguments ) { $this->assertEquals( count( $arguments[0] ), count( $coordinates ) ); foreach ( $coordinates as $geoCoordinate ) { - $this->assertInstanceOf( 'DataValues\LatLongValue', $geoCoordinate ); + $this->assertInstanceOf( LatLongValue::class, $geoCoordinate ); } } diff --git a/tests/phpunit/elements/LocationTest.php b/tests/Unit/Elements/LocationTest.php similarity index 71% rename from tests/phpunit/elements/LocationTest.php rename to tests/Unit/Elements/LocationTest.php index af8204fee..66d617f57 100644 --- a/tests/phpunit/elements/LocationTest.php +++ b/tests/Unit/Elements/LocationTest.php @@ -8,20 +8,18 @@ /** * @covers Maps\Elements\Location * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class LocationTest extends \PHPUnit_Framework_TestCase { public function latLongValueProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( new LatLongValue( 0, 0 ) ); - $argLists[] = array( new LatLongValue( 4, 2 ) ); - $argLists[] = array( new LatLongValue( 42, 42 ) ); - $argLists[] = array( new LatLongValue( -4.2, -42 ) ); + $argLists[] = [ new LatLongValue( 0, 0 ) ]; + $argLists[] = [ new LatLongValue( 4, 2 ) ]; + $argLists[] = [ new LatLongValue( 42, 42 ) ]; + $argLists[] = [ new LatLongValue( -4.2, -42 ) ]; return $argLists; } diff --git a/tests/phpunit/elements/PolygonTest.php b/tests/Unit/Elements/PolygonTest.php similarity index 96% rename from tests/phpunit/elements/PolygonTest.php rename to tests/Unit/Elements/PolygonTest.php index ab7364d13..7c95b8de4 100644 --- a/tests/phpunit/elements/PolygonTest.php +++ b/tests/Unit/Elements/PolygonTest.php @@ -7,8 +7,6 @@ /** * @covers Maps\Elements\Polygon * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -22,7 +20,7 @@ class PolygonTest extends LineTest { * @return string */ public function getClass() { - return 'Maps\Elements\Polygon'; + return Polygon::class; } /** diff --git a/tests/phpunit/elements/RectangleTest.php b/tests/Unit/Elements/RectangleTest.php similarity index 80% rename from tests/phpunit/elements/RectangleTest.php rename to tests/Unit/Elements/RectangleTest.php index 15bfc880b..45d1fefbf 100644 --- a/tests/phpunit/elements/RectangleTest.php +++ b/tests/Unit/Elements/RectangleTest.php @@ -8,8 +8,6 @@ /** * @covers Maps\Elements\Rectangle * - * @since 3.0 - * * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ @@ -23,22 +21,22 @@ class RectangleTest extends BaseElementTest { * @return string */ public function getClass() { - return 'Maps\Elements\Rectangle'; + return Rectangle::class; } public function validConstructorProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( new LatLongValue( 4, 2 ), new LatLongValue( -4, -2 ) ); - $argLists[] = array( new LatLongValue( -42, -42 ), new LatLongValue( -4, -2 ) ); + $argLists[] = [ new LatLongValue( 4, 2 ), new LatLongValue( -4, -2 ) ]; + $argLists[] = [ new LatLongValue( -42, -42 ), new LatLongValue( -4, -2 ) ]; return $argLists; } public function invalidConstructorProvider() { - $argLists = array(); + $argLists = []; - $argLists[] = array( new LatLongValue( 4, 2 ), new LatLongValue( 4, 2 ) ); + $argLists[] = [ new LatLongValue( 4, 2 ), new LatLongValue( 4, 2 ) ]; return $argLists; } @@ -59,10 +57,10 @@ public function testGetCorners( Rectangle $rectangle, array $arguments ) { * @param array $arguments */ public function testSetCorners( Rectangle $rectangle, array $arguments ) { - $coordinates = array( + $coordinates = [ new LatLongValue( 42, 42 ), new LatLongValue( 0, 0 ) - ); + ]; foreach ( $coordinates as $coordinate ) { $rectangle->setRectangleNorthEast( $coordinate ); diff --git a/tests/Unit/Geocoders/MapsOldGeocoderAdapterTest.php b/tests/Unit/Geocoders/MapsOldGeocoderAdapterTest.php new file mode 100644 index 000000000..32259efd8 --- /dev/null +++ b/tests/Unit/Geocoders/MapsOldGeocoderAdapterTest.php @@ -0,0 +1,52 @@ + + */ +class MapsOldGeocoderAdapterTest extends \PHPUnit_Framework_TestCase { + + public function testWhenInnerGeocoderHasResult_itGetsReturnedInArrayForm() { + $geocoder = new InMemoryGeocoder( [ + 'New York' => new LatLongValue( 40.7642499, -73.9545249 ) + ] ); + + $decoratedGeocoder = new \MapsOldGeocoderAdapter( $geocoder, 'maw' ); + + $this->assertSame( + [ + 'lat' => 40.7642499, + 'lon' => -73.9545249, + ], + $decoratedGeocoder->geocode( 'New York' ) + ); + } + + public function testWhenInnerGeocoderHasNoResult_falseIsReturned() { + $geocoder = new InMemoryGeocoder( [ + 'New York' => new LatLongValue( 40.7642499, -73.9545249 ) + ] ); + + $decoratedGeocoder = new \MapsOldGeocoderAdapter( $geocoder, 'maw' ); + + $this->assertFalse( $decoratedGeocoder->geocode( 'durkadurkastan' ) ); + } + +// public function testWhenInnerGeocoderHasNoResult_falseIsReturned() { +// $decoratedGeocoder = new \MapsDecoratedGeocoder( new InMemoryGeocoder( [] ), 'maw' ); +// +// $this->assertSame( [ 'maw' ], $decoratedGeocoder->getAliases() ); +// } + + // TODO: test exception case if we decided to not use null in the interface + +} diff --git a/tests/Unit/Geocoders/NominatimGeocoderTest.php b/tests/Unit/Geocoders/NominatimGeocoderTest.php new file mode 100644 index 000000000..382f36a21 --- /dev/null +++ b/tests/Unit/Geocoders/NominatimGeocoderTest.php @@ -0,0 +1,60 @@ + + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +class NominatimGeocoderTest extends \PHPUnit_Framework_TestCase { + + const NEW_YORK_FETCH_URL = 'https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&q=New+York'; + + public function testHappyPath() { + $fileFetcher = new InMemoryFileFetcher( [ + self::NEW_YORK_FETCH_URL + => '[{"place_id":"97961780","licence":"Data © OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright","osm_type":"way","osm_id":"161387758","boundingbox":["40.763858","40.7642664","-73.9548572","-73.954092"],"lat":"40.7642499","lon":"-73.9545249","display_name":"NewYork Hospital Drive, Upper East Side, Manhattan, New York County, New York City, New York, 10021, United States of America","place_rank":"27","category":"highway","type":"service","importance":0.275}]' + ] ); + + $geocoder = new NominatimGeocoder( $fileFetcher ); + + $this->assertSame( 40.7642499, $geocoder->geocode( 'New York' )->getLatitude() ); + $this->assertSame( -73.9545249, $geocoder->geocode( 'New York' )->getLongitude() ); + } + + public function testWhenFetcherThrowsException_nullIsReturned() { + $geocoder = new NominatimGeocoder( new InMemoryFileFetcher( [] ) ); + + $this->assertNull( $geocoder->geocode( 'New York' ) ); + } + + /** + * @dataProvider invalidResponseProvider + */ + public function testWhenFetcherReturnsInvalidResponse_nullIsReturned( $invalidResponse ) { + $geocoder = new NominatimGeocoder( new InMemoryFileFetcher( [ + self::NEW_YORK_FETCH_URL => $invalidResponse + ] ) ); + + $this->assertNull( $geocoder->geocode( 'New York' ) ); + } + + public function invalidResponseProvider() { + return [ + 'Not JSON' => [ '~=[,,_,,]:3' ], + 'Not a JSON array' => [ '42' ], + 'Empty JSON array' => [ '[]' ], + 'Missing lon key' => [ '[{"lat":"40.7642499","FOO":"-73.9545249"}]' ], + 'Missing lat key' => [ '[{"FOO":"40.7642499","lon":"-73.9545249"}]' ], + ]; + } + + // TODO: test malicious address escaping + +} diff --git a/tests/Unit/Semantic/DataValues/CoordinateValueTest.php b/tests/Unit/Semantic/DataValues/CoordinateValueTest.php new file mode 100644 index 000000000..33bd56e66 --- /dev/null +++ b/tests/Unit/Semantic/DataValues/CoordinateValueTest.php @@ -0,0 +1,112 @@ + + */ +class CoordinateValueTest extends \PHPUnit_Framework_TestCase { + + public function setUp() { + if ( !defined( 'SMW_VERSION' ) ) { + $this->markTestSkipped( 'SMW is not available' ); + } + } + + public function testConstruct() { + $geoDI = new SMWDIGeoCoord( 23, 42 ); + + /** + * @var CoordinateValue $geoValue + */ + $geoValue = DataValueFactory::newDataItemValue( $geoDI ); + + $this->assertInstanceOf( CoordinateValue::class, $geoValue ); + + $this->assertEquals( $geoDI, $geoValue->getDataItem() ); + $this->assertEquals( '23° 0\' 0", 42° 0\' 0"', $geoValue->getShortWikiText() ); + } + + /** + * @dataProvider coordinateProvider + */ + public function testGetQueryDescription( $lat, $long, $serialization ) { + $geoValue = $this->newInstance(); + + $description = $geoValue->getQueryDescription( $serialization ); + + $this->assertIsCorrectCoordValue( $description, $lat, $long ); + } + + private function assertIsCorrectCoordValue( $description, $lat, $long ) { + /** + * @var CoordinateDescription $description + */ + $this->assertInstanceOf( CoordinateDescription::class, $description ); + $this->assertEquals( $lat, $description->getDataItem()->getLatitude() ); + $this->assertEquals( $long, $description->getDataItem()->getLongitude() ); + } + + protected function newInstance() { + return new CoordinateValue( SMWDataItem::TYPE_GEO ); + } + + public function coordinateProvider() { + return [ + [ + 23, + 42, + '23° 0\' 0", 42° 0\' 0"', + ], + [ + 0, + 0, + '0° 0\' 0", 0° 0\' 0"', + ], + [ + -23.5, + -42.5, + '-23° 30\' 0", -42° 30\' 0"', + ], + ]; + } + + /** + * @dataProvider coordinateWithDistanceProvider + */ + public function testGetQueryDescriptionForArea( $serialization ) { + $geoValue = $this->newInstance(); + + $description = $geoValue->getQueryDescription( $serialization ); + + $this->assertInstanceOf( AreaDescription::class, $description ); + } + + public function coordinateWithDistanceProvider() { + return [ + [ + '23° 0\' 0", 42° 0\' 0"(1km)', + 1000, + ], + [ + '0° 0\' 0", 0° 0\' 0" ( 1 m )', + 1, + ], + [ + '-23° 30\' 0", -42° 30\' 0" (9001m)', + 9001, + ], + ]; + } + +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 000000000..ae41a115b --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,18 @@ + - */ -class DistanceParserTest extends \ValueParsers\Test\StringValueParserTest { - - /** - * @see ValueParserTestBase::validInputProvider - * - * @since 3.0 - * - * @return array - */ - public function validInputProvider() { - $argLists = array(); - - $valid = array( - '1' => 1, - '1m' => 1, - '42 km' => 42000, - '4.2 km' => 4200, - '4.2 m' => 4.2, - ); - - foreach ( $valid as $value => $expected ) { - $argLists[] = array( (string)$value, $expected ); - } - - return $argLists; - } - - /** - * @see ValueParserTestBase::getParserClass - * - * @since 3.0 - * - * @return string - */ - protected function getParserClass() { - return 'Maps\DistanceParser'; - } - - /** - * @see ValueParserTestBase::requireDataValue - * - * @since 3.0 - * - * @return boolean - */ - protected function requireDataValue() { - return false; - } - -}