Personal tools

Sponsorname

Your company could advertise here

www.fla-consulting.eu

MediaWiki:Common.js: Difference between revisions

From GxPlex

Jump to: navigation, search
refactor: move VoteNY toggle logic to Vote.js
Tag: Replaced
Add GxPlex Search dynamic filter JS
Line 1: Line 1:
/* site-wide JS — VoteNY toggle is handled in Vote.js */
/* site-wide JS — VoteNY toggle is handled in Vote.js */
/* GxPlex Search — dynamic filter UI */
( function () {
if ( mw.config.get( 'wgPageName' ) !== 'GxPlex_Search' ) {
return;
}
var TOPICS = [
'Medical Devices',
'In Vitro Diagnostics',
'EU Regulation',
'Clinical',
'Labelling',
'Post-Market Surveillance',
'Performance Evaluation',
'Traceability'
];
var allResults = [];
/* ---- helpers ---- */
function esc( str ) {
return String( str || '' )
.replace( /&/g, '&' )
.replace( /</g, '&lt;' )
.replace( />/g, '&gt;' )
.replace( /"/g, '&quot;' );
}
function el( tag, attrs, children ) {
var node = document.createElement( tag );
Object.keys( attrs || {} ).forEach( function ( k ) {
node.setAttribute( k, attrs[ k ] );
} );
( children || [] ).forEach( function ( c ) {
node.appendChild( typeof c === 'string' ? document.createTextNode( c ) : c );
} );
return node;
}
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( ', ' );
}
/* ---- build UI ---- */
function buildUI( container ) {
/* filters row */
var topicSel = el( 'select', { id: 'gplx-filter-topic', class: 'gplx-filter-select' } );
[ [ '', 'All topics' ] ].concat( TOPICS.map( function ( t ) { return [ t, t ]; } ) )
.forEach( function ( pair ) {
topicSel.appendChild( el( 'option', { value: pair[ 0 ] }, [ pair[ 1 ] ] ) );
} );
var regionSel = el( 'select', { id: 'gplx-filter-region', class: 'gplx-filter-select' } );
regionSel.appendChild( el( 'option', { value: '' }, [ 'All regions' ] ) );
var textInput = el( 'input', {
type: 'search',
id: 'gplx-filter-text',
class: 'gplx-filter-input',
placeholder: 'Document name…'
} );
var filters = el( 'div', { class: 'gplx-search-filters' }, [
el( 'div', { class: 'gplx-filter-group' }, [
el( 'label', { class: 'gplx-filter-label', for: 'gplx-filter-topic' }, [ 'Topic' ] ),
topicSel
] ),
el( 'div', { class: 'gplx-filter-group' }, [
el( 'label', { class: 'gplx-filter-label', for: 'gplx-filter-region' }, [ 'Region' ] ),
regionSel
] ),
el( 'div', { class: 'gplx-filter-group gplx-filter-group--grow' }, [
el( 'label', { class: 'gplx-filter-label', for: 'gplx-filter-text' }, [ 'Search' ] ),
textInput
] )
] );
var status = el( 'p', { id: 'gplx-search-status', class: 'gplx-search-status' } );
var results = el( 'div', { id: 'gplx-search-results' } );
container.innerHTML = '';
container.appendChild( filters );
container.appendChild( status );
container.appendChild( results );
return { topicSel: topicSel, regionSel: regionSel, textInput: textInput };
}
/* ---- data ---- */
function buildQuery( topic ) {
return ( topic ? '[[Category:' + topic + ']]' : '' )
+ '[[Status::+]]'
+ '|?Document name=Document'
+ '|?Status'
+ '|?Area of validity=Region'
+ '|?Document type=Type'
+ '|?Scope'
+ '|limit=500'
+ '|sort=Document name'
+ '|order=asc';
}
function parseResponse( data ) {
var raw = ( data.query && data.query.results ) || {};
return Object.keys( raw ).map( function ( key ) {
var page = raw[ key ];
var p = page.printouts || {};
return {
name: getProp( p, 'Document' ) || page.fulltext,
url: page.fullurl,
status: getProp( p, 'Status' ),
region: getProp( p, 'Region' ),
type: getProp( p, 'Type' ),
scope: getProp( p, 'Scope' )
};
} );
}
/* ---- render ---- */
function updateRegionDropdown( results, sel ) {
var prev = sel.value;
var seen = {};
results.forEach( function ( r ) {
r.region.split( ',' ).forEach( function ( v ) {
v = v.trim();
if ( v ) { seen[ v ] = true; }
} );
} );
while ( sel.options.length > 1 ) { sel.remove( 1 ); }
Object.keys( seen ).sort().forEach( function ( v ) {
var opt = new Option( v, v, false, v === prev );
sel.add( opt );
} );
}
function applyFilters( results ) {
var region = ( document.getElementById( 'gplx-filter-region' ).value || '' ).trim().toLowerCase();
var text = ( document.getElementById( 'gplx-filter-text' ).value || '' ).trim().toLowerCase();
return results.filter( function ( r ) {
if ( region && r.region.toLowerCase().indexOf( region ) === -1 ) { return false; }
if ( text && r.name.toLowerCase().indexOf( text ) === -1 ) { return false; }
return true;
} );
}
function renderTable( results ) {
var container = document.getElementById( 'gplx-search-results' );
if ( !results.length ) {
container.innerHTML = '<p class="gplx-no-results">No documents match the selected filters.</p>';
return;
}
var rows = results.map( function ( r ) {
return '<tr>'
+ '<td><a href="' + esc( r.url ) + '">' + esc( r.name ) + '</a>'
+ ( r.scope ? '<br><span class="gplx-result-scope">' + esc( r.scope ) + '</span>' : '' )
+ '</td>'
+ '<td>' + esc( r.status ) + '</td>'
+ '<td>' + esc( r.region ) + '</td>'
+ '<td>' + esc( r.type ) + '</td>'
+ '</tr>';
} );
container.innerHTML = '<table class="wikitable sortable gplx-results-table">'
+ '<thead><tr><th>Document</th><th>Status</th><th>Region</th><th>Type</th></tr></thead>'
+ '<tbody>' + rows.join( '' ) + '</tbody>'
+ '</table>';
}
function setStatus( msg, busy ) {
var el = document.getElementById( 'gplx-search-status' );
el.textContent = msg;
el.className = 'gplx-search-status' + ( busy ? ' gplx-search-busy' : '' );
}
function refresh() {
var visible = applyFilters( allResults );
setStatus( visible.length + ' of ' + allResults.length
+ ' document' + ( allResults.length !== 1 ? 's' : '' ), false );
renderTable( visible );
}
function load( topic, regionSel ) {
setStatus( 'Loading…', true );
document.getElementById( 'gplx-search-results' ).innerHTML = '';
( new mw.Api() ).get( {
action: 'ask',
query: buildQuery( topic ),
format: 'json'
} ).done( function ( data ) {
allResults = parseResponse( data );
updateRegionDropdown( allResults, regionSel );
refresh();
} ).fail( function () {
setStatus( 'Failed to load results. Please reload the page.', false );
} );
}
/* ---- init ---- */
mw.loader.using( [ 'mediawiki.api' ], function () {
$( function () {
var container = document.getElementById( 'gplx-search-app' );
if ( !container ) { return; }
var controls = buildUI( container );
var debounce;
controls.topicSel.addEventListener( 'change', function () {
load( controls.topicSel.value, controls.regionSel );
} );
controls.regionSel.addEventListener( 'change', refresh );
controls.textInput.addEventListener( 'input', function () {
clearTimeout( debounce );
debounce = setTimeout( refresh, 250 );
} );
load( '', controls.regionSel );
} );
} );
}() );

