MediaWiki:Gadget-WhereWikimediansLive.js

Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;

Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
/*
* WhereWikimediansLive
*
* Permet de s'ajouter à la [[Wikipédia:Cartographie de la communauté]].
*
* Auteur : [[User:0x010C]]
* {{Projet:JavaScript/Script|WhereWikimediansLive}}
*/
//<nowiki>



var _wwlMessages = {
	'fr': {
		'wwl-button-edit': 'Modifier mon marqueur',
		'wwl-button-remove': 'Supprimer ma position',
		'wwl-button-add': 'Ajouter ma position',
		'wwl-dialog-remove-title': 'Voulez-vous vraiment retirer votre position ?',
		'wwl-dialog-remove-message': 'L\'information restera cependant disponible dans l\'historique. Si vous souhaitez que les informations soient également retirées de l\'historique, contactez un masqueur par e-mail à l\'adresse oversight-commons@lists.wikimedia.org.',
		'wwl-dialog-remove-button-cancel': 'Annuler',
		'wwl-dialog-remove-button-delete': 'Supprimer',
		'wwl-form-button-add': 'Ajouter',
		'wwl-form-link-new-translation': 'Ajouter une description dans une autre langue',
		'wwl-form-fieldset-wikis-title': 'Mes wikis',
		'wwl-form-fieldset-descriptions-title': 'Présentation',
		'wwl-form-button-save': 'Enregistrer',
		'wwl-form-fieldset-wikis-text': 'Sélectionnez votre projet Wikimédia principal, choisissez votre langue, puis cliquez sur "Ajouter". Répétez l\'opération pour les autres projets auxquels vous participez.',
		'wwl-form-description-placeholder': 'Présentez-vous en quelques mots.',
		'wwl-notify-success-add': 'Votre position a été ajoutée sur la carte !',
		'wwl-notify-success-edit': 'Vos informations ont correctement été modifiées sur la carte.',
		'wwl-notify-success-remove': 'Votre position a été retirée de la carte.',
		'wwl-notify-wait': 'Enregistrement en cours, veuillez patienter. En fonction de votre configuation, cette étape peut durer jusqu\'à 1 minute.',
		'wwl-notify-error-get': 'Impossible de récupérer les données sur Commons.',
		'wwl-notify-error-save': 'Une erreur est survenue lors de l\'enregistrement des informations sur Commons.',
	},
	'en': {
		'wwl-button-edit': 'Edit my marker',
		'wwl-button-remove': 'Delete my position',
		'wwl-button-add': 'Add my position',
		'wwl-dialog-remove-title': 'Are you sure you want to remove your position? ?',
		'wwl-dialog-remove-message': 'The information will however remain available in the history. If you want the information also to be removed from the history, contact a masker by e-mail at oversight-commons@lists.wikimedia.org.',
		'wwl-dialog-remove-button-cancel': 'Cancel',
		'wwl-dialog-remove-button-delete': 'Remove',
		'wwl-form-button-add': 'Add',
		'wwl-form-link-new-translation': 'Add a description in an other language',
		'wwl-form-fieldset-wikis-title': 'My wikis',
		'wwl-form-fieldset-descriptions-title': 'Description',
		'wwl-form-button-save': 'Save',
		'wwl-form-fieldset-wikis-text': 'Select your main Wikimedia project, choose your language and click "Add". Repeat for the other projects you contribute to.',
		'wwl-form-description-placeholder': 'Present yourself in a few words.',
		'wwl-notify-success-add': 'Your position has been successfully added to the map!',
		'wwl-notify-success-edit': 'Your information has been correctly modified on the map.',
		'wwl-notify-success-remove': 'Your position has been removed from the map.',
		'wwl-notify-wait': 'Saving in progress. Please, be patient, it may take up to 1 minute.',
		'wwl-notify-error-get': 'Unable to retrieve data from Commons.',
		'wwl-notify-error-save': 'An error occurred while registering Commons information.',
	}
};


if ( $( '#wwl-map' ).length ) {
	mw.loader.using( [ 'ext.kartographer.frame', 'mediawiki.api', 'oojs-ui' ], function() {
		// Initialize all neaded vars
		var kartoBox = mw.loader.require( 'ext.kartographer.box' ),
				api = mw.config.get( 'wgWikiID' ) === 'commonswiki' ? new mw.Api() : new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' ),
				localApi = new mw.Api(),
				username = mw.config.get( 'wgUserName' ),
				map,
				popup,
				marker,
				userData,
				userLanguage = mw.config.get( 'wgUserLanguage' ),
				allLanguages = {},
				dropdownLanguages = [],
				currentWiki = {
					'dbname': mw.config.get( 'wgDBname' ),
					'langcode': null,
					'sitecode': null,
				},
				siteMatrix = {
					//multilingual wikis
					'wiki': { label: 'Wikipedia', name: 'Wikipedia', data: 'wiki', shortcode: 'w', color: '#ACFA58', sites: [] },
					'wiktionary': { label: 'Wiktionary', name: 'Wiktionary', data: 'wiktionary', shortcode: 'wikt', color: '#F4FA58', sites: [] },
					'wikibooks': { label: 'Wikibooks', name: 'Wikibooks', data: 'wikibooks', shortcode: 'b', color: '#e2cc8a', sites: [] },
					'wikinews': { label: 'Wikinews', name: 'Wikinews', data: 'wikinews', shortcode: 'n', color: '#575ff9', sites: [] },
					'wikiquote': { label: 'Wikiquote', name: 'Wikiquote', data: 'wikiquote', shortcode: 'q', color: '#57f9b9', sites: [] },
					'wikisource': { label: 'Wikisource', name: 'Wikisource', data: 'wikisource', shortcode: 's', color: '#FAAC58', sites: [] },
					'wikiversity': { label: 'Wikiversity', name: 'Wikiversity', data: 'wikiversity', shortcode: 'v', color: '#cecece', sites: [] },
					'wikivoyage': { label: 'Wikivoyage', name: 'Wikivoyage', data: 'wikivoyage', shortcode: 'voy', color: '#f957ba', sites: [] },
					//monolingual wikis
					'meta': { label: 'Meta', name: 'Meta', data: 'meta', shortcode: 'm', color: '#D358F7' },
					'commons': { label: 'Wikimedia Commons', name: 'Wikimedia Commons', data: 'commons', shortcode: 'c', color: '#58ACFA' },
					'wikidata': { label: 'Wikidata', name: 'Wikidata', data: 'wikidata', shortcode: 'd', color: '#FA5858' },
					'species': { label: 'Wikispecies', name: 'Wikispecies', data: 'species', shortcode: 'species', color: '#339650' },
					'mediawiki': { label: 'MediaWiki', name: 'MediaWiki', data: 'mediawiki', shortcode: 'mw', color: '#ffffc8' },
				};

		// Get initial datas
		function getData() {
			api.get( {
				action: 'query',
				prop: 'revisions',
				rvprop: [ 'content' ],
				titles: 'Data:Wikimedians.map',
				formatversion: '2',
			} ).fail( function( data ) {
				mw.notify( mw.msg( 'wwl-notify-error-get' ) , { autoHide: false, title: 'WhereWikimediansLives', type: 'error' } );
				console.log( 'WhereWikimediansLive: Failed to fetch initial datas from Commons.' );
				console.log( data );
			} ).then( function( data ) {
				content = JSON.parse( data.query.pages[ 0 ].revisions[ 0 ].content );

				$.each( content.data.features, function( key, userInfos ) {
					if ( userInfos.username === username ) {
						var projects = [];
						$.each( userInfos.data, function( project, langs ) {
							$.each( langs, function( _, lang ) {
								projects.push( { project: project, lang:lang } );
							} );
						} );
						userData = {
							lat: userInfos.geometry.coordinates[ 1 ],
							lng: userInfos.geometry.coordinates[ 0 ],
							projects: projects,
							descriptions: userInfos.properties.description,
						};
						return false;
					}
				} );
				return localApi.get( {
					action: "sitematrix",
					format: "json",
					formatversion: 2
				} );
			} ).then( function( data ) {
				$.each( data.sitematrix, function( key, lang ) {
					if ( key !== 'specials' && key !== 'count' ) {
						allLanguages[ lang.code ] = {
							'name': lang.name,
							'localname': lang.localname,
						};
						$.each( lang.site, function( _, site ) {
							if ( site.private !== true && site.closed !== true && site.fishbowl !== true ) {
								siteMatrix[ site.code ].sites.push( {
									'data': lang.code,
									'dbname': site.dbname,
									'label': lang.localname
								} );
							}
							if ( site.dbname === currentWiki.dbname ) {
								currentWiki.langcode = lang.code;
								currentWiki.sitecode = site.code;
							}
							if ( lang.code === userLanguage ) {
								siteMatrix[ site.code ].label = site.sitename;
							}
						} );
					}
				} );

				if( currentWiki.sitecode === null ) {
					$.each( data.sitematrix.specials, function( _, site ) {
						if ( site.dbname === currentWiki.dbname ) {
							currentWiki.sitecode = site.code;
							return false;
						}
					} )
				}
				if ( currentWiki.langcode === null ) {
					currentWiki.langcode = 'en';
				}

				$.each( siteMatrix, function( _, project ) {

					if ( project.sites !== undefined ) {
						for( var i = 0; i < project.sites.length; i++ ) {
							if ( project.sites[ i ].label === undefined ) {
								project.sites.splice( i, 1 );
							}
						}
						project.sites.sort(function(a,b) { return ( a.label.toLowerCase() > b.label.toLowerCase() ) ? 1 : ( ( b.label.toLowerCase() > a.label.toLowerCase() ) ? -1 : 0 ); } );
					}
				} );

				$.each( allLanguages, function( code, langInfos ) {
					if ( langInfos.localname !== undefined ) {
						dropdownLanguages.push( { data: code, label: langInfos.localname } );
					}
				} );
				dropdownLanguages.sort(function(a,b) { return ( a.label.toLowerCase() > b.label.toLowerCase() ) ? 1 : ( ( b.label.toLowerCase() > a.label.toLowerCase() ) ? -1 : 0 ); } );
				addButtons();
			} );
		}

		// Add the buttons at the bottom of the page
		function addButtons() {
			var buttonContainer = $( '#wwl-buttons' );
			if ( buttonContainer.length === 0 ) {
				buttonContainer = $( '<div id="wwl-buttons" class="wwl-default-buttons" >' );
				$( '#wwl-map' ).after( buttonContainer );
			}

			if ( userData !== undefined ) {
				var editButton = new OO.ui.ButtonWidget( {
					label: mw.msg( 'wwl-button-edit' ),
					icon: 'settings',
					title: 'Edit',
					flags: [ 'progressive' ]
				} );
				editButton.on( 'click', function() {
					editButton.setDisabled( true );
					openMap();
				} );
				var removeButton = new OO.ui.ButtonWidget( {
					label: mw.msg( 'wwl-button-remove' ),
					icon: 'remove',
					title: 'Remove',
					flags: [ 'destructive' ]
				} );
				removeButton.on( 'click', function() {
					openRemoveDialog();
				} );
				buttonContainer.append( editButton.$element[ 0 ] );
				buttonContainer.append( removeButton.$element[ 0 ] );
			} else {
				var addButton = new OO.ui.ButtonWidget( {
					label: mw.msg( 'wwl-button-add' ),
					icon: 'add',
					title: 'Add',
					flags: [ 'primary', 'progressive' ]
				} );
				addButton.on( 'click', function() {
					addButton.setDisabled( true );
					openMap();
				} );
				buttonContainer.append( addButton.$element[ 0 ] );
			}
		}

		function openRemoveDialog() {
			var messageDialog = new OO.ui.MessageDialog();
			var windowManager = new OO.ui.WindowManager();
			$( 'body' ).append( windowManager.$element );
			windowManager.addWindows( [ messageDialog ] );

			windowManager.openWindow( messageDialog, {
				title: mw.msg( 'wwl-dialog-remove-title' ),
				message: mw.msg( 'wwl-dialog-remove-message' ),
				size: 'medium',
				actions: [ {
					label: mw.msg( 'wwl-dialog-remove-button-cancel' ),
					action: 'cancel'
				},
									{
										label: mw.msg( 'wwl-dialog-remove-button-delete' ),
										action: 'delete',
										flags: 'destructive'
									},
								 ],
			} ).then( function( opened ) {
				opened.then( function( closing, data ) {
					if ( data && data.action == 'delete' ) {
						removeDataFromMap();
					}
				} );
			} );
		}

		function openMap() {
			var lat, lng, zoom;
			if ( userData === undefined ) {
				// Get the coordinates of the map
				lat = $( '#wwl-map .mw-kartographer-map' ).attr( 'data-lat' );
				lng = $( '#wwl-map .mw-kartographer-map' ).attr( 'data-lon' );
				zoom = $( '#wwl-map .mw-kartographer-map' ).attr( 'data-zoom' );
			} else {
				lat = userData.lat;
				lng = userData.lng;
				zoom = 12;
			}

			if ( map === undefined ) {
				// Create the map
				map = kartoBox.map( {
					container: $( '#wwl-map' ).empty().css( {
						height: 500
					} )[ 0 ],
					center: [ lat, lng ],
					zoom: zoom,
					alwaysInteractive: true,
					//allowFullScreen: true, //TODO: allow full screen selection-map
				} );

				// Prepare the popup
				preparePopup();
				if ( userData !== undefined ) {
					marker.setLatLng( [ lat, lng ] ).addTo( map ).openPopup();
				}
			}
		}

		function generateGeoJSON( lat, lng, descriptions, wikis, color ) {
			return {
				"type": "Feature",
				"properties": {
					"marker-size": "small",
					"marker-color": color,
					"marker-symbol": "circle-stroked",
					"title": '<div style="margin-bottom: 5px;">' + username + '</div>',
					"description": descriptions
				},
				"geometry": {
					"type": "Point",
					"coordinates": [
						parseFloat( lng ),
						parseFloat( lat )
					]
				},
				"username": username,
				"data": wikis
			};
		}

		function createForm() {
			// Initialise all widgets and fieldsets
			var projectDropdown = new OO.ui.DropdownInputWidget( { classes: [ 'wwl-dropdown' ], options: Object.keys( siteMatrix ).map( function ( key ) { return siteMatrix[ key ]; } ) } ).setValue( currentWiki.sitecode ),
					projectLangDropdown = new OO.ui.DropdownInputWidget( { classes: [ 'wwl-dropdown' ], options: ( siteMatrix[ currentWiki.sitecode ].sites !== undefined ? siteMatrix[ currentWiki.sitecode ].sites : siteMatrix.wiki.sites ) } ).setValue( currentWiki.langcode ),
					addWikiButton = new OO.ui.ButtonInputWidget( { label: mw.msg( 'wwl-form-button-add' ), flags: [ 'constructive' ] } ),
					allWikisMultiselect = new OO.ui.TagMultiselectWidget( { allowArbitrary: true, allowEditTags: false, allowDuplicates: false, inputPosition: 'none' } ),
					descriptionLangDropdowns = [],
					descriptionInputs = [],
					addDescriptionLink = new OO.ui.ButtonWidget( { framed: false, flags: [ 'constructive' ], label: mw.msg( 'wwl-form-link-new-translation' ) } ),
					wikisFieldset = new OO.ui.FieldsetLayout( { label: mw.msg( 'wwl-form-fieldset-wikis-title' ), classes: [ 'wwl-fieldset' ] } ),
					descriptionsFieldset = new OO.ui.FieldsetLayout( { label: mw.msg( 'wwl-form-fieldset-descriptions-title' ), classes: [ 'wwl-fieldset' ] } ),
					saveButton = new OO.ui.ButtonInputWidget( { label: mw.msg( 'wwl-form-button-save' ), flags: [ 'constructive', 'primary' ] } );


			// Add the widgets in the fieldsets
			wikisFieldset.addItems( [
				new OO.ui.FieldLayout(
					new OO.ui.Widget( { content: [ new OO.ui.HorizontalLayout( {
						items: [ projectDropdown, projectLangDropdown, addWikiButton ]
					} ) ]
														} ),
					{
						label: mw.msg( 'wwl-form-fieldset-wikis-text' ),
						align: 'top'
					}
				),
				allWikisMultiselect
			] );
			descriptionsFieldset.addItems( [
				addDescriptionLink
			] );

			// Managing the addition of new descriptions
			function addDescriptionWidgets( lang, description ) {
				lang = lang || 'en';
				description = description || '';
				var descriptionLangDropdown = new OO.ui.DropdownInputWidget( { options: dropdownLanguages, classes: [ 'wwl-dropdown' ] } ).setValue( lang );
				var descriptionInput = new OO.ui.TextInputWidget( { placeholder: mw.msg( 'wwl-form-description-placeholder' ), multiline: true, value: '', classes: [ 'wwl-textarea' ] } ).setValue( description );
				descriptionsFieldset.addItems( [
					new OO.ui.Widget( {
						content: [ new OO.ui.HorizontalLayout( {
							items: [ descriptionLangDropdown, descriptionInput ]
						} ) ]
					} ),
				], descriptionsFieldset.getItemCount() - 1 );

				descriptionLangDropdowns.push( descriptionLangDropdown );
				descriptionInputs.push( descriptionInput );
			}

			//Populate
			if ( userData !== undefined ) {
				$.each( userData.descriptions, function( lang, description ) {
					addDescriptionWidgets( lang, description.split( '<div class="wwl-projects">' )[ 0 ].replace( '<br>', '\n' ) );
				} );
				$.each( userData.projects, function( _, wiki ) {
					allWikisMultiselect.addTag( wiki.project + ',' + wiki.lang, wiki.lang + wiki.project );
				} );
			}
			else {
				addDescriptionWidgets();
			}

			// Manage the differents interactions and events with the widgets
			projectDropdown.on( 'change', function( project ) {
				projectLangDropdown.setOptions( ( siteMatrix[ project ].sites !== undefined ? siteMatrix[ project ].sites : siteMatrix.wiki.sites ) ).setValue( currentWiki.langcode );
			} );
			addWikiButton.on( 'click', function() {
				allWikisMultiselect.addTag( projectDropdown.getValue() + ',' + projectLangDropdown.getValue(), projectLangDropdown.getValue() + projectDropdown.getValue() );
			} );
			addDescriptionLink.on( 'click', addDescriptionWidgets );
			saveButton.on( 'click', function() {
				saveButton.setDisabled( true );
				mw.notify( mw.msg( 'wwl-notify-wait' ) );

				var wikis = {},
						descriptions = {},
						wikisDescription = '',
						color;

				$.each( allWikisMultiselect.getValue(), function( key, wiki ) {
					wiki = wiki.split( ',' );
					if ( key === 0 ) {
						color = siteMatrix[ wiki[ 0 ] ].color;
					}
					if ( wikis[ wiki[ 0 ] ] === undefined ) {
						wikis[ wiki[ 0 ] ] = [];
					}
					wikis[ wiki[ 0 ] ].push( wiki[ 1 ] );
				} );
				$.each( wikis, function( project, langs ) {
					if ( siteMatrix[ project ].sites !== undefined ) {
						wikisDescription += '<br>\'\'\'' + siteMatrix[ project ].name + ':\'\'\' ';
						$.each( langs, function( key, lang ) {
							if ( key !== 0 ) {
								wikisDescription += ', ';
							}
							wikisDescription += '[[' + siteMatrix[ project ].shortcode + ':' + lang + ':User:' + username + '|' + lang + ']]';
						} );
					}
					else {
						wikisDescription += '<br>[[' + siteMatrix[ project ].shortcode + ':User:' + username + '|\'\'\'' + siteMatrix[ project ].name + '\'\'\']]';
					}
				} );

				$.each( descriptionInputs , function( key, _ ) {
					descriptions[ descriptionLangDropdowns[ key ].getValue() ] = descriptionInputs[ key ].getValue().replace(/(\r\n|\n\r|\r|\n)/g, '<br>' )
				} );
				$.each( descriptions, function( key, _ ) {
					descriptions[ key ] += '<div class="wwl-projects"><small>' + wikisDescription + '</small></div>';
				} );

				var geojson = generateGeoJSON( marker.getLatLng().lat.toFixed( 6 ), marker.getLatLng().lng.toFixed( 6 ), descriptions, wikis, color )
				if ( userData === undefined ) {
					addDataToMap( geojson );
				}
				else {
					editDataOnMap( geojson );
				}
			} );

			return $( '<div class="wwl-form">' ).append( wikisFieldset.$element[ 0 ] ).append( descriptionsFieldset.$element[ 0 ] ).append( saveButton.$element[ 0 ] )[ 0 ];
		}

		function preparePopup() {

			popup = L.popup( {
				minWidth: 465,
				className: ''
			} );

			popup.setContent( createForm() );

			marker = L.marker([0, 0], {
				icon: L.icon( {
					iconUrl: 'https://maps.wikimedia.org/v4/marker/pin-l-building+FFD700.png',
					iconSize: [ 35, 90 ],
					iconAnchor: [ 17, 47 ],
					popupAnchor: [ 0, -47 ],
				} )
			} ).bindPopup( popup );

			map.on( 'click', onMapClick );

		}

		function onMapClick( e ) {
			lat = e.latlng.lat;
			lng = e.latlng.lng;
			marker.setLatLng( [ lat, lng ] ).addTo( map ).openPopup();
		}

		function addDataToMap( geojson ) {
			api.edit( 'Data:Wikimedians.map', function ( revision ) {
				var content = JSON.parse( revision.content );
				content.data.features.push( geojson );
				return {
					text: JSON.stringify( content, null, 4 ),
					summary: 'Adding ' + username + ' to the map.',
					//tag: ''
				};
			} )
				.then( function () {
				mw.notify( mw.msg( 'wwl-notify-success-add' ) );
				onSaved();
			} )
				.fail( onFail );
		}

		function editDataOnMap( geojson ) {
			api.edit( 'Data:Wikimedians.map', function ( revision ) {
				var content = JSON.parse( revision.content );
				$.each( content.data.features, function( key, userContent ) {
					if ( userContent.username === username ) {
						content.data.features[ key ] = geojson;
						return false;
					}
				} );
				return {
					text: JSON.stringify( content, null, 4 ),
					summary: 'Change informations of ' + username + '.',
					//tag: ''
				};
			} )
				.then( function () {
				mw.notify( mw.msg( 'wwl-notify-success-edit' ) );
				onSaved();
			} )
				.fail( onFail );
		}

		function removeDataFromMap() {
			api.edit( 'Data:Wikimedians.map', function ( revision ) {
				var content = JSON.parse( revision.content );
				$.each( content.data.features, function( key, userContent ) {
					if ( userContent.username === username ) {
						content.data.features.splice(key, 1);
						return false;
					}
				} );
				return {
					text: JSON.stringify( content, null, 4 ),
					summary: 'Removing ' + username + ' from the map.',
					//tag: ''
				};
			} )
				.then( function () {
				mw.notify( mw.msg( 'wwl-notify-success-remove' ) );
				onSaved();
			} )
				.fail( onFail );
		}

		function onSaved() {
			localApi.post( {
				action: 'purge',
				forcelinkupdate: '1',
				titles: mw.config.get( 'wgPageName' )
			} ).done( function( data ) {
				location.reload();
			} );
		}

		function onFail() {
			mw.notify( mw.msg( 'wwl-notify-error-save' ) );
			console.log( 'WhereWikimediansLive: Error while saving datas on commons.' );
			console.log( data );
		}

		if ( typeof wwlMessages !== 'undefined' ) {
			Object.assign( _wwlMessages, wwlMessages );
		}
		mw.messages.set( _wwlMessages[ 'en' ] );
		if ( userLanguage !== 'en' && userLanguage in _wwlMessages ) {
			mw.messages.set( _wwlMessages[ userLanguage ] );
		}

		$( '#wwl-defaulttext' ).hide();
		$( '#wwl-gadgettext' ).show();
		getData();

	} );
}

//</nowiki>