MediaWiki:Common.js: Difference between revisions
(Forgot Collapsible tables code...) |
(Add some notes on the intentions of the videogallery() code, I won't get around to progressing on it tonight.) |
||
(31 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
/* Any JavaScript here will be loaded for all users on every page load. */ | /* Any JavaScript here will be loaded for all users on every page load. */ | ||
/* Test if an element has a certain class | |||
* | |||
* @deprecated: Use $(element).hasClass() instead. | |||
*/ | |||
window.hasClass = ( function() { | |||
var reCache = {}; | |||
return function (element, className) { | |||
return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className); | |||
}; | |||
})(); | |||
/* Helper script for .hlist class in common.css | |||
*/ | |||
if ( $.client.profile().name == 'msie' ) { | |||
/* Add pseudo-selector class to last child list items in IE 8 */ | |||
if ( $.client.profile().versionBase == '8' ) { | |||
$( '.hlist' ).find( 'dd:last-child, dt:last-child, li:last-child' ) | |||
.addClass( 'hlist-last-child' ); | |||
} | |||
/* Generate interpuncts and parens for IE < 8 */ | |||
if ( $.client.profile().versionBase < '8' ) { | |||
$( '.hlist' ).find( 'dt + dd, dt + dt' ).prev() | |||
.append( '<b>:</b> ' ); | |||
$( '.hlist' ).find( 'dd + dd, dd + dt, li + li' ).prev() | |||
.append( '<b>·</b> ' ); | |||
$( '.hlist' ).find( 'dl dl, ol ol, ul ul' ) | |||
.prepend( '( ' ).append( ') ' ); | |||
} | |||
} | |||
/** Collapsible tables ********************************************************* | /** Collapsible tables ********************************************************* | ||
Line 11: | Line 44: | ||
var collapseCaption = "hide"; | var collapseCaption = "hide"; | ||
var expandCaption = "show"; | var expandCaption = "show"; | ||
/*Original version | |||
window.collapseTable = function( tableIndex ){ | window.collapseTable = function( tableIndex ){ | ||
var Button = document.getElementById( "collapseButton" + tableIndex ); | var Button = document.getElementById( "collapseButton" + tableIndex ); | ||
Line 32: | Line 66: | ||
} | } | ||
Button.firstChild.data = collapseCaption; | Button.firstChild.data = collapseCaption; | ||
} | |||
} | |||
*/ | |||
/*Revised to provide alternate button labels for test results which now only partially expand/collapse*/ | |||
var partCollapseCaption = "collapse"; | |||
var partExpandCaption = "expand"; | |||
window.collapseTable = function( tableIndex ){ | |||
var Button = document.getElementById( "collapseButton" + tableIndex ); | |||
var Table = document.getElementById( "collapsibleTable" + tableIndex ); | |||
if ( !Table || !Button ) { | |||
return false; | |||
} | |||
var Rows = Table.rows; | |||
//Revised to check for either title | |||
if ( Button.firstChild.data == collapseCaption || Button.firstChild.data == partCollapseCaption) { | |||
for ( var i = 1; i < Rows.length; i++ ) { | |||
Rows[i].style.display = "none"; | |||
} | |||
//Revised to output button label appropriate for table | |||
Button.firstChild.data = (document.getElementById( "collapsibleTable" + tableIndex ).className.indexOf("testresults")!=-1?partExpandCaption:expandCaption); | |||
} else { | |||
for ( var i = 1; i < Rows.length; i++ ) { | |||
Rows[i].style.display = Rows[0].style.display; | |||
} | |||
//Revised to output button label appropriate for table | |||
Button.firstChild.data = (document.getElementById( "collapsibleTable" + tableIndex ).className.indexOf("testresults")!=-1?partCollapseCaption:collapseCaption); | |||
} | } | ||
} | } | ||
Line 91: | Line 156: | ||
$( createCollapseButtons ); | $( createCollapseButtons ); | ||
/** Dynamic Navigation Bars (experimental) ************************************* | /** Dynamic Navigation Bars (experimental) ************************************* | ||
* | * | ||
Line 186: | Line 251: | ||
$( createNavigationBarToggleButton ); | $( createNavigationBarToggleButton ); | ||
/** Drop-down list helper code ************************************* | |||
* | |||
* Description: See [http://www.mediawiki.org/wiki/Drop-Down_List]. | |||
* Maintainers: UNMAINTAINED | |||
*/ | |||
function ddm() { | |||
// Variables, change these in case you need to set other class names (mmhide_ for contribute users for example) | |||
var parentClass='isParent'; //gets applied when the LI has a nested UL | |||
var activeParentClass='isActive'; //gets applied when the nested UL is visible | |||
var preventHoverClass='nohover'; //denotes a navigation that should not get any hover effects | |||
var indicateJSClass='dhtml'; //gets applied to the main navigation when Javascript is available | |||
var toHideClass='hiddenChild'; //gets applied to hide the nested UL | |||
var toShowClass='shownChild'; //gets applied to show the nested UL | |||
var currentClass='current'; //denotes the current active sub element and prevents collapsing | |||
var d=document.getElementById('nav'); //denotes the navigation element | |||
// if DOM is not available stop right here. | |||
if(!document.getElementById && !document.createTextNode) { | |||
return; | |||
} | |||
// if the navigation element is available, apply the class denoting DHTML capabilities | |||
if(d) { | |||
d.className+=d.className==''?indicateJSClass:''+indicateJSClass; | |||
var lis,i,firstUL,j,apply; | |||
// loop through all LIs and check which ones have a nested UL | |||
lis=d.getElementsByTagName('li'); | |||
for(i=0;i<lis.length;i++) { | |||
firstUL=lis[i].getElementsByTagName('ul')[0] | |||
// if there is a nested UL, deactivate the first nested link and apply the class to show | |||
// there is a nested list | |||
if(firstUL) { | |||
lis[i].childNodes[0].onclick=function(){return false;} | |||
lis[i].className+=lis[i].className==''?parentClass:''+parentClass; | |||
// check if there is a "current" element | |||
apply=true; | |||
if(new RegExp('\\b'+currentClass+'\\b').test(lis[i].className)) { | |||
apply=false; | |||
} | |||
if(apply) { | |||
for(j=0;j<firstUL.getElementsByTagName('li').length;j++) { | |||
if(new RegExp('\\b'+currentClass+'\\b').test(firstUL.getElementsByTagName('li')[j].className)) { | |||
apply=false; | |||
break | |||
} | |||
} | |||
} | |||
// if there is no current element, apply the class to hide the nested list | |||
if(apply) { | |||
firstUL.className+=firstUL.className==''?toHideClass:''+toHideClass; | |||
// check if there is a class to prevent hover effects and only apply the function | |||
// onclick if that is the case, otherwise apply it onclick and onhover | |||
if(new RegExp('\\b'+preventHoverClass+'\\b').test(d.className)) { | |||
lis[i].onclick=function(){doddm(this);} | |||
} else { | |||
lis[i].onclick=function(){doddm(this);} | |||
lis[i].onmouseover=function(){doddm(this);} | |||
lis[i].onmouseout=function(){doddm(null);} | |||
} | |||
// if there is a current element, define the list as being kept open and apply the | |||
// classes to show the nested list and define the parent LI as an active one | |||
} else { | |||
lis[i].keepopen=1; | |||
firstUL.className+=firstUL.className==''?toShowClass:''+toShowClass; | |||
lis[i].className=lis[i].className.replace(parentClass,activeParentClass); | |||
} | |||
} | |||
} | |||
} | |||
// function to show and hide the nested lists and add the classes to the parent LIs | |||
function doddm(o) { | |||
var childUL,isobj,swap; | |||
// loop through all LIs of the navigation | |||
lis=d.getElementsByTagName('li'); | |||
for(i=0;i<lis.length;i++) { | |||
isobj=lis[i]==o; | |||
// function to exchange class names in an object | |||
swap=function(tmpobj,tmporg,tmprep) { | |||
tmpobj.className=tmpobj.className.replace(tmporg,tmprep) | |||
} | |||
// if the current LI does not have an indicator to be kept visible | |||
if(!lis[i].keepopen) { | |||
childUL=lis[i].getElementsByTagName('ul')[0]; | |||
// check if there is a nested UL and if the current LI is not the one clicked on | |||
// and exchange the classes accordingly (ie. hide all other nested lists and | |||
// make the LIs parent rather than active. | |||
if(childUL) { | |||
if(new RegExp('\\b'+preventHoverClass+'\\b').test(d.className)) { | |||
if(new RegExp('\\b'+activeParentClass+'\\b').test(lis[i].className)) { | |||
swap(childUL,isobj?toShowClass:toHideClass,isobj?toHideClass:toShowClass); | |||
swap(lis[i],isobj?activeParentClass:parentClass,isobj?parentClass:activeParentClass); | |||
} else { | |||
swap(childUL,isobj?toHideClass:toShowClass,isobj?toShowClass:toHideClass); | |||
swap(lis[i],isobj?parentClass:activeParentClass,isobj?activeParentClass:parentClass); | |||
} | |||
} else { | |||
swap(childUL,isobj?toHideClass:toShowClass,isobj?toShowClass:toHideClass); | |||
swap(lis[i],isobj?parentClass:activeParentClass,isobj?activeParentClass:parentClass); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
/** Video Galleries ********************************************************* | |||
* | |||
* Description: Allow random video galleries /w wiki caching. | |||
*/ | |||
/* This is intended to allow for randomized list of videos per page load to avoid editors resumitting pointless edits trying to surface their videos (or at least make such edits pointless). Some other niceties should also be possible, like: | |||
-rotating through all the available videos over time on a single page load | |||
-providing bigger, non-fullscreen in page playback | |||
-detecting broken videos where APIs provide error codes (we can't output categories here though, so unclear if we can provide useful notices. But we can possibly not show the broken video) | |||
-(other suggestions?) | |||
It would be nice if this could take advantage of the pre-existing video templates, but I have a feeling that won't work out and much of the interactions with the video service APIs may need to be re-implemented here. I think only YouTube, and DailyMotion get any on site use currently. | |||
*/ | |||
function videogallery(){ | |||
$(".videogallery a").each(function(){ | |||
$(this).css("background","#f00");//Test | |||
}); | |||
} | |||
window.onload=function() { | |||
ddm(); | |||
videogallery(); | |||
} |
Latest revision as of 07:09, 29 September 2017
/* Any JavaScript here will be loaded for all users on every page load. */ /* Test if an element has a certain class * * @deprecated: Use $(element).hasClass() instead. */ window.hasClass = ( function() { var reCache = {}; return function (element, className) { return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className); }; })(); /* Helper script for .hlist class in common.css */ if ( $.client.profile().name == 'msie' ) { /* Add pseudo-selector class to last child list items in IE 8 */ if ( $.client.profile().versionBase == '8' ) { $( '.hlist' ).find( 'dd:last-child, dt:last-child, li:last-child' ) .addClass( 'hlist-last-child' ); } /* Generate interpuncts and parens for IE < 8 */ if ( $.client.profile().versionBase < '8' ) { $( '.hlist' ).find( 'dt + dd, dt + dt' ).prev() .append( '<b>:</b> ' ); $( '.hlist' ).find( 'dd + dd, dd + dt, li + li' ).prev() .append( '<b>·</b> ' ); $( '.hlist' ).find( 'dl dl, ol ol, ul ul' ) .prepend( '( ' ).append( ') ' ); } } /** Collapsible tables ********************************************************* * * Description: Allows tables to be collapsed, showing only the header. See * [[Wikipedia:NavFrame]]. * Maintainers: [[User:R. Koot]] */ var autoCollapse = 2; var collapseCaption = "hide"; var expandCaption = "show"; /*Original version window.collapseTable = function( tableIndex ){ var Button = document.getElementById( "collapseButton" + tableIndex ); var Table = document.getElementById( "collapsibleTable" + tableIndex ); if ( !Table || !Button ) { return false; } var Rows = Table.rows; if ( Button.firstChild.data == collapseCaption ) { for ( var i = 1; i < Rows.length; i++ ) { Rows[i].style.display = "none"; } Button.firstChild.data = expandCaption; } else { for ( var i = 1; i < Rows.length; i++ ) { Rows[i].style.display = Rows[0].style.display; } Button.firstChild.data = collapseCaption; } } */ /*Revised to provide alternate button labels for test results which now only partially expand/collapse*/ var partCollapseCaption = "collapse"; var partExpandCaption = "expand"; window.collapseTable = function( tableIndex ){ var Button = document.getElementById( "collapseButton" + tableIndex ); var Table = document.getElementById( "collapsibleTable" + tableIndex ); if ( !Table || !Button ) { return false; } var Rows = Table.rows; //Revised to check for either title if ( Button.firstChild.data == collapseCaption || Button.firstChild.data == partCollapseCaption) { for ( var i = 1; i < Rows.length; i++ ) { Rows[i].style.display = "none"; } //Revised to output button label appropriate for table Button.firstChild.data = (document.getElementById( "collapsibleTable" + tableIndex ).className.indexOf("testresults")!=-1?partExpandCaption:expandCaption); } else { for ( var i = 1; i < Rows.length; i++ ) { Rows[i].style.display = Rows[0].style.display; } //Revised to output button label appropriate for table Button.firstChild.data = (document.getElementById( "collapsibleTable" + tableIndex ).className.indexOf("testresults")!=-1?partCollapseCaption:collapseCaption); } } function createCollapseButtons(){ var tableIndex = 0; var NavigationBoxes = new Object(); var Tables = document.getElementsByTagName( "table" ); for ( var i = 0; i < Tables.length; i++ ) { if ( hasClass( Tables[i], "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 ); Button.className = "collapseButton"; //Styles are declared in Common.css ButtonLink.style.color = Header.style.color; ButtonLink.setAttribute( "id", "collapseButton" + tableIndex ); ButtonLink.setAttribute( "href", "#" ); addHandler( ButtonLink, "click", new Function( "evt", "collapseTable(" + tableIndex + " ); return killEvt( evt );") ); ButtonLink.appendChild( ButtonText ); Button.appendChild( document.createTextNode( "[" ) ); Button.appendChild( ButtonLink ); Button.appendChild( document.createTextNode( "]" ) ); Header.insertBefore( Button, Header.firstChild ); tableIndex++; } } for ( var i = 0; i < tableIndex; i++ ) { if ( hasClass( NavigationBoxes[i], "collapsed" ) || ( tableIndex >= autoCollapse && hasClass( NavigationBoxes[i], "autocollapse" ) ) ) { collapseTable( i ); } else if ( hasClass( NavigationBoxes[i], "innercollapse" ) ) { var element = NavigationBoxes[i]; while (element = element.parentNode) { if ( hasClass( element, "outercollapse" ) ) { collapseTable ( i ); break; } } } } } $( createCollapseButtons ); /** Dynamic Navigation Bars (experimental) ************************************* * * Description: See [[Wikipedia:NavFrame]]. * Maintainers: UNMAINTAINED */ // set up the words in your language var NavigationBarHide = '[' + collapseCaption + ']'; var NavigationBarShow = '[' + expandCaption + ']'; // shows and hides content and picture (if available) of navigation bars // Parameters: // indexNavigationBar: the index of navigation bar to be toggled window.toggleNavigationBar = function(indexNavigationBar){ var NavToggle = document.getElementById("NavToggle" + indexNavigationBar); var NavFrame = document.getElementById("NavFrame" + indexNavigationBar); if (!NavFrame || !NavToggle) { return false; } // if shown now if (NavToggle.firstChild.data == NavigationBarHide) { for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) { if (hasClass(NavChild, 'NavContent') || hasClass(NavChild, 'NavPic')) { NavChild.style.display = 'none'; } } NavToggle.firstChild.data = NavigationBarShow; // if hidden now } else if (NavToggle.firstChild.data == NavigationBarShow) { for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) { if (hasClass(NavChild, 'NavContent') || hasClass(NavChild, 'NavPic')) { NavChild.style.display = 'block'; } } NavToggle.firstChild.data = NavigationBarHide; } } // adds show/hide-button to navigation bars function createNavigationBarToggleButton(){ var indexNavigationBar = 0; // iterate over all < div >-elements var divs = document.getElementsByTagName("div"); for (var i = 0; NavFrame = divs[i]; i++) { // if found a navigation bar if (hasClass(NavFrame, "NavFrame")) { indexNavigationBar++; var NavToggle = document.createElement("a"); NavToggle.className = 'NavToggle'; NavToggle.setAttribute('id', 'NavToggle' + indexNavigationBar); NavToggle.setAttribute('href', 'javascript:toggleNavigationBar(' + indexNavigationBar + ');'); var isCollapsed = hasClass( NavFrame, "collapsed" ); /* * Check if any children are already hidden. This loop is here for backwards compatibility: * the old way of making NavFrames start out collapsed was to manually add style="display:none" * to all the NavPic/NavContent elements. Since this was bad for accessibility (no way to make * the content visible without JavaScript support), the new recommended way is to add the class * "collapsed" to the NavFrame itself, just like with collapsible tables. */ for (var NavChild = NavFrame.firstChild; NavChild != null && !isCollapsed; NavChild = NavChild.nextSibling) { if ( hasClass( NavChild, 'NavPic' ) || hasClass( NavChild, 'NavContent' ) ) { if ( NavChild.style.display == 'none' ) { isCollapsed = true; } } } if (isCollapsed) { for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) { if ( hasClass( NavChild, 'NavPic' ) || hasClass( NavChild, 'NavContent' ) ) { NavChild.style.display = 'none'; } } } var NavToggleText = document.createTextNode(isCollapsed ? NavigationBarShow : NavigationBarHide); NavToggle.appendChild(NavToggleText); // Find the NavHead and attach the toggle link (Must be this complicated because Moz's firstChild handling is borked) for(var j=0; j < NavFrame.childNodes.length; j++) { if (hasClass(NavFrame.childNodes[j], "NavHead")) { NavToggle.style.color = NavFrame.childNodes[j].style.color; NavFrame.childNodes[j].appendChild(NavToggle); } } NavFrame.setAttribute('id', 'NavFrame' + indexNavigationBar); } } } $( createNavigationBarToggleButton ); /** Drop-down list helper code ************************************* * * Description: See [http://www.mediawiki.org/wiki/Drop-Down_List]. * Maintainers: UNMAINTAINED */ function ddm() { // Variables, change these in case you need to set other class names (mmhide_ for contribute users for example) var parentClass='isParent'; //gets applied when the LI has a nested UL var activeParentClass='isActive'; //gets applied when the nested UL is visible var preventHoverClass='nohover'; //denotes a navigation that should not get any hover effects var indicateJSClass='dhtml'; //gets applied to the main navigation when Javascript is available var toHideClass='hiddenChild'; //gets applied to hide the nested UL var toShowClass='shownChild'; //gets applied to show the nested UL var currentClass='current'; //denotes the current active sub element and prevents collapsing var d=document.getElementById('nav'); //denotes the navigation element // if DOM is not available stop right here. if(!document.getElementById && !document.createTextNode) { return; } // if the navigation element is available, apply the class denoting DHTML capabilities if(d) { d.className+=d.className==''?indicateJSClass:''+indicateJSClass; var lis,i,firstUL,j,apply; // loop through all LIs and check which ones have a nested UL lis=d.getElementsByTagName('li'); for(i=0;i<lis.length;i++) { firstUL=lis[i].getElementsByTagName('ul')[0] // if there is a nested UL, deactivate the first nested link and apply the class to show // there is a nested list if(firstUL) { lis[i].childNodes[0].onclick=function(){return false;} lis[i].className+=lis[i].className==''?parentClass:''+parentClass; // check if there is a "current" element apply=true; if(new RegExp('\\b'+currentClass+'\\b').test(lis[i].className)) { apply=false; } if(apply) { for(j=0;j<firstUL.getElementsByTagName('li').length;j++) { if(new RegExp('\\b'+currentClass+'\\b').test(firstUL.getElementsByTagName('li')[j].className)) { apply=false; break } } } // if there is no current element, apply the class to hide the nested list if(apply) { firstUL.className+=firstUL.className==''?toHideClass:''+toHideClass; // check if there is a class to prevent hover effects and only apply the function // onclick if that is the case, otherwise apply it onclick and onhover if(new RegExp('\\b'+preventHoverClass+'\\b').test(d.className)) { lis[i].onclick=function(){doddm(this);} } else { lis[i].onclick=function(){doddm(this);} lis[i].onmouseover=function(){doddm(this);} lis[i].onmouseout=function(){doddm(null);} } // if there is a current element, define the list as being kept open and apply the // classes to show the nested list and define the parent LI as an active one } else { lis[i].keepopen=1; firstUL.className+=firstUL.className==''?toShowClass:''+toShowClass; lis[i].className=lis[i].className.replace(parentClass,activeParentClass); } } } } // function to show and hide the nested lists and add the classes to the parent LIs function doddm(o) { var childUL,isobj,swap; // loop through all LIs of the navigation lis=d.getElementsByTagName('li'); for(i=0;i<lis.length;i++) { isobj=lis[i]==o; // function to exchange class names in an object swap=function(tmpobj,tmporg,tmprep) { tmpobj.className=tmpobj.className.replace(tmporg,tmprep) } // if the current LI does not have an indicator to be kept visible if(!lis[i].keepopen) { childUL=lis[i].getElementsByTagName('ul')[0]; // check if there is a nested UL and if the current LI is not the one clicked on // and exchange the classes accordingly (ie. hide all other nested lists and // make the LIs parent rather than active. if(childUL) { if(new RegExp('\\b'+preventHoverClass+'\\b').test(d.className)) { if(new RegExp('\\b'+activeParentClass+'\\b').test(lis[i].className)) { swap(childUL,isobj?toShowClass:toHideClass,isobj?toHideClass:toShowClass); swap(lis[i],isobj?activeParentClass:parentClass,isobj?parentClass:activeParentClass); } else { swap(childUL,isobj?toHideClass:toShowClass,isobj?toShowClass:toHideClass); swap(lis[i],isobj?parentClass:activeParentClass,isobj?activeParentClass:parentClass); } } else { swap(childUL,isobj?toHideClass:toShowClass,isobj?toShowClass:toHideClass); swap(lis[i],isobj?parentClass:activeParentClass,isobj?activeParentClass:parentClass); } } } } } } /** Video Galleries ********************************************************* * * Description: Allow random video galleries /w wiki caching. */ /* This is intended to allow for randomized list of videos per page load to avoid editors resumitting pointless edits trying to surface their videos (or at least make such edits pointless). Some other niceties should also be possible, like: -rotating through all the available videos over time on a single page load -providing bigger, non-fullscreen in page playback -detecting broken videos where APIs provide error codes (we can't output categories here though, so unclear if we can provide useful notices. But we can possibly not show the broken video) -(other suggestions?) It would be nice if this could take advantage of the pre-existing video templates, but I have a feeling that won't work out and much of the interactions with the video service APIs may need to be re-implemented here. I think only YouTube, and DailyMotion get any on site use currently. */ function videogallery(){ $(".videogallery a").each(function(){ $(this).css("background","#f00");//Test }); } window.onload=function() { ddm(); videogallery(); }