User:Tfdyrtswa3w4se5dr/fastload.js

This is an archived version of this page, as edited by Tfdyrtswa3w4se5dr (talk | contribs) at 11:08, 5 July 2015. It may differ significantly from the current version.

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// Fastload for Wikipedia
// Released under CC0 1.0 Public Domain Dedication.
// https://creativecommons.org/publicdomain/zero/1.0/

// Known Bugs:
// 1. Discussion tag directs to "Talk:Talk:Page_title".
// 2. Link to edit first summary paragraph is incorrect.

/* jshint boss: true */

(function(doc, undefined){
  'use strict';
  
  // No support for Internet Explorer 9 or lower without a polyfill.
  if (!history.___pushState || !localStorage) return null;
  
  // Removes old cache
  localStorage.clear();
  
  // Check Mobile
  var isMobile = /Android|iPhone|iPad|iPod|IEMobile/i.test(navigator.userAgent);
  
  // Query Selectors
  var $ = function (query) { return doc.querySelector(query); };
  $.id = function (query) { return doc.getElementById(query); };
  
  var endpoint = '/w/index.php';
  
  var urlBase = ___location.protocol + '//' + ___location.host + endpoint +
     '?action=render&title=';
     
  var noop = function () {};
       
  var Page = {
    content: $.id('content'),
    container: $.id('bodyContent'),
    firstHeading: $.id('firstHeading'),
  };
  
  var Tabs = {
    main: $('#ca-nstab-main a'),
    edit: $('#ca-edit a'),
    move: $('#ca-move a'),
    history: $('#ca-history a'),
    discussion: $('#ca-talk a'),
    star: $('#ca-watch a')
  };
  
  
  var attr = function (element, name, value) {
    element.setAttribute(name, 
      (typeof value === 'function') ?
         value(element.getAttribute(name)) : value );
  };
  
  var Indicator = {
    loading: function () {
      Page.content.style.opacity = 0.75;
    },
    reset: function () {
      Page.content.style.opacity = null;
    }
  };
  
  // AJAX utility
  var ajax = function (url, callback, error) {
    var req = new XMLHttpRequest();
    req.onreadystatechange = function () {
      if (req.readyState == 4 && req.status == 200)
        callback(req.responseText);
    };
    req.onerror = error;
    req.open("GET", url, true);
    req.send();
  };
  
  ajax.prefixCache = 'fastload-';
  
  ajax.cache = function (url, callback, error) {
    var cache;
    if (cache = localStorage.getItem(ajax.prefixCache + url)) {
      callback(cache);
    } else {
      ajax(url, function (data) {
        callback(data);
        try {
        	localStorage.setItem(ajax.prefixCache + url, data);
        } catch (e) {
        	localStorage.clear();
        	localStorage.setItem(ajax.prefixCache + url, data);
        }
      }, error);
    }
  };
  
  // Updates Cache Now
  localStorage.setItem(ajax.prefixCache + urlBase + mw.config.values.wgTitle, Page.container.innerHTML);
  
  // Writes Wikitext to DOM
  var updateDom = function (data, title, pageName) {
    Page.container.innerHTML = data;
    Page.firstHeading.childNodes[0].nodeValue = title;
    
    var oldClassName = doc.body.className.match(/(?! |^)page-[^ ]+/);
    doc.body.classList.remove(oldClassName[0]);
    doc.body.classList.add('page-' + pageName);
    
    try {
      attr(Tabs.main,       'href', '/wiki/' + pageName);
      attr(Tabs.discussion, 'href', '/wiki/Talk:' + pageName);
      attr(Tabs.edit,       'href', endpoint + '?title=' + pageName + '&action=edit');
      attr(Tabs.history,    'href', endpoint + '?title=' + pageName + '&action=history');
      attr(Tabs.move,       'href', '/wiki/Special:MovePage/' + pageName);
      attr(Tabs.star,       'href', function (link) {
        return link.replace(/title=[^&]+/, 'title=' + pageName);
      });
    } catch (e) { }
    
    doc.title = title + ' — Wikipedia';
    doc.body.scrollTop = 0;
  };
  
  // Loads when Hover
  var delay;
  var eventName = isMobile ? 'touchstart' : 'mouseover';
  Page.container.addEventListener(eventName, function (event) {
    if (delay) {
      clearTimeout(delay);
      delay = null;
    } else {
      delay = setTimeout(function(){
        var target = event.target, href = target.getAttribute('href');
        delay = null;

        // Ignore unless clicked on a /wiki/ link.
        if (!target || target.tagName !== 'A' || href.indexOf('/wiki/') == -1) 
          return true;
        
        var pageName = href.replace(/^(\/\/[^\/]+)?\/wiki\//, '');
        
        ajax.cache(urlBase + pageName, noop, noop);
        
      }, 475);
    }
    
  });
  
  Page.container.addEventListener('click', function (event) {
    var target = event.target, href = target.getAttribute('href');
    
    // Ignore unless clicked on a /wiki/ link.
    if (!target || target.tagName !== 'A' || href.indexOf('/wiki/') == -1) 
      return true;
    
    var pageName = href.replace(/^(\/\/[^\/]+)?\/wiki\//, '');
    var title = target.getAttribute('title');
    
    Indicator.loading();
    event.preventDefault();
    
    ajax.cache(urlBase + pageName, function (data) {
      setTimeout(function () { 
      	updateDom(data, title, pageName); 
      	Indicator.reset(); 
      }, 100);
      history.___pushState({
        pageName: pageName, 
        title: title, 
        url: href
      }, title, href);
    }, function () {
      window.___location.href = href;
    });
  });
  
  var currentPath = null;
  
  window.onpopstate = function (event) {
    var state = event.state;
    if (currentPath !== ___location.href) {
      currentPath = ___location.href;
      if (state && state.pageName) {
        ajax.cache(urlBase + state.pageName, function (data) {
          updateDom(data, state.title, state.pageName);
        });
      } else {
        window.___location = ___location.href;
      }
      
    }
  };
  
})(document);