Dokumentation für das Modul Calendar[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]

Anwendung

Das Modul wird direkt von der Vorlage {{Kalender}} aufgerufen. Parameterbeschreibung siehe dort. Im Projektnamensraum befindet sich die technische Dokumentation Wikivoyage:Kalender. Das Modul ersetzt die Erweiterung „Calendar-Wikivoyage“.

Beispiel

Juni 2025
MoDiMiDoFrSaSo
1
2345678
9101112131415
16171819202122
23242526272829
30

{{ Kalender | Titellink = Nachrichten:$B $Y | prevLink = [[Nachrichten:$P $Q|<<]] | nextLink = [[Nachrichten:$N $O|>>]] | Hervorhebung = 2 4 6 | 5 = Nachrichten:$B $Y }}

Hervorhebung des aktuellen Tags

Der Parameter showToday (zeigeHeute) legt fest, ob und in welcher Weise der aktuelle Tag hervorgehoben wird. Folgende Werte sind möglich:

  • |showToday=true – Das Skript nimmt die Hervorhebung selbst vor. Da die Seiten nicht täglich geparst werden, kann sich die Aktualisierung verzögern.
  • |showToday=javascript – Im Tabellentag table wird die Klasse voy-calendar-show-today eingefügt. Zudem enthält das Tag die Klasse voy-calendar-yyyy-m, aus der das Jahr und der Monat hervorgehen wie z. B. voy-calendar-2025-6. Alle Zellen mit den Tagesangaben enthalten eine Klasse in der Form voy-calendar-d wie z. B. voy-calendar-23. Mit Hilfe eines Javascript-Skripts lässt sich die Klasse voy-calendar-today einfügen, die die Hervorhebung des aktuellen Tags bewirkt.
  • |showToday=false – Der aktuelle Tag wird nicht hervorgehoben.

Beispiel für ein geeignetes Javascript-Skript:

