Skip to content
Snippets Groups Projects
personalize.js 9.46 KiB
Newer Older
  • Learn to ignore specific revisions
  • var entries = []; // list of news items
    
    var days   = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
                  "Friday", "Saturday"];
    var months = ["January", "February", "March", "April", "May", "June", "July",
                  "August", "September", "October", "November", "December"];
    
    // event complete: stop propagation of the event
    function stopPropagation(event) {
      if (event.preventDefault) {
        event.preventDefault();
        event.stopPropagation();
      } else {
       event.returnValue = false;
      }
    }
    
    // scroll back to the previous article
    function prevArticle(event) {
      var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      for (var i=entries.length; --i>=0;) {
        if (!entries[i].anchor) continue;
        if (entries[i].anchor.offsetTop < scrollTop) {
          window.location.hash=entries[i].anchor.id;
          stopPropagation(event);
          break;
        }
      }
    }
    
    // advance to the next article
    function nextArticle(event) {
      var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      for (var i=1; i<entries.length; i++) {
        if (!entries[i].anchor) continue;
        if (entries[i].anchor.offsetTop-20 >scrollTop) {
          window.location.hash=entries[i].anchor.id;
          stopPropagation(event);
          break;
        }
      }
    }
    
    // process keypresses
    function navkey(event) {
      var checkbox = document.getElementById('navkeys');
      if (!checkbox || !checkbox.checked) return;
    
      if (!event) event=window.event;
      if (event.originalTarget &&
        event.originalTarget.nodeName.toLowerCase() == 'input' &&
        event.originalTarget.id != 'navkeys') return;
    
      if (!document.documentElement) return;
      if (!entries[0].anchor || !entries[0].anchor.offsetTop) return;
    
      key=event.keyCode;
      if (key == 'J'.charCodeAt(0)) nextArticle(event);
      if (key == 'K'.charCodeAt(0)) prevArticle(event);
    }
    
    // create (or reset) a cookie
    function createCookie(name,value,days) {
      if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
      }
      else expires = "";
      document.cookie = name+"="+value+expires+"; path=/";
    }
    
    // read a cookie
    function readCookie(name) {
      var nameEQ = name + "=";
      if (!document.cookie) return;
      var ca = document.cookie.split(';');
      for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
      }
      return null;
    }
    
    // each time the value of the option changes, update the cookie
    function selectOption() {
      var checkbox = document.getElementById('navkeys');
      if (!checkbox) return;
      createCookie("navkeys", checkbox.checked?'true':'false', 365);
    }
    
    // add navkeys option to sidebar
    function addOption(event) {
      var sidebar = document.getElementById('sidebar');
      if (!sidebar) return;
    
      var h2 = null;
      for (var i=entries.length; --i>=0;) {
        if (document.getElementById("news-" + i)) break;
        if (entries[i].parent.offsetTop > 0) {
          var a = entries[i].anchor = document.createElement('a');
          a.id = "news-" + i;
          entries[i].parent.insertBefore(a, entries[i].parent.firstChild);
          if (h2 == null) h2 = document.createElement('h2');
        }
      }
    
      if (h2 != null && !document.getElementById("navkeys")) {
        h2.appendChild(document.createTextNode('Options'));
        sidebar.appendChild(h2);
    
        var form = document.createElement('form');
        var p = document.createElement('p');
        var input = document.createElement('input');
        input.type = "checkbox";
        input.id = "navkeys";
        p.appendChild(input);
        var a = document.createElement('a');
        a.title = "Navigate entries";
        a.appendChild(document.createTextNode('Enable '));
        var code = document.createElement('code');
        code.appendChild(document.createTextNode('J'));
        a.appendChild(code);
        a.appendChild(document.createTextNode(' and '));
        code = document.createElement('code');
        code.appendChild(document.createTextNode('K'));
        a.appendChild(code);
        a.appendChild(document.createTextNode(' keys'));
        p.appendChild(a);
        form.appendChild(p);
        sidebar.appendChild(form);
    
        var cookie = readCookie("navkeys");
        if (cookie && cookie == 'true') input.checked = true;
        input.onclick = selectOption;
        document.onkeydown = navkey;
      }
    }
    
    // Parse an HTML5-liberalized version of RFC 3339 datetime values
    Date.parseRFC3339 = function (string) {
        var date=new Date();
        date.setTime(0);
        var match = string.match(/(\d{4})-(\d\d)-(\d\d)\s*(?:[\sT]\s*(\d\d):(\d\d)(?::(\d\d))?(\.\d*)?\s*(Z|([-+])(\d\d):(\d\d))?)?/);
        if (!match) return;
        if (match[2]) match[2]--;
        if (match[7]) match[7] = (match[7]+'000').substring(1,4);
        var field = [null,'FullYear','Month','Date','Hours','Minutes','Seconds','Milliseconds'];
        for (var i=1; i<=7; i++) if (match[i]) date['setUTC'+field[i]](match[i]);
        if (match[9]) date.setTime(date.getTime()+
            (match[9]=='-'?1:-1)*(match[10]*3600000+match[11]*60000) );
        return date.getTime();
    }
    
    // convert datetime to local date
    var localere = /^(\w+) (\d+) (\w+) \d+ 0?(\d\d?:\d\d):\d\d ([AP]M) (EST|EDT|CST|CDT|MST|MDT|PST|PDT)/;
    function localizeDate(element) {
      var date = new Date();
      date.setTime(Date.parseRFC3339(element.getAttribute('datetime')));
      if (!date.getTime()) return;
    
      var local = date.toLocaleString();
      if (element.parentNode.nodeName == 'a') local = date.toLocaleTimeString();
      var match = local.match(localere);
      if (match) { /* Firefox */
        element.innerHTML = match[4] + ' ' + match[5].toLowerCase();
        element.title = match[6] + " \u2014 " + 
          match[1] + ', ' + match[3] + ' ' + match[2];
        return days[date.getDay()] + ', ' + months[date.getMonth()] + ' ' +
          date.getDate() + ', ' + date.getFullYear();
      } else {
        local = local.replace(/ GMT(-\d\d\d\d) \(.*\)$/, ''); /* Webkit */
        element.title = element.innerHTML + ' GMT';
        element.innerHTML = local;
        return days[date.getDay()] + ', ' + date.getDate() + ' ' +
          months[date.getMonth()] + ' ' + date.getFullYear();
      }
    
    }
    
    // find entries (and localizeDates)
    function findEntries() {
    
      var times = document.getElementsByTagName('time');
       
      for (var i=0; i<times.length; i++) {
        if (times[i].title == "GMT") {
          var date = localizeDate(times[i]);
    
          var parent = times[i];
          while (parent && 
            (!parent.className || parent.className.split(' ')[0] != 'news')) {
            parent = parent.parentNode;
          }
    
          if (parent) {
            var info = entries[entries.length] = new Object();
            info.parent   = parent;
            info.date     = date;
            info.datetime = times[i].getAttribute('datetime').substring(0,10);
          }
        }
      }
    
    }
    
    // insert/remove date headers to indicate change of date in local time zone
    function moveDateHeaders() {
      var lastdate = ''
      for (var i=0; i<entries.length; i++) {
        var parent = entries[i].parent;
        var date = entries[i].date;
    
        sibling = parent.previousSibling;
        while (sibling && sibling.nodeType != 1) {
           sibling = sibling.previousSibling;
        }
    
        if (sibling && sibling.nodeName.toLowerCase() == 'h2') {
          if (lastdate == date) {
            sibling.parentNode.removeChild(sibling);
          } else {
            sibling.childNodes[0].innerHTML = date;
            sibling.childNodes[0].setAttribute('datetime',entries[i].datetime);
            lastdate = date;
          }
        } else if (lastdate != date) {
          var h2 = document.createElement('h2');
          var time = document.createElement('time');
          time.setAttribute('datetime',entries[i].datetime);
          time.appendChild(document.createTextNode(date));
          h2.appendChild(time);
          parent.parentNode.insertBefore(h2, parent);
          lastdate = date;
        }
      }
    }
    
    function moveSidebar() {
      var sidebar = document.getElementById('sidebar');
      if (sidebar.currentStyle && sidebar.currentStyle['float'] == 'none') return;
      if (window.getComputedStyle && document.defaultView.getComputedStyle(sidebar,null).getPropertyValue('float') == 'none') return;
    
      var h1 = sidebar.previousSibling;
      while (h1.nodeType != 1) h1=h1.previousSibling;
      if (h1.nodeName.toLowerCase() == 'h1') h1.parentNode.removeChild(h1);
    
      var footer = document.getElementById('footer');
      var ul = footer.lastChild;
      while (ul.nodeType != 1) ul=ul.previousSibling;
    
      var twisty = document.createElement('a');
      twisty.appendChild(document.createTextNode('\u25bc'));
      twisty.title = 'hide';
      twisty.onclick = function() {
        var display = 'block';
        if (this.childNodes[0].nodeValue == '\u25ba') {
          this.title = 'hide';
          this.childNodes[0].nodeValue = '\u25bc';
        } else {
          this.title = 'show';
          this.childNodes[0].nodeValue = '\u25ba';
          display = 'none';
        }
        ul.style.display = display;
        createCookie("subscriptions", display, 365);
      }
    
      var cookie = readCookie("subscriptions");
      if (cookie && cookie == 'none') twisty.onclick();
    
      for (var node=footer.lastChild; node; node=footer.lastChild) {
        if (twisty && node.nodeType == 1 && node.nodeName.toLowerCase() == 'h2') {
          node.appendChild(twisty);
          twisty = null;
        }
        footer.removeChild(node);
        sidebar.insertBefore(node, sidebar.firstChild);
      }
    
      var body = document.getElementById('body');
      sidebar.parentNode.removeChild(sidebar);
      body.parentNode.insertBefore(sidebar, body);
      body.style.marginRight = 0;
    }
    
    // adjust dates to local time zones, optionally provide navigation keys
    function personalize() {
      moveSidebar();
      findEntries(); 
      addOption();
      moveDateHeaders();
    }
    
    // hook event
    document.addEventListener("DOMContentLoaded", personalize, false);