Personal tools

Sponsorname

Your company could advertise here

www.fla-consulting.eu

MediaWiki:Common.js

From GxPlex

Revision as of 17:00, 23 June 2026 by Gxplex admin (talk | contribs) (Update search: columns Scope, Language, Restricted; full-text filter)
Jump to: navigation, search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* 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: 'Search…'
		} );

		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'
			+ '|?Area of validity=Region'
			+ '|?Document type=Type'
			+ '|?Scope'
			+ '|?Language'
			+ '|?Restricted access=Restricted'
			+ '|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,
				region: getProp( p, 'Region' ),
				type: getProp( p, 'Type' ),
				scope: getProp( p, 'Scope' ),
				language: getProp( p, 'Language' ),
				restricted: getProp( p, 'Restricted' )
			};
		} );
	}

	/* ---- 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 ) {
				var haystack = [ r.name, r.scope, r.type, r.language ].join( ' ' ).toLowerCase();
				if ( haystack.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 ) {
			var restricted = r.restricted && r.restricted.toLowerCase() === 'yes'
				? ' <span class="gplx-badge-restricted">Restricted</span>'
				: '';
			return '<tr>'
				+ '<td><a href="' + esc( r.url ) + '">' + esc( r.name ) + '</a>' + restricted + '</td>'
				+ '<td>' + esc( r.scope ) + '</td>'
				+ '<td>' + esc( r.language ) + '</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>Scope</th><th>Language</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 );
		} );
	} );
}() );