MediaWiki:Common.js: Różnice pomiędzy wersjami

Z Dubbingpedia
Skocz do:nawigacja, szukaj
m Test
Znacznik: Usunięcie całej zawartości strony
mNie podano opisu zmian
Linia 1: Linia 1:
/* 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 );
    }
}() );

Wersja z 01:19, 11 sie 2026

/* 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 );
    }
}() );