Jump to content

User:Unready/ui.refresh.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Unready (talk | contribs) at 11:37, 27 April 2015 (Version 1.0.1: Bug fix - ignore timeout events if checkbox is unchecked). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/*
 * Description:
 * Refresh page content periodically
 *
 * Version 1.0: 27 April 2015
 *   Original version for Wikipedia use
 *
 * License: CC-BY-SA
 *   http://creativecommons.org/licenses/by-sa/3.0/
 */

((window.user = window.user || {}).ui = window.user.ui || {}).refresh =
(function ($)
{
  'use strict';

  // Based on Special:RecentChanges & Special:Watchlist
  //   div#bodyContent.mw-body-content
  //   div#mw-content-text
  //   div.mw-changeslist
  // id bodyContent and mw-content-text seem to be usable options
  // class mw-body-content and mw-changeslist may be Wikipedia-only
  var g_ContentID = 'mw-content-text';

  var g_self,
      g_interval = 120, // default refresh interval (seconds)
      g_domContent,
      g_domInput, g_domIMG,
      g_request,
      g_idTimeout = -1; // cannot run = -1; okay to run = 0; running > 0

  // init g_self before document.ready
  //   in case document.ready executes immediately
  g_self =
  {
    message : 'Initializing',
    version : 'Version 1.0.1: 27 April 2015'
  };

  // process checkbox events
  function onCheck()
  {
    if (g_domInput.checked)
    {
      if (g_idTimeout === 0)
      { // start refreshing
        g_idTimeout = window.setTimeout(onTick, g_interval * 1000);
        g_self.message = 'OK';
      }
    }
    else
    {
      if (g_idTimeout > 0)
      { // try to stop the next tick, although it may already be too late
        window.clearTimeout(g_idTimeout);
        g_idTimeout = 0;
        g_self.message = 'Stopped';
      }
    }
  }

  // process GET return
  function onReady()
  {
    var domString = g_request.responseText,
        domNewContent,
        domList,
        domTop,
        i;

    // strip off doctype tag
    domString = domString.replace(/^\s*<![^>]*>\s*/, '');
    // strip off html tags
    domString = domString.replace(/^\s*<\s*html[^>]*>\s*/i, '');
    domString = domString.replace(/\s*<\s*\/html[^>]*>\s*$/i, '');
    // strip off head (and hope there's no quoted </head>)
    // use search, because it seems match could be too big for replace
    i = domString.search(/<\s*\/head[^>]*>/i);
    if (i !== -1)
    {
      domString = domString.substr(i);
      domString = domString.replace(/^.*<\s*\/head[^>]*>\s*/i, '');
    }
    // strip off body tags
    domString = domString.replace(/^\s*<\s*body[^>]*>\s*/i, '');
    domString = domString.replace(/\s*<\s*\/body[^>]*>\s*$/i, '');
    // force it to parse
    domTop = document.createElement('body');
    domTop.innerHTML = domString;
    domList = domTop.getElementsByTagName('div');
    for (i in domList)
    {
      if (domList[i].id === g_ContentID)
      {
        domNewContent = domList[i];
      }
    }
    if (!domNewContent)
    {
      g_self.message = 'onReady :: unable to parse new content';
      return;
    }
    // replace content
    domTop = g_domContent.parentNode;
    domTop.replaceChild(domNewContent, g_domContent);
    g_domContent = domNewContent;
    // hide the throbber
    g_domIMG.setAttribute('style', 'display:none;');
    // set timer
    g_idTimeout = window.setTimeout(onTick, g_interval * 1000);
  }

  // wait until request completes
  function onChange()
  {
    if (g_request.readyState === 4)
    {
      g_request.onreadystatechange = undefined;
      if (g_request.status === 200)
      {
        onReady();
      }
      else
      {
        g_self.message = 'onChange :: GET returned "' +
          g_request.statusText + '"';
      }
    }
  }

  // process timeout events
  function onTick()
  { // ignore the event if the box isn't checked
    if (g_domInput.checked)
    { // show the throbber
      g_domIMG.removeAttribute('style');
      // use window.location.href, to include GET parameters
      g_request.open(
        'GET',
        window.location.href,
        true);
      g_request.onreadystatechange = onChange;
      g_request.send();
    }
  }

  $(function main()
  {
    var domH1,
        domSpan, domChild,
        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('');

    g_domContent = document.getElementById(g_ContentID); // div
    if (!g_domContent)
    {
      g_self.message = 'main :: No element found with ID ' + g_ContentID;
      return;
    }
    if (window.XMLHttpRequest)
    { // most browsers
      g_request = new XMLHttpRequest();
    }
    else
    {
      g_self.message = 'main :: Unable to create XMLHttpRequest';
      return;
    }
    // span to contain all new DOM elements
    domSpan = document.createElement('span');
    domSpan.setAttribute
    (
      'style',
      'font-size: 40%; margin: 5px; vertical-align: middle;'
    );
    // label for checkbox
    domChild = document.createElement('label');
    domChild.setAttribute('for', 'ui-refresh-input');
    domChild.setAttribute('title', 'Enable auto-refresh');
    domChild.setAttribute('style', 'border-bottom: 1px dotted;');
    domChild.innerHTML = 'Auto-refresh:';
    domSpan.appendChild(domChild.cloneNode(true));
    // checkbox
    domChild = document.createElement('input');
    domChild.setAttribute('id', 'ui-refresh-input');
    domChild.setAttribute('type', 'checkbox');
    domChild.setAttribute('style', 'vertical-align: middle;');
    domChild.checked = true;
    g_domInput = domChild.cloneNode(true);
    domSpan.appendChild(g_domInput);
    // add checkbox event listener
    if (document.addEventListener)
    { // for most browsers, except IE 8 and earlier
      g_domInput.addEventListener('click', onCheck);
    }
    else if (document.attachEvent)
    { // for IE 8 and earlier
      g_domInput.attachEvent('onclick', onCheck);
    }
    else
    {
      g_self.message = 'main :: Unable to add event listener';
      return;
    }
    // throbber, initially hidden
    domChild = document.createElement('img');
    domChild.setAttribute('src', uriData);
    domChild.setAttribute('alt', 'Refreshing page');
    domChild.setAttribute('style', 'display:none;');
    g_domIMG = domChild.cloneNode(true);
    domSpan.appendChild(g_domIMG);
    // add span to h1
    domH1 = document.getElementById('firstHeading');
    if (!domH1)
    {
      g_self.message = 'main :: No element found with ID firstHeading';
      return;
    }
    domH1.appendChild(domSpan);
    // done with DOM
    g_idTimeout = window.setTimeout(onTick, g_interval * 1000);
    g_self.message = 'OK';
  });

  return g_self;
}(jQuery));