tooltip_tweet_localtime

By touta Last update Nov 9, 2009 — Installed 99 times.

There are 10 previous versions of this script.

// ==UserScript==
// @name           tooltip_tweet_localtime
// @namespace      http://twitter.com/towtter
// @description    Adds local time tool tip to each tweet
// @include        http://twitter.com/*
// @exclude        http://twitter.com/account/*
// @exclude        http://twitter.com/following
// @exclude        http://twitter.com/followers
// @exclude        http://twitter.com/login
// @exclude        http://twitter.com/invitations/find*
// ==/UserScript==

// strftime function has almost same features as C language, but not support %B %A %j %U %W
function strftime(form, date){
  var WDAYNAMES = {
    'Sun':0,'Mon':1,'Tue':2,'Wed':3,'Thu':4,'Fri':5,'Sat':6
  };
  var MONTHNAMES = {
    'Jan':0,'Feb':1,'Mar':2,'Apr':3,'May':4,'Jun':5,
    'Jul':6,'Aug':7,'Sep':8,'Oct':9,'Nov':10,'Dec':11
  };
  var dt = date.toString().split(/[\s:]/);
  var wDay = dt[0], aMon = dt[1], day = dt[2], year = dt[3], hour = dt[4], min = dt[5], sec = dt[6];
  var formats = [];
  var result = '';
  var i=0;
  var format = '';
  while (i < form.length) {
    var c = form.charAt(i);
    if (c == '%') {
      format = c;
      i += 1;
      c = form.charAt(i);
      if (c.match(/[a-zA-Z]+/)){
        format += c;
        formats.push(format);
        i += 1;
        continue;
      }
    } else {
      formats.push(c);
    }
    i += 1;
  }

  for (i=0; i<formats.length; i++){
    format = formats[i];
    switch (format) {
    case '%a': 
      result += wDay;
      break;
    case '%b': 
      result += aMon;
      break;
    case '%c': 
      result += day + ' ' + hour + ":" + min + ":" + sec;
      break;
    case '%d': 
      result += day;
      break;
    case '%H': 
      result += hour;
      break;
    case '%I':
      var h = Number(hour);
      if (h > 12) result += (h - 12);
      else if (h == 0) result += (h + 12);
      else result += h;
      break;
    case '%m':
      var m = MONTHNAMES[aMon] + 1;
      if (m < 10) result += '0' + m;
      else result += m;
      break;
    case '%M': result += min;
      break;
    case '%p':
      if (hour >= 12) result += "PM";
      else result += "AM";
      break;
    case '%S': 
      result += sec;
      break;
    case '%w':
      result += WDAYNAMES[wDay];
      break;
    case '%x':
      result += day + "/" + mon + "/" + year.substring(2, 4);
      break;
    case '%X':
      var h = Number(hour);
      if (h >= 12) {
        if (h > 12) result += (h - 12) + ":" + min + " PM";
        else result += h + ":" + min + " PM";
      }
      else {
        if (h == 0) result += (h + 12) + ":" + min + " AM";
        else result += h + ":" + min + " AM";
      }
      break;
    case '%y': result += year.substring(2, 4);
      break;
    case '%Y': result += year;
      break;
    default :
      result += format;
    }
  }
  return result;
}
function formatDigit(x, digit){
  var fmt = x.toString();
  var i = fmt.lastIndexOf('.');
  if (i > 0){
    fmt = fmt.substring(0, i+digit+1);
  }
  return fmt;
}
TwitterUserProfile = {
  data: {},
  user_cache: {},
  access_id: '',
  is_user_page: false,
  dateformat: '%a %X %b %d',
  DST: {
    "Alaska|Pacific Time|Arizona|Mountain Time|Central Time|Eastern Time|Indiana" :{
      start_dst : { month : 2, nth : 2, hour : 2, wday : 'Sun' 
        },
      end_dst   : { month : 10, nth : 1, hour : 2, wday : 'Sun' 
        }
    },
    "Dublin|Edinburgh|Lisbon|London|Monrovia" : {
      start_dst : { month : 2, nth : -1, hour : 1, wday : 'Sun' 
        },
      end_dst   : { month : 9, nth : -1, hour : 1, wday : 'Sun' 
        }
    },
    "Amsterdam|Belgrade|Berlin|Bern|Bratislava|Brussels|Budapest|Copenhagen|Ljubljana|Madrid|Paris|Prague|Rome|Sarajevo|Skopje|Stockholm|Vienna|Warsaw|West Central Africa|Zagreb" : {
      start_dst : { month : 2, nth : -1, hour : 1, wday : 'Sun' 
        },
      end_dst   : { month : 9, nth : -1, hour : 1, wday : 'Sun' 
        }      
    },
    "Baghdad|Kuwait|Moscow|Nairobi|Riyadh|St\. Petersburg|Volgograd" : {
      start_dst : { month : 2, nth : -1, hour : 1, wday : 'Sun' 
        },
      end_dst   : { month : 9, nth : -1, hour : 1, wday : 'Sun' 
        }
    },
    "Newfoundland" : {
      start_dst : { month : 3, nth : 1, hour : 2, wday : 'Sun' 
        },
      end_dst   : { month : 9, nth : -1, hour : 2, wday : 'Sun' 
        }      
    }
  },
  getUserProfile: function(id, status_id, pt){
    if (this.user_cache[id] != undefined){
      this.renderLocalTime(id, status_id, pt);
    } else {
      this.access_id = id;
      GM_xmlhttpRequest({
        method: 'GET',
        url: 'http://www.twitter.com/users/show/' + id + '.json',
        onload : function (response){
          TwitterUserProfile.processProfile(response.responseText);
          if (TwitterUserProfile.is_user_page) TwitterUserProfile.dispUsersProfile(TwitterUserProfile.data);
          if ((status_id) && (pt)) TwitterUserProfile.renderLocalTime(id, status_id, pt);
        }
      });        
    }
  },
  // evaluate json object and caching user data
  processProfile: function(response){
    eval("var obj=" + response);
    for (name in obj) {
      this.data[name] = obj[name];
    }
    var utc_offset = 0;
    var time_diff = '';
    if (this.data['utc_offset'] != null)
      utc_offset = parseInt(this.data['utc_offset']);
    this.user_cache[this.access_id] = {
      utc_offset: 0,
      time_zone: ''
    };
    this.user_cache[this.access_id].utc_offset = utc_offset;
    this.user_cache[this.access_id].time_zone = this.data['time_zone'];
  },
  // rendering local time
  renderLocalTime : function(id, status_id, pt) {
    var spanTags = document.getElementById(status_id).getElementsByTagName("span");
    for (var i = 0; i < spanTags.length; i++) {
      if (spanTags[i].className == 'published timestamp'){
        var pbtime = spanTags[i];
        break;
      }
    }
    if (pbtime.getAttribute('title')) return;
    var utc_offset = 0;
    var time_zone = '';
    var time_diff = '';
    utc_offset = parseInt(this.user_cache[id].utc_offset);
    time_zone = this.user_cache[id].time_zone;
    var utc = Date.parse(pt);
    var local = new Date();
    utc = utc +  local.getTimezoneOffset() * 60 * 1000 + utc_offset * 1000;
    local.setTime(utc);
    for (var dst in this.DST) {
      var re = new RegExp(dst);
      if ((time_zone) && (time_zone.match(re))){
        var d = this.DST[dst];
        if (this.isdst(local, d)) {
          utc = utc + 3600 * 1000;
          utc_offset = utc_offset + 3600;
          break;
        }
      }
    }
    local.setTime(utc);
    time_diff = local.getTimezoneOffset() / 60 + utc_offset / 3600;
    var time_diff_min = 0;
    if (time_diff < 0) {
      time_diff_min = Math.abs(time_diff) + Math.ceil(time_diff);
      time_diff = time_diff + time_diff_min;
    }
    else {
      time_diff_min = Math.abs(time_diff) - Math.floor(time_diff);
      time_diff = time_diff - time_diff_min;            
    }
    time_diff_min = time_diff_min * 60;
    if (time_diff_min < 10) time_diff_min = "0" + time_diff_min;
    if (time_diff >= 0) time_diff = "+" + time_diff;
    time_diff = time_diff + ":" + time_diff_min;
    var local_time = strftime(this.dateformat, local);
    if ((time_diff != '') && (time_diff != '+0:00')) local_time = local_time + " (" + time_diff + ")";
    if (time_zone != '') 
      local_time = local_time + " [" + time_zone + "]";
    local_time = 'Local Time:' + local_time;
    pbtime.setAttribute("title", local_time);
  },
  dispUsersProfile: function(profile){
    var start_date = Date.parse(profile.created_at);
    var _now = new Date();
    var user_days = (_now.getTime() - start_date) / 1000 / 3600 / 24;
    var side_profile = document.getElementById("side").getElementsByTagName("div")[0];
    var tbl = side_profile.getElementsByTagName("table")[0];
    var row = tbl.getElementsByTagName("tr")[0];
    if (row){
      var td = null;
      td = document.getElementById("days_twitter_following");
      if (!td) {
        td = document.createElement("td");
        td.id = "days_twitter_following";
        var date_text = document.createElement("span");
        date_text.className = "stats_count numeric";
        date_text.innerHTML = Math.ceil(user_days);
        var date_lbl = document.createElement("span");
        date_lbl.className = "label";
        date_lbl.style.fontSize = "8px";
        date_lbl.innerHTML = "days<br/>follow twitter";
        td.appendChild(date_text);
        td.appendChild(date_lbl);
        row.appendChild(td);
        var update_count = document.getElementById("update_count");
        var count = update_count.innerHTML;
        var ave = profile.statuses_count / user_days;
        if (ave < 1){
          ave = user_days / profile.statuses_count;
          ave = Math.ceil(ave);
          count += ' (1/' + ave + 'day)'; 
        } else {
          count += ' (' + formatDigit(ave, 1) + '/day)';
        }
        update_count.innerHTML = count;
      }
    }

  },
  isdst: function(t, dst) {
    var this_year = new Date().getFullYear();
    var start_dst = dst["start_dst"];
    var end_dst = dst["end_dst"];
    var dst_start = this.getDateOfNumberOfWday(this_year, start_dst.month, start_dst.wday, start_dst.nth);
    var dst_end = this.getDateOfNumberOfWday(this_year, end_dst.month, end_dst.wday, end_dst.nth);
    if ((t.getMonth() >= dst_start.getMonth()) && (t.getMonth() <= dst_end.getMonth())) {
      if (t.getMonth() == dst_start.getMonth()){
        var judge = t.getDate() - dst_start.getDate();
        if (judge > 0) return true;
        if (judge < 0) return false;
        if (t.getHours() < start_dst.hour) return false;
      } else if ((t.getMonth() == dst_end.getMonth())) {
        var judge = t.getDate() - dst_end.getDate();
        if (judge < 0) return true;
        if (judge > 0) return false;
        if ((t.getHours() + 1) >= end_dst.hour) return false;
      }
      return true;
    }
  },
  getDateOfNumberOfWday: function(year, month, wday, n) {
    var d = new Date(year, month, 1);
    var getWday = function(date){
      return date.toString().split(/[\s:]/)[0];
    };
    var nextMonth = d.getMonth() < 11 ? d.getMonth() + 1 : 0;
    var m = d.getMonth();
    var i = 1;
    for (;;){
      if (getWday(d) == wday) {
        if (i == n){
          return d;
        } else {
          i += 1;
          d.setDate(d.getDate() + 7);
          if ((n == -1) && (d.getMonth() == nextMonth)){
            d.setDate(d.getDate() - 7);
            return d;
          }
          continue;
        }
      }
      d.setDate(d.getDate() + 1);
      if (d.getMonth() == nextMonth) break;
    }
  }
};