function addTodayToCalendar() { 	'use strict';  	var calendars = $( '.voy-calendar-show-today' ); 	if ( calendars.length ) { 		let classPrefix = '.voy-calendar-';  		let today = new Date(), 			d = String( today.getDate() ), 			m = String( today.getMonth() + 1 ), // January is 0 			yyyy = today.getFullYear();  		let monthFilter = `${classPrefix}${yyyy}-${m}`, 			daySelector = classPrefix + d;  		calendars.filter( monthFilter ).each( function() { 			$( this ).find( daySelector ).addClass( 'voy-calendar-today' ); 		} ); 	} } addTodayToCalendar(); 
Hinweise
-- Module:Calendar  -- require( 'strict' ) -- module variable and administration local cl = { 	moduleInterface = { 		suite  = 'Calendar', 		serial = '2025-06-19', 		item   = 56528415 	},  	-- miscellaneous i18n messages 	i18n = { 		classPrefix    = 'voy-calendar-', 		dayClasses     = { 'sundays', 'mondays', 'tuesdays', 'wednesdays', 'thursdays', 		                   'fridays', 'saturdays' }, 		titleFormat    = '%s %i',  		noMonthOrYear  = '[[Category:Kalender: Monat oder Jahr nicht spezifiziert]]', 		showToday      = '[[Category:Kalender: Kalender zeigt aktuellen Tag an]]', 		unknownParams  = '<span class="error">Fehlerhafte(r) Parameter</span>[[Category:Kalender: fehlerhafte Parameter]]', 		usingCalendar  = '[[Category:Seiten, die die Kalender-Vorlage verwenden]]', 		wrongCharCount = '<span class="error">Fehlerhafte Zeichenanzahl</span>[[Category:Kalender: fehlerhafte Zeichenanzahl]]', 		wrongHighlight = '<span class="error">Fehlerhafte Hervorhebung</span>[[Category:Kalender: fehlerhafte Hervorhebung]]', 		wrongLang      = '<span class="error">Fehlerhafte Sprache</span>[[Category:Kalender: fehlerhafte Sprache]]', 		wrongMonth     = '<span class="error">Fehlerhafter Monat</span>[[Category:Kalender: fehlerhafter Monat]]', 		wrongStart     = '<span class="error">Fehlerhafter Wochenanfang</span>[[Category:Kalender: fehlerhafter Wochenanfang]]', 		wrongWidth     = '<span class="error">Fehlerhafte Tabellenbreite</span>[[Category:Kalender: fehlerhafte Tabellenbreite]]', 		wrongYear      = '<span class="error">Fehlerhaftes Jahr</span>[[Category:Kalender: fehlerhaftes Jahr]]' 	},  	-- possible argument identifiers 	-- keep position and tableWidth for backward compatibility 	params = { 		align     = { 'position', 'align', 'Ausrichtung', 'Lage', default = 'right' }, -- keep position 		dayCharsCount   = { 'dayCharsCount', default = '0' }, 		generalLinks    = { 'generalLinks', 'Tageslinks' }, 		highlightedDays = { 'highlightedDays', 'Hervorhebung' }, 		lang      = { 'lang', 'Sprache' }, 		month     = { 'month', 'Monat' }, 		monthCharsCount = { 'monthCharsCount', default = '0' }, 		nextLink  = { 'nextLink' }, 		offset    = { 'offset', 'Versatz', default = '0' }, 		prevLink  = { 'prevLink' }, 		showToday = { 'showToday', 'zeigeHeute', default = 'true' }, -- alt: 'javascript' 		start     = { 'start', 'Wochenanfang', default = '1' }, -- 0 ... 6 		title     = { 'title', 'Titel' }, 		titleLink = { 'titleLink', 'titlelink', 'Titellink' }, 		width     = { 'tableWidth', 'width', 'Breite', 'Tabellenbreite', default = 'default' }, -- keep tableWidth 		year      = { 'year', 'Jahr' } 	},  	-- possible alignment values 	align = { 		left      = 'left', 		links     = 'left', 		right     = 'right', 		rechts    = 'right', 		center    = 'center', 		mitte     = 'center', 		zentriert = 'center' 	},  	-- possible width values 	width = { 		default   = 'default', 		standard  = 'default', 		none      = 'none', 		no        = 'none', 		n         = 'none', 		keine     = 'none', 		nein      = 'none' 	},  	-- possible lang values in addition to language codes 	-- no means Norwegian (Bokmål or Nynorsk) 	lang = { 		content   = 'content', 		standard  = 'content', 		none      = 'content', 		n         = 'content', 		keine     = 'content', 		nein      = 'content' 	},  	-- allowed namespaces for categories for Calendar module 	-- see also: https://de.wikivoyage.org/w/api.php?action=query&meta=siteinfo&siprop=namespaces 	notAllowedNamespaces = { 		[ 10 ]  = 1, -- Template 		[ 11 ]  = 1, -- Template Talk 		[ 828 ] = 1, -- Module 		[ 829 ] = 1  -- Module Talk 	},  	-- wiki language 	tableLang = mw.getContentLanguage():getCode() }  local errorMsgs = {} local categories = cl.i18n.usingCalendar -- using without additional spaces  -- add error message to errorMsgs table local function addErrorMsg( msg ) 	table.insert( errorMsgs, cl.i18n[ msg ] ) end  -- get errorMsgs table as string local function getErrorMsgs() 	local result = table.concat( errorMsgs, ' ' ) 	if result ~= '' then 		result = result .. ' ' 	end 	return result end  -- check if param is set: not nil or empty local function isSet( param ) 	return param and param ~= '' end  -- helper function round local function round( n ) 	return ( n >= 0 ) and math.floor( n + 0.5 ) or math.ceil( n - 0.5 ) end  -- helper function getInteger local function getInteger( s, default ) 	return math.floor( tonumber( s ) or tonumber( default ) or 0 ) end  -- check for possible arguments against list = params table local function checkParams( frameArgs, list ) 	local args = { numberedKeys = false } 	local complete = {}  	-- named arguments 	for key, value in pairs( list ) do 		if type( value ) == 'table' then 			for key2, value2 in ipairs( value ) do 				complete[ value2 ] = key 				args[ key ] = args[ key ] or frameArgs[ value2 ] 			end 			args[ key ] = args[ key ] or '' 		elseif value ~= '' then 			complete[ value ] = key 			args[ key ] = frameArgs[ value ] or '' 		else 			complete[ key ] = key 			args[ key ] = frameArgs[ key ] or '' 		end 		if args[ key ] == '' and type( value ) == 'table' and value.default then 			args[ key ] = value.default 		end 	end  	local ok = true 	local intKey 	for key, value in pairs( frameArgs ) do 		-- numbered arguments 		intKey = tonumber( key ) 		if intKey then 			-- frameArgs[ key ] cannot be nil 			if intKey < 1 or intKey > 31 then 				ok = false 			else 				args[ key ] = mw.text.trim( frameArgs[ key ] ) 				args.numberedKeys = true 			end 		end 		if not complete[ key ] and not intKey then 			ok = false 		end 	end 	if not ok then 		addErrorMsg( 'unknownParams' ) 	end 	return args end  -- date functions local function formatDate( aDate, aFormat ) 	return mw.getContentLanguage():formatDate( aFormat, aDate, true ) end  local function getDayOfWeek( day, month, year ) 	return formatDate( ( '%i-%i-%i' ):format( year, month, day ), 'w' ) end  local function getDaysInMonth( month, year ) 	local daysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 	local days = daysInMonth[ month ]  	-- leap year check 	if month == 2 and year % 4 == 0 then 		days = days + 1 		if year % 100 == 0 and year % 400 ~= 0 then 			days = days - 1 		end 	end 	return days end  -- Using Mediawiki:Key local function getMessage( key, length ) 	local message = mw.message.new( key ) 	message = message:inLanguage( cl.tableLang ):plain() 	if isSet( length ) and length > 0 then 		message = message:sub( 1, length ) 	end	 	return message end  local function getMonthName( month, length ) 	local monthKeys = { 'january', 'february', 'march', 'april', 'may_long', 		'june', 'july', 'august', 'september', 'october', 'november', 'december' } 	return getMessage( monthKeys[ month ], length ) end  local function getMonthNameAbbrev( month, length ) 	local monthKeys = { 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 		'sep', 'oct', 'nov', 'dec' } 	return getMessage( monthKeys[ month ], length ) end  local function getDayName( weekday, length ) 	local dayKeys = { 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 		'friday', 'saturday' } 	return getMessage( dayKeys[ weekday ], length ) end  local function getDayNameAbbrev( weekday, length ) 	local dayKeys = { 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' } 	return getMessage( dayKeys[ weekday ], length ) end  local function replace( s, tab ) 	if not isSet( s ) then 		return '' 	end 	for key, val in pairs( tab ) do 		s = s:gsub( '%$' .. key, val ) 	end 	s = s:gsub( '%$%%', '$' ) -- $% -> $, escape of magic character $ 	return s end  local function getClass( key, prefix ) 	return ( prefix and prefix or '' ) .. cl.i18n.classPrefix .. key end  local function getTitleRow( args ) 	local colspan = isSet( args.nextLink ) and 6 or 7 	local row = mw.html.create( 'tr' ) 		:addClass( getClass( 'title-row' ) ) 	if isSet( args.prevLink ) then 		colspan = colspan - 1 		row:node( mw.html.create( 'td' ) 			:addClass( getClass( 'prev-link' ) ) 			:wikitext( args.prevLink ) 		) 	end 	row:node( mw.html.create( 'th' ) 		:addClass( getClass( 'title' ) ) 		:attr( 'colspan', colspan ) 		:wikitext( args.title ) 	) 	if isSet( args.nextLink ) then 		row:node( mw.html.create( 'td' ) 			:addClass( getClass( 'next-link' ) ) 			:wikitext( args.nextLink ) 		) 	end 	return tostring( row ) end  -- header line with abbreviated days local function getWeekdaysRow( args ) 	local pos 	local row = mw.html.create( 'tr' ) 		:addClass( getClass( 'weekdays' ) ) 	for i = 0, 6, 1 do 		pos = ( i + args.start ) % 7 + 1 		row:node( mw.html.create( 'th' ) 			:addClass( getClass( cl.i18n.dayClasses[ pos ] ) ) 			:wikitext( getDayNameAbbrev( pos, args.dayCharsCount ) ) 		) 	end 	return tostring( row ) end  local function addTableWrapper( args, rows ) 	-- table classes 	local classes = getClass( '' ):sub(1, -2) .. 		getClass( ( '%i-%i' ):format( args.year, args.month ), ' ' ) .. 		( args.width == 'default' and getClass( 'default-width', ' ' ) or '' ) 	if args.align == 'left' then 		classes = classes .. getClass( 'left', ' ' ) 	elseif args.align == 'center' then 		classes = classes .. getClass( 'center', ' ' ) 	else -- default: right 		classes = classes .. getClass( 'right', ' ' ) 	end 	if args.showToday == 'javascript' then 		classes = classes .. getClass( 'show-today', ' ' ) 	end 	if isSet( args.generalLinks ) then 		classes = classes .. getClass( 'general-day-links', ' ' ) 	end  	local table = mw.html.create( 'table' ) 		:addClass( classes ) 		:wikitext( '\n' .. rows .. '\n' ) 	if not cl.width[ args.width ] then 		table:css( 'width', args.width ) 	end 	return tostring( table ) end  local function getWikilink( link, display ) 	return isSet( display ) and ( '[[%s|%s]]' ):format( link, display ) or 		( '[[%s]]' ):format( link ) end  local function populateTable( args ) 	-- header lines with title and abbreviated days 	local rows = { getTitleRow( args ), getWeekdaysRow( args ) }  	-- adding days: setting offset 	local firstDayInMonth = getDayOfWeek( 1, args.month, args.year ) 	firstDayInMonth = firstDayInMonth - args.start 	if firstDayInMonth < 0 then 		firstDayInMonth = firstDayInMonth + 7 	end  	-- table with dates considering offset and weekday of month’s first day 	local dates = { '', '', '', '', '', '', '' } 	for i = 1, getDaysInMonth( args.month, args.year ), 1 do 		dates[ i + firstDayInMonth ] = tostring( i ) 	end 	local trows = math.ceil( #dates / 7 ) -- count of table rows  	-- creating html table 	local classes, day, day2, intDay, link, pos, row 	-- additional place holders depending on day 	local function addPairsToTable( day, pos ) 		args.placeholders.a = getDayNameAbbrev( pos ) 		args.placeholders.A = getDayName( pos ) 		args.placeholders.d = ( '%02d' ):format( day ) 		args.placeholders.D = tonumber( day ) 		args.placeholders.e = ( '%2d' ):format( day ) 	end  	for i = 0, trows - 1, 1 do 		row = mw.html.create( 'tr' ) 			:addClass( getClass( 'row ' ) .. getClass( 'row-' .. i ) ) 		for j = 1, 7, 1 do 			pos = ( args.start + j - 1 ) % 7 + 1 			day = dates[ 7 * i + j ] -- unlinked day number or ''  			if isSet( day ) then 				intDay = tonumber( day ) 				day2 = day -- possibly linked day number  				-- numbered links or general links 				if args[ intDay ] then 					addPairsToTable( day, pos ) 					link = replace( args[ intDay ], args.placeholders ) 					day2 = getWikilink( link, day ) 				elseif isSet( args.generalLinks ) then 					addPairsToTable( day, pos ) 					link = replace( args.generalLinks, args.placeholders ) 					day2 = getWikilink( link, day ) 				end  				classes = getClass( cl.i18n.dayClasses[ pos ] ) .. getClass( day, ' ' ) .. 					( args.highlightedDays[ day ] and getClass( 'highlighted', ' ' ) or '' ) 				if args.showToday == 'true' and args.currentDay == intDay then 					classes = classes .. getClass( 'today', ' ' ) 				end 				row:node( mw.html.create( 'td' ) 					:addClass( classes ) 					:wikitext( day2 ) 				) 			else 				row:node( mw.html.create( 'td' ) 					:wikitext( '' ) 				) 			end 		end 		table.insert( rows, tostring( row ) ) 	end  	-- adding table-tag wrapper 	return addTableWrapper( args, table.concat( rows, '\n' ) ) end  local function checkParameterValues( args ) 	args.start = getInteger( args.start ) 	if args.start < 0 or args.start > 6 then 		args.start = 1 		addErrorMsg( 'wrongStart' ) 	end 	args.dayCharsCount = getInteger( args.dayCharsCount ) 	if args.dayCharsCount < 0 or args.dayCharsCount > 5 then 		args.dayCharsCount = 0 		addErrorMsg( 'wrongCharCount' ) 	end 	args.monthCharsCount = getInteger( args.monthCharsCount ) 	if args.monthCharsCount < 0 or args.monthCharsCount > 10 then 		args.monthCharsCount = 0 		addErrorMsg( 'wrongCharCount' ) 	end 	args.offset = getInteger( args.offset ) 	args.align = cl.align[ args.align:lower() ] or ''  	if isSet( args.lang ) then 		args.lang = args.lang:lower() 		if not cl.lang[ args.lang ] then 			if isSet( mw.language.fetchLanguageName( args.lang, cl.tableLang ) ) then 				cl.tableLang = args.lang 			else 				addErrorMsg( 'wrongLang' ) 			end 		end 	end  	args.currentDay = getInteger( os.date( '%d' ) ) -- today 	args.currentMonth = getInteger( os.date( '%m' ) ) 	args.currentYear = getInteger( os.date( '%Y' ) )  	if not isSet( args.month ) or not isSet( args.year ) then 		categories = categories .. cl.i18n.noMonthOrYear 	end 	args.month = getInteger( args.month, args.currentMonth ) 	if args.month < 1 or args.month > 12 then 		args.month = args.currentMonth 		addErrorMsg( 'wrongMonth' ) 	end 	args.year = getInteger( args.year, args.currentYear ) 	if args.year < 1970 or args.year > 2400 then 		args.year = args.currentYear 		addErrorMsg( 'wrongYear' ) 	end  	if args.offset ~= 0 then 		local offsetMonth = args.offset % 12 		local offsetYear = round( ( args.offset - offsetMonth ) / 12 ) 		args.month = args.month + offsetMonth 		args.year = args.year + offsetYear 		if args.month > 12 then 			args.month = args.month - 12 			args.year = args.year + 1 		end 		if args.month < 1 then 			args.month = args.month + 12 			args.year = args.year - 1 		end 	end  	-- don't show current day if month/year is outdated or in future 	args.showToday = args.showToday:lower() 	if args.showToday == 'true' or args.showToday == 'javascript' then 		if args.currentYear ~= tonumber( args.year ) or 			args.currentMonth ~= tonumber( args.month ) then 			args.showToday = 'false' 		else 			categories = categories .. cl.i18n.showToday 		end 	end  	args.nextMonthYear = args.year 	args.nextMonth = args.month + 1 	if args.nextMonth == 13 then 		args.nextMonth = 1 		args.nextMonthYear = args.nextMonthYear + 1 	end 	args.prevMonthYear = args.year 	args.prevMonth = args.month - 1 	if args.prevMonth == 0 then 		args.prevMonth = 12 		args.prevMonthYear = args.prevMonthYear - 1 	end  	if isSet( args.titleLink ) or isSet( args.prevLink ) or isSet( args.nextLink ) or 		isSet( args.generalLinks ) or args.numberedKeys then 		args.placeholders = { 			b = getMonthNameAbbrev( args.month ), 			B = getMonthName( args.month ), 			m = ( '%02d' ):format( args.month ), 			M = ( '%02d' ):format( args.nextMonth ), 			n = getMonthNameAbbrev( args.nextMonth ), 			N = getMonthName( args.nextMonth ), 			o = tostring( args.nextMonthYear ):sub( 3, 4 ), 			O = tostring( args.nextMonthYear ), 			p = getMonthNameAbbrev( args.prevMonth ), 			P = getMonthName( args.prevMonth ), 			q = tostring( args.prevMonthYear ):sub( 3, 4 ), 			Q = tostring( args.prevMonthYear ), 			R = ( '%02d' ):format( args.prevMonth ), 			y = tostring( args.year ):sub( 3, 4 ), 			Y = tostring( args.year ) 		} 		args.titleLink = replace( args.titleLink, args.placeholders ) 		args.prevLink = replace( args.prevLink, args.placeholders ) 		args.nextLink = replace( args.nextLink, args.placeholders ) 	end  	if not isSet( args.title ) then 		args.title = cl.i18n.titleFormat:format( getMonthName( args.month, 			args.monthCharsCount ), args.year ) 	end 	if isSet( args.titleLink ) then 		args.title = getWikilink( args.titleLink, args.title ) 	end  	local highlighted = {} 	if isSet( args.highlightedDays ) then 		args.highlightedDays = args.highlightedDays:gsub( '[,;%s%c%z]+', ' ' ) 		local s = mw.text.split( args.highlightedDays, ' ', true ) -- plain 		for i = 1, #s, 1 do 			s[ i ] = getInteger( mw.text.trim( s[ i ] ) ) 			if s[ i ] > 0 and s[ i ] < 32 then 				highlighted[ tostring( s[ i ] ) ] = 1 			else 				addErrorMsg( 'wrongHighlight' ) 			end 		end 	end 	args.highlightedDays = highlighted  	if isSet( args.width ) then 		args.width = args.width:lower() 		if cl.width[ args.width ] then 			args.width = cl.width[ args.width ] 		end  		if not cl.width[ args.width ] then 			local unit, n = args.width:gsub( '^[.%d]+([%a%%]+)$', '%1' ) 			if n > 0 then 				local widthUnits = { em = 1, ex = 1, pc = 1, pt = 1, px = 1, [ 'in' ] = 1, mm = 1, cm = 1 } 				if unit ~= '%' and not widthUnits[ unit ] then 					args.width = 'default' 					addErrorMsg( 'wrongWidth' ) 				end 			else 				args.width = 'default' 				addErrorMsg( 'wrongWidth' ) 			end 		end 	end end  function cl.calendar( frame ) 	local args = checkParams( frame:getParent().args, cl.params ) 	checkParameterValues( args )  	return getErrorMsgs() .. populateTable( args ) .. 		( cl.notAllowedNamespaces[ mw.title.getCurrentTitle().namespace ] and '' or categories ) end  return cl