Fandom Developers Wiki

This page, or parts of it, are still untranslated. Please translate it to the appropriate language (русский).

Для разработчиков[]

Если вы в рамках Фэндома много пользуетесь JavaScript, вы заметите, что используете одни и те же функции снова и снова. Мы собрали коллекцию этих функций, которые можно скопировать отсюда и вставить в свой проект.

Переменные[]

Кеширование API[]

Кеширует ссылку на экземпляр объекта mw.Api. Для более подробной информации посетите документацию MediaWiki.

var api = new mw.Api();

Кеширование настроек[]

Кеширует переменные параметров конфигурации.

var config = mw.config.get([
    'wgAction',
    'wgArticlePath',
    'wgCanonicalSpecialPageName',
    'wgPagename',
    'wgTitle',
    'wgSiteName'
]);

Цвета[]

Определение яркости[]

Определяет, светлый ли цвет. Может быть использован для того, чтобы понять, светлый ли передний план и фон статьи или темный. Это позволяет вам выбирать высококонтрастный цвет для этих элементов.

Параметр color принимает значение цвета в формате RGB или HEX. Функция возвращает логическое значение, равное true, если заданный цвет светлый.

function isBright(color) {
    var m = color.match(/(?:([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2}))|(?:(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3}))/);
    if (!m) return false;
    var rgb = m[1] ? { r: parseInt(m[1], 16), g: parseInt(m[2], 16), b: parseInt(m[3], 16) }
                   : { r: parseInt(m[4], 10), g: parseInt(m[5], 10), b: parseInt(m[6], 10) };
    return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000 >= 128;
}

Получение цвета фона[]

Получает цвет фона статьи и возвращает строку, представляющую этот цвет в качестве значения в CSS.

function getBackgroundColor() {
    return getComputedStyle(document.body).getPropertyValue('--theme-page-background-color');
}

Элементы[]

Добавление HTML-элемента в содержимое страницы[]

Добавляет элемент HTML в конец содержимого страницы:

var element = document.createElement("p"); // "p" — тип создаваемого элемента
element.style = "color:blue"; // для изменения атрибутов элемента используйте element.(атрибут) = "значение"
element.contentText = "Текст параграфа"; // это устанавливает innerHTML элемента на "Текст параграфа"
document.getElementById('mw-content-text').appendChild(element); // а это добавляет готовый элемент на страницу

Tip: You can replace 'mw-content-text' with the ID of the desired element on the page.

Modals[]

Open image lightbox[]

Function to open the image lightbox for an arbitrary image programmatically, without modifying url query or reloading the page.

function openLightbox(fileName) {
	const page = document.querySelector('.page');
	if (!page) return;

	// create a minimal lightbox trigger element
	// <a class="image">
	//   <img data-image-key="${fileName}.png">
	// </a>
	const link = document.createElement('a');
	link.className = 'image';
	const img = document.createElement('img');
	img.dataset.imageKey = fileName;
	link.appendChild(img);

	// note: lightbox is shown only for images inside
	// the <div class="page"> element
	page.appendChild(link);

	// open lightbox
	link.click();

	// delete the trigger
	page.removeChild(link);
}

The function can then be called using an image name, for example:

openLightbox('Site-logo.png');
openLightbox('Site-background-dark');
openLightbox('nonexistent.png');

Ввод[]

Текстовое поле[]

Следующий код добавит текстовое поле в конец страницы "Example Page":

if (mw.config.get("wgPageName") === "Example_Page") {
  // если загруженная страница называется "Example Page", код начнет работу
  var inputBox = document.createElement("div"); // создает элемент div, который будет содержать в себе поле ввода
  var input = document.createElement("input"); // создает элемент input, который и будет принимать ввод
  input.id = "input"; // устанавливает ID элемента input на "input"
  input.style.display = "inline-block"; // устанавливает style.display на "inline-block", и он будет в одну строку
  var textParagraph = document.createElement("p"); // создает абзац текста
  textParagraph.innerHTML = "дважды два: "; // устанавливает стандартный текст абзаца
  textParagraph.style.display = "inline-block"; // устанавливает style.display на "inline-block", и он будет в одну строку
  textParagraph.id = "textParagraph"; // меняет id абзаца на "textParagraph"
  var newLine = document.createElement("br"); // создает элемент br для начала новой строки
  var getAnswer = document.createElement("button"); // создает кнопку проверки
  getAnswer.innerHTML = "Проверить"; // меняет текст кнопки на "Проверить"
  getAnswer.addEventListener("click", function() {
    document.getElementById("textParagraph").innerHTML= "дважды два: " + document.getElementById("input").value * 2;
  }); // добавляет кнопке обработчик клика по ней, и теперь она будет выставлять элементу textParagraph следующий текст: "дважды два: (значение)"
  inputBox.appendChild(textParagraph.appendChild(input)); // добавляет элемент input в блок с полем ввода
  inputBox.appendChild(textParagraph); // добавляет элемент textParagraph в блок с полем ввода
  inputBox.appendChild(newLine); // добавляет новую строку в блок с полем ввода
  inputBox.appendChild(getAnswer); // добавляет кнопку getAnswer в блок с полем ввода
  document.getElementById("mw-content-text").appendChild(inputBox); // вставляет блок с полем ввода на страницу
}

