From WikiChip
Difference between revisions of "MediaWiki:Common.js"
(adding a floating scrollbar) |
|||
Line 37: | Line 37: | ||
// If shown now | // If shown now | ||
if ( navToggle.firstChild.data == navigationBarHide ) { | if ( navToggle.firstChild.data == navigationBarHide ) { | ||
− | for ( navChild = navFrame.firstChild; navChild != null; navChild = navChild.nextSibling ) { | + | for ( navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling ) { |
if ( hasClass( navChild, 'NavPic' ) ) { | if ( hasClass( navChild, 'NavPic' ) ) { | ||
navChild.style.display = 'none'; | navChild.style.display = 'none'; | ||
Line 49: | Line 49: | ||
// If hidden now | // If hidden now | ||
} else if ( navToggle.firstChild.data == navigationBarShow ) { | } else if ( navToggle.firstChild.data == navigationBarShow ) { | ||
− | for ( navChild = navFrame.firstChild; navChild != null; navChild = navChild.nextSibling ) { | + | for ( navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling ) { |
if ( $( navChild ).hasClass( 'NavPic' ) || $( navChild ).hasClass( 'NavContent' ) ) { | if ( $( navChild ).hasClass( 'NavPic' ) || $( navChild ).hasClass( 'NavContent' ) ) { | ||
navChild.style.display = 'block'; | navChild.style.display = 'block'; | ||
Line 80: | Line 80: | ||
navToggleText = document.createTextNode( navigationBarHide ); | navToggleText = document.createTextNode( navigationBarHide ); | ||
− | for ( navChild = navFrame.firstChild; navChild != null; navChild = navChild.nextSibling ) { | + | for ( navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling ) { |
if ( $( navChild ).hasClass( 'NavPic' ) || $( navChild ).hasClass( 'NavContent' ) ) { | if ( $( navChild ).hasClass( 'NavPic' ) || $( navChild ).hasClass( 'NavContent' ) ) { | ||
if ( navChild.style.display == 'none' ) { | if ( navChild.style.display == 'none' ) { | ||
Line 208: | Line 208: | ||
mw.hook( 'wikipage.content' ).add( createCollapseButtons ); | mw.hook( 'wikipage.content' ).add( createCollapseButtons ); | ||
+ | |||
+ | |||
+ | /*******************************************************************/ | ||
+ | /*******************************************************************/ | ||
+ | /*! | ||
+ | * jQuery floatingScroll Plugin v2.3.1 | ||
+ | * supported by jQuery v1.4.3+ | ||
+ | * | ||
+ | * https://github.com/Amphiluke/floating-scroll | ||
+ | * http://amphiluke.github.io/floating-scroll/ | ||
+ | * | ||
+ | * Copyright (c) 2011-2017 Amphiluke | ||
+ | */ | ||
+ | (function (global, factory) { | ||
+ | "use strict"; | ||
+ | if (typeof define === "function" && define.amd) { | ||
+ | define(["jquery"], factory); | ||
+ | } else if (typeof module === "object" && module.exports) { | ||
+ | factory(require("jquery")); | ||
+ | } else { | ||
+ | factory(global.jQuery); | ||
+ | } | ||
+ | }(this, function ($) { | ||
+ | "use strict"; | ||
+ | |||
+ | function FScroll(cont) { | ||
+ | var inst = this, | ||
+ | scrollBody = cont.closest(".fl-scrolls-body"); | ||
+ | inst.cont = cont[0]; | ||
+ | if (scrollBody.length) { | ||
+ | inst.scrollBody = scrollBody; | ||
+ | } | ||
+ | inst.sbar = inst.initScroll(); | ||
+ | inst.visible = true; | ||
+ | inst.updateAPI(); // recalculate floating scrolls and hide those of them whose containers are out of sight | ||
+ | inst.syncSbar(inst.cont); | ||
+ | inst.addEventHandlers(); | ||
+ | } | ||
+ | |||
+ | $.extend(FScroll.prototype, { | ||
+ | initScroll: function () { | ||
+ | var flscroll = $("<div class='fl-scrolls'></div>"); | ||
+ | $("<div></div>").appendTo(flscroll).css({width: this.cont.scrollWidth + "px"}); | ||
+ | return flscroll.appendTo(this.cont); | ||
+ | }, | ||
+ | |||
+ | addEventHandlers: function () { | ||
+ | var inst = this, | ||
+ | handlers, | ||
+ | i, len; | ||
+ | handlers = inst.eventHandlers = [ | ||
+ | { | ||
+ | $el: inst.scrollBody || $(window), | ||
+ | handlers: { | ||
+ | // Don't use `$.proxy()` since it makes impossible event unbinding individually per instance | ||
+ | // (see the warning at http://api.jquery.com/unbind/) | ||
+ | scroll: function () {inst.checkVisibility();}, | ||
+ | resize: function () {inst.updateAPI();} | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | $el: inst.sbar, | ||
+ | handlers: { | ||
+ | scroll: function () {inst.visible && inst.syncCont(this, true);} | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | $el: $(inst.cont), | ||
+ | handlers: { | ||
+ | scroll: function () {inst.syncSbar(this, true);}, | ||
+ | focusin: function () { | ||
+ | setTimeout(function () { | ||
+ | inst.syncSbar(inst.cont); | ||
+ | }, 0); | ||
+ | }, | ||
+ | // The `adjustScroll` event type is kept for backward compatibility only. | ||
+ | "update.fscroll adjustScroll": function (e) { | ||
+ | // Check event namespace to ensure that this is not an extraneous event in a bubbling phase | ||
+ | if (e.namespace === "fscroll" || e.type === "adjustScroll") { | ||
+ | inst.updateAPI(); | ||
+ | } | ||
+ | }, | ||
+ | "destroy.fscroll": function (e) { | ||
+ | if (e.namespace === "fscroll") { | ||
+ | inst.destroyAPI(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | ]; | ||
+ | for (i = 0, len = handlers.length; i < len; i++) { | ||
+ | handlers[i].$el.bind(handlers[i].handlers); | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | checkVisibility: function () { | ||
+ | var inst = this, | ||
+ | mustHide = (inst.sbar[0].scrollWidth <= inst.sbar[0].offsetWidth), | ||
+ | contRect, | ||
+ | maxVisibleY; | ||
+ | if (!mustHide) { | ||
+ | contRect = inst.cont.getBoundingClientRect(); | ||
+ | maxVisibleY = inst.scrollBody | ||
+ | ? inst.scrollBody[0].getBoundingClientRect().bottom | ||
+ | : window.innerHeight || document.documentElement.clientHeight; | ||
+ | mustHide = ((contRect.bottom <= maxVisibleY) || (contRect.top > maxVisibleY)); | ||
+ | } | ||
+ | if (inst.visible === mustHide) { | ||
+ | inst.visible = !mustHide; | ||
+ | // we cannot simply hide a floating scroll bar since its scrollLeft property will not update in that case | ||
+ | inst.sbar.toggleClass("fl-scrolls-hidden"); | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | syncCont: function (sender, preventSyncSbar) { | ||
+ | // Prevents next syncSbar function from changing scroll position | ||
+ | if (this.preventSyncCont === true) { | ||
+ | this.preventSyncCont = false; | ||
+ | return; | ||
+ | } | ||
+ | this.preventSyncSbar = !!preventSyncSbar; | ||
+ | this.cont.scrollLeft = sender.scrollLeft; | ||
+ | }, | ||
+ | |||
+ | syncSbar: function (sender, preventSyncCont) { | ||
+ | // Prevents next syncCont function from changing scroll position | ||
+ | if (this.preventSyncSbar === true) { | ||
+ | this.preventSyncSbar = false; | ||
+ | return; | ||
+ | } | ||
+ | this.preventSyncCont = !!preventSyncCont; | ||
+ | this.sbar[0].scrollLeft = sender.scrollLeft; | ||
+ | }, | ||
+ | |||
+ | // Recalculate scroll width and container boundaries | ||
+ | updateAPI: function () { | ||
+ | var inst = this, | ||
+ | cont = inst.cont, | ||
+ | pos = cont.getBoundingClientRect(); | ||
+ | inst.sbar.width($(cont).outerWidth()); | ||
+ | if (!inst.scrollBody) { | ||
+ | inst.sbar.css("left", pos.left + "px"); | ||
+ | } | ||
+ | $("div", inst.sbar).width(cont.scrollWidth); | ||
+ | inst.checkVisibility(); // fixes issue #2 | ||
+ | }, | ||
+ | |||
+ | // Remove a scrollbar and all related event handlers | ||
+ | destroyAPI: function () { | ||
+ | var handlers = this.eventHandlers, | ||
+ | i, len; | ||
+ | for (i = 0, len = handlers.length; i < len; i++) { | ||
+ | handlers[i].$el.unbind(handlers[i].handlers); | ||
+ | } | ||
+ | this.sbar.remove(); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | // `attachScroll` is the old alias used in v1.X. Temporally kept for backward compatibility. | ||
+ | $.fn.attachScroll = $.fn.floatingScroll = function (method) { | ||
+ | if (!arguments.length || method === "init") { | ||
+ | this.each(function () { | ||
+ | new FScroll($(this)); | ||
+ | }); | ||
+ | } else if (FScroll.prototype.hasOwnProperty(method + "API")) { | ||
+ | this.trigger(method + ".fscroll"); | ||
+ | } | ||
+ | return this; | ||
+ | }; | ||
+ | })); | ||
+ | /*******************************************************************/ | ||
+ | /*******************************************************************/ | ||
+ | |||
Line 218: | Line 391: | ||
}); | }); | ||
}()); | }()); | ||
+ | |||
+ | $(function() { | ||
+ | $('.comptable').floatingScrollbar(); | ||
+ | }); |
Revision as of 18:23, 18 May 2017
/**
* Dynamic Navigation Bars. See [[Wikipedia:NavFrame]]
*
* Based on script from en.wikipedia.org, 2008-09-15.
*
* @source www.mediawiki.org/wiki/MediaWiki:Gadget-NavFrame.js
* @maintainer Helder.wiki, 2012–2013
* @maintainer Krinkle, 2013
*/
( function () {
// Set up the words in your language
var collapseCaption = 'hide';
var expandCaption = 'show';
var navigationBarHide = '[' + collapseCaption + ']';
var navigationBarShow = '[' + expandCaption + ']';
/**
* Shows and hides content and picture (if available) of navigation bars.
*
* @param {number} indexNavigationBar The index of navigation bar to be toggled
* @param {jQuery.Event} e Event object
*/
function toggleNavigationBar( indexNavigationBar, e ) {
var navChild,
navToggle = document.getElementById( 'NavToggle' + indexNavigationBar ),
navFrame = document.getElementById( 'NavFrame' + indexNavigationBar );
// Prevent browser from jumping to href "#"
e.preventDefault();
if ( !navFrame || !navToggle ) {
return false;
}
// If shown now
if ( navToggle.firstChild.data == navigationBarHide ) {
for ( navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling ) {
if ( hasClass( navChild, 'NavPic' ) ) {
navChild.style.display = 'none';
}
if ( hasClass( navChild, 'NavContent' ) ) {
navChild.style.display = 'none';
}
}
navToggle.firstChild.data = navigationBarShow;
// If hidden now
} else if ( navToggle.firstChild.data == navigationBarShow ) {
for ( navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling ) {
if ( $( navChild ).hasClass( 'NavPic' ) || $( navChild ).hasClass( 'NavContent' ) ) {
navChild.style.display = 'block';
}
}
navToggle.firstChild.data = navigationBarHide;
}
}
/**
* Adds show/hide-button to navigation bars.
*
* @param {jQuery} $content
*/
function createNavigationBarToggleButton( $content ) {
var i, j, navFrame, navToggle, navToggleText, navChild,
indexNavigationBar = 0,
navFrames = $content.find( 'div.NavFrame' ).toArray();
// Iterate over all (new) nav frames
for ( i = 0; i < navFrames.length; i++ ) {
navFrame = navFrames[i];
// If found a navigation bar
indexNavigationBar++;
navToggle = document.createElement( 'a' );
navToggle.className = 'NavToggle';
navToggle.setAttribute( 'id', 'NavToggle' + indexNavigationBar );
navToggle.setAttribute( 'href', '#' );
$( navToggle ).on( 'click', $.proxy( toggleNavigationBar, null, indexNavigationBar ) );
navToggleText = document.createTextNode( navigationBarHide );
for ( navChild = navFrame.firstChild; navChild !== null; navChild = navChild.nextSibling ) {
if ( $( navChild ).hasClass( 'NavPic' ) || $( navChild ).hasClass( 'NavContent' ) ) {
if ( navChild.style.display == 'none' ) {
navToggleText = document.createTextNode( navigationBarShow );
break;
}
}
}
navToggle.appendChild( navToggleText );
// Find the NavHead and attach the toggle link (Must be this complicated because Moz's firstChild handling is borked)
for ( j = 0; j < navFrame.childNodes.length; j++ ) {
if ( $( navFrame.childNodes[j] ).hasClass( 'NavHead' ) ) {
navFrame.childNodes[j].appendChild( navToggle );
}
}
navFrame.setAttribute( 'id', 'NavFrame' + indexNavigationBar );
}
}
mw.hook( 'wikipage.content' ).add( createNavigationBarToggleButton );
}());
/**
* Collapsible tables
*
* @version 2.0.2 (2014-03-14)
* @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
* @author [[User:R. Koot]]
* @author [[User:Krinkle]]
* @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which
* is supported in MediaWiki core.
*/
/*global $, mw */
var autoCollapse = 2;
var collapseCaption = 'hide';
var expandCaption = 'show';
function collapseTable( tableIndex ) {
var Button = document.getElementById( 'collapseButton' + tableIndex );
var Table = document.getElementById( 'collapsibleTable' + tableIndex );
if ( !Table || !Button ) {
return false;
}
var Rows = Table.rows;
var i;
if ( Button.firstChild.data === collapseCaption ) {
for ( i = 1; i < Rows.length; i++ ) {
Rows[i].style.display = 'none';
}
Button.firstChild.data = expandCaption;
} else {
for ( i = 1; i < Rows.length; i++ ) {
Rows[i].style.display = Rows[0].style.display;
}
Button.firstChild.data = collapseCaption;
}
}
function createClickHandler( tableIndex ) {
return function ( e ) {
e.preventDefault();
collapseTable( tableIndex );
};
}
function createCollapseButtons() {
var tableIndex = 0;
var NavigationBoxes = {};
var Tables = document.getElementsByTagName( 'table' );
var i;
for ( i = 0; i < Tables.length; i++ ) {
if ( $( Tables[i] ).hasClass( 'collapsible' ) ) {
/* only add button and increment count if there is a header row to work with */
var HeaderRow = Tables[i].getElementsByTagName( 'tr' )[0];
if ( !HeaderRow ) {
continue;
}
var Header = HeaderRow.getElementsByTagName( 'th' )[0];
if ( !Header ) {
continue;
}
NavigationBoxes[tableIndex] = Tables[i];
Tables[i].setAttribute( 'id', 'collapsibleTable' + tableIndex );
var Button = document.createElement( 'span' );
var ButtonLink = document.createElement( 'a' );
var ButtonText = document.createTextNode( collapseCaption );
// TODO: Declare styles in [[MediaWiki:Gadget-collapsibleTables.css]]
// Button.className = 'collapseButton';
Button.style.styleFloat = 'right';
Button.style.cssFloat = 'right';
Button.style.fontWeight = 'normal';
Button.style.textAlign = 'right';
Button.style.width = '6em';
ButtonLink.style.color = Header.style.color;
ButtonLink.setAttribute( 'id', 'collapseButton' + tableIndex );
ButtonLink.setAttribute( 'href', '#' );
$( ButtonLink ).on( 'click', createClickHandler( tableIndex ) );
ButtonLink.appendChild( ButtonText );
Button.appendChild( document.createTextNode( '[' ) );
Button.appendChild( ButtonLink );
Button.appendChild( document.createTextNode( ']' ) );
Header.insertBefore( Button, Header.firstChild );
tableIndex++;
}
}
for ( i = 0; i < tableIndex; i++ ) {
if ( $( NavigationBoxes[i] ).hasClass( 'collapsed' ) ||
( tableIndex >= autoCollapse && $( NavigationBoxes[i] ).hasClass( 'autocollapse' ) )
) {
collapseTable( i );
}
}
}
mw.hook( 'wikipage.content' ).add( createCollapseButtons );
/*******************************************************************/
/*******************************************************************/
/*!
* jQuery floatingScroll Plugin v2.3.1
* supported by jQuery v1.4.3+
*
* https://github.com/Amphiluke/floating-scroll
* http://amphiluke.github.io/floating-scroll/
*
* Copyright (c) 2011-2017 Amphiluke
*/
(function (global, factory) {
"use strict";
if (typeof define === "function" && define.amd) {
define(["jquery"], factory);
} else if (typeof module === "object" && module.exports) {
factory(require("jquery"));
} else {
factory(global.jQuery);
}
}(this, function ($) {
"use strict";
function FScroll(cont) {
var inst = this,
scrollBody = cont.closest(".fl-scrolls-body");
inst.cont = cont[0];
if (scrollBody.length) {
inst.scrollBody = scrollBody;
}
inst.sbar = inst.initScroll();
inst.visible = true;
inst.updateAPI(); // recalculate floating scrolls and hide those of them whose containers are out of sight
inst.syncSbar(inst.cont);
inst.addEventHandlers();
}
$.extend(FScroll.prototype, {
initScroll: function () {
var flscroll = $("<div class='fl-scrolls'></div>");
$("<div></div>").appendTo(flscroll).css({width: this.cont.scrollWidth + "px"});
return flscroll.appendTo(this.cont);
},
addEventHandlers: function () {
var inst = this,
handlers,
i, len;
handlers = inst.eventHandlers = [
{
$el: inst.scrollBody || $(window),
handlers: {
// Don't use `$.proxy()` since it makes impossible event unbinding individually per instance
// (see the warning at http://api.jquery.com/unbind/)
scroll: function () {inst.checkVisibility();},
resize: function () {inst.updateAPI();}
}
},
{
$el: inst.sbar,
handlers: {
scroll: function () {inst.visible && inst.syncCont(this, true);}
}
},
{
$el: $(inst.cont),
handlers: {
scroll: function () {inst.syncSbar(this, true);},
focusin: function () {
setTimeout(function () {
inst.syncSbar(inst.cont);
}, 0);
},
// The `adjustScroll` event type is kept for backward compatibility only.
"update.fscroll adjustScroll": function (e) {
// Check event namespace to ensure that this is not an extraneous event in a bubbling phase
if (e.namespace === "fscroll" || e.type === "adjustScroll") {
inst.updateAPI();
}
},
"destroy.fscroll": function (e) {
if (e.namespace === "fscroll") {
inst.destroyAPI();
}
}
}
}
];
for (i = 0, len = handlers.length; i < len; i++) {
handlers[i].$el.bind(handlers[i].handlers);
}
},
checkVisibility: function () {
var inst = this,
mustHide = (inst.sbar[0].scrollWidth <= inst.sbar[0].offsetWidth),
contRect,
maxVisibleY;
if (!mustHide) {
contRect = inst.cont.getBoundingClientRect();
maxVisibleY = inst.scrollBody
? inst.scrollBody[0].getBoundingClientRect().bottom
: window.innerHeight || document.documentElement.clientHeight;
mustHide = ((contRect.bottom <= maxVisibleY) || (contRect.top > maxVisibleY));
}
if (inst.visible === mustHide) {
inst.visible = !mustHide;
// we cannot simply hide a floating scroll bar since its scrollLeft property will not update in that case
inst.sbar.toggleClass("fl-scrolls-hidden");
}
},
syncCont: function (sender, preventSyncSbar) {
// Prevents next syncSbar function from changing scroll position
if (this.preventSyncCont === true) {
this.preventSyncCont = false;
return;
}
this.preventSyncSbar = !!preventSyncSbar;
this.cont.scrollLeft = sender.scrollLeft;
},
syncSbar: function (sender, preventSyncCont) {
// Prevents next syncCont function from changing scroll position
if (this.preventSyncSbar === true) {
this.preventSyncSbar = false;
return;
}
this.preventSyncCont = !!preventSyncCont;
this.sbar[0].scrollLeft = sender.scrollLeft;
},
// Recalculate scroll width and container boundaries
updateAPI: function () {
var inst = this,
cont = inst.cont,
pos = cont.getBoundingClientRect();
inst.sbar.width($(cont).outerWidth());
if (!inst.scrollBody) {
inst.sbar.css("left", pos.left + "px");
}
$("div", inst.sbar).width(cont.scrollWidth);
inst.checkVisibility(); // fixes issue #2
},
// Remove a scrollbar and all related event handlers
destroyAPI: function () {
var handlers = this.eventHandlers,
i, len;
for (i = 0, len = handlers.length; i < len; i++) {
handlers[i].$el.unbind(handlers[i].handlers);
}
this.sbar.remove();
}
});
// `attachScroll` is the old alias used in v1.X. Temporally kept for backward compatibility.
$.fn.attachScroll = $.fn.floatingScroll = function (method) {
if (!arguments.length || method === "init") {
this.each(function () {
new FScroll($(this));
});
} else if (FScroll.prototype.hasOwnProperty(method + "API")) {
this.trigger(method + ".fscroll");
}
return this;
};
}));
/*******************************************************************/
/*******************************************************************/
/* highlight/un-highlight comptable rows */
(function () {
$(".comptable tr").click(function() {
$(this).toggleClass("comptable-highlight", this.clicked);
});
}());
$(function() {
$('.comptable').floatingScrollbar();
});