User:The Transhumanist/ViewAnnotationToggler.js: Difference between revisions

Content deleted Content added
correction
update comment
 
(314 intermediate revisions by the same user not shown)
Line 1:
// <syntaxhighlight lang="javascript">
/*
Test script by TheDJ
For processing list items:
To hide annotations
*/
 
/* anno.js: Adds a sidebar menu item and hot key to toggle annotations.
var i = 0;
i++;
// This runs immediately.
// It is safe to do things like this, UNLESS they need to change something in the page.
// You CAN use it to do data processing, start requests to the api etc.
 
Based on: https://en.wikipedia.org/w/index.php?title=User:PleaseStand/hide-vector-sidebar.js&oldid=580854231
// An anonymous function block wrapped inside $()
and https://en.wikipedia.org/wiki/User:Thespaceface/MetricFirst.js
$( function() {
// do stuff to change the page
});
// $() is an alias for jQuery(), the main function of the jQuery library,
// which is always available for script writers on Wikipedia
// When used like this, it is a shortcut for $( document ).ready(), and it will
// execute your anonymous function as soon as the page is ready to be
// manipulated by JS, or immediately if it is ready now.
// See also: http://api.jquery.com/jquery/#jQuery3
 
The hot key is Shift-Alt-a.
// Attach a function to be run once the 'wikipage.content' part of a page is available
mw.hook( 'wikipage.content').add( function ($content ) {
// Like document.ready, this will run once that part of the page is
// ready/updated.
// $content is a jQuery list of DOM elements, that has just become available.
// See also: http://api.jquery.com/jquery/
});
// This is used by many scripts in MediaWiki, because it also works after
// saving with Visual Editor, or when previewing with Live preview tools etc.
// There are several such named hooks like:
// wikipage.diff, wikipage.editform, wikipage.categories
 
IMPORTANT: The menu item for this script is not in the side bar menu.
// mw, an alias for mediaWiki, is another javascript libary that is always
It is in the more tab at the top of the page. This is because having
// available to MediaWiki and Wikipedia scripters.
it in the sidebar menu interferes with the script's page scrolling adjustment.
// See also: https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw
// For the hook specific part of this library, which we use above, see:
// https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.hook
 
Currently, this script applies regex upon matches within the ID element 'mw-content-text'.
// Note that large parts of this mw library are not ready for usage by default,
It wraps the annotations in <span class="anno"> and </span>. Then it hides/shows the elements
// and you might have to load some parts using mw.loader, before they can be used.
with that class. There is probably a much more efficient method than the one I use below. If you happen to know of one, please let me know.
// For loading dependencies and guaranteeing order between dependencies,
// use ResourceLoader.
// See also: https://www.mediawiki.org/wiki/ResourceLoader/Developing_with_ResourceLoader#Client-side_.28dynamically.29
 
Besides that, the script isn't finished yet. The current problem I'm trying to solve is this:
// Example
 
Hiding or showing annotations affects the position of the viewport, so unfortunately,
// Run only on view (not edit) pages. See [[mw:Manual:Interface/JavaScript#Page-specific]]
the reader is jolted away from what he was reading. This is bad.
if ( mw.config.get('wgAction') === 'view' ) {
 
I'd like the material that was in the viewport to stay there, which means the viewport
// Attach a function to be run once the 'wikipage.content' part of a page is available
must be repositioned relative to the top of the page each time the toggle is activated.
mw.hook( 'wikipage.content').add( function ($contents ) {
// Like document.ready, this will run, once that part of the page is
// ready/updated.
// $contents is a jQuery list of DOM elements, that has just become available.
// See also: http://api.jquery.com/jquery/
 
If you have any ideas on how to fix this, I'd be most interested.
// Get all the <li> elements from $contents, but skip those with a class or ID,
// because they might have special functionality that you don't want to break.
// We generally avoid things like this, because they will break easily.
// Wikipedia is so diverse and big, that to do anything,
// your content really needs a class or ID.
var listItems = $contents.find( 'li:not([class]):not([id])' );
// Iterate over each of the <li> items
listItems.each( function( index, li ) {
// This part is complicated, because we need to look at text
// and text is not structured. Get the li item, and wrap it with jquery
// Then get all the direct children nodes
var nodes = $(li).contents();
var marker = false;
var ul = false;
for ( var i = 0; i < nodes.length; i++ ) {
// We need to find text nodes, that have our - marker.
if ( nodes[i].nodeType === Node.TEXT_NODE &&
nodes[i].textContent.indexOf(' – ') >= 0)
{
// We found the node which contains our marker
marker = i;
break;
}
}
// Check to see if the last node is an UL, so we don't break nesting
if( nodes[nodes.length-1].tagName === "UL" ) {
ul = nodes[nodes.length-1];
}
// only useful if it's the second element or later
if( marker > 0 ) {
// Use jquery to create a new span
// We use span, because it is an inline element.
// We give it a class so we can find it back later
// This element is already part of the document, but it is not attached to anything visible yet.
var wrapper = $('<span>').addClass('myscript-wrapper');
// Move the node with our marker, and all nodes that follow it into this new wrapper.
// This removes them from the original <li>
wrapper.append(nodes.slice(marker, ul ? nodes.length-1 : nodes.length));
// Append the wrapper to our original list item to make the wrapper visible.
$(li).append(wrapper);
if ( ul ) {
$(li).append( ul );
}
}
});
// Now we have structure, and we can apply our manipulations and functionality
// We simply hide all our elements
$( '.myscript-wrapper' ).hide();
// You would now add controls to show them etc. etc.
});
}
 
Sincerely,
/*
The Transhumanist
//List item processor
 
//Based on a script by Writ Keeper
Brief comments are provided within the sourcecode below. For extensive explanatory
//This selector grabs all of the <li> elements that are within #mw-content-text, and then does something for each of them
notes on what the source code does and how it works, see the Script's workshop on
$("#mw-content-text li").each( function (ind, el)
the talk page.
{
//first, grab the text from the current li element; we want only the top level text, so filter out all of the other stuff.
var currentText = $(el).contents().filter(function(){return this.nodeType === 3; });
 
//Process only if there's something to process
if(currentText.text().length > 0)
{
//replace the character
var newText = currentText.text().replace(/–/g,'XXX');
//reinsert the updated string back into the DOM
currentText.replaceWith(newText);
}
});
*/
 
// Start off with a bodyguard function to reserve mw and $ (see Explanatory notes on talk page).
( function ( mw, $ ) {
 
// we can now rely on mw and $ within the safety of our “bodyguard” function, to mean
// "mediawiki" and "jQuery", respectively
 
// ============== ready() event listener/handler ==============
// below is jQuery short-hand for $(document).ready(function() { ... });
// it makes the rest of the script wait until the page's DOM is loaded and ready
$(function() {
// ============== deactivation filters (guard clauses) ==============
// End the script if "Editing " is in the page title (so it doesn't conflict with script editor)
if (document.title.indexOf("Editing ") === 0) {
// use a return statement to end the local function and hence the program's body
// important: this approach does not work outside of a function
return;
}
 
 
// =================== Prep work =====================
var y1; var y2;
var annoSwitch;
var cont = document.getElementById('mw-content-text');
// wrap the annotations in spans with class "anno"
cont.outerHTML = cont.outerHTML.replace(/(<li>.*?)( –.*)/g,'$1<span class="anno">$2</span>');
 
// ================= Core control structure =================
// Only activate on Vector skin
if ( mw.config.get( 'skin' ) === 'vector' ) {
$( function() {
 
// get the value of our status variable from memory
// (this tells us what mode to start in)
var annostatus = localStorage.getItem('annostatus');
 
// run the function corresponding to the current status
if ( annostatus === "hide" ) {
annoHide();
} else {
annoShow();
}
} );
}
 
// ======================== Subroutines ===========================
// Functions (aka subroutines) are activated only when they are called.
// Below are the functions called in the core control structure of the program above.
// They are at the end of the program, so that the script's flow
// is easier to follow.
 
// ============ Function to hide annotations ==============
function annoHide() {
// store status so it persists across page loads
localStorage.setItem("annostatus", "hide");
 
y1 = window.scrollY;
// alert( "vertical scroll position is " + y1);
 
//Select the set of annotations that are above where the viewpoint is scrolled to
var $annos_above = $(".anno").filter( function(){
var rect = this.getBoundingClientRect();
if ( rect.bottom < 0 ) {
return true;
} else {
return false;
}
} );
 
//For each annotation above the viewport, get the difference in height in the containing element as that annotation is hidden
var scroll_amount = 0;
$annos_above.each( function(){
var height_before = $(this).parent().outerHeight(true);
$(this).hide();
var height_after = $(this).parent().outerHeight(true);
scroll_amount = scroll_amount + (height_after-height_before);
} );
 
//Hide the remaining annotations (hide elements with the anno class)
$( ".anno" ).hide();
 
window.scrollTo(0, y1);
y1 = window.scrollY;
// alert( "vertical scroll position is " + y1);
 
//Scroll the window by the required amount
window.scrollBy(0, scroll_amount);
 
// now we have to update the menu item
// (referred to in this script as "annoSwitch").
// To do that, first we remove it (if it exists):
if ( annoSwitch ) {
annoSwitch.parentNode.removeChild(annoSwitch);
}
 
// and then we create it (or its replacement) from scratch:
annoSwitch = mw.util.addPortletLink( 'p-cactions', '#', 'Annotations \(show\)', '', 'Show annotations', 'a' );
// annoSwitch = mw.util.addPortletLink( 'p-tb', '#', 'Annotations \(show\)', 'ca-anno', 'Show the annotations', 'a' );
 
// make the menu item clickable by binding it to a click handler
// (which activates the actions between the curly brakets when clicked):
$( annoSwitch ).click( function ( e ) {
e.preventDefault(); // prevents any default action -- we want only the following action to run:
annoShow();
} );
}
// ============ Function to show annotations ==============
function annoShow() {
// store status so it persists across page loads
localStorage.setItem("annostatus", "show");
 
// show the annotations (show elements with the anno class)
$( ".anno").show();
 
// now we have to update the menu item
// (referred to in this script as "annoSwitch").
// To do that, first we remove it (if it exists):
if ( annoSwitch ) {
annoSwitch.parentNode.removeChild(annoSwitch);
}
 
// and then we create it (or its replacement) from scratch:
annoSwitch = mw.util.addPortletLink( 'p-cactions', '#', 'Annotations \(hide\)', '', 'Hide annotations', 'a' );
// annoSwitch = mw.util.addPortletLink( 'p-tb', '#', 'Annotations \(hide\)', 'ca-anno', 'Hide the annotations', 'a' );
 
$( annoSwitch ).click( function ( e ) {
e.preventDefault(); // prevents any default action -- we want only the following action to run:
annoHide();
} );
}
} );
}( mediaWiki, jQuery ) );
// </syntaxhighlight>
 
// sample code for getting and setting viewport position:
// y = window.scrollY;
// alert( "vertical scroll position is " + y);
// window.scrollTo(0, y);