Tip: You can replace 'mw-content-text' with the ID of the desired element on the page.

Запуск[]

После DOM[]

Запускает код после окончания загрузки DOM. Использует соответствующую функцию обратного вызова jQuery.

$(function() {
    // ваш код
});

После MW API[]

Запускает код только после окончания загрузки API MediaWiki.

mw.loader.using('mediawiki.api', function() {
    // ваш код
});

После MW Utilities[]

Запускает код только после окончания загрузки библиотеки утилит MediaWiki.

mw.loader.using('mediawiki.util', function() {
    // ваш код
});

После MW API и Utilities[]

Запускает код только после загрузки API MediaWiki и библиотеки утилит.

mw.loader.using(['mediawiki.util', 'mediawiki.api'], function() {
    // ваш код
});

После содержимого[]

Запускает код, когда содержимое страницы вики добавляется в DOM. Эта функция включает в себя событие готовности страницы при загрузке (в том числе и после правок), а также запуск кода при предпросмотре содержимого этой страницы.

mw.hook("wikipage.content").add(function($content) {
    // ваш код
});

For users[]

Adding target titles to redlinks[]

Wiki links have a their target page stored in the title attribute, which on many browsers is displayed as a tooltip when hovering over the link. The following snippet (by HumansCanWinElves) adds such titles to redlinks too.

$('.main-container').on('mouseover', 'a.new:not([title])[href]', function() {
      var regExp = /(?<=\/wiki\/)([^?]+)(?=(\?.+)?)/,
          match = regExp.exec($(this).attr('href')),
          title;

      if (match) {
          title = decodeURIComponent(match[0]).replace(/_/g, ' ');
          $(this).attr('title', title);
      }
});

Using a different theme for a certain wiki[]

Special:Preferences allows choosing between light or dark theme, but the selection is network-wide, with the only dynamic option to defer to the theme defined as the default one by the admins of each wiki. Sometimes you want to use different themes for different wikis based on your own choosing.

Some notes:

  • This should have been mostly possible by just CSS, if the built-in theme stylesheets weren't being weirdly added below the user stylesheets. As it is now, JavaScript is required, with the cost of a little delay on each page load when the default theme is displayed until the new theme takes over.
  • The script ThemeSelector already allows presetting a theme for a certain wiki, but the need to import the script makes the delay longer and therefore more annoying, so putting some code directly on your JS page may be preferrable.
  • As other customizations, it wouldn't work on the Discussions area.

To switch to dark theme on a certain wiki, add the following code to your local personal Special:Mypage/common.js page on that wiki (expand to see the code):

(function setDarkTheme() {
	var themeSheet1 = document.createElement('link'),
	    themeSheet2 = document.createElement('link');

    themeSheet1.rel = 'stylesheet';
    themeSheet1.href = '/wikia.php?controller=ThemeApi&method=themeVariables&variant=dark';

    themeSheet2.rel = 'stylesheet';
    themeSheet2.href = '/load.php?fandomdesktop=1&lang=en&modules=' +
	    	'ext.fandom.GlobalComponents.GlobalComponentsTheme.dark.css%7C' +
	    	'ext.fandom.GlobalComponents.GlobalNavigationTheme.dark.css' +
	    	'&only=styles&skin=fandomdesktop';

	document.head.appendChild(themeSheet1);
	document.head.appendChild(themeSheet2);

	document.body.classList.remove('theme-fandomdesktop-light');
	document.body.classList.add('theme-fandomdesktop-dark');
	mw.config.set('isDarkTheme', true);
})();

To switch to light theme on a certain wiki, add the following code to your local personal Special:Mypage/common.js page on that wiki (expand to see the code):

(function setLightTheme() {
	var themeSheet1 = document.createElement('link'),
	    themeSheet2 = document.createElement('link');

    themeSheet1.rel = 'stylesheet';
    themeSheet1.href = '/wikia.php?controller=ThemeApi&method=themeVariables&variant=light';

    themeSheet2.rel = 'stylesheet';
    themeSheet2.href = '/load.php?fandomdesktop=1&lang=en&modules=' +
	    	'ext.fandom.GlobalComponents.GlobalComponentsTheme.light.css%7C' +
	    	'ext.fandom.GlobalComponents.GlobalNavigationTheme.light.css' +
	    	'&only=styles&skin=fandomdesktop';

	document.head.appendChild(themeSheet1);
	document.head.appendChild(themeSheet2);

	document.body.classList.remove('theme-fandomdesktop-dark');
	document.body.classList.add('theme-fandomdesktop-light');
	mw.config.set('isDarkTheme', false);
})();

Alternatively, add the following code to your global JS page and put the wikis you want to change the theme for in the lines that begin with case:, replacing the example wikis (expand to see the code):

(function setTheme() {
	var themeSheet1 = document.createElement('link'),
	    themeURL1 = '/wikia.php?controller=ThemeApi&method=themeVariables&variant=',
	    themeSheet2 = document.createElement('link'),
	    themeURL2 = '/load.php?fandomdesktop=1&lang=en&modules=' +
	    	'ext.fandom.GlobalComponents.GlobalComponentsTheme.$1.css%7C' +
	    	'ext.fandom.GlobalComponents.GlobalNavigationTheme.$1.css' +
	    	'&only=styles&skin=fandomdesktop';
	
	switch (mw.config.get('wgServerName')) {
		// Wikis to switch to dark mode
		case 'community.fandom.com':
		case 'dev.fandom.com':
		case 'math.wikia.org':
			themeSheet1.rel = "stylesheet";
			themeSheet1.href = themeURL1 + 'dark';
			document.head.appendChild(themeSheet1);

			themeSheet2.rel = "stylesheet";
			themeSheet2.href = themeURL2.replace(/\$1/g, 'dark');
			document.head.appendChild(themeSheet2);

			document.body.classList.remove('theme-fandomdesktop-light');
			document.body.classList.add('theme-fandomdesktop-dark');
			mw.config.set('isDarkTheme', true);
			break;

		// Wikis to switch to light mode
		case 'wreckit-woodhouse.fandom.com':
		case 'harrypotter.fandom.com':
			themeSheet1.rel = "stylesheet";
			themeSheet1.href = themeURL1 + 'light';
			document.head.appendChild(themeSheet1);

			themeSheet2.rel = "stylesheet";
			themeSheet2.href = themeURL2.replace(/\$1/g, 'light');
			document.head.appendChild(themeSheet2);

			document.body.classList.remove('theme-fandomdesktop-dark');
			document.body.classList.add('theme-fandomdesktop-light');
			mw.config.set('isDarkTheme', false);
			break;
	}
})();

Tables[]

Table progress tracking[]

This code adds a percent of checked boxes (completion percent) on every table that has progress tracking. The percent is added in the top left cell.

function percent_completed() {
    // Selects all tables that have progress tracking.
    const tables = document.querySelectorAll('.table-progress-tracking');
    
    for (let i = 0; i < tables.length; i++) {
    	
    	// Important for updating percentages when page loads.
        observer.observe(tables[i], {
            subtree: true,
            childNodes: true,
            attributes: true
        });
        
        var selected_boxes = 0;
    	var total_boxes = -1; // Omits the table header row.
        for (let row of tables[i].rows) {
            total_boxes += 1;
            for (let cell of row.cells) {
                cell.addEventListener("change", percent_completed); // On cell change, update percent.
                if (cell.getAttribute('data-sort-value') == "1") {
                    selected_boxes += 1;
                }
            }
        }
        
        const th = tables[i].querySelector('th'); // Selects the first table header cell (top left).
        const text = Math.round(selected_boxes / total_boxes * 100) + '%';
        if (th.textContent !== text) {
            th.textContent = text;
        }
    }
}

const observer = new MutationObserver(percent_completed);
percent_completed(); // Execute function on page load.