MediaWiki:Common.js
Z Dubbingpedia
Uwaga: aby zobaczyć zmiany po opublikowaniu, może zajść potrzeba wyczyszczenia pamięci podręcznej przeglądarki.
- Firefox / Safari: Przytrzymaj Shift podczas klikania Odśwież bieżącą stronę, lub naciśnij klawisze Ctrl+F5, lub Ctrl+R (⌘-R na komputerze Mac)
- Google Chrome: Naciśnij Ctrl-Shift-R (⌘-Shift-R na komputerze Mac)
- Internet Explorer / Edge: Przytrzymaj Ctrl, jednocześnie klikając Odśwież, lub naciśnij klawisze Ctrl+F5
- Opera: Naciśnij klawisze Ctrl+F5.
/* global mw */
( function () {
'use strict';
var COLUMN_CLASSES = {
number: 'pdk-episodes__number',
date: 'pdk-episodes__date',
title: 'pdk-episodes__title',
original: 'pdk-episodes__original'
};
function buildGrid( rows ) {
var grid = [];
rows.forEach( function ( row, rowIndex ) {
var column = 0;
grid[ rowIndex ] = grid[ rowIndex ] || [];
Array.prototype.forEach.call( row.cells, function ( cell ) {
var rowOffset;
var columnOffset;
while ( grid[ rowIndex ][ column ] ) {
column += 1;
}
for ( rowOffset = 0; rowOffset < cell.rowSpan; rowOffset += 1 ) {
grid[ rowIndex + rowOffset ] = grid[ rowIndex + rowOffset ] || [];
for ( columnOffset = 0; columnOffset < cell.colSpan; columnOffset += 1 ) {
grid[ rowIndex + rowOffset ][ column + columnOffset ] = cell;
}
}
column += cell.colSpan;
} );
} );
return grid;
}
function makeGroups( dataRows ) {
var groups = [];
var index = 0;
while ( index < dataRows.length ) {
var firstRow = dataRows[ index ];
var span = 1;
Array.prototype.forEach.call( firstRow.cells, function ( cell ) {
span = Math.max( span, cell.rowSpan || 1 );
} );
var groupRows = dataRows.slice( index, index + span );
groupRows.forEach( function ( row, rowOffset ) {
row.classList.add( 'pdk-episodes__row' );
if ( rowOffset > 0 ) {
row.classList.add( 'pdk-episodes__continuation' );
}
} );
groups.push( {
rows: groupRows,
originalIndex: groups.length
} );
index += span;
}
return groups;
}
function parseDate( value ) {
var exact = value.match( /\b(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})\b/ );
if ( exact ) {
return Number( exact[ 3 ] ) * 10000 + Number( exact[ 2 ] ) * 100 + Number( exact[ 1 ] );
}
var month = value.match( /\b(\d{1,2})[.\/-](\d{4})\b/ );
if ( month ) {
return Number( month[ 2 ] ) * 10000 + Number( month[ 1 ] ) * 100;
}
var year = value.match( /\b(\d{4})\b/ );
return year ? Number( year[ 1 ] ) * 10000 : null;
}
function textForColumn( group, column, grid, rowIndexes ) {
var value = '';
group.rows.some( function ( row ) {
var rowIndex = rowIndexes.get( row );
var cell = grid[ rowIndex ] && grid[ rowIndex ][ column ];
var candidate = cell ? cell.textContent.trim() : '';
if ( candidate ) {
value = candidate;
return true;
}
return false;
} );
return value;
}
function createMobileControls( table, descriptors, applySort ) {
var sortable = descriptors.filter( function ( descriptor ) {
return descriptor.sortType;
} );
if ( !sortable.length ) {
return null;
}
var labels = {};
sortable.forEach( function ( descriptor ) {
labels[ descriptor.label ] = ( labels[ descriptor.label ] || 0 ) + 1;
} );
var seen = {};
var controls = document.createElement( 'div' );
controls.className = 'pdk-episodes__mobile-sort';
var select = document.createElement( 'select' );
select.setAttribute( 'aria-label', 'Sortuj listę odcinków' );
var original = document.createElement( 'option' );
original.value = '';
original.textContent = 'Kolejność według serii';
select.appendChild( original );
sortable.forEach( function ( descriptor ) {
seen[ descriptor.label ] = ( seen[ descriptor.label ] || 0 ) + 1;
var option = document.createElement( 'option' );
option.value = String( descriptor.column );
option.textContent = labels[ descriptor.label ] > 1 ?
descriptor.label + ' (' + seen[ descriptor.label ] + ')' : descriptor.label;
select.appendChild( option );
} );
var direction = document.createElement( 'button' );
direction.type = 'button';
direction.disabled = true;
direction.textContent = '↑';
direction.title = 'Zmień kierunek sortowania';
direction.setAttribute( 'aria-label', 'Zmień kierunek sortowania' );
select.addEventListener( 'change', function () {
if ( select.value === '' ) {
direction.disabled = true;
direction.textContent = '↑';
applySort( null, 'original' );
return;
}
direction.disabled = false;
direction.textContent = '↑';
applySort( Number( select.value ), 'ascending' );
} );
direction.addEventListener( 'click', function () {
var next = direction.textContent === '↑' ? 'descending' : 'ascending';
direction.textContent = next === 'ascending' ? '↑' : '↓';
applySort( Number( select.value ), next );
} );
controls.appendChild( select );
controls.appendChild( direction );
table.parentNode.insertBefore( controls, table );
return {
select: select,
direction: direction
};
}
function initializeTable( table ) {
if ( table.dataset.pdkEpisodesReady === '1' ) {
return;
}
table.dataset.pdkEpisodesReady = '1';
var rows = Array.prototype.slice.call( table.rows );
var grid = buildGrid( rows );
var rowIndexes = new Map();
rows.forEach( function ( row, index ) {
rowIndexes.set( row, index );
} );
var headerRow = rows.find( function ( row ) {
return !row.classList.contains( 'pdk-episodes__season' ) &&
row.querySelector( 'th[data-pdk-sort], th[data-pdk-column]' );
} );
if ( !headerRow ) {
return;
}
headerRow.classList.add( 'pdk-episodes__head' );
var headerIndex = rowIndexes.get( headerRow );
var descriptors = [];
var usedHeaders = new Set();
( grid[ headerIndex ] || [] ).forEach( function ( cell, column ) {
if ( !cell || usedHeaders.has( cell ) ) {
return;
}
usedHeaders.add( cell );
descriptors.push( {
cell: cell,
column: column,
sortType: cell.dataset.pdkSort || '',
columnType: cell.dataset.pdkColumn || '',
label: cell.textContent.trim()
} );
} );
var columnCounts = {};
descriptors.forEach( function ( descriptor ) {
if ( descriptor.columnType ) {
columnCounts[ descriptor.columnType ] =
( columnCounts[ descriptor.columnType ] || 0 ) + 1;
}
} );
var dataRows = rows.filter( function ( row ) {
return row !== headerRow &&
!row.classList.contains( 'pdk-episodes__season' ) &&
row.cells.length > 0 &&
!Array.prototype.some.call( row.cells, function ( cell ) {
return cell.tagName === 'TH';
} );
} );
descriptors.forEach( function ( descriptor ) {
dataRows.forEach( function ( row ) {
var rowIndex = rowIndexes.get( row );
var cell = grid[ rowIndex ] && grid[ rowIndex ][ descriptor.column ];
if ( !cell || cell.tagName !== 'TD' ) {
return;
}
if ( descriptor.columnType && COLUMN_CLASSES[ descriptor.columnType ] ) {
cell.classList.add( COLUMN_CLASSES[ descriptor.columnType ] );
if ( columnCounts[ descriptor.columnType ] > 1 ) {
cell.classList.add( 'pdk-episodes__column--labelled' );
}
}
if ( !cell.dataset.pdkLabel ) {
cell.dataset.pdkLabel = descriptor.label;
}
} );
} );
var groups = makeGroups( dataRows );
var originalRows = rows.map( function ( row ) {
return { row: row, parent: row.parentNode };
} );
var collator = new Intl.Collator( 'pl', { numeric: true, sensitivity: 'base' } );
var currentColumn = null;
var currentDirection = 'original';
var mobileControls;
function restoreOriginalOrder() {
originalRows.forEach( function ( entry ) {
entry.parent.appendChild( entry.row );
} );
}
function updateIndicators( column, direction ) {
descriptors.forEach( function ( descriptor ) {
descriptor.cell.removeAttribute( 'aria-sort' );
} );
if ( column !== null && direction !== 'original' ) {
var active = descriptors.find( function ( descriptor ) {
return descriptor.column === column;
} );
if ( active ) {
active.cell.setAttribute( 'aria-sort', direction );
}
}
if ( mobileControls ) {
mobileControls.select.value = column === null ? '' : String( column );
mobileControls.direction.disabled = column === null;
mobileControls.direction.textContent = direction === 'descending' ? '↓' : '↑';
}
}
function applySort( column, direction ) {
currentColumn = column;
currentDirection = direction;
if ( column === null || direction === 'original' ) {
restoreOriginalOrder();
table.classList.remove( 'pdk-episodes--sorted' );
updateIndicators( null, 'original' );
return;
}
var descriptor = descriptors.find( function ( item ) {
return item.column === column;
} );
if ( !descriptor ) {
return;
}
var sorted = groups.slice().sort( function ( left, right ) {
var leftText = textForColumn( left, column, grid, rowIndexes );
var rightText = textForColumn( right, column, grid, rowIndexes );
var leftValue = descriptor.sortType === 'date' ? parseDate( leftText ) : leftText;
var rightValue = descriptor.sortType === 'date' ? parseDate( rightText ) : rightText;
var leftMissing = leftValue === null || leftValue === '';
var rightMissing = rightValue === null || rightValue === '';
if ( leftMissing !== rightMissing ) {
return leftMissing ? 1 : -1;
}
var comparison = descriptor.sortType === 'date' ?
leftValue - rightValue : collator.compare( leftValue, rightValue );
if ( comparison === 0 ) {
return left.originalIndex - right.originalIndex;
}
return direction === 'descending' ? -comparison : comparison;
} );
var parent = groups.length && groups[ 0 ].rows.length ?
groups[ 0 ].rows[ 0 ].parentNode : null;
if ( parent ) {
sorted.forEach( function ( group ) {
group.rows.forEach( function ( row ) {
parent.appendChild( row );
} );
} );
}
table.classList.add( 'pdk-episodes--sorted' );
updateIndicators( column, direction );
}
descriptors.filter( function ( descriptor ) {
return descriptor.sortType;
} ).forEach( function ( descriptor ) {
var button = document.createElement( 'button' );
var icon = document.createElement( 'span' );
button.type = 'button';
button.className = 'pdk-episodes__sort';
button.title = 'Sortuj według: ' + descriptor.label;
button.setAttribute( 'aria-label', 'Sortuj według: ' + descriptor.label );
icon.className = 'pdk-episodes__sort-icon';
icon.setAttribute( 'aria-hidden', 'true' );
button.appendChild( icon );
button.addEventListener( 'click', function () {
var nextDirection = 'ascending';
if ( currentColumn === descriptor.column && currentDirection === 'ascending' ) {
nextDirection = 'descending';
} else if ( currentColumn === descriptor.column && currentDirection === 'descending' ) {
applySort( null, 'original' );
return;
}
applySort( descriptor.column, nextDirection );
} );
descriptor.cell.appendChild( button );
} );
mobileControls = createMobileControls( table, descriptors, applySort );
}
function initialize( content ) {
var root = content && content[ 0 ] ? content[ 0 ] : content || document;
Array.prototype.forEach.call(
root.querySelectorAll( 'table.js-pdk-episodes' ),
initializeTable
);
}
if ( typeof mw !== 'undefined' && mw.hook ) {
mw.hook( 'wikipage.content' ).add( initialize );
} else if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', function () {
initialize( document );
} );
} else {
initialize( document );
}
}() );