/* site-wide JS — VoteNY toggle is handled in Vote.js */ /* GxPlex Search — chainable filter buttons with pagination */ ( function () { if ( mw.config.get( 'wgPageName' ) !== 'GxPlex_Search' ) { return; } var PAGE_SIZE = 50; var FILTER_GROUPS = [ { key: 'type', label: 'Type' }, { key: 'validityArea', label: 'Validity area' }, { key: 'scopes', label: 'Scope(s)' }, { key: 'status', label: 'Status' }, { key: 'docType', label: 'Document type' }, { key: 'language', label: 'Language' }, { key: 'restricted', label: 'Restricted access' } ]; var DOC_QUERY = '[[Document:+]]' + '|?DocReference=reference' + '|?DocValidityArea=validityArea' + '|?DocScopes=scopes' + '|?DocName=docName' + '|?DocVersion=version' + '|?DocStatus=status' + '|?DocType=docType' + '|?DocLanguage=language' + '|?DocDescription=description' + '|?DocRestricted=restricted' + '|?DocSubmittedBy=submittedBy' + '|?DocContributors=contributors' + '|limit=500' + '|sort=DocName' + '|order=asc'; var REF_QUERY = '[[Reference:+]]' + '|?HasDocument=linkedDoc' + '|?HasDocument.DocReference=reference' + '|?HasDocument.DocValidityArea=validityArea' + '|?HasDocument.DocScopes=scopes' + '|?HasDocument.DocName=docName' + '|?HasDocument.DocVersion=version' + '|?HasDocument.DocStatus=status' + '|?HasDocument.DocType=docType' + '|?HasDocument.DocLanguage=language' + '|?HasDocument.DocDescription=description' + '|?HasDocument.DocRestricted=restricted' + '|?HasDocument.DocSubmittedBy=submittedBy' + '|?HasDocument.DocContributors=contributors' + '|?RefScope=refScope' + '|?RefLanguage=refLanguage' + '|?RefTagsEN=tagsEN' + '|limit=500'; var allResults = []; var filteredResults = []; var currentPage = 1; var activeFilters = {}; /* ---- helpers ---- */ function esc( str ) { return String( str || '' ) .replace( /&/g, '&' ) .replace( //g, '>' ) .replace( /"/g, '"' ); } function getProp( printouts, key ) { var arr = printouts[ key ]; if ( !arr || !arr.length ) { return ''; } return arr.map( function ( v ) { if ( typeof v === 'string' ) { return v; } return v.item !== undefined ? v.item : ( v.fulltext || '' ); } ).filter( Boolean ).join( ', ' ); } function splitValues( str ) { return String( str || '' ).split( ',' ).map( function ( v ) { return v.trim(); } ).filter( Boolean ); } /* ---- parse SMW responses ---- */ function parseResults( data, type ) { var raw = ( data.query && data.query.results ) || {}; return Object.keys( raw ).map( function ( key ) { var page = raw[ key ]; var p = page.printouts || {}; var docName = getProp( p, 'docName' ); return { _type: type, fulltext: page.fulltext, url: page.fullurl, displayName: type === 'Document' ? ( docName || page.fulltext.replace( /^Document:/, '' ) ) : page.fulltext.replace( /^Reference:/, '' ), reference: getProp( p, 'reference' ), validityArea: getProp( p, 'validityArea' ), scopes: getProp( p, 'scopes' ), docName: docName, version: getProp( p, 'version' ), status: getProp( p, 'status' ), docType: getProp( p, 'docType' ), language: getProp( p, 'language' ), description: getProp( p, 'description' ), restricted: getProp( p, 'restricted' ), submittedBy: getProp( p, 'submittedBy' ), contributors: getProp( p, 'contributors' ), preview: '' }; } ); } /* ---- text extracts (250 chars, batches of 50) ---- */ function fetchExtracts( results, callback ) { if ( !results.length ) { callback(); return; } var byTitle = {}; results.forEach( function ( r ) { byTitle[ r.fulltext ] = r; } ); var titles = results.map( function ( r ) { return r.fulltext; } ); var batches = []; for ( var i = 0; i < titles.length; i += 50 ) { batches.push( titles.slice( i, i + 50 ) ); } var done = 0; var api = new mw.Api(); batches.forEach( function ( batch ) { api.get( { action: 'query', prop: 'extracts', exchars: 250, exintro: true, explaintext: true, titles: batch.join( '|' ), format: 'json' } ).always( function ( data ) { if ( data && data.query && data.query.pages ) { Object.keys( data.query.pages ).forEach( function ( id ) { var pg = data.query.pages[ id ]; if ( byTitle[ pg.title ] ) { byTitle[ pg.title ].preview = ( pg.extract || '' ) .replace( /\s+/g, ' ' ).trim().slice( 0, 250 ); } } ); } if ( ++done === batches.length ) { callback(); } } ); } ); } /* ---- filter button data ---- */ function collectFieldValues( results ) { var values = {}; FILTER_GROUPS.forEach( function ( g ) { values[ g.key ] = {}; } ); results.forEach( function ( r ) { FILTER_GROUPS.forEach( function ( g ) { var raw = g.key === 'type' ? r._type : r[ g.key ]; splitValues( raw ).forEach( function ( v ) { values[ g.key ][ v ] = true; } ); } ); } ); return values; } /* ---- render filter buttons ---- */ function renderFilterButtons( filterSection, values ) { filterSection.innerHTML = ''; activeFilters = {}; var hasAnyValue = FILTER_GROUPS.some( function ( g ) { return Object.keys( values[ g.key ] || {} ).length > 0; } ); if ( !hasAnyValue ) { var msg = document.createElement( 'p' ); msg.className = 'gplx-no-results'; msg.textContent = 'No documents or references indexed yet. Import data to enable filters.'; filterSection.appendChild( msg ); return; } FILTER_GROUPS.forEach( function ( g ) { activeFilters[ g.key ] = {}; var vals = Object.keys( values[ g.key ] || {} ).sort(); if ( !vals.length ) { return; } var group = document.createElement( 'div' ); group.className = 'gplx-filter-group'; var label = document.createElement( 'span' ); label.className = 'gplx-filter-label'; label.textContent = g.label; var row = document.createElement( 'div' ); row.className = 'gplx-filter-btn-row'; vals.forEach( function ( v ) { var btn = document.createElement( 'button' ); btn.type = 'button'; btn.className = 'gplx-filter-btn'; btn.textContent = v; btn.setAttribute( 'aria-pressed', 'false' ); btn.addEventListener( 'click', function () { if ( activeFilters[ g.key ][ v ] ) { delete activeFilters[ g.key ][ v ]; btn.classList.remove( 'is-active' ); btn.setAttribute( 'aria-pressed', 'false' ); } else { activeFilters[ g.key ][ v ] = true; btn.classList.add( 'is-active' ); btn.setAttribute( 'aria-pressed', 'true' ); } refresh(); } ); row.appendChild( btn ); } ); group.appendChild( label ); group.appendChild( row ); filterSection.appendChild( group ); } ); } /* ---- filter logic: AND across groups, OR within group ---- */ function matchesFilters( result ) { return FILTER_GROUPS.every( function ( g ) { var active = Object.keys( activeFilters[ g.key ] || {} ); if ( !active.length ) { return true; } var fieldVal = g.key === 'type' ? result._type : ( result[ g.key ] || '' ); var parts = splitValues( fieldVal ); return active.some( function ( av ) { return parts.some( function ( p ) { return p.toLowerCase() === av.toLowerCase(); } ); } ); } ); } function applyFilters( results ) { var textEl = document.getElementById( 'gplx-filter-text' ); var text = textEl ? textEl.value.trim().toLowerCase() : ''; return results.filter( function ( r ) { if ( !matchesFilters( r ) ) { return false; } if ( text ) { var hay = [ r.displayName, r.reference, r.validityArea, r.scopes, r.docName, r.version, r.status, r.docType, r.language, r.description, r.restricted, r.submittedBy, r.contributors, r.preview ].join( ' ' ).toLowerCase(); if ( hay.indexOf( text ) === -1 ) { return false; } } return true; } ); } /* ---- pagination ---- */ function getPageRange( current, total ) { if ( total <= 7 ) { var pages = []; for ( var i = 1; i <= total; i++ ) { pages.push( i ); } return pages; } var result = [ 1 ]; var left = current - 2; var right = current + 2; if ( left > 2 ) { result.push( '...' ); } for ( var j = Math.max( 2, left ); j <= Math.min( total - 1, right ); j++ ) { result.push( j ); } if ( right < total - 1 ) { result.push( '...' ); } result.push( total ); return result; } function renderPagination( total ) { var el = document.getElementById( 'gplx-pagination' ); if ( !el ) { return; } var totalPages = Math.ceil( total / PAGE_SIZE ); if ( totalPages <= 1 ) { el.innerHTML = ''; return; } var frag = document.createDocumentFragment(); function pageBtn( label, page, isCurrent, isDisabled ) { var btn = document.createElement( 'button' ); btn.type = 'button'; btn.className = 'gplx-page-btn' + ( isCurrent ? ' gplx-page-btn--current' : '' ); btn.textContent = label; btn.disabled = isDisabled || isCurrent; if ( isCurrent ) { btn.setAttribute( 'aria-current', 'page' ); } if ( !isDisabled && !isCurrent ) { btn.addEventListener( 'click', function () { currentPage = page; renderPage(); var s = document.getElementById( 'gplx-search-status' ); if ( s ) { s.scrollIntoView( { behavior: 'smooth', block: 'nearest' } ); } } ); } return btn; } frag.appendChild( pageBtn( '‹ Previous', currentPage - 1, false, currentPage === 1 ) ); getPageRange( currentPage, totalPages ).forEach( function ( p ) { if ( p === '...' ) { var span = document.createElement( 'span' ); span.className = 'gplx-page-ellipsis'; span.textContent = '…'; frag.appendChild( span ); } else { frag.appendChild( pageBtn( String( p ), p, p === currentPage, false ) ); } } ); frag.appendChild( pageBtn( 'Next ›', currentPage + 1, false, currentPage === totalPages ) ); el.innerHTML = ''; el.appendChild( frag ); } /* ---- render results table ---- */ function renderTable( pageResults ) { var container = document.getElementById( 'gplx-search-results' ); if ( !pageResults.length ) { container.innerHTML = '
No results match the selected filters.
'; return; } var rows = pageResults.map( function ( r ) { var typeBadge = r._type === 'Document' ? 'Document' : 'Reference'; var restricted = r.restricted && r.restricted.toLowerCase() === 'yes' ? ' Restricted' : ''; var preview = r.preview ? '| Type | Title | ' + 'Validity area | Status | Language | Document type | ' + '
|---|