「MediaWiki:Common.js」の版間の差分
表示
編集の要約なし |
編集の要約なし |
||
| (同じ利用者による、間の11版が非表示) | |||
| 1行目: | 1行目: | ||
/* RTA Wiki: PCの匿名利用者には各ページでメインメニューを左側に表示 */ | |||
(function () { | |||
if ( | |||
mw.config.get( 'wgUserName' ) || | |||
!window.matchMedia( '(min-width: 1000px)' ).matches | |||
) { | |||
return; | |||
} | |||
function pinMainMenu() { | |||
var pinButton = document.querySelector( | |||
'[data-event-name="pinnable-header.vector-main-menu.pin"]' | |||
); | |||
if ( pinButton ) { | |||
pinButton.click(); | |||
} | |||
} | |||
if ( document.documentElement.classList.contains( 'vector-animations-ready' ) ) { | |||
pinMainMenu(); | |||
return; | |||
} | |||
var observer = new MutationObserver( function () { | |||
if ( document.documentElement.classList.contains( 'vector-animations-ready' ) ) { | |||
pinMainMenu(); | |||
observer.disconnect(); | |||
} | |||
} ); | |||
observer.observe( document.documentElement, { | |||
attributes: true, | |||
attributeFilter: [ 'class' ] | |||
} ); | |||
}()); | |||
/* RTA Wiki: 管理者以外には既存ページの編集導線を表示しない */ | /* RTA Wiki: 管理者以外には既存ページの編集導線を表示しない */ | ||
mw.loader.using( 'mediawiki.util' ).then( function () { | mw.loader.using( 'mediawiki.util' ).then( function () { | ||
| 20行目: | 55行目: | ||
} ); | } ); | ||
/* RTA Wiki: | /* RTA Wiki: 時・分・秒・ミリ秒の入力から記録時間・記録秒を自動設定する */ | ||
mw.loader.using( 'mediawiki.util' ).then( function () { | mw.loader.using( 'mediawiki.util' ).then( function () { | ||
function setUpRecordTimeInputs() { | function setUpRecordTimeInputs() { | ||
| 26行目: | 61行目: | ||
'input[name="RTA記録[記録時間]"], input[name$="[記録時間]"]' | 'input[name="RTA記録[記録時間]"], input[name$="[記録時間]"]' | ||
); | ); | ||
var | var storedSecondsInput = document.querySelector( | ||
'input[name="RTA記録[記録秒]"], input[name$="[記録秒]"]' | 'input[name="RTA記録[記録秒]"], input[name$="[記録秒]"]' | ||
); | ); | ||
| 32行目: | 67行目: | ||
if ( | if ( | ||
!timeInput || ! | !timeInput || !storedSecondsInput || !controls || | ||
controls.dataset.rtaTimeSetUp === '1' | controls.dataset.rtaTimeSetUp === '1' | ||
) { | ) { | ||
| 44行目: | 79行目: | ||
controls.style.flexWrap = 'wrap'; | controls.style.flexWrap = 'wrap'; | ||
function makeInput( id, labelText, maxLength ) { | function makeInput( id, labelText, maxLength, inputMode ) { | ||
var label = document.createElement( 'label' ); | var label = document.createElement( 'label' ); | ||
var input = document.createElement( 'input' ); | var input = document.createElement( 'input' ); | ||
input.id = id; | input.id = id; | ||
input.type = 'text'; | input.type = 'text'; | ||
input.inputMode = | input.inputMode = inputMode; | ||
input.size = 3; | input.size = 3; | ||
input.maxLength = maxLength; | input.maxLength = maxLength; | ||
input.value = '0'; | input.value = '0'; | ||
input.autocomplete = 'off'; | input.autocomplete = 'off'; | ||
input.style.width = '4.5em'; | input.style.width = '4.5em'; | ||
input.style.boxSizing = 'border-box'; | input.style.boxSizing = 'border-box'; | ||
label.style.display = 'inline-flex'; | label.style.display = 'inline-flex'; | ||
label.style.alignItems = 'center'; | label.style.alignItems = 'center'; | ||
label.style.gap = '4px'; | label.style.gap = '4px'; | ||
label.appendChild( input ); | label.appendChild( input ); | ||
label.appendChild( document.createTextNode( labelText ) ); | |||
controls.appendChild( label ); | controls.appendChild( label ); | ||
| 70行目: | 104行目: | ||
} | } | ||
var hoursInput = makeInput( 'rta-record-hours', '時', 6 ); | var hoursInput = makeInput( 'rta-record-hours', '時', 6, 'numeric' ); | ||
var minutesInput = makeInput( 'rta-record-minutes', '分', 2 ); | var minutesInput = makeInput( 'rta-record-minutes', '分', 2, 'numeric' ); | ||
var | var secondsInput = makeInput( 'rta-record-seconds', '秒', 6, 'decimal' ); | ||
var message = document.createElement( 'small' ); | var message = document.createElement( 'small' ); | ||
| 81行目: | 115行目: | ||
function normalizeDigits( value ) { | function normalizeDigits( value ) { | ||
return value.replace( /[0-9]/g, function ( character ) { | return value | ||
.replace( /[0-9]/g, function ( character ) { | |||
return String.fromCharCode( character.charCodeAt( 0 ) - 0xFEE0 ); | |||
} ) | |||
.replace( /[.。]/g, '.' ) | |||
.trim(); | |||
} | } | ||
| 93行目: | 130行目: | ||
function setVisibleValuesFromStoredTime() { | function setVisibleValuesFromStoredTime() { | ||
var value = normalizeDigits( timeInput.value ); | var value = normalizeDigits( timeInput.value ); | ||
var match = value.match( /^(\d+):([0-5]\d):([0-5]\d)$/ ); | var match = value.match( /^(\d+):([0-5]\d):([0-5]\d(?:\.\d{1,3})?)$/ ); | ||
if ( !match ) { | if ( !match ) { | ||
| 101行目: | 138行目: | ||
hoursInput.value = String( Number( match[1] ) ); | hoursInput.value = String( Number( match[1] ) ); | ||
minutesInput.value = String( Number( match[2] ) ); | minutesInput.value = String( Number( match[2] ) ); | ||
secondsInput.value = match[3]; | |||
} | } | ||
| 107行目: | 144行目: | ||
var hoursText = normalizeDigits( hoursInput.value ); | var hoursText = normalizeDigits( hoursInput.value ); | ||
var minutesText = normalizeDigits( minutesInput.value ); | var minutesText = normalizeDigits( minutesInput.value ); | ||
var secondsText = normalizeDigits( | var secondsText = normalizeDigits( secondsInput.value ); | ||
hoursInput.value = hoursText; | hoursInput.value = hoursText; | ||
minutesInput.value = minutesText; | minutesInput.value = minutesText; | ||
secondsInput.value = secondsText; | |||
if ( | if ( | ||
!/^\d+$/.test( hoursText ) || | !/^\d+$/.test( hoursText ) || | ||
!/^\d+$/.test( minutesText ) || | !/^\d+$/.test( minutesText ) || | ||
!/^\d+$/.test( secondsText ) | !/^\d+(?:\.\d{1,3})?$/.test( secondsText ) | ||
) { | ) { | ||
timeInput.value = ''; | timeInput.value = ''; | ||
storedSecondsInput.value = ''; | |||
showMessage( ' | showMessage( '時・分・秒を正しく入力してください。秒は小数点以下3桁までです。', true ); | ||
return false; | return false; | ||
} | } | ||
| 126行目: | 163行目: | ||
var hours = Number( hoursText ); | var hours = Number( hoursText ); | ||
var minutes = Number( minutesText ); | var minutes = Number( minutesText ); | ||
var | var secondParts = secondsText.split( '.' ); | ||
var wholeSeconds = Number( secondParts[0] ); | |||
var milliseconds = Number( ( secondParts[1] || '' ).padEnd( 3, '0' ) ); | |||
if ( | if ( | ||
!Number.isSafeInteger( hours ) || | !Number.isSafeInteger( hours ) || | ||
minutes > 59 || | minutes > 59 || | ||
wholeSeconds > 59 | |||
) { | ) { | ||
timeInput.value = ''; | timeInput.value = ''; | ||
storedSecondsInput.value = ''; | |||
showMessage( '分・秒は 0〜59 の範囲で入力してください。', true ); | showMessage( '分・秒は 0〜59 の範囲で入力してください。', true ); | ||
return false; | return false; | ||
} | } | ||
var | var totalMilliseconds = | ||
( ( hours * 60 + minutes ) * 60 + wholeSeconds ) * 1000 + | |||
milliseconds; | |||
if ( | if ( !Number.isSafeInteger( totalMilliseconds ) || totalMilliseconds === 0 ) { | ||
timeInput.value = ''; | timeInput.value = ''; | ||
storedSecondsInput.value = ''; | |||
showMessage( '0秒より大きい記録時間を入力してください。', true ); | showMessage( '0秒より大きい記録時間を入力してください。', true ); | ||
return false; | return false; | ||
} | |||
var formattedSeconds = String( wholeSeconds ).padStart( 2, '0' ); | |||
if ( milliseconds > 0 ) { | |||
formattedSeconds += '.' + String( milliseconds ).padStart( 3, '0' ); | |||
} | } | ||
| 151行目: | 197行目: | ||
String( hours ) + ':' + | String( hours ) + ':' + | ||
String( minutes ).padStart( 2, '0' ) + ':' + | String( minutes ).padStart( 2, '0' ) + ':' + | ||
formattedSeconds; | |||
storedSecondsInput.value = ( totalMilliseconds / 1000 ).toFixed( 3 ); | |||
showMessage( | showMessage( | ||
'保存値: ' + timeInput.value + ' (' + | '保存値: ' + timeInput.value + '(' + totalMilliseconds + ' ミリ秒)', | ||
false | false | ||
); | ); | ||
| 163行目: | 210行目: | ||
setVisibleValuesFromStoredTime(); | setVisibleValuesFromStoredTime(); | ||
[ hoursInput, minutesInput, | [ hoursInput, minutesInput, secondsInput ].forEach( function ( input ) { | ||
input.addEventListener( 'input', updateRecordValues ); | input.addEventListener( 'input', updateRecordValues ); | ||
input.addEventListener( 'change', updateRecordValues ); | input.addEventListener( 'change', updateRecordValues ); | ||
| 178行目: | 225行目: | ||
if ( timeInput.value ) { | if ( timeInput.value ) { | ||
updateRecordValues(); | |||
} else { | } else { | ||
showMessage( '時・分・秒を入力してください。秒は小数点以下3桁まで入力できます。', false ); | |||
} | } | ||
} | } | ||
| 285行目: | 332行目: | ||
start(); | start(); | ||
} | } | ||
} ); | |||
/* RTA Wiki: 記録カードの年・版・実施条件・確認区分による絞り込み */ | |||
mw.loader.using( 'mediawiki.util' ).then( function () { | |||
function setUpRecordCardFilters() { | |||
document.querySelectorAll( '.rta-record-cards--filterable' ).forEach( function ( container, index ) { | |||
if ( container.dataset.rtaFilterable === '1' ) { | |||
return; | |||
} | |||
container.dataset.rtaFilterable = '1'; | |||
var cards = Array.from( container.children ).filter( function ( element ) { | |||
return element.classList.contains( 'rta-record-card' ); | |||
} ); | |||
var years = Array.from( new Set( cards.map( function ( card ) { | |||
return card.dataset.rtaYear; | |||
} ).filter( Boolean ) ) ).sort().reverse(); | |||
var versions = Array.from( new Set( cards.map( function ( card ) { | |||
return card.dataset.rtaVersion; | |||
} ).filter( Boolean ) ) ).sort(); | |||
var control = document.createElement( 'div' ); | |||
var yearLabel = document.createElement( 'label' ); | |||
var yearSelect = document.createElement( 'select' ); | |||
var versionLabel = document.createElement( 'label' ); | |||
var versionSelect = document.createElement( 'select' ); | |||
var conditionLabel = document.createElement( 'label' ); | |||
var conditionSelect = document.createElement( 'select' ); | |||
var verificationLabel = document.createElement( 'label' ); | |||
var verificationSelect = document.createElement( 'select' ); | |||
var result = document.createElement( 'span' ); | |||
var yearId = 'rta-record-year-filter-' + index; | |||
var versionId = 'rta-record-version-filter-' + index; | |||
var conditionId = 'rta-record-condition-filter-' + index; | |||
var verificationId = 'rta-record-verification-filter-' + index; | |||
control.className = 'rta-record-filter'; | |||
yearLabel.htmlFor = yearId; | |||
yearLabel.textContent = '年:'; | |||
yearSelect.id = yearId; | |||
[ [ '', 'すべて' ] ].concat( years.map( function ( year ) { | |||
return [ year, year + '年' ]; | |||
} ) ).forEach( function ( item ) { | |||
var option = document.createElement( 'option' ); | |||
option.value = item[ 0 ]; | |||
option.textContent = item[ 1 ]; | |||
yearSelect.appendChild( option ); | |||
} ); | |||
versionLabel.htmlFor = versionId; | |||
versionLabel.textContent = '作品の版:'; | |||
versionSelect.id = versionId; | |||
[ [ '', 'すべて' ] ].concat( versions.map( function ( version ) { | |||
return [ version, version ]; | |||
} ) ).forEach( function ( item ) { | |||
var option = document.createElement( 'option' ); | |||
option.value = item[ 0 ]; | |||
option.textContent = item[ 1 ]; | |||
versionSelect.appendChild( option ); | |||
} ); | |||
conditionLabel.htmlFor = conditionId; | |||
conditionLabel.textContent = '実施条件:'; | |||
conditionSelect.id = conditionId; | |||
[ | |||
[ '', 'すべて' ], | |||
[ 'normal', '通常RTA' ], | |||
[ 'event', '大会・イベント記録' ], | |||
[ 'race', '並走' ], | |||
[ 'single-segment', 'シングルセグメント' ] | |||
].forEach( function ( item ) { | |||
var option = document.createElement( 'option' ); | |||
option.value = item[ 0 ]; | |||
option.textContent = item[ 1 ]; | |||
conditionSelect.appendChild( option ); | |||
} ); | |||
verificationLabel.htmlFor = verificationId; | |||
verificationLabel.textContent = '確認区分:'; | |||
verificationSelect.id = verificationId; | |||
[ | |||
[ '', 'すべて' ], | |||
[ '動画・配信で確認', '動画・配信で確認' ], | |||
[ '動画なし・資料で確認', '動画なし・資料で確認' ], | |||
[ '参考記録(確認資料なし)', '参考記録(確認資料なし)' ], | |||
[ '区分未設定', '区分未設定' ] | |||
].forEach( function ( item ) { | |||
var option = document.createElement( 'option' ); | |||
option.value = item[ 0 ]; | |||
option.textContent = item[ 1 ]; | |||
verificationSelect.appendChild( option ); | |||
} ); | |||
result.className = 'rta-record-filter__result'; | |||
control.append( | |||
yearLabel, yearSelect, | |||
versionLabel, versionSelect, | |||
conditionLabel, conditionSelect, | |||
verificationLabel, verificationSelect, | |||
result | |||
); | |||
container.parentNode.insertBefore( control, container ); | |||
function applyFilters() { | |||
var visibleCount = 0; | |||
cards.forEach( function ( card ) { | |||
var event = card.dataset.rtaEvent === 'はい'; | |||
var race = card.dataset.rtaRace === 'はい'; | |||
var singleSegment = card.dataset.rtaSingleSegment === 'はい'; | |||
var yearMatches = !yearSelect.value || | |||
card.dataset.rtaYear === yearSelect.value; | |||
var versionMatches = !versionSelect.value || | |||
card.dataset.rtaVersion === versionSelect.value; | |||
var conditionMatches = ( | |||
!conditionSelect.value || | |||
( conditionSelect.value === 'normal' && !event && !race && !singleSegment ) || | |||
( conditionSelect.value === 'event' && event ) || | |||
( conditionSelect.value === 'race' && race ) || | |||
( conditionSelect.value === 'single-segment' && singleSegment ) | |||
); | |||
var verificationMatches = !verificationSelect.value || | |||
( card.dataset.rtaVerification || '区分未設定' ) === verificationSelect.value; | |||
card.hidden = !( | |||
yearMatches && | |||
versionMatches && | |||
conditionMatches && | |||
verificationMatches | |||
); | |||
if ( !card.hidden ) { | |||
visibleCount++; | |||
} | |||
} ); | |||
result.textContent = visibleCount + ' / ' + cards.length + '件を表示'; | |||
} | |||
yearSelect.addEventListener( 'change', applyFilters ); | |||
versionSelect.addEventListener( 'change', applyFilters ); | |||
conditionSelect.addEventListener( 'change', applyFilters ); | |||
verificationSelect.addEventListener( 'change', applyFilters ); | |||
applyFilters(); | |||
} ); | |||
} | |||
function start() { | |||
setUpRecordCardFilters(); | |||
mw.hook( 'wikipage.content' ).add( setUpRecordCardFilters ); | |||
} | |||
if ( document.readyState === 'loading' ) { | |||
document.addEventListener( 'DOMContentLoaded', start ); | |||
} else { | |||
start(); | |||
} | |||
} ); | |||
/* RTA記録フォーム:確認区分に応じた必須入力 */ | |||
$( function () { | |||
var form = document.getElementById( 'pfForm' ); | |||
if ( !form ) { | |||
return; | |||
} | |||
var verification = form.querySelector( '#rta-verification select' ); | |||
var evidenceUrl = form.querySelector( '#rta-evidence-url input' ); | |||
var basis = form.querySelector( '#rta-confirmation-basis textarea' ); | |||
var evidenceMark = form.querySelector( '#rta-evidence-required' ); | |||
var basisMark = form.querySelector( '#rta-basis-required' ); | |||
if ( !verification || !evidenceUrl || !basis || !evidenceMark || !basisMark ) { | |||
return; | |||
} | |||
function updateRequiredFields() { | |||
var value = verification.value; | |||
var requireUrl = value === '動画・配信で確認'; | |||
var requireBasis = value === '動画なし・資料で確認'; | |||
evidenceUrl.required = requireUrl; | |||
basis.required = requireBasis; | |||
evidenceUrl.setAttribute( 'aria-required', requireUrl ? 'true' : 'false' ); | |||
basis.setAttribute( 'aria-required', requireBasis ? 'true' : 'false' ); | |||
evidenceMark.style.display = requireUrl ? 'inline' : 'none'; | |||
basisMark.style.display = requireBasis ? 'inline' : 'none'; | |||
} | |||
verification.addEventListener( 'change', updateRequiredFields ); | |||
updateRequiredFields(); | |||
} ); | } ); | ||
2026年10月25日 (日) 22:51時点における最新版
/* RTA Wiki: PCの匿名利用者には各ページでメインメニューを左側に表示 */
(function () {
if (
mw.config.get( 'wgUserName' ) ||
!window.matchMedia( '(min-width: 1000px)' ).matches
) {
return;
}
function pinMainMenu() {
var pinButton = document.querySelector(
'[data-event-name="pinnable-header.vector-main-menu.pin"]'
);
if ( pinButton ) {
pinButton.click();
}
}
if ( document.documentElement.classList.contains( 'vector-animations-ready' ) ) {
pinMainMenu();
return;
}
var observer = new MutationObserver( function () {
if ( document.documentElement.classList.contains( 'vector-animations-ready' ) ) {
pinMainMenu();
observer.disconnect();
}
} );
observer.observe( document.documentElement, {
attributes: true,
attributeFilter: [ 'class' ]
} );
}());
/* RTA Wiki: 管理者以外には既存ページの編集導線を表示しない */
mw.loader.using( 'mediawiki.util' ).then( function () {
function hideEditLinks() {
if ( mw.config.get( 'wgUserGroups' ).includes( 'sysop' ) ) {
return;
}
document.querySelectorAll(
'#ca-edit, #ca-ve-edit, #ca-formedit, [id^="ca-formedit"], a[href*="action=formedit"]'
).forEach( function ( element ) {
( element.closest( 'li' ) || element ).remove();
} );
}
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', hideEditLinks );
} else {
hideEditLinks();
}
} );
/* RTA Wiki: 時・分・秒・ミリ秒の入力から記録時間・記録秒を自動設定する */
mw.loader.using( 'mediawiki.util' ).then( function () {
function setUpRecordTimeInputs() {
var timeInput = document.querySelector(
'input[name="RTA記録[記録時間]"], input[name$="[記録時間]"]'
);
var storedSecondsInput = document.querySelector(
'input[name="RTA記録[記録秒]"], input[name$="[記録秒]"]'
);
var controls = document.getElementById( 'rta-time-inputs' );
if (
!timeInput || !storedSecondsInput || !controls ||
controls.dataset.rtaTimeSetUp === '1'
) {
return;
}
controls.dataset.rtaTimeSetUp = '1';
controls.style.display = 'flex';
controls.style.gap = '10px';
controls.style.alignItems = 'center';
controls.style.flexWrap = 'wrap';
function makeInput( id, labelText, maxLength, inputMode ) {
var label = document.createElement( 'label' );
var input = document.createElement( 'input' );
input.id = id;
input.type = 'text';
input.inputMode = inputMode;
input.size = 3;
input.maxLength = maxLength;
input.value = '0';
input.autocomplete = 'off';
input.style.width = '4.5em';
input.style.boxSizing = 'border-box';
label.style.display = 'inline-flex';
label.style.alignItems = 'center';
label.style.gap = '4px';
label.appendChild( input );
label.appendChild( document.createTextNode( labelText ) );
controls.appendChild( label );
return input;
}
var hoursInput = makeInput( 'rta-record-hours', '時', 6, 'numeric' );
var minutesInput = makeInput( 'rta-record-minutes', '分', 2, 'numeric' );
var secondsInput = makeInput( 'rta-record-seconds', '秒', 6, 'decimal' );
var message = document.createElement( 'small' );
message.style.display = 'block';
message.style.marginTop = '4px';
message.style.color = '#54595d';
controls.insertAdjacentElement( 'afterend', message );
function normalizeDigits( value ) {
return value
.replace( /[0-9]/g, function ( character ) {
return String.fromCharCode( character.charCodeAt( 0 ) - 0xFEE0 );
} )
.replace( /[.。]/g, '.' )
.trim();
}
function showMessage( text, isError ) {
message.textContent = text;
message.style.color = isError ? '#d33' : '#54595d';
}
function setVisibleValuesFromStoredTime() {
var value = normalizeDigits( timeInput.value );
var match = value.match( /^(\d+):([0-5]\d):([0-5]\d(?:\.\d{1,3})?)$/ );
if ( !match ) {
return;
}
hoursInput.value = String( Number( match[1] ) );
minutesInput.value = String( Number( match[2] ) );
secondsInput.value = match[3];
}
function updateRecordValues() {
var hoursText = normalizeDigits( hoursInput.value );
var minutesText = normalizeDigits( minutesInput.value );
var secondsText = normalizeDigits( secondsInput.value );
hoursInput.value = hoursText;
minutesInput.value = minutesText;
secondsInput.value = secondsText;
if (
!/^\d+$/.test( hoursText ) ||
!/^\d+$/.test( minutesText ) ||
!/^\d+(?:\.\d{1,3})?$/.test( secondsText )
) {
timeInput.value = '';
storedSecondsInput.value = '';
showMessage( '時・分・秒を正しく入力してください。秒は小数点以下3桁までです。', true );
return false;
}
var hours = Number( hoursText );
var minutes = Number( minutesText );
var secondParts = secondsText.split( '.' );
var wholeSeconds = Number( secondParts[0] );
var milliseconds = Number( ( secondParts[1] || '' ).padEnd( 3, '0' ) );
if (
!Number.isSafeInteger( hours ) ||
minutes > 59 ||
wholeSeconds > 59
) {
timeInput.value = '';
storedSecondsInput.value = '';
showMessage( '分・秒は 0〜59 の範囲で入力してください。', true );
return false;
}
var totalMilliseconds =
( ( hours * 60 + minutes ) * 60 + wholeSeconds ) * 1000 +
milliseconds;
if ( !Number.isSafeInteger( totalMilliseconds ) || totalMilliseconds === 0 ) {
timeInput.value = '';
storedSecondsInput.value = '';
showMessage( '0秒より大きい記録時間を入力してください。', true );
return false;
}
var formattedSeconds = String( wholeSeconds ).padStart( 2, '0' );
if ( milliseconds > 0 ) {
formattedSeconds += '.' + String( milliseconds ).padStart( 3, '0' );
}
timeInput.value =
String( hours ) + ':' +
String( minutes ).padStart( 2, '0' ) + ':' +
formattedSeconds;
storedSecondsInput.value = ( totalMilliseconds / 1000 ).toFixed( 3 );
showMessage(
'保存値: ' + timeInput.value + '(' + totalMilliseconds + ' ミリ秒)',
false
);
return true;
}
setVisibleValuesFromStoredTime();
[ hoursInput, minutesInput, secondsInput ].forEach( function ( input ) {
input.addEventListener( 'input', updateRecordValues );
input.addEventListener( 'change', updateRecordValues );
input.addEventListener( 'blur', updateRecordValues );
} );
if ( timeInput.form ) {
timeInput.form.addEventListener( 'submit', function ( event ) {
if ( !updateRecordValues() ) {
event.preventDefault();
}
} );
}
if ( timeInput.value ) {
updateRecordValues();
} else {
showMessage( '時・分・秒を入力してください。秒は小数点以下3桁まで入力できます。', false );
}
}
function start() {
setUpRecordTimeInputs();
mw.hook( 'wikipage.content' ).add( setUpRecordTimeInputs );
}
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', start );
} else {
start();
}
} );
/* RTA Wiki: 記録カードの並べ替え */
mw.loader.using( 'mediawiki.util' ).then( function () {
function setUpRecordCardSorts() {
document.querySelectorAll( '.rta-record-cards--sortable' ).forEach( function ( container, index ) {
if ( container.dataset.rtaSortable === '1' ) {
return;
}
container.dataset.rtaSortable = '1';
var control = document.createElement( 'div' );
var label = document.createElement( 'label' );
var select = document.createElement( 'select' );
var selectId = 'rta-record-sort-' + index;
control.className = 'rta-record-sort';
label.htmlFor = selectId;
label.textContent = '並び順:';
select.id = selectId;
[
[ 'time-asc', 'タイムが速い順' ],
[ 'time-desc', 'タイムが遅い順' ],
[ 'date-desc', '記録日が新しい順' ],
[ 'date-asc', '記録日が古い順' ]
].forEach( function ( item ) {
var option = document.createElement( 'option' );
option.value = item[ 0 ];
option.textContent = item[ 1 ];
select.appendChild( option );
} );
control.appendChild( label );
control.appendChild( select );
container.parentNode.insertBefore( control, container );
function sortCards() {
var cards = Array.from( container.children ).filter( function ( element ) {
return element.classList.contains( 'rta-record-card' );
} );
cards.sort( function ( a, b ) {
var mode = select.value;
var aSeconds = Number( a.dataset.rtaSeconds );
var bSeconds = Number( b.dataset.rtaSeconds );
var aDate = a.dataset.rtaDate || '';
var bDate = b.dataset.rtaDate || '';
if ( mode === 'time-asc' || mode === 'time-desc' ) {
if ( !Number.isFinite( aSeconds ) ) {
return 1;
}
if ( !Number.isFinite( bSeconds ) ) {
return -1;
}
return mode === 'time-asc' ?
aSeconds - bSeconds :
bSeconds - aSeconds;
}
if ( !aDate ) {
return 1;
}
if ( !bDate ) {
return -1;
}
return mode === 'date-asc' ?
aDate.localeCompare( bDate ) :
bDate.localeCompare( aDate );
} );
cards.forEach( function ( card ) {
container.appendChild( card );
} );
}
select.addEventListener( 'change', sortCards );
} );
}
function start() {
setUpRecordCardSorts();
mw.hook( 'wikipage.content' ).add( setUpRecordCardSorts );
}
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', start );
} else {
start();
}
} );
/* RTA Wiki: 記録カードの年・版・実施条件・確認区分による絞り込み */
mw.loader.using( 'mediawiki.util' ).then( function () {
function setUpRecordCardFilters() {
document.querySelectorAll( '.rta-record-cards--filterable' ).forEach( function ( container, index ) {
if ( container.dataset.rtaFilterable === '1' ) {
return;
}
container.dataset.rtaFilterable = '1';
var cards = Array.from( container.children ).filter( function ( element ) {
return element.classList.contains( 'rta-record-card' );
} );
var years = Array.from( new Set( cards.map( function ( card ) {
return card.dataset.rtaYear;
} ).filter( Boolean ) ) ).sort().reverse();
var versions = Array.from( new Set( cards.map( function ( card ) {
return card.dataset.rtaVersion;
} ).filter( Boolean ) ) ).sort();
var control = document.createElement( 'div' );
var yearLabel = document.createElement( 'label' );
var yearSelect = document.createElement( 'select' );
var versionLabel = document.createElement( 'label' );
var versionSelect = document.createElement( 'select' );
var conditionLabel = document.createElement( 'label' );
var conditionSelect = document.createElement( 'select' );
var verificationLabel = document.createElement( 'label' );
var verificationSelect = document.createElement( 'select' );
var result = document.createElement( 'span' );
var yearId = 'rta-record-year-filter-' + index;
var versionId = 'rta-record-version-filter-' + index;
var conditionId = 'rta-record-condition-filter-' + index;
var verificationId = 'rta-record-verification-filter-' + index;
control.className = 'rta-record-filter';
yearLabel.htmlFor = yearId;
yearLabel.textContent = '年:';
yearSelect.id = yearId;
[ [ '', 'すべて' ] ].concat( years.map( function ( year ) {
return [ year, year + '年' ];
} ) ).forEach( function ( item ) {
var option = document.createElement( 'option' );
option.value = item[ 0 ];
option.textContent = item[ 1 ];
yearSelect.appendChild( option );
} );
versionLabel.htmlFor = versionId;
versionLabel.textContent = '作品の版:';
versionSelect.id = versionId;
[ [ '', 'すべて' ] ].concat( versions.map( function ( version ) {
return [ version, version ];
} ) ).forEach( function ( item ) {
var option = document.createElement( 'option' );
option.value = item[ 0 ];
option.textContent = item[ 1 ];
versionSelect.appendChild( option );
} );
conditionLabel.htmlFor = conditionId;
conditionLabel.textContent = '実施条件:';
conditionSelect.id = conditionId;
[
[ '', 'すべて' ],
[ 'normal', '通常RTA' ],
[ 'event', '大会・イベント記録' ],
[ 'race', '並走' ],
[ 'single-segment', 'シングルセグメント' ]
].forEach( function ( item ) {
var option = document.createElement( 'option' );
option.value = item[ 0 ];
option.textContent = item[ 1 ];
conditionSelect.appendChild( option );
} );
verificationLabel.htmlFor = verificationId;
verificationLabel.textContent = '確認区分:';
verificationSelect.id = verificationId;
[
[ '', 'すべて' ],
[ '動画・配信で確認', '動画・配信で確認' ],
[ '動画なし・資料で確認', '動画なし・資料で確認' ],
[ '参考記録(確認資料なし)', '参考記録(確認資料なし)' ],
[ '区分未設定', '区分未設定' ]
].forEach( function ( item ) {
var option = document.createElement( 'option' );
option.value = item[ 0 ];
option.textContent = item[ 1 ];
verificationSelect.appendChild( option );
} );
result.className = 'rta-record-filter__result';
control.append(
yearLabel, yearSelect,
versionLabel, versionSelect,
conditionLabel, conditionSelect,
verificationLabel, verificationSelect,
result
);
container.parentNode.insertBefore( control, container );
function applyFilters() {
var visibleCount = 0;
cards.forEach( function ( card ) {
var event = card.dataset.rtaEvent === 'はい';
var race = card.dataset.rtaRace === 'はい';
var singleSegment = card.dataset.rtaSingleSegment === 'はい';
var yearMatches = !yearSelect.value ||
card.dataset.rtaYear === yearSelect.value;
var versionMatches = !versionSelect.value ||
card.dataset.rtaVersion === versionSelect.value;
var conditionMatches = (
!conditionSelect.value ||
( conditionSelect.value === 'normal' && !event && !race && !singleSegment ) ||
( conditionSelect.value === 'event' && event ) ||
( conditionSelect.value === 'race' && race ) ||
( conditionSelect.value === 'single-segment' && singleSegment )
);
var verificationMatches = !verificationSelect.value ||
( card.dataset.rtaVerification || '区分未設定' ) === verificationSelect.value;
card.hidden = !(
yearMatches &&
versionMatches &&
conditionMatches &&
verificationMatches
);
if ( !card.hidden ) {
visibleCount++;
}
} );
result.textContent = visibleCount + ' / ' + cards.length + '件を表示';
}
yearSelect.addEventListener( 'change', applyFilters );
versionSelect.addEventListener( 'change', applyFilters );
conditionSelect.addEventListener( 'change', applyFilters );
verificationSelect.addEventListener( 'change', applyFilters );
applyFilters();
} );
}
function start() {
setUpRecordCardFilters();
mw.hook( 'wikipage.content' ).add( setUpRecordCardFilters );
}
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', start );
} else {
start();
}
} );
/* RTA記録フォーム:確認区分に応じた必須入力 */
$( function () {
var form = document.getElementById( 'pfForm' );
if ( !form ) {
return;
}
var verification = form.querySelector( '#rta-verification select' );
var evidenceUrl = form.querySelector( '#rta-evidence-url input' );
var basis = form.querySelector( '#rta-confirmation-basis textarea' );
var evidenceMark = form.querySelector( '#rta-evidence-required' );
var basisMark = form.querySelector( '#rta-basis-required' );
if ( !verification || !evidenceUrl || !basis || !evidenceMark || !basisMark ) {
return;
}
function updateRequiredFields() {
var value = verification.value;
var requireUrl = value === '動画・配信で確認';
var requireBasis = value === '動画なし・資料で確認';
evidenceUrl.required = requireUrl;
basis.required = requireBasis;
evidenceUrl.setAttribute( 'aria-required', requireUrl ? 'true' : 'false' );
basis.setAttribute( 'aria-required', requireBasis ? 'true' : 'false' );
evidenceMark.style.display = requireUrl ? 'inline' : 'none';
basisMark.style.display = requireBasis ? 'inline' : 'none';
}
verification.addEventListener( 'change', updateRequiredFields );
updateRequiredFields();
} );