MediaWiki:Mobile.js

Материал из База знаний Эскорт

Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Internet Explorer / Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
/*
 * База знаний Эскорт — MediaWiki:Mobile.js (копия Common.js для мобильной версии)
 *
 * 1. Фильтр каталога на заглавной странице: категории + поиск по модели.
 *    Плитки создаёт шаблон «Плитка продукта» (атрибуты data-cat и data-search).
 * 2. Номера разделов в оглавлении «01, 02 …» на страницах с «Карточкой датчика»,
 *    чтобы они совпадали с нумерацией в тексте (её задаёт Common.css).
 * 3. Мобильная версия: блок «Далее» выносится из последнего сворачиваемого
 *    раздела в конец статьи, чтобы переход к соседней модели был виден всегда.
 *
 * Синтаксис — ES5: так скрипт проходит проверку ResourceLoader в MediaWiki 1.41.
 */
( function () {
	'use strict';

	/*
	 * Подписи интерфейса. Для EN/ES вики tools/build-lang.py подставляет переводы
	 * (собранные файлы — в MediaWiki/en и MediaWiki/es).
	 * Порядок категорий = порядок кнопок; коды совпадают с параметром «категория» шаблона.
	 */
	var TEXT = {
		cats: [
			[ 'all', 'Все' ],
			[ 'fuel', 'Уровень топлива' ],
			[ 'angle', 'Угол наклона' ],
			[ 'level', 'Уровень воды и сыпучих' ],
			[ 'ble', 'BLE-инфраструктура' ],
			[ 'other', 'Прочие датчики' ],
			[ 'meteo', 'Сокол Метео' ]
		],
		filter: 'Фильтр каталога',
		search: 'Поиск по каталогу',
		placeholder: 'Модель или тип: TD-BLE, угол…',
		empty: 'Ничего не найдено. Проверьте написание модели или напишите в поддержку: help@escortsensors.com'
	};
	var CATS = TEXT.cats;

	function el( tag, attrs, text ) {
		var node = document.createElement( tag );
		var key;
		for ( key in attrs ) {
			if ( Object.prototype.hasOwnProperty.call( attrs, key ) ) {
				node.setAttribute( key, attrs[ key ] );
			}
		}
		if ( text !== undefined ) {
			node.appendChild( document.createTextNode( text ) );
		}
		return node;
	}

	function initCatalog( catalog ) {
		if ( catalog.getAttribute( 'data-es-ready' ) ) {
			return;
		}
		catalog.setAttribute( 'data-es-ready', '1' );

		var tiles = Array.prototype.slice.call( catalog.querySelectorAll( '.es-tile' ) );
		var state = { cat: 'all', q: '' };
		var bar = el( 'div', { 'class': 'es-filter', role: 'group', 'aria-label': TEXT.filter } );
		var empty = el( 'div', { 'class': 'es-filter__empty', role: 'status', hidden: 'hidden' },
			TEXT.empty );
		var chips = el( 'div', { 'class': 'es-filter__chips' } );
		var buttons = [];

		CATS.forEach( function ( c ) {
			var used = c[ 0 ] === 'all' || tiles.some( function ( t ) {
				return t.getAttribute( 'data-cat' ) === c[ 0 ];
			} );
			if ( !used ) {
				return;
			}
			var btn = el( 'button', { type: 'button', 'class': 'es-chip', 'aria-pressed': c[ 0 ] === 'all' ? 'true' : 'false', 'data-cat': c[ 0 ] }, c[ 1 ] );
			var count = el( 'span', { 'class': 'es-chip__count' } );
			btn.appendChild( count );
			btn.addEventListener( 'click', function () {
				state.cat = c[ 0 ];
				apply();
			} );
			buttons.push( { btn: btn, count: count, cat: c[ 0 ] } );
			chips.appendChild( btn );
		} );
		bar.appendChild( chips );

		var search = el( 'input', {
			type: 'search',
			'class': 'es-filter__search',
			placeholder: TEXT.placeholder,
			'aria-label': TEXT.search
		} );
		search.addEventListener( 'input', function () {
			state.q = search.value.trim().toLowerCase();
			apply();
		} );
		bar.appendChild( search );

		/* Поиск идёт по модели, типу, тегам и названию категории («угол» → «Угол наклона») */
		var labels = {};
		CATS.forEach( function ( c ) {
			labels[ c[ 0 ] ] = c[ 1 ].toLowerCase();
		} );
		tiles.forEach( function ( t ) {
			t.esSearch = ( t.getAttribute( 'data-search' ) || '' ) + ' ' + ( labels[ t.getAttribute( 'data-cat' ) ] || '' );
		} );

		function matchesQuery( t ) {
			return !state.q || t.esSearch.indexOf( state.q ) !== -1;
		}

		function apply() {
			var shown = 0;
			tiles.forEach( function ( t ) {
				var ok = matchesQuery( t ) && ( state.cat === 'all' || t.getAttribute( 'data-cat' ) === state.cat );
				if ( ok ) {
					t.removeAttribute( 'hidden' );
					shown++;
				} else {
					t.setAttribute( 'hidden', 'hidden' );
				}
			} );
			buttons.forEach( function ( b ) {
				var n = tiles.filter( function ( t ) {
					return matchesQuery( t ) && ( b.cat === 'all' || t.getAttribute( 'data-cat' ) === b.cat );
				} ).length;
				b.count.textContent = String( n );
				b.btn.setAttribute( 'aria-pressed', b.cat === state.cat ? 'true' : 'false' );
			} );
			if ( shown ) {
				empty.setAttribute( 'hidden', 'hidden' );
			} else {
				empty.removeAttribute( 'hidden' );
			}
		}

		catalog.parentNode.insertBefore( bar, catalog );
		catalog.parentNode.insertBefore( empty, catalog.nextSibling );
		apply();
	}

	function padTocNumbers() {
		if ( !document.querySelector( '.mw-parser-output .es-card' ) ) {
			return;
		}
		var nums = document.querySelectorAll( '.vector-toc-level-1 > .vector-toc-link .vector-toc-numb' );
		Array.prototype.forEach.call( nums, function ( n ) {
			if ( /^\d$/.test( n.textContent ) ) {
				n.textContent = '0' + n.textContent;
			}
		} );
	}

	function liftNext( root ) {
		Array.prototype.forEach.call( root.querySelectorAll( '.es-next' ), function ( next ) {
			var section = next.parentNode;
			while ( section && !( section.tagName === 'SECTION' && /\bcollapsible-block\b/.test( section.className ) ) ) {
				section = section.parentNode;
			}
			if ( section && section.parentNode ) {
				section.parentNode.appendChild( next );
			}
		} );
	}

	mw.hook( 'wikipage.content' ).add( function ( $content ) {
		var root = $content && $content[ 0 ] ? $content[ 0 ] : document;
		Array.prototype.forEach.call( root.querySelectorAll( '.es-catalog' ), initCatalog );
		liftNext( root );
	} );

	$( padTocNumbers );
}() );