(function(){
   var statuses = [];
   var loc_user_name = '';
   function init(){
     var loc = window.location.toString();
     if (loc.match(/http:\/\/twitter\.com\/([^\/]+\/?)(.*)/)) {
       TwitterUserProfile.is_user_page = true;
       loc_user_name = RegExp.$1;
       if (loc_user_name[loc_user_name.length-1] == "/") {
         TwitterUserProfile.is_user_page = false;
         loc_user_name = loc_user_name.substring(0, loc_user_name.length-1);
       }
       if (loc_user_name.match(/following|followers|login/)){
         loc_user_name = "";
         TwitterUserProfile.is_user_page = false;
       }
       var path = RegExp.$2;
       if (path.match(/\w+/)){
         loc_user_name = "";
         TwitterUserProfile.is_user_page = false;
       }
     }
     if (loc_user_name != "") {
       TwitterUserProfile.getUserProfile(loc_user_name);
     }
     allocEvent();
   }

   function allocEvent(){
     var spanTags = document.getElementsByTagName("span");
     for (var i = 0; i < spanTags.length; i += 1) {
       var span = spanTags[i];
       if (span.className == "published timestamp") {
         if ((span) && (span.addEventListener)) {
           var status_id = span.parentNode.parentNode.parentNode.parentNode.id;
           // prevent to add duplicate event
           if (statuses.indexOf(status_id) == -1){
             span.addEventListener("mouseover", function(e){return show_time(e, loc_user_name);}, false);             
             statuses.push(status_id);
           }
         }
       }
     }     
   }

   function show_time(e, loc_user_name){
     var tstamp = eval(e.target.getAttribute("data"));
     if (loc_user_name == '') {
       var status = e.target.parentNode.parentNode.parentNode;
       var un = status.getElementsByTagName("strong")[0];
       if (un){
         var user_name = un.getElementsByTagName("a")[0].text;
       }    
     } else {
       var user_name = loc_user_name;
     }
     var status_id = e.target.parentNode.parentNode.parentNode.parentNode.id;
     TwitterUserProfile.getUserProfile(user_name, status_id, tstamp);
   }

   function monitor(){
     if (document.getElementsByClassName ('meta entry-meta').length != statuses.length){
       allocEvent();
     }
     setTimeout (monitor, 200);     
   }

   init();

   setTimeout (monitor, 200);

})();