Revision as of 16:55, 23 June 2026

/* site-wide JS — VoteNY toggle is handled in Vote.js */

/* GxPlex Search — dynamic filter UI */
( function () {
	if ( mw.config.get( 'wgPageName' ) !== 'GxPlex_Search' ) {
		return;
	}

	var TOPICS = [
		'Medical Devices',
		'In Vitro Diagnostics',
		'EU Regulation',
		'Clinical',
		'Labelling',
		'Post-Market Surveillance',
		'Performance Evaluation',
		'Traceability'
	];

	var allResults = [];

	/* ---- helpers ---- */

	function esc( str ) {
		return String( str || '' )
			.replace( /&/g, '&amp;' )
			.replace( /</g, '&lt;' )
			.replace( />/g, '&gt;' )
			.replace( /"/g, '&quot;' );
	}

	function el( tag, attrs, children ) {
		var node = document.createElement( tag );
		Object.keys( attrs || {} ).forEach( function ( k ) {
			node.setAttribute( k, attrs[ k ] );
		} );
		( children || [] ).forEach( function ( c ) {
			node.appendChild( typeof c === 'string' ? document.createTextNode( c ) : c );
		} );
		return node;
	}

	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( ', ' );
	}

	/* ---- build UI ---- */

	function buildUI( container ) {
		/* filters row */
		var topicSel = el( 'select', { id: 'gplx-filter-topic', class: 'gplx-filter-select' } );
		[ [ '', 'All topics' ] ].concat( TOPICS.map( function ( t ) { return [ t, t ]; } ) )
			.forEach( function ( pair ) {
				topicSel.appendChild( el( 'option', { value: pair[ 0 ] }, [ pair[ 1 ] ] ) );
			} );

		var regionSel = el( 'select', { id: 'gplx-filter-region', class: 'gplx-filter-select' } );
		regionSel.appendChild( el( 'option', { value: '' }, [ 'All regions' ] ) );

		var textInput = el( 'input', {
			type: 'search',
			id: 'gplx-filter-text',
			class: 'gplx-filter-input',
			placeholder: 'Document name…'
		} );

		var filters = el( 'div', { class: 'gplx-search-filters' }, [
			el( 'div', { class: 'gplx-filter-group' }, [
				el( 'label', { class: 'gplx-filter-label', for: 'gplx-filter-topic' }, [ 'Topic' ] ),
				topicSel
			] ),
			el( 'div', { class: 'gplx-filter-group' }, [
				el( 'label', { class: 'gplx-filter-label', for: 'gplx-filter-region' }, [ 'Region' ] ),
				regionSel
			] ),
			el( 'div', { class: 'gplx-filter-group gplx-filter-group--grow' }, [
				el( 'label', { class: 'gplx-filter-label', for: 'gplx-filter-text' }, [ 'Search' ] ),
				textInput
			] )
		] );

		var status = el( 'p', { id: 'gplx-search-status', class: 'gplx-search-status' } );
		var results = el( 'div', { id: 'gplx-search-results' } );

		container.innerHTML = '';
		container.appendChild( filters );
		container.appendChild( status );
		container.appendChild( results );

		return { topicSel: topicSel, regionSel: regionSel, textInput: textInput };
	}

	/* ---- data ---- */

	function buildQuery( topic ) {
		return ( topic ? '[[Category:' + topic + ']]' : '' )
			+ '[[Status::+]]'
			+ '|?Document name=Document'
			+ '|?Status'
			+ '|?Area of validity=Region'
			+ '|?Document type=Type'
			+ '|?Scope'
			+ '|limit=500'
			+ '|sort=Document name'
			+ '|order=asc';
	}

	function parseResponse( data ) {
		var raw = ( data.query && data.query.results ) || {};
		return Object.keys( raw ).map( function ( key ) {
			var page = raw[ key ];
			var p = page.printouts || {};
			return {
				name: getProp( p, 'Document' ) || page.fulltext,
				url: page.fullurl,
				status: getProp( p, 'Status' ),
				region: getProp( p, 'Region' ),
				type: getProp( p, 'Type' ),
				scope: getProp( p, 'Scope' )
			};
		} );
	}

	/* ---- render ---- */

	function updateRegionDropdown( results, sel ) {
		var prev = sel.value;
		var seen = {};
		results.forEach( function ( r ) {
			r.region.split( ',' ).forEach( function ( v ) {
				v = v.trim();
				if ( v ) { seen[ v ] = true; }
			} );
		} );
		while ( sel.options.length > 1 ) { sel.remove( 1 ); }
		Object.keys( seen ).sort().forEach( function ( v ) {
			var opt = new Option( v, v, false, v === prev );
			sel.add( opt );
		} );
	}

	function applyFilters( results ) {
		var region = ( document.getElementById( 'gplx-filter-region' ).value || '' ).trim().toLowerCase();
		var text = ( document.getElementById( 'gplx-filter-text' ).value || '' ).trim().toLowerCase();
		return results.filter( function ( r ) {
			if ( region && r.region.toLowerCase().indexOf( region ) === -1 ) { return false; }
			if ( text && r.name.toLowerCase().indexOf( text ) === -1 ) { return false; }
			return true;
		} );
	}

	function renderTable( results ) {
		var container = document.getElementById( 'gplx-search-results' );
		if ( !results.length ) {
			container.innerHTML = '<p class="gplx-no-results">No documents match the selected filters.</p>';
			return;
		}
		var rows = results.map( function ( r ) {
			return '<tr>'
				+ '<td><a href="' + esc( r.url ) + '">' + esc( r.name ) + '</a>'
				+ ( r.scope ? '<br><span class="gplx-result-scope">' + esc( r.scope ) + '</span>' : '' )
				+ '</td>'
				+ '<td>' + esc( r.status ) + '</td>'
				+ '<td>' + esc( r.region ) + '</td>'
				+ '<td>' + esc( r.type ) + '</td>'
				+ '</tr>';
		} );
		container.innerHTML = '<table class="wikitable sortable gplx-results-table">'
			+ '<thead><tr><th>Document</th><th>Status</th><th>Region</th><th>Type</th></tr></thead>'
			+ '<tbody>' + rows.join( '' ) + '</tbody>'
			+ '</table>';
	}

	function setStatus( msg, busy ) {
		var el = document.getElementById( 'gplx-search-status' );
		el.textContent = msg;
		el.className = 'gplx-search-status' + ( busy ? ' gplx-search-busy' : '' );
	}

	function refresh() {
		var visible = applyFilters( allResults );
		setStatus( visible.length + ' of ' + allResults.length
			+ ' document' + ( allResults.length !== 1 ? 's' : '' ), false );
		renderTable( visible );
	}

	function load( topic, regionSel ) {
		setStatus( 'Loading…', true );
		document.getElementById( 'gplx-search-results' ).innerHTML = '';
		( new mw.Api() ).get( {
			action: 'ask',
			query: buildQuery( topic ),
			format: 'json'
		} ).done( function ( data ) {
			allResults = parseResponse( data );
			updateRegionDropdown( allResults, regionSel );
			refresh();
		} ).fail( function () {
			setStatus( 'Failed to load results. Please reload the page.', false );
		} );
	}

	/* ---- init ---- */

	mw.loader.using( [ 'mediawiki.api' ], function () {
		$( function () {
			var container = document.getElementById( 'gplx-search-app' );
			if ( !container ) { return; }

			var controls = buildUI( container );
			var debounce;

			controls.topicSel.addEventListener( 'change', function () {
				load( controls.topicSel.value, controls.regionSel );
			} );
			controls.regionSel.addEventListener( 'change', refresh );
			controls.textInput.addEventListener( 'input', function () {
				clearTimeout( debounce );
				debounce = setTimeout( refresh, 250 );
			} );

			load( '', controls.regionSel );
		} );
	} );
}() );