User:Putnik/Events-calendar-editor.js
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)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*
* EventsEditor
*
* Allow the user to easily add new events to an [[Template:Events calendar]].
*
* Author: [[User:0x010C]], [[User:Putnik]]
*/
//<nowiki>
( function ( mw ) {
mw.loader.using( [ 'oojs-ui', 'mediawiki.util', 'mediawiki.widgets.datetime' ], function() {
var messages = ( function () {
var translations = {
en: {
addEvent: 'Add an event',
add: 'Add!',
cancel: 'Cancel',
generalInformation: 'General information',
eventDetails: 'Event details:',
name: 'Name',
dateStart: 'Start date',
dateEnd: 'End date',
description: 'Description',
link: 'Event wikipage',
location: 'Location',
locationHelp: 'If your city is not in the list, it must be added to the list [[Events calendar/parameters.json]]',
tags: 'Tags',
languageCodes: 'Language codes',
repeatRules: 'Repeat rules',
repeat: 'Repeat event',
repeatHelp: 'Event will be shown in the calendar several times in accordance with the recurrence conditions',
frequency: 'Frequency',
frequencyHelp: 'Period after which event will occur again; can be extended by the Interval parameter',
weekly: 'Weekly',
interval: 'Interval',
intervalHelp: 'Allows to specify that the event occurs once in N periods, e.g. every 2 weeks',
dateUntil: 'Until date',
dateUntilHelp: 'The last date when event will take place (optional)',
},
fr: {
addEvent: 'Ajouter un évènement',
add: 'Ajouter !',
cancel: 'Annuler',
generalInformation: 'Informations générales',
eventDetails: 'Détails de l\'évènement :',
name: 'Nom',
dateStart: 'Date de début',
dateEnd: 'Date de fin',
description: 'Description',
link: 'Page wiki de l\'évènement',
location: 'Lieu',
locationHelp: 'Si votre ville n\'est pas dans la liste, il faut l\'ajouter à la liste [[Events calendar/parameters.json]]',
tags: 'Tags',
},
ru: {
addEvent: 'Добавить событие',
add: 'Добавить!',
cancel: 'Отменить',
generalInformation: 'Общая информация',
eventDetails: 'Детали события:',
name: 'Название',
dateStart: 'Дата начала',
dateEnd: 'Дата окончания',
description: 'Описание',
link: 'Вики-страница события',
location: 'Место',
locationHelp: 'Если вашего города нет в списке, его необходимо добавить в список [[Events calendar/parameters.json]]',
tags: 'Тэги',
languageCodes: 'Коды языков',
repeatRules: 'Правила повтора',
repeat: 'Повторять событие',
repeatHelp: 'Событие будет показано в календаре несколько раз в соответствии с условиями повторения',
frequency: 'Частота',
frequencyHelp: 'Период, через который событие произойдет снова; может быть расширено параметром «Интервал»',
weekly: 'Еженедельно',
interval: 'Интервал',
intervalHelp: 'Позволяет указать, что событие происходит один раз в N периодов, например каждые 2 недели',
dateUntil: 'До даты',
dateUntilHelp: 'Последняя дата проведения мероприятия (необязательно)',
}
},
chain = mw.language.getFallbackLanguageChain(),
len = chain.length,
ret = {},
i = len - 1;
while ( i >= 0 ) {
if ( translations.hasOwnProperty( chain[i] ) ) {
$.extend( ret, translations[chain[i]] );
}
i--;
}
return ret;
}() );
function EventsEditor( config ) {
EventsEditor.parent.call( this, config );
}
OO.inheritClass( EventsEditor, OO.ui.ProcessDialog );
EventsEditor.static.name = 'eventsEditorDialog';
EventsEditor.static.title = messages.addEvent;
EventsEditor.static.size = 'larger';
EventsEditor.static.height = 400;
EventsEditor.static.actions = [
{ label: messages.add, action: 'save', flags: [ 'primary', 'progressive' ] },
{ label: messages.cancel, flags: 'safe' }
];
EventsEditor.prototype.getBodyHeight = function () {
return 500;
};
EventsEditor.prototype.initialize = function () {
EventsEditor.parent.prototype.initialize.apply( this, arguments );
var self = this;
var MainPageLayout = function( name, config ) {
MainPageLayout.super.call( this, name, config );
this.nameInput = new OO.ui.TextInputWidget();
this.dateStartInput = new mw.widgets.datetime.DateTimeInputWidget( { type: 'datetime', clearable: false, } );
this.dateEndInput = new mw.widgets.datetime.DateTimeInputWidget( { type: 'datetime', clearable: false, } );
this.descriptionInput = new OO.ui.TextInputWidget( { multiline: true, autosize: true, rows: 4, } );
this.linkInput = new OO.ui.TextInputWidget();
this.locationInput = new OO.ui.DropdownInputWidget();
this.tagsInput = new OO.ui.MenuTagMultiselectWidget( { label: 'TagMultiselectWidget', menu: { items: [] }, allowArbitrary: true, allowDuplicates: false, $overlay: self.$overlay, } );
this.langsInput = new OO.ui.MenuTagMultiselectWidget( { label: 'TagMultiselectWidget', menu: { items: [] }, allowArbitrary: true, allowDuplicates: false, $overlay: self.$overlay, } );
//TODO: Change the min/max date of dateStartInput and dateEndInput depending of the value choosen on the other field
/*this.dateStartInput.on( 'change', function( date ) {
} );*/
//Populate location and tags inputs
var _self = this;
new mw.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.locationInput.setOptions( _self.populateMenu( content.locations ) );
_self.tagsInput.addOptions( _self.populateMenu( content.tags ) );
} );
// Create a Fieldset layout.
var fieldset = new OO.ui.FieldsetLayout( {
label: messages.eventDetails,
} );
fieldset.addItems( [
new OO.ui.FieldLayout( this.nameInput, { label: messages.name, align: 'left', help: '', } ),
new OO.ui.FieldLayout( this.dateStartInput, { label: messages.dateStart, align: 'left', help: '', } ),
new OO.ui.FieldLayout( this.dateEndInput, { label: messages.dateEnd, align: 'left', help: '', } ),
new OO.ui.FieldLayout( this.descriptionInput, { label: messages.description, align: 'left', help: '', } ),
new OO.ui.FieldLayout( this.linkInput, { label: messages.link, align: 'left', help: '', } ),
new OO.ui.FieldLayout( this.locationInput, { label: messages.location, align: 'left', help: messages.locationHelp, } ),
new OO.ui.FieldLayout( this.tagsInput, { label: messages.tags, align: 'left', help: '', } ),
new OO.ui.FieldLayout( this.langsInput, { label: messages.languageCodes, align: 'left', help: '', } ),
] );
this.$element.append( fieldset.$element );
};
OO.inheritClass( MainPageLayout, OO.ui.PageLayout );
MainPageLayout.prototype.setupOutlineItem = function () {
this.outlineItem.setLabel( messages.generalInformation );
};
MainPageLayout.prototype.populateMenu = function( data, level, parents ) {
level = level || 0;
parents = parents || '';
var list = [];
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 ];
}
}
list.push( { data: parents + data, label: offset + text, } );
if ( value.sub !== undefined ) {
list = list.concat( _self.populateMenu( value.sub, level + 1, parents + data + ',' ) );
}
} );
return list;
};
var RrulePageLayout = function( name, config ) {
RrulePageLayout.super.call( this, name, config );
this.repeatSwitch = new OO.ui.ToggleSwitchWidget( { value: false } );
this.freqSelect = new OO.ui.SelectWidget( { items: [
new OO.ui.OptionWidget( { data: 'weekly', label: messages.weekly } )
] } );
this.freqSelect.selectItemByData( 'weekly' );
this.intervalInput = new OO.ui.NumberInputWidget( { input: { value: 1 }, min: 1, max: 100 } );
this.dateUntilInput = new mw.widgets.datetime.DateTimeInputWidget( { type: 'datetime', clearable: true } );
// Create a Fieldset layout.
var fieldset = new OO.ui.FieldsetLayout( {
label: messages.repeatRules,
} );
fieldset.addItems( [
new OO.ui.FieldLayout( this.repeatSwitch, { label: messages.repeat, align: 'left', help: messages.repeatHelp, } ),
new OO.ui.FieldLayout( this.freqSelect, { label: messages.frequency, align: 'left', help: messages.frequencyHelp, } ),
new OO.ui.FieldLayout( this.intervalInput, { label: messages.interval, align: 'left', help: messages.intervalHelp, } ),
new OO.ui.FieldLayout( this.dateUntilInput, { label: messages.dateUntil, align: 'left', help: messages.dateUntilHelp, } ),
] );
this.$element.append( fieldset.$element );
};
OO.inheritClass( RrulePageLayout, OO.ui.PageLayout );
RrulePageLayout.prototype.setupOutlineItem = function () {
this.outlineItem.setLabel( messages.repeatRules );
};
this.booklet = new OO.ui.BookletLayout( {
outlined: true
} );
this.mainPage = new MainPageLayout( 'main' );
this.rrulePage = new RrulePageLayout( 'rrule' );
this.booklet.addPages( [ this.mainPage, this.rrulePage ] );
this.$body.append( this.booklet.$element );
};
EventsEditor.prototype.getSetupProcess = function ( data ) {
data = data || {};
var dialog = this;
return EventsEditor.super.prototype.getSetupProcess.call( this, data ).next( function () {
if ( data.id !== undefined ) {
dialog.preload = data;
dialog.mainPage.dateStartInput.setValue( new Date( data.dtstart * 1000 ) );
dialog.mainPage.dateEndInput.setValue( new Date( data.dtend * 1000 ) );
dialog.mainPage.nameInput.setValue( data.title || '' );
dialog.mainPage.descriptionInput.setValue( data.description || '' );
dialog.mainPage.linkInput.setValue( data.link || '' );
dialog.mainPage.locationInput.setValue( data.location.join( ',' ) );
if ( data.tags !== undefined ) {
dialog.mainPage.tagsInput.setValue( data.tags );
}
if ( data.langs !== undefined ) {
dialog.mainPage.langsInput.setValue( data.langs );
}
if ( data.rrule !== undefined ) {
dialog.rrulePage.repeatSwitch.setValue( true );
dialog.rrulePage.freqSelect.selectItemByData( data.rrule.freq || 'weekly' );
dialog.rrulePage.intervalInput.setValue( data.rrule.interval || 1 );
if ( data.rrule.until !== undefined ) {
dialog.rrulePage.dateUntilInput.setValue( new Date( data.rrule.until * 1000 ) );
}
}
}
else {
dialog.preload = {};
dialog.preload.id = 0;
}
}, this );
};
EventsEditor.prototype.getActionProcess = function ( action ) {
var dialog = this;
if ( action ) {
if ( action === 'save' ) {
var now = parseInt( new Date().getTime()/1000 );
var event = {
id: now + '-' + mw.config.get( 'wgUserName' ).replace( / /g, '_' ) + '@meta.wikimedia.org',
dtcreated: now,
dtmodified: now,
dtstart: parseInt( this.mainPage.dateStartInput.getValueAsDate().getTime()/1000 ),
dtend: parseInt( this.mainPage.dateEndInput.getValueAsDate().getTime()/1000 ),
title: this.mainPage.nameInput.getValue(),
description: this.mainPage.descriptionInput.getValue(),
link: this.mainPage.linkInput.getValue(),
registration: false, //TODO
geoloc: {}, //TODO
location: this.mainPage.locationInput.getValue().split( ',' ),
tags: this.mainPage.tagsInput.getValue(),
langs: this.mainPage.langsInput.getValue(),
};
if ( dialog.preload.id !== 0 ) {
event.id = dialog.preload.id;
event.dtcreated = dialog.preload.dtcreated;
}
if ( this.rrulePage.repeatSwitch.getValue() ) {
event.rrule = {
freq: this.rrulePage.freqSelect.getData() || 'weekly',
};
var interval = this.rrulePage.intervalInput.getValue();
if ( interval !== 1 ) {
event.rrule.interval = interval;
}
if ( this.rrulePage.dateUntilInput.getValue() ) {
event.rrule.until = parseInt( this.rrulePage.dateUntilInput.getValueAsDate().getTime() / 1000 );
}
}
mw.loader.using( 'mediawiki.api', function() {
new mw.Api().edit(
'Events calendar/events.json',
function ( revision ) {
var jsonContent = JSON.parse( revision.content );
var summary;
if ( dialog.preload.id === 0 ) {
jsonContent.push( event );
summary = 'Add new event "' + event.title + '" (' + event.location.join( ', ' ) + ')';
}
else {
$.each( jsonContent, function( key, _ ) {
if ( jsonContent[ key ].id === event.id ) {
jsonContent[ key ] = event;
summary = 'Edit event "' + event.title + '" (' + event.location.join( ', ' ) + ')';
return false;
}
} );
}
return {
text: JSON.stringify( jsonContent, null, 4 ),
summary: summary,
};
}
)
.then( function () {
console.log( 'Saved! ');
} );
} );
return new OO.ui.Process( function () {
dialog.close( { action: action } );
} );
}
}
return EventsEditor.parent.prototype.getActionProcess.call( this, action );
};
var popup, eventsEditor;
mw.hook( 'eventscalendar.ready' ).add( function( $eventsCalendar ) {
if ( popup === undefined ) {
popup = new OO.ui.WindowManager();
$( 'body' ).append( popup.$element );
eventsEditor = new EventsEditor();
popup.addWindows( [ eventsEditor ] );
}
$( '.ec-button-add' ).show().click( function( e ) {
e.preventDefault();
popup.openWindow( eventsEditor );
} );
$( '.ec-pencil' ).css( 'cursor', 'pointer' ).show().click( function( e ) {
e.preventDefault();
var eventId = $( this ).attr( 'id' );
console.log( eventId );
new mw.Api().get( {
action: 'query',
prop: 'revisions',
rvprop: [ 'content' ],
titles: String( 'Events calendar/events.json' ),
formatversion: '2',
} ).fail( function( data ) {
console.log( data );
} ).then( function( data ) {
var content = JSON.parse( data.query.pages[ 0 ].revisions[ 0 ].content );
$.each( content, function( _, event ) {
if ( event.id.split( '@' )[ 0 ].replace( ' ', '_' ) === eventId ) {
console.log( 'found' );
popup.openWindow( eventsEditor, event );
return false;
}
} );
} );
} );
} );
mw.hook( 'eventscalendar.deleting' ).add( function( $eventsCalendar ) {
$eventsCalendar.find( '.mw-ui-button' ).off( 'click' );
} );
} );
} )( mediaWiki );
//</nowiki>