Current File : /home/jvzmxxx/wiki1/extensions/Kartographer/modules/kartographer.js
( function ( $, mw ) {

	// Load this script after lib/mapbox-lib.js
	var scale, urlFormat, windowManager, mapDialog,
		mapServer = mw.config.get( 'wgKartographerMapServer' ),
		forceHttps = mapServer[ 4 ] === 's',
		config = L.mapbox.config;

	config.REQUIRE_ACCESS_TOKEN = false;
	config.FORCE_HTTPS = forceHttps;
	config.HTTP_URL = forceHttps ? false : mapServer;
	config.HTTPS_URL = !forceHttps ? false : mapServer;

	function bracketDevicePixelRatio() {
		var i, scale,
			brackets = mw.config.get( 'wgKartographerSrcsetScales' ),
			baseRatio = window.devicePixelRatio || 1;
		if ( !brackets ) {
			return 1;
		}
		brackets.unshift( 1 );
		for ( i = 0; i < brackets.length; i++ ) {
			scale = brackets[ i ];
			if ( scale >= baseRatio || ( baseRatio - scale ) < 0.1 ) {
				return scale;
			}
		}
		return brackets[ brackets.length - 1 ];
	}

	scale = bracketDevicePixelRatio();
	scale = ( scale === 1 ) ? '' : ( '@' + scale + 'x' );
	urlFormat = '/{z}/{x}/{y}' + scale + '.png';

	mw.kartographer = {};

	mw.kartographer.FullScreenControl = L.Control.extend( {
		options: {
			// Do not switch for RTL because zoom also stays in place
			position: 'topright'
		},

		onAdd: function ( map ) {
			var container = L.DomUtil.create( 'div', 'leaflet-bar' ),
				link = L.DomUtil.create( 'a', 'oo-ui-icon-fullScreen', container );

			link.href = '#';
			link.title = mw.msg( 'kartographer-fullscreen-text' );
			this.map = map;

			L.DomEvent.addListener( link, 'click', this.onShowFullScreen, this );
			L.DomEvent.disableClickPropagation( container );

			return container;
		},

		onShowFullScreen: function ( e ) {
			L.DomEvent.stop( e );
			mw.kartographer.openFullscreenMap( this.options.mapPositionData, this.map );
		}
	} );

	/**
	 * Create a new interactive map
	 *
	 * @param {HTMLElement} container Map container
	 * @param {Object} data Map data
	 * @param {number} data.latitude Latitude
	 * @param {number} data.longitude Longitude
	 * @param {number} data.zoom Zoom
	 * @param {string} [data.style] Map style
	 * @param {string[]} [data.overlays] Names of overlay groups to show
	 * @param {boolean} [data.enableFullScreenButton] add zoom
	 * @return {L.mapbox.Map} Map object
	 */
	mw.kartographer.createMap = function ( container, data ) {
		var map,
			style = data.style || mw.config.get( 'wgKartographerDfltStyle' );

		map = L.map( container );
		if ( !container.clientWidth ) {
			// HACK: If the container is not naturally measurable, try jQuery
			// which will pick up CSS dimensions. T125263
			/*jscs:disable disallowDanglingUnderscores */
			map._size = new L.Point(
				$( container ).width(),
				$( container ).height()
			);
			/*jscs:enable disallowDanglingUnderscores */
		}
		map.setView( [ data.latitude, data.longitude ], data.zoom );
		map.attributionControl.setPrefix( '' );

		if ( data.enableFullScreenButton ) {
			map.addControl( new mw.kartographer.FullScreenControl( { mapPositionData: data } ) );
		}

		/**
		 * @property {L.TileLayer} Reference to `Wikimedia` tile layer.
		 */
		map.wikimediaLayer = L.tileLayer( mapServer + '/' + style + urlFormat, {
			maxZoom: 18,
			attribution: mw.message( 'kartographer-attribution' ).parse()
		} ).addTo( map );

		/**
		 * @property {Object} Hash map of data groups and their corresponding
		 *   {@link L.mapbox.FeatureLayer layers}.
		 */
		map.dataLayers = {};

		if ( data.overlays ) {

			getMapGroupData( data.overlays ).done( function ( mapData ) {
				$.each( data.overlays, function ( index, group ) {
					if ( mapData.hasOwnProperty( group ) && mapData[ group ] ) {
						map.dataLayers[ group ] = mw.kartographer.addDataLayer( map, mapData[ group ] );
					} else {
						mw.log( 'Layer not found or contains no data: "' + group + '"' );
					}
				} );
			} );

		}
		return map;
	};

	mw.kartographer.dataLayerOpts = {
		// Disable double-sanitization by mapbox's internal sanitizer
		// because geojson has already passed through the MW internal sanitizer
		sanitizer: function ( v ) {
			return v;
		}
	};

	/**
	 * Create a new GeoJSON layer and add it to map.
	 *
	 * @param {L.mapbox.Map} map Map to get layers from
	 * @param {Object} geoJson
	 */
	mw.kartographer.addDataLayer = function ( map, geoJson ) {
		try {
			return L.mapbox.featureLayer( geoJson, mw.kartographer.dataLayerOpts ).addTo( map );
		} catch ( e ) {
			mw.log( e );
		}
	};

	/**
	 * Get "editable" geojson layer for the map.
	 *
	 * If a layer doesn't exist, create and attach one.
	 *
	 * @param {L.mapbox.Map} map Map to get layers from
	 * @param {L.mapbox.FeatureLayer} map.kartographerLayer show tag-specific info in this layer
	 * @return {L.mapbox.FeatureLayer|null} GeoJSON layer, if present
	 */
	mw.kartographer.getKartographerLayer = function ( map ) {
		if ( !map.kartographerLayer ) {
			map.kartographerLayer = L.mapbox.featureLayer().addTo( map );
		}
		return map.kartographerLayer;
	};

	/**
	 * Updates "editable" GeoJSON layer from a string.
	 *
	 * Validates the GeoJSON against the `sanitize-mapdata` api
	 * before executing it.
	 *
	 * The deferred object will be resolved with a `boolean` flag
	 * indicating whether the GeoJSON was valid and was applied.
	 *
	 * @param {L.mapbox.Map} map Map to set the GeoJSON for
	 * @param {string} geoJsonString GeoJSON data, empty string to clear
	 * @return {jQuery.Promise} Promise which resolves when the GeoJSON is updated, and rejects if there was an error
	 */
	mw.kartographer.updateKartographerLayer = function ( map, geoJsonString ) {
		var deferred = $.Deferred();

		if ( geoJsonString === '' ) {
			return deferred.resolve().promise();
		}

		new mw.Api().post( {
			action: 'sanitize-mapdata',
			text: geoJsonString,
			title: mw.config.get( 'wgPageName' )
		} ).done( function ( resp ) {
			var geoJson, layer,
				data = resp[ 'sanitize-mapdata' ];

			geoJsonString = data && data.sanitized;

			if ( geoJsonString && !data.error ) {
				try {
					geoJson = JSON.parse( geoJsonString );
					layer = mw.kartographer.getKartographerLayer( map );
					layer.setGeoJSON( geoJson );
					deferred.resolve();
				} catch ( e ) {
					deferred.reject( e );
				}
			} else {
				deferred.reject();
			}
		} );

		return deferred.promise();
	};

	function getWindowManager() {
		if ( !windowManager ) {
			windowManager = new OO.ui.WindowManager();
			mapDialog = new mw.kartographer.MapDialog();
			$( 'body' ).append( windowManager.$element );
			windowManager.addWindows( [ mapDialog ] );
		}
		return windowManager;
	}

	/**
	 * Open a full screen map
	 *
	 * @param {Object} data Map data
	 * @param {L.mapbox.Map} [map] Optional map to get current state from
	 */
	mw.kartographer.openFullscreenMap = function ( data, map ) {
		mw.loader.using( 'ext.kartographer.fullscreen' ).done( function () {
			var center;
			if ( map ) {
				center = map.getCenter();
				data.latitude = center.lat;
				data.longitude = center.lng;
				data.zoom = map.getZoom();
			}
			// full screen map should never show "full screen" button
			data.enableFullScreenButton = false;
			getWindowManager()
				.openWindow( mapDialog, data )
				.then( function ( opened ) { return opened; } )
				.then( function ( closing ) {
					if ( map ) {
						map.setView( mapDialog.map.getCenter(), mapDialog.map.getZoom() );
					}
					return closing;
				} );
		} );
	};

	/**
	 * Gets the map data attached to an element.
	 *
	 * @param {HTMLElement} element Element
	 * @return {Object|null} Map properties
	 * @return {number} return.latitude Latitude
	 * @return {number} return.longitude Longitude
	 * @return {number} return.zoom Zoom level
	 * @return {string} return.style Map style
	 * @return {string[]} return.overlays Overlay groups
	 */
	function getMapData( element ) {
		var $el = $( element );
		// Prevent users from adding map divs directly via wikitext
		if ( $el.attr( 'mw-data' ) !== 'interface' ) {
			return null;
		}

		return {
			latitude: +$el.data( 'lat' ),
			longitude: +$el.data( 'lon' ),
			zoom: +$el.data( 'zoom' ),
			style: $el.data( 'style' ),
			overlays: $el.data( 'overlays' )
		};
	}

	/**
	 * Returns the map data for the page.
	 *
	 * If the data is not already loaded (`wgKartographerLiveData`), an
	 * asynchronous request will be made to fetch the missing groups.
	 * The new data is then added to `wgKartographerLiveData`.
	 *
	 * @param {string[]} overlays Overlay group names
	 * @return {jQuery.Promise} Promise which resolves with the group data, an object keyed by group name
	 */
	function getMapGroupData( overlays ) {
		var deferred = $.Deferred(),
			groupsLoaded = mw.config.get( 'wgKartographerLiveData' ) || {},
			groupsToLoad = [];

		$( overlays ).each( function ( key, value ) {
			if ( !( value in groupsLoaded ) ) {
				groupsToLoad.push( value );
			}
		} );

		if ( !groupsToLoad.length ) {
			return deferred.resolve( groupsLoaded ).promise();
		}

		new mw.Api().get( {
			action: 'query',
			formatversion: '2',
			titles: mw.config.get( 'wgPageName' ),
			prop: 'mapdata',
			mpdgroups: groupsToLoad.join( '|' )
		} ).done( function ( data ) {
			var rawMapData = data.query.pages[ 0 ].mapdata,
				mapData = JSON.parse( rawMapData );

			$.extend( groupsLoaded, mapData );
			mw.config.set( 'wgKartographerLiveData', groupsLoaded );

			deferred.resolve( groupsLoaded );
		} );

		return deferred.promise();
	}

	mw.hook( 'wikipage.content' ).add( function ( $content ) {
		var mapsInArticle = [];

		$content.on( 'click', '.mw-kartographer-link', function ( ) {
			var data = getMapData( this );

			if ( data ) {
				mw.kartographer.openFullscreenMap( data );
			}
		} );

		L.Map.mergeOptions( {
			sleepTime: 250,
			wakeTime: 1000,
			sleepNote: false,
			sleepOpacity: 1
		} );
		$content.find( '.mw-kartographer-interactive' ).each( function () {
			var map,
				data = getMapData( this );

			if ( data ) {
				data.enableFullScreenButton = true;
				map = mw.kartographer.createMap( this, data );
				map.doubleClickZoom.disable();

				mapsInArticle.push( map );

				$( this ).on( 'dblclick', function () {
					mw.kartographer.openFullscreenMap( data, map );
				} );
			}
		} );

		// Allow customizations of interactive maps in article.
		mw.hook( 'wikipage.maps' ).fire( mapsInArticle, false /* isFullScreen */ );
	} );

}( jQuery, mediaWiki ) );