Current File : /home/jvzmxxx/wiki1/extensions/Kartographer/modules/dialog-sidebar/sidebar.js
/* globals module */
/**
 * Sidebar class for displaying map details and other services.
 *
 * @class Kartographer.DialogSideBar
 */
module.exports = ( function ( $, mw ) {

	/**
	 * @constructor
	 * @param {Object} options
	 */
	var SideBar = function ( options ) {
			/**
			 * @property {Kartographer.Dialog.DialogClass}
			 */
			this.dialog = options.dialog;

			/**
			 * @property {Object}
			 */
			this.metadata = mw.config.get( 'wgKartographerExternalLinks' );
			this.parseExternalLinks();
		},
		MODULE_NAME = 'ext.kartographer.dialog.sidebar',
		selectedType;

	/**
	 * Replaces link variables with contextual data.
	 *
	 * @param {string} url
	 * @return {string}
	 */
	SideBar.prototype.formatLink = function ( url ) {
		var mapPosition = this.mapPosition,
			link = url.replace( new RegExp( '{latitude}', 'g' ), mapPosition.center.lat );
		link = link.replace( new RegExp( '{longitude}', 'g' ), mapPosition.center.lng );
		link = link.replace( new RegExp( '{zoom}', 'g' ), mapPosition.zoom );
		link = link.replace( new RegExp( '{title}', 'g' ), mw.config.get( 'wgTitle' ) );
		link = link.replace( new RegExp( '{language}', 'g' ), mw.config.get( 'wgContentLanguage' ) || mw.config.get( 'wgUserLanguage' ) );
		return link;
	};

	// eslint-disable-next-line valid-jsdoc
	/**
	 * Toggles the sidebar
	 *
	 * @param {boolean} open Whether to open the sidebar or close it.
	 * @chainable
	 */
	SideBar.prototype.toggle = function ( open ) {

		if ( this.$el ) {
			this.tearDown();
		}
		if ( !open ) {
			return;
		}

		this.render();
		return this;
	};

	// eslint-disable-next-line valid-jsdoc
	/**
	 * Renders the sidebar.
	 *
	 * @chainable
	 */
	SideBar.prototype.render = function () {
		var sidebar = this,
			map = sidebar.dialog.map,
			$container;

		/**
		 * @property {jQuery}
		 */
		$container = sidebar.$el = $( '<div class="mw-kartographer-mapDialog-sidebar">' );

		/**
		 * @property {Object}
		 */
		sidebar.mapPosition = map.getMapPosition( { scaled: true } );

		sidebar.createCloseButton().$element.appendTo( $container );

		/**
		 * @property {jQuery}
		 */
		sidebar.$mapDetailsContainer = $( '<div>' ).addClass( 'mw-kartographer-mapdetails' ).appendTo( $container );

		/**
		 * @property {jQuery}
		 */
		sidebar.$descriptionContainer = $( '<div>' ).addClass( 'mw-kartographer-description' ).appendTo( $container );

		/**
		 * @property {jQuery}
		 */
		sidebar.$filterContainer = $( '<div>' ).addClass( 'mw-kartographer-filterservices' ).appendTo( $container );

		/**
		 * @property {jQuery}
		 */
		sidebar.$servicesContainer = $( '<div>' ).addClass( 'mw-kartographer-externalservices' ).appendTo( $container );

		sidebar.renderMapDetails();
		sidebar.renderDescription();
		sidebar.renderTypeFilter();
		sidebar.renderExternalServices();

		$container.appendTo( sidebar.dialog.$body );

		map.on( 'move', sidebar.onMapMove, sidebar );

		sidebar.$servicesContainer.on( 'click', 'a', function () {
			mw.track( 'mediawiki.kartographer', {
				action: 'sidebar-click',
				isFullScreen: true,
				service: $( this ).data( 'service' ),
				type: selectedType,
				feature: map.parentMap || map.parentLink
			} );
		} );

		return sidebar;
	};

	/**
	 * Throttled function that is called on map `move` events, and that
	 * re-renders the parts of the sidebar that depend on the map position.
	 */
	SideBar.prototype.onMapMove = OO.ui.throttle( function () {
		this.mapPosition = this.dialog.map.getMapPosition( { scaled: true } );

		this.renderMapDetails();
		this.renderExternalServices();
	}, 350 );

	/**
	 * Renders the map details partial into its container.
	 */
	SideBar.prototype.renderMapDetails = function () {
		var sidebar = this,
			partial = mw.template.get( MODULE_NAME, 'dialog-sidebar-mapdetails.mustache' ).render( {
				LBL_COORDINATES: mw.msg( 'kartographer-sidebar-coordinates' ),
				LBL_LATITUDE: mw.msg( 'kartographer-sidebar-latitude' ),
				LBL_LONGITUDE: mw.msg( 'kartographer-sidebar-longitude' ),
				LBL_MAP_DETAILS: mw.msg( 'kartographer-sidebar-mapdetails' ),
				latitude: sidebar.mapPosition.center.lat,
				longitude: sidebar.mapPosition.center.lng,
				zoom: sidebar.mapPosition.zoom
			} );

		sidebar.$mapDetailsContainer.html( partial );
	};

	/**
	 * Renders the description partial into its container.
	 */
	SideBar.prototype.renderDescription = function () {
		this.$descriptionContainer.text( mw.msg( 'kartographer-sidebar-description' ) );
	};

	/**
	 * Renders the type filter dropdown into its container.
	 */
	SideBar.prototype.renderTypeFilter = function () {
		var sidebar = this,
			dropdown = sidebar.createFilterDropdown(),
			defaultType = sidebar.metadata.types[ 0 ],
			first = true;

		dropdown.getMenu().on( 'select', function ( item ) {
			selectedType = item.getData();
			sidebar.renderExternalServices();

			// First selection is the default, skip it.
			if ( !first ) {
				mw.track( 'mediawiki.kartographer', {
					action: 'sidebar-type',
					isFullScreen: true,
					type: selectedType,
					feature: sidebar.dialog.map.parentMap || sidebar.dialog.map.parentLink
				} );
			}
			first = false;
		} );
		dropdown.getMenu().selectItemByData( selectedType || defaultType );

		sidebar.$filterContainer.append( dropdown.$element );
	};

	/**
	 * Renders the external services partial into its container.
	 */
	SideBar.prototype.renderExternalServices = function () {
		var sidebar = this,
			services = sidebar.byType[ selectedType ],
			featured = [],
			regular = [],
			partial;

		if ( !selectedType ) {
			return;
		}

		$.each( services, function ( serviceId, links ) {
			// Only one link is supported per type per service for now.
			var link = links[ 0 ],
				service = sidebar.byService[ serviceId ],
				formatted = service.featured ? featured : regular;

			formatted.push( {
				id: serviceId,
				name: service.name,
				featured: service.featured,
				linkLabel: sidebar.metadata.localization[ selectedType ],
				link: sidebar.formatLink( link.url )
			} );
		} );

		partial = mw.template.get( MODULE_NAME, 'dialog-sidebar-externalservices.mustache' ).render(
			{
				LBL_EXTERNAL_SERVICES: mw.msg( 'kartographer-sidebar-externalservices' ),
				LBL_SERVICE: mw.msg( 'kartographer-sidebar-service' ),
				services: featured.concat( regular ),
				latitude: sidebar.mapPosition.center.lat,
				longitude: sidebar.mapPosition.center.lng,
				zoom: sidebar.mapPosition.zoom
			}
		);

		sidebar.$servicesContainer.html( partial );
	};

	/**
	 * Parses external links and builds the convenient {@link #byService} and
	 * {@link #byType} catalogs of services.
	 */
	SideBar.prototype.parseExternalLinks = function () {
		var services = this.metadata.services,
			byService = {},
			byType = {};

		$.each( services, function ( key, service ) {
			byService[ service.id ] = service;
			service.byType = {};

			$.each( service.links, function ( key, link ) {
				service.byType[ link.type ] = service.byType[ link.type ] || [];
				service.byType[ link.type ].push( link );

				byType[ link.type ] = byType[ link.type ] || {};
				byType[ link.type ][ service.id ] = [];
				byType[ link.type ][ service.id ].push( link );
			} );
		} );

		/**
		 * @property {Object}
		 */
		this.byService = byService;

		/**
		 * @property {Object}
		 */
		this.byType = byType;
	};

	/**
	 * Creates a close button instance.
	 *
	 * @return {OO.ui.ButtonWidget}
	 */
	SideBar.prototype.createCloseButton = function () {
		// Add close button to the sidebar
		var sidebar = this,
			button = new OO.ui.ButtonWidget( {
				icon: 'close',
				title: mw.msg( 'kartographer-fullscreen-close' ),
				framed: false,
				classes: [ 'mw-kartographer-mapDialog-closeButton' ]
			} ).connect( this, { click: sidebar.dialog.toggleSideBar.bind( sidebar.dialog, false ) } );
		return button;
	};

	/**
	 * Create a filter dropdown instance.
	 *
	 * @return {OO.ui.DropdownWidget}
	 */
	SideBar.prototype.createFilterDropdown = function () {
		var items = [],
			labels = this.metadata.localization;

		$.each( this.metadata.types, function ( key, type ) {
			items.push(
				new OO.ui.MenuOptionWidget( {
					data: type,
					label: labels[ type ],
					title: labels[ type ]
				} )
			);
		} );

		return new OO.ui.DropdownWidget( {
			label: mw.msg( 'kartographer-sidebar-filterdropdown' ),
			menu: {
				items: items
			}
		} );
	};

	// eslint-disable-next-line valid-jsdoc
	/**
	 * Detaches events and removes the element.
	 *
	 * @chainable
	 */
	SideBar.prototype.tearDown = function () {
		this.dialog.map.off( 'move', this.onMapMove, this );

		this.$el.remove();
		this.$el = null;
		return this;
	};

	return SideBar;
}( jQuery, mediaWiki ) );