//__NOINDEX__
/*
* Description:
* Refresh page content periodically
*
* Version 1.0: 27 April 2015
* Original version for Wikipedia use
* Version 1.1: 28 April 2015
* Use jQuery
* Version 1.2: 29 April 2015
* Dynamically determine selector
* Allow interval configuration
* Version 1.3: 30 April 2015
* Support action=history
* Version 1.4: 3 May 2015
* Add programmatic toggle
*
* License: CC-BY-SA
* http://creativecommons.org/licenses/by-sa/3.0/
*/
((window.user = window.user || {}).ui = window.user.ui || {}).refresh =
(function (mw, $)
{
'use strict';
var g_self,
g_selector,
g_jqContent, g_jqInput, g_jqImg, g_jqLi,
g_wAction = mw.config.get('wgAction'),
g_interval = 120, // default refresh interval (seconds)
g_hTimeout = -1; // cannot run = -1; okay to run = 0; running > 0
// process click events on radio buttons for action=history
// mostly "borrowed" from MediaWiki 1.26wmf3
// example:
// $._data( $('li > input[type="radio"]')[0] ).events.click[0].handler
// it's not possible to attach the existing handler, because
// 1. the existing handler cannot deal with
// changing the number of list items
// 2. if the previous page had only one list item,
// there's no reference to the handler available
function updateDiffRadios()
{
var li, inputs, oldidRadio, diffRadio,
nextState = 'before';
if (!g_jqLi.length)
{
return;
}
g_jqLi.each(function()
{
li = $(this);
inputs = li.find('input[type="radio"]');
oldidRadio = inputs.filter('[name="oldid"]').eq(0);
diffRadio = inputs.filter('[name="diff"]').eq(0);
li.removeClass('selected between before after');
if (!oldidRadio.length || !diffRadio.length)
{
return;
}
if (oldidRadio.prop('checked'))
{
li.addClass('selected after');
nextState = 'after';
}
else if (diffRadio.prop('checked'))
{
li.addClass('selected ' + nextState);
nextState = 'between';
}
else
{
li.addClass(nextState);
}
});
}
// get interval (sec) from module properties
// and convert it to msec
function getInterval()
{
if ((typeof g_self.interval === 'number') &&
(g_self.interval > 0) &&
(g_self.interval < 604801 )) // 7 days + 1 sec
{
g_interval = g_self.interval;
}
else
{
g_self.interval = g_interval;
}
return g_interval * 1000;
}
// process checkbox events
function onCheck()
{
if (g_jqInput.prop('checked'))
{
if (g_hTimeout === 0)
{ // schedule a tick
g_jqImg.hide(); // in case it was showing after an error
g_hTimeout = window.setTimeout(onTick, getInterval());
g_self.message = 'OK';
}
}
else
{
if (g_hTimeout > 0)
{ // stop the scheduled tick
window.clearTimeout(g_hTimeout);
g_hTimeout = 0;
g_self.message = 'Stopped';
}
}
}
// process Ajax done event
function onDone(htmlString)
{
var jqNewContent = $(htmlString).find(g_selector);
if (jqNewContent.length !== 1)
{
g_self.message = 'onDone :: ' + jqNewContent.length +
' elements found for (' + g_selector + ')';
g_jqInput.prop('checked', false);
return;
}
// refresh content
g_jqContent.replaceWith(jqNewContent);
g_jqContent = jqNewContent;
// for action=history ...
if (g_wAction === 'history')
{ // ... attach click listeners and fake a click
g_jqLi = g_jqContent.find('li');
g_jqLi.find('input[type="radio"]')
.click(updateDiffRadios);
updateDiffRadios();
}
// go back to sleep
g_jqImg.hide();
g_hTimeout = window.setTimeout(onTick, getInterval());
}
// process Ajax fail event
function onFail(jqDummy, textStatus, errorThrown)
{
g_self.message = 'onFail :: ' + textStatus + ' ' + errorThrown;
g_jqInput.prop('checked', false);
}
// handle timer events,
function onTick()
{
g_hTimeout = 0;
g_jqImg.show();
// ajax defaults to window.location.href
$.ajax({dataType: 'html'})
.done(onDone)
.fail(onFail);
}
// turn refresh on and off programmatically
function toggle(state)
{
if (!!g_jqInput &&
(typeof state === 'boolean') &&
(g_jqInput.prop('checked') !== state))
{
g_jqInput.click();
}
}
// init g_self before document.ready
// in case document.ready executes immediately
g_self =
{
interval : g_interval,
message : 'Initializing',
toggle : toggle,
version : 'Version 1.4.1: 15 May 2015'
};
$(function main()
{
var jqSpan, jqH1,
i, done,
actions =
[
'view',
'history'
],
selectors =
[
'.mw-changeslist', // RecentChanges & Watchlist, all skins
'#pagehistory', // action=history, all skins
'#mw-content-text' // all pages, all skins
],
uriData =
[
'data:image/gif;base64,',
'R0lGODlhKwALAMIAAP///wAAAIKCggAAAP///////////////yH/C05FVFNDQVBF',
'Mi4wAwEAAAAh+QQFCgADACwAAAAAKwALAAADNDiyzPNQtRbhpHfWTCP/mgduYEl+',
'Z8mlGauG1ii+7bzadBejeL64sIfvAtQJR7yioHJsJQAAIfkEBQoAAgAsAAAAAAsA',
'CwAAAw0os8zaMMpJq70YPykSACH5BAUKAAEALAAAAAAbAAsAAAMtGLLM8TCMSalq',
'WERZ+8jY5nVgI45U6URoqmps+71n+8KQPKs1evejC2jzaAUSACH5BAEKAAEALBAA',
'AAAbAAsAAAMtGLLM8TCMSalqWERZ+8jY5nVgI45U6URoqmps+71n+8KQPKs1evej',
'C2jzaAUSADs='
].join(''),
htmlString =
[
'<span id="ui-refresh">',
'<label for="ui-refresh-input"',
' title="Enable auto-refresh">Auto-refresh:</label>',
'<input id="ui-refresh-input" type="checkbox">',
'<img src="' + uriData + '" alt="Refreshing page">',
'</span>'
].join('');
// allow listed actions, else deny
done = false;
for ( i = 0 ; (i < actions.length) && !done ; ++i )
{
done = (actions[i] === g_wAction);
}
if (!done)
{
g_self.message = 'main :: unsupported action : ' + g_wAction;
return;
}
// determine the "best" selector
done = false;
for ( i = 0 ; (i < selectors.length) && !done ; ++i )
{
g_selector = selectors[i];
g_jqContent = $(g_selector);
done = (g_jqContent.length === 1);
}
if (!done)
{
g_self.message = 'main :: No suitable selector';
return;
}
// span with all the new DOM elements
jqSpan = $(htmlString);
// checkbox checked, with handler
g_jqInput = jqSpan.children('input')
.prop('checked', true)
.click(onCheck);
// throbber, initially hidden
g_jqImg = jqSpan.children('img')
.hide();
// add span to h1
jqH1 = $('h1:first:visible'); // Minerva made me do it
if (jqH1.length !== 1)
{
g_self.message = 'main :: Problem with (h1:first:visible)';
g_jqInput = undefined;
g_jqImg = undefined;
return;
}
jqH1.append(jqSpan);
// done with DOM
g_hTimeout = window.setTimeout(onTick, getInterval());
g_self.message = 'OK';
});
return g_self;
}(mediaWiki, jQuery));