// vim: ts=4 sw=4 et ai
// <nowiki>
( function () {
// sample value: {"a": {"b": "WP:RFA", "c": {"d": "WP:ANI"}}}
var gMenuJson = null;
// sample value: ["a", "b"]
var gPressedKeys = [];
var gGeneralKeyListener = null;
// GUI components
var gBackBtn;
//var gBreadcrumb;
var SUPERJUMP_PANEL_ID = "superjump-container-panel";
var SUPERJUMP_TABLE_ID = "superjump-keys-table";
var MENU_JSON_LOCALSTORAGE_KEY = "enwp_superjump_menu_json";
var MENU_JSON_LOCALSTORAGE_SEPARATOR = "|";
function initAccessKeyListeners() {
for( var key in gMenuJson ) {
initAccessKeyListener( key, function () { handleKey( key, gMenuJson, /* accessKey */ true ); } );
}
}
function navigateToPath( keys ) {
var menu = gMenuJson;
for( var i = 0; i < keys.length - 1; i++ ) {
menu = menu[ keys[i] ];
}
gPressedKeys = keys.slice( 0, keys.length - 1 );
var lastKey = keys[ keys.length - 1 ];
handleKey( lastKey, menu );
}
function handleKey( key, menu, accessKey ) {
if( key == "Escape" ) {
closeInterface();
gPressedKeys = [];
return;
} else if( key == "Backspace" ) {
if( gPressedKeys.length > 1 ) {
navigateToPath( gPressedKeys.slice( 0, gPressedKeys.length - 1 ) );
}
return;
}
var submenu = menu[ key ];
if( typeof submenu === typeof "" ) {
window.location.href = mw.util.getUrl( submenu );
} else if( submenu ) {
gPressedKeys.push( key );
displayOrUpdateInterface( makePanel( submenu ) );
if( gGeneralKeyListener ) {
document.removeEventListener( "keydown", gGeneralKeyListener );
gGeneralKeyListener = null;
}
gGeneralKeyListener = function ( event ) {
handleKey( event.key, submenu );
};
document.addEventListener( "keydown", gGeneralKeyListener );
}
}
function displayOrUpdateInterface( panel ) {
panel.id = SUPERJUMP_TABLE_ID;
var containerPanel = document.getElementById( SUPERJUMP_PANEL_ID );
if( !containerPanel ) {
containerPanel = createInterface();
document.body.appendChild( containerPanel );
}
containerPanel.replaceChild( panel, document.getElementById( SUPERJUMP_TABLE_ID ) );
gBackBtn.disabled = gPressedKeys.length < 2;
//gBreadcrumb.textContent = "Pressed: " + gPressedKeys.map( function ( x ) { return "[" + x + "]"; } ).join( " > " );
}
function createInterface() {
containerPanel = document.createElement( "div" );
containerPanel.id = SUPERJUMP_PANEL_ID;
var topBar = document.createElement( "div" );
gBackBtn = document.createElement( "button" );
gBackBtn.textContent = "Back [Backspace]";
gBackBtn.addEventListener( "click", function () {
navigateToPath( gPressedKeys.slice( 0, gPressedKeys.length - 1 ) );
} );
topBar.appendChild( gBackBtn );
var closeBtn = document.createElement( "button" );
closeBtn.textContent = "Close [Esc]";
closeBtn.addEventListener( "click", closeInterface );
topBar.appendChild( closeBtn );
containerPanel.appendChild( topBar );
var startingPanel = document.createElement( "div" );
startingPanel.id = SUPERJUMP_TABLE_ID;
containerPanel.appendChild( startingPanel );
//var bottomBar = document.createElement( "div" );
//gBreadcrumb = document.createElement( "span" );
//bottomBar.appendChild( gBreadcrumb );
//var editConfigBtn = document.createElement( "button" );
//editConfigBtn.textContent = "Edit configuration";
//editConfigBtn.addEventListener( "click", function () {
// window.location.href = mw.util.getUrl( getMenuJsonPageTitle(), { action: "edit" } );
//} );
//bottomBar.appendChild( editConfigBtn );
//containerPanel.appendChild( bottomBar );
return containerPanel;
}
function closeInterface() {
var panel = document.getElementById( SUPERJUMP_PANEL_ID );
panel.parentNode.removeChild( panel );
if( gGeneralKeyListener ) {
document.removeEventListener( "keydown", gGeneralKeyListener );
}
}
function makePanel( menu ) {
var table = document.createElement( "table" );
var keys = Object.keys( menu );
var numItems = keys.length;
var tds = new Array( numItems );
for( var i = 0; i < numItems; i++ ) {
var td = document.createElement( "td" );
var keySpan = document.createElement( "span" );
keySpan.className = "key-span";
keySpan.textContent = "[" + keys[i] + "]";
td.appendChild( keySpan );
var actionSpan = document.createElement( "span" );
var menuItem = menu[ keys[i] ];
if( typeof menuItem === typeof "" ) {
actionSpan.textContent = menuItem;
} else {
var numChoices = Object.keys( menuItem ).length;
actionSpan.textContent = numChoices + " choice" + ( numChoices !== 1 ? "s" : "" );
}
td.appendChild( actionSpan );
tds[i] = td;
}
var numRows = Math.max( 2, Math.ceil( Math.sqrt( numItems ) ) );
var numCols = numRows;
for( var i = 0; i < numRows; i++ ) {
var tr = document.createElement( "tr" );
for( var j = 0; j < numCols; j++ ) {
var cell = tds[ i * numCols + j ];
if( cell ) {
tr.appendChild( cell );
}
}
table.appendChild( tr );
}
return table;
}
function initAccessKeyListener( key, listener ) {
var hasOurAccessKey = document.querySelectorAll( "a[accesskey=" + key + "]" );
if( hasOurAccessKey.length ) {
for( var i = 0; i < hasOurAccessKey.length; i++ ) {
hasOurAccessKey[i].setAttribute( "accesskey", "" );
$( hasOurAccessKey[i] ).updateTooltipAccessKeys();
}
}
$( "body" ).append( $( "<a>" )
.attr( { href: "#", accesskey: key } )
.css( { position: "fixed", opacity: "0" } )
.text( "superjump-link-" + key )
.addClass( "superjump-accesskey-sink" )
.click( listener ) );
}
function setMenuJson() {
var reqParams = {
format: "json",
action: "query",
prop: "revisions",
titles: getMenuJsonPageTitle(),
rvprop: "content|ids",
rvslots: "main"
};
var storedRevidAndMenuJson = getStoredRevidAndMenuJson();
var storedRevid, storedMenuJson;
if( storedRevidAndMenuJson ) {
storedRevid = storedRevidAndMenuJson[0];
storedMenuJson = storedRevidAndMenuJson[1];
reqParams.rvstartid = parseInt( storedRevid ) + 1;
reqParams.rvdir = "newer";
}
return $.getJSON(
mw.util.wikiScript( "api" ),
reqParams
).then( function ( data ) {
if( !data || !data.query || !data.query.pages ) {
mw.notify( "Error loading menu JSON page!" );
return;
}
var pageId = Object.keys( data.query.pages )[0];
var pageObj = data.query.pages[pageId];
if( pageObj.missing ) {
mw.notify( "Error! You'll need to create " + getMenuJsonPageTitle() + " to use superjump." );
return;
}
var revs = pageObj.revisions;
if( !revs ) {
gMenuJson = JSON.parse(storedMenuJson);
return;
}
var mostRecentRev = revs[ revs.length - 1 ];
var apiRevid = mostRecentRev.revid;
var apiJson = mostRecentRev.slots.main["*"];
if( isLocalStorageAvailable() ) {
var storageValue = apiRevid + MENU_JSON_LOCALSTORAGE_SEPARATOR + apiJson;
window.localStorage.setItem( MENU_JSON_LOCALSTORAGE_KEY, storageValue );
}
gMenuJson = JSON.parse(apiJson);
} );
}
function getMenuJsonPageTitle() {
return "User:" + mw.config.get( "wgUserName" ) + "/superjump-config.json";
}
function getStoredRevidAndMenuJson() {
var localStorageAvailable = isLocalStorageAvailable();
if( localStorageAvailable ) {
var storedRevidAndMenuJson = window.localStorage.getItem( MENU_JSON_LOCALSTORAGE_KEY );
if( storedRevidAndMenuJson && storedRevidAndMenuJson.indexOf( MENU_JSON_LOCALSTORAGE_SEPARATOR ) >= 0 ) {
return storedRevidAndMenuJson.split( MENU_JSON_LOCALSTORAGE_SEPARATOR );
}
}
return null;
}
function isLocalStorageAvailable() {
try {
var storage = window.localStorage,
x = '__storage_test__';
storage.setItem( x, x );
storage.removeItem( x );
return true;
} catch( e ) {
return false;
}
}
$.when( $.ready, mw.loader.using( "mediawiki.util" ) )
.then( setMenuJson )
.then( function () {
mw.util.addCSS( "#" + SUPERJUMP_PANEL_ID + "{ position: fixed; "+
"top: 50%; left: 50%; margin-right: -50%; transform: translate(-50%, -50%); " +
"background-color:white; padding: 1em; border:thin solid gray;" +
"box-shadow:0px 7px 7px 0px rgba(0,0,0,0.3)}"+
"#" + SUPERJUMP_PANEL_ID + " > div * { margin-left: 0.75em; }"+
"#" + SUPERJUMP_TABLE_ID + " td{padding: 0.5em;}"+
"#" + SUPERJUMP_TABLE_ID + " .key-span{font-family:monospace; cursor:default; padding-right: 0.1em; font-size: 200%}"+
"#" + SUPERJUMP_TABLE_ID + " span{vertical-align:middle;}");
initAccessKeyListeners();
} );
} )();
// </nowiki>