MediaWiki:Mobile.js
Chú ý: Sau khi lưu trang, có thể bạn sẽ phải xóa bộ nhớ đệm của trình duyệt để xem các thay đổi.
- Firefox / Safari: Nhấn giữ phím Shift trong khi nhấn Tải lại (Reload), hoặc nhấn tổ hợp Ctrl-F5 hay Ctrl-R (⌘R trên Mac)
- Google Chrome: Nhấn tổ hợp Ctrl-Shift-R (⇧⌘R trên Mac)
- Internet Explorer / Edge: Nhấn giữ phím Ctrl trong khi nhấn Làm tươi (Refresh), hoặc nhấn tổ hợp Ctrl-F5
- Opera: Nhấn tổ hợp Ctrl-F5.
'use strict';
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
/**
* Initialize Tabber
*
* @param {HTMLElement} tabber
*/
function initTabber(tabber) {
var key = tabber.getAttribute('id').substring(7),
tabPanels = tabber.querySelectorAll(':scope > .tabber__section > .tabber__panel');
var container = document.createElement('header'),
tabList = document.createElement('nav'),
prevButton = document.createElement('div'),
nextButton = document.createElement('div');
var buildTabs = function buildTabs() {
var fragment = new DocumentFragment();
[].concat(_toConsumableArray(tabPanels)).forEach(function (tabPanel) {
var hash = mw.util.escapeIdForAttribute(tabPanel.title) + '-' + key,
tab = document.createElement('a');
tabPanel.setAttribute('id', hash);
tabPanel.setAttribute('role', 'tabpanel');
tabPanel.setAttribute('aria-labelledby', 'tab-' + hash);
tabPanel.setAttribute('aria-hidden', true);
tab.innerText = tabPanel.title;
tab.classList.add('tabber__tab');
tab.setAttribute('title', tabPanel.title);
tab.setAttribute('role', 'tab');
tab.setAttribute('href', '#' + hash);
tab.setAttribute('id', 'tab-' + hash);
tab.setAttribute('aria-select', false);
tab.setAttribute('aria-controls', hash);
fragment.append(tab);
});
tabList.append(fragment);
container.classList.add('tabber__header');
tabList.classList.add('tabber__tabs');
tabList.setAttribute('role', 'tablist');
prevButton.classList.add('tabber__header__prev');
nextButton.classList.add('tabber__header__next');
container.append(prevButton, tabList, nextButton);
};
buildTabs();
tabber.prepend(container);
// Initalize previous and next buttons
var initButtons = function initButtons() {
var PREVCLASS = 'tabber__header--prev-visible',
NEXTCLASS = 'tabber__header--next-visible';
/* eslint-disable mediawiki/class-doc */
var scrollTabs = function scrollTabs(offset) {
var scrollLeft = tabList.scrollLeft + offset;
// Scroll to the start
if (scrollLeft <= 0) {
tabList.scrollLeft = 0;
container.classList.remove(PREVCLASS);
container.classList.add(NEXTCLASS);
} else {
tabList.scrollLeft = scrollLeft;
// Scroll to the end
if (scrollLeft + tabList.offsetWidth >= tabList.scrollWidth) {
container.classList.remove(NEXTCLASS);
container.classList.add(PREVCLASS);
} else {
container.classList.add(NEXTCLASS);
container.classList.add(PREVCLASS);
}
}
};
var setupButtons = function setupButtons() {
var isScrollable = tabList.scrollWidth > container.offsetWidth;
if (isScrollable) {
(function () {
var scrollOffset = container.offsetWidth / 2;
// Just to add the right classes
scrollTabs(0);
prevButton.addEventListener('click', function () {
scrollTabs(-scrollOffset);
}, false);
nextButton.addEventListener('click', function () {
scrollTabs(scrollOffset);
}, false);
})();
} else {
container.classList.remove(NEXTCLASS);
container.classList.remove(PREVCLASS);
}
};
/* eslint-enable mediawiki/class-doc */
setupButtons();
// Listen for window resize
window.addEventListener('resize', function () {
mw.util.debounce(250, setupButtons());
});
};
/**
* Show panel based on target hash
*
* @param {string} targetHash
*/
function showPanel(targetHash) {
var ACTIVETABCLASS = 'tabber__tab--active',
ACTIVEPANELCLASS = 'tabber__panel--active',
targetPanel = document.getElementById(targetHash),
targetTab = document.getElementById('tab-' + targetHash),
section = targetPanel.parentElement,
activePanel = section.querySelector(':scope > .' + ACTIVEPANELCLASS);
/* eslint-disable mediawiki/class-doc */
if (activePanel) {
// Just to be safe since there can be multiple active classes
// even if there shouldn't be
var activeTabs = tabList.querySelectorAll('.' + ACTIVETABCLASS);
if (activeTabs.length > 0) {
activeTabs.forEach(function (activeTab) {
activeTab.classList.remove(ACTIVETABCLASS);
activeTab.setAttribute('aria-selected', false);
});
}
activePanel.classList.remove(ACTIVEPANELCLASS);
activePanel.setAttribute('aria-hidden', true);
section.style.height = activePanel.offsetHeight + 'px';
section.style.height = targetPanel.offsetHeight + 'px';
} else {
section.style.height = targetPanel.offsetHeight + 'px';
}
// Add active class to the tab
targetTab.classList.add(ACTIVETABCLASS);
targetTab.setAttribute('aria-selected', true);
targetPanel.classList.add(ACTIVEPANELCLASS);
targetPanel.setAttribute('aria-hidden', false);
// Scroll to tab
section.scrollLeft = targetPanel.offsetLeft;
/* eslint-enable mediawiki/class-doc */
}
/**
* Retrieve target hash and trigger show panel
* If no targetHash is invalid, use the first panel
*
* @param {HTMLElement} tabber
*/
function switchTab() {
var targetHash = window.location.hash.substr(1);
// Switch to the first tab if no targetHash or no tab is detected
if (!targetHash || !tabList.querySelector('#tab-' + targetHash)) {
targetHash = tabList.firstElementChild.getAttribute('id').substring(4);
}
showPanel(targetHash);
}
switchTab();
// Only run if client is not a touch device
if (matchMedia('(hover: hover)').matches) {
initButtons();
}
// window.addEventListener( 'hashchange', switchTab, false );
// Respond to clicks on the nav tabs
[].concat(_toConsumableArray(tabList.children)).forEach(function (tab) {
tab.addEventListener('click', function (event) {
var targetHash = tab.getAttribute('href').substring(1);
event.preventDefault();
// Add hash to the end of the URL
history.pushState(null, null, '#' + targetHash);
showPanel(targetHash);
});
});
tabber.classList.add('tabber--live');
}
function main() {
var tabbers = document.querySelectorAll('.tabber');
if (tabbers) {
mw.loader.load('ext.tabberNeue.icons');
tabbers.forEach(function (tabber) {
initTabber(tabber);
});
}
}
main();
( function () {
'use strict';
function trySettingTab( indexLayout, hash ) {
var possiblePanelName = hash.slice( 1 );
var possiblePanel = possiblePanelName && indexLayout.getTabPanel( possiblePanelName );
if ( possiblePanel ) {
indexLayout.setTabPanel( possiblePanelName );
indexLayout.scrollElementIntoView();
}
}
/**
* This function fetches sample code in different programming languages
* from the sub-sections of the section "Sample Code" and places
* them into an OOUI tabbed window.
*
* @param {jQuery} $tabbedWindows
*/
function makeTabWindow( $tabbedWindows ) {
var tabs = [];
$tabbedWindows.each( function () {
var panelLayout,
indexLayout = new OO.ui.IndexLayout( {
expanded: false
} );
$( this ).find( 'h3 > .mw-editsection' ).remove();
$( this ).find( 'h3' ).each( function () {
var id = $( this ).find( 'span[class=mw-headline]' ).attr( 'id' );
var $content = $( this ).nextUntil( 'h3' );
var tabPanel = new OO.ui.TabPanelLayout( id, {
expanded: false,
label: $( this ).text(),
// Attach the original DOM elements directly by reference.
// This means they move directly in memory instead of getting copied/serialized/parsed as HTML.
// If we didn't move them, but instead copied and re-parsed HTML, then it would disconnect events
// and other live references from gadgets and extensions, which breaks sorting features, responsive gallery, etc.
$content: $content
} );
tabPanel.$element.css( 'padding', '0.5em' );
tabs.push( tabPanel );
} );
indexLayout.addTabPanels( tabs );
tabs = [];
panelLayout = new OO.ui.PanelLayout( {
expanded: false,
framed: true,
content: [ indexLayout ]
} );
$( this ).empty().append( panelLayout.$element );
// Select and scroll to any initially linked item in the address
trySettingTab( indexLayout, location.hash );
// Keep address bar updated with sharable link (also makes forward/backward browser navigation work)
if ( history.replaceState ) {
indexLayout.on( 'set', function ( tabPanel ) {
history.replaceState( null, document.title, '#' + tabPanel.getName() );
} );
}
// Support anchor links on the same page (from table of Contents, or [[#Section]] links)
window.addEventListener( 'hashchange', function () {
trySettingTab( indexLayout, location.hash );
} );
} );
}
$( function () {
// Quick check (dependency-free, this is executed for all pages/actions/namespaces)
var $tabbedWindows,
supportedNamespaces = [ 'API', 'Help', 'Manual', '' ],
action = mw.config.get( 'wgAction' ),
namespace = mw.config.get( 'wgCanonicalNamespace' );
if (
action === 'view' &&
supportedNamespaces.indexOf( namespace ) !== -1
) {
// Expensive checks (only on the subset of supported pages)
// eslint-disable-next-line no-jquery/no-global-selector
$tabbedWindows = $( '.mw-gadget-tabbedwindow' );
if ( $tabbedWindows.length > 0 ) {
// Viewing an API subject page with tabs on it, let's make them nice!
mw.loader.using( [ 'oojs-ui-widgets' ] ).then( function () {
makeTabWindow( $tabbedWindows );
} );
}
}
} );
}() );
mw.loader.load('https://vi.wikibooks.org/w/index.php?title=MediaWiki:Mobile.js/OOUI-ProcessDialog.js&action=raw&ctype=text/javascript');