MediaWiki:Gadget-eventsCalendarNavigation.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/*
* EventsCalendar
*
* Change a static [[Template:Events calendar]] into a dynamic one.
* Allow the user to toggle between the different views (grid, list, map),
* to navigate between different months and to dynamicaly manage filters.
*
* Author: [[User:0x010C]]
* Creation: 14 April 2017
* Last edit: 4 May 2017
*/
//<nowiki>

( function ( mw  ) {
	const baseTemplate = '{{Events calendar|display=$(display)|lang=$(lang)|month=$(month)|year=$(year)|locations=$(locations)|tags=$(tags)}}';
	window.eventsCalendars = [];

	var EventsCalendar = function( $element ) {
		this.$element = $element;

		this.display = $element.attr( 'data-display' );
		this.lang = $element.attr( 'data-lang' );
		this.year = parseInt( $element.attr( 'data-year' ) );
		this.month = parseInt( $element.attr( 'data-month' ) );
		this.locations = $element.attr( 'data-locations' );
		this.tags = $element.attr( 'data-tags' );

		this.preparePopup();
		this.addListeners();
	};

	EventsCalendar.prototype.addListeners = function() {
		var self = this;
		$( '.events-calendar-noscript' ).hide();
		this.$element.find( '.events-calendar-grid' ).css( 'cursor', 'pointer' ).click( function() {
			self.display = 'grid';
			self.reloadView();
		} );
		this.$element.find( '.events-calendar-list' ).css( 'cursor', 'pointer' ).click( function() {
			self.display = 'list';
			self.reloadView();
		} );
		this.$element.find( '.events-calendar-map' ).css( 'cursor', 'pointer' ).click( function() {
			self.display = 'map';
			self.reloadView();
		} );
		this.$element.find( '.events-calendar-prev' ).css( 'cursor', 'pointer' ).click( function() {
			self.month--;
			if ( self.month === 0 ) {
				self.month = 12;
				self.year--;
			}
			self.reloadView();
		} );
		this.$element.find( '.events-calendar-next' ).css( 'cursor', 'pointer' ).click( function() {
			self.month = ( self.month % 12 ) + 1;
			if ( self.month === 1 ) {
				self.year++;
			}
			self.reloadView();
		} );
		this.$element.find( '.events-calendar-settings' ).css( 'cursor', 'pointer' ).click( function() {
			self.popup.openWindow( self.popupContent );
		} );
		$( '.ec-advanced-icons' ).show();
	};
	EventsCalendar.prototype.removeListeners = function() {
		this.$element.find( '.events-calendar-grid' ).off( 'click' );
		this.$element.find( '.events-calendar-list' ).off( 'click' );
		this.$element.find( '.events-calendar-map' ).off( 'click' );
		this.$element.find( '.events-calendar-prev' ).off( 'click' );
		this.$element.find( '.events-calendar-next' ).off( 'click' );
	};
	EventsCalendar.prototype.reloadView = function() {
		var template = baseTemplate.replace( '$(display)', this.display )
		.replace( '$(lang)', this.lang )
		.replace( '$(year)', this.year )
		.replace( '$(month)', this.month )
		.replace( '$(locations)', this.locations )
		.replace( '$(tags)', this.tags );

		this.removeListeners();
		mw.hook( 'eventscalendar.deleting' ).fire( this.$element );

		var self = this;
		mw.loader.using( [ 'mediawiki.api' ], function() {
			var api = new mw.Api();
			api.parse( template ).then( function( html ) {
				self.$element.fadeOut(30, function() {
					$(this).html( $( html ).html() )
						.fadeIn(200)
						.queue(function(){
						self.addListeners();
						mw.hook( 'wikipage.content' ).fire( $( 'body' ) );
						mw.hook( 'eventscalendar.ready' ).fire( self.$element );
					})
						.dequeue();
				});
			} );
		} );
	};
	EventsCalendar.prototype.preparePopup = function() {
		var self = this;
		mw.loader.using( 'oojs-ui', function() {
			function SettingsProcessDialog( config ) {
				SettingsProcessDialog.parent.call( this, config );
			}

			OO.inheritClass( SettingsProcessDialog, OO.ui.ProcessDialog );

			SettingsProcessDialog.static.name = 'settingsProcessDialog';
			SettingsProcessDialog.static.title = 'Paramètres';
			SettingsProcessDialog.static.size = 'large';
			SettingsProcessDialog.static.actions = [
				{ action: 'save', label: 'Filtrer !', flags: [ 'primary', 'progressive' ] },
				{ label: 'Annuler', flags: 'safe' }
			];
			
			SettingsProcessDialog.prototype.initialize = function () {
				SettingsProcessDialog.parent.prototype.initialize.apply( this, arguments );

				var displayFieldset = new OO.ui.FieldsetLayout( { label: 'Options d\'affichage', } );
				var filterFieldset = new OO.ui.FieldsetLayout( { label: 'Options de filtrage', } );

				self.langInput = new OO.ui.TextInputWidget( { value: self.lang } );
				self.locationsInput = new OO.ui.MenuTagMultiselectWidget( { menu: { items: [] }, allowArbitrary: true, allowDuplicates: false, $overlay: this.$overlay } );
				self.tagsInput = new OO.ui.MenuTagMultiselectWidget( { label: 'TagMultiselectWidget', menu: { items: [] }, allowArbitrary: true, allowDuplicates: false, $overlay: this.$overlay } );

				displayFieldset.addItems( [ new OO.ui.FieldLayout( self.langInput, {label: 'Langue :', align: 'left', help: '' } ), ] );

				filterFieldset.addItems( [ 
					new OO.ui.FieldLayout( self.locationsInput, { label: 'Lieux :', align: 'left', help: '' } ),
					new OO.ui.FieldLayout( self.tagsInput, { label: 'Tags :', align: 'left', help: '', } ),
				] );
				
				this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
				this.content.$element.append( displayFieldset.$element ).append( filterFieldset.$element );
				this.$body.append( this.content.$element );
				
				var api = new mw.Api();
				var _self = this;
				api.get( {
					action: 'query',
					prop: 'revisions',
					rvprop: [ 'content' ],
					titles: 'Events calendar/parameters.json',
					formatversion: '2',
				} ).then( function( data ) {
					var content = JSON.parse( data.query.pages[ 0 ].revisions[ 0 ].content );
					_self.populateMenu( self.locationsInput, content.locations );
					_self.populateMenu( self.tagsInput, content.tags );
					
					if ( self.locations.length > 0 ) {
						self.locationsInput.setValue( self.locations.split( ',' ) );
					}
					if ( self.tags.length > 0 ) {
						self.tagsInput.setValue( self.tags.split( ',' ) );
					}
				} );
			};
			SettingsProcessDialog.prototype.populateMenu = function( selectWidget, data, level ) {
				level = level || 0;
				var _self = this;
				$.each( data, function( key, value ) {
					var data = '',
							text = '',
							offset = '';
					for(var i=0; i<level; i++) {
						offset = offset + ' ';
					}
					if ( typeof value.text === 'string' ) {
						data = value.text;
						text = value.text;
					}
					else {
						if ( value.text.en !== undefined ) {
							data = value.text.en;
							text = value.text.en;
						}
						if ( value.text[ self.lang ] !== undefined ) {
							text = value.text[ self.lang ];
						}
					}
					
					selectWidget.addOptions( [ {
						data: data,
						label: offset + text,
					} ] );
					
					if ( value.sub !== undefined ) {
						_self.populateMenu( selectWidget, value.sub, level + 1 );
					}
				} );
			};
			SettingsProcessDialog.prototype.getActionProcess = function ( action ) {
				var dialog = this;
				
				if ( action ) {
					if ( action === 'save' ) {
						self.locations = self.locationsInput.getValue().join( ',' );
						self.tags = self.tagsInput.getValue().join( ',' );
						self.lang = self.langInput.getValue();
						
						self.reloadView();
					}
					return new OO.ui.Process( function () {
						dialog.close( { action: action } );
					} );
				}
				return SettingsProcessDialog.parent.prototype.getActionProcess.call( this, action );
			};

			self.popup = new OO.ui.WindowManager();
			$( 'body' ).append( self.popup.$element );

			self.popupContent = new SettingsProcessDialog();
			self.popup.addWindows( [ self.popupContent ] );
		} );
	};


	$( '.events-calendar' ).each( function() {
		eventsCalendars.push( new EventsCalendar( $( this ) ) );
		mw.hook( 'eventscalendar.ready' ).fire( $( this ) );
	} )

} )( mediaWiki );

//</nowiki>