// Twatter, by Kent Brewster
// https://github.com/kentbrew/twatter
// Remember when you could roll your own Twitter timelines? You still can.
(function (w, d, a) {
var $ = w[a.k] = {
'w': w,
'd': d,
'a': a,
'v': {'css': ''},
'f': (function () {
return {
newLink: function (href, innerHTML) {
var a = $.d.createElement('A');
a.href = href;
a.target = '_blank',
a.innerHTML = innerHTML;
return a;
},
targetBlank: function (a) {
a.target = '_blank';
},
ping: function (r) {
var s = $.d.getElementById($.a.k + '_ping');
s.parentNode.removeChild(s);
if (r.body) {
// we have an HTML fragment; render it and let the DOM sort things out
var temp = $.d.createElement('SPAN');
temp.innerHTML = r.body;
// master tweet list
var ol = temp.getElementsByTagName('OL')[0];
// tweets
var li = ol.getElementsByTagName('LI');
for (var i = 0; i < li.length; i = i + 1) {
// some list items belong to sublists; don't use them
if (li[i].parentNode === ol) {
// tweet head
var hd = li[i].getElementsByTagName('DIV')[0];
var a = hd.getElementsByTagName('A');
for (var n = a.length - 1, j = n; j > -1; j = j - 1) {
var scribe = a[j].getAttribute('data-scribe');
switch(scribe) {
case 'element:user_link':
/*
// avatar
var img = a[j].getElementsByTagName('IMG')[0];
var avatarLink = $.d.createElement('A');
avatarLink.className = $.a.k + '_avatarlink';
avatarLink.href = a[j].href;
$.f.targetBlank(avatarLink);
avatarLink.target = '_blank';
var avatarImage = $.d.createElement('IMG');
avatarImage.className = $.a.k + '_avatarImage';
avatarImage.src = img.getAttribute('data-src-1x');
avatarLink.appendChild(avatarImage);
*/
// name, nick, and link
var spans = a[j].getElementsByTagName('SPAN');
var nameLink = $.d.createElement('A');
nameLink.className = $.a.k + '_nameLink';
// var name = $.d.createElement('SPAN');
// name.innerHTML = spans[0].innerHTML;
// nameLink.appendChild(name);
nameLink.appendChild($.d.createTextNode('@' + a[j].href.split('/').pop()));
nameLink.href = a[j].href;
$.f.targetBlank(nameLink);
break;
case 'element:mini_timestamp':
// link timestamp to individual status page
var timeLink = $.d.createElement('A');
timeLink.className = $.a.k + '_timeLink';
timeLink.innerHTML = a[j].innerHTML;
timeLink.href = a[j].href;
$.f.targetBlank(timeLink);
break;
}
}
// tweet body
var p = li[i].getElementsByTagName('P')[0];
var a = p.getElementsByTagName('A');
for (var n = a.length - 1, j = n; j > -1; j = j - 1) {
var scribe = a[j].getAttribute('data-scribe');
switch(scribe) {
case 'element:url':
p.insertBefore($.f.newLink(a[j].title, a[j].title.split('/')[2]), a[j]);
break;
case 'element:mention':
p.insertBefore($.f.newLink(a[j].href, '@' + a[j].getElementsByTagName('B')[0].innerHTML), a[j]);
break;
case 'element:hashtag':
p.insertBefore($.f.newLink(a[j].href, '#' + a[j].getElementsByTagName('B')[0].innerHTML), a[j]);
break;
default:
}
}
var a = p.getElementsByTagName('A');
for (var n = a.length - 1, j = n; j > -1; j = j - 1) {
var scribe = a[j].getAttribute('data-scribe');
var embed = a[j].getAttribute('data-pre-embedded');
if (scribe || embed) {
p.removeChild(a[j]);
}
}
var span = $.d.createElement('SPAN');
span.className = 'content';
span.innerHTML = p.innerHTML;
var out = $.d.createElement('LI');
out.className = $.a.k + '_item';
// out.appendChild(avatarLink);
var container = $.d.createElement('SPAN');
container.appendChild(nameLink);
container.appendChild(span);
container.appendChild(timeLink);
out.appendChild(container);
$.s.appendChild(out);
}
}
}
},
makeStyleFrom: function (obj, str) {
// make CSS rules
var name, i, k, pad, rules = '', selector = str || '';
for (k in obj) {
if (obj[k].hasOwnProperty) {
// found a rule
if (typeof obj[k] === 'string') {
rules = rules + k + ': ' + obj[k] + '; ';
}
}
}
// add selector and rules to stylesheet
if (selector && rules) {
$.v.css = $.v.css + selector + ' { ' + rules + '}\n';
}
// any children we need to handle?
for (k in obj) {
if (obj[k].hasOwnProperty) {
if (typeof obj[k] === 'object') {
// found a selector
name = k.split(', ');
// handle multiple selector names
for (i = 0; i < name.length; i = i + 1) {
pad = '';
// & means "add this to my parent selector"
if (name[i].match(/^&/)) {
name[i] = name[i].split('&')[1];
} else {
if (selector) {
pad = ' ';
}
}
// beat until stiff
$.f.makeStyleFrom(obj[k], selector + pad + name[i].replace(/^\s+|\s+$/g,""));
}
}
}
}
},
// build stylesheet
presentation : function (rules) {
var css, rules;
css = $.d.createElement('STYLE');
css.type = 'text/css';
// each rule has our key at its root to minimize style collisions
rules = rules.replace(/#_/g, '#' + a.k + '_');
rules = rules.replace(/\._/g, '.' + a.k + '_');
// add rules to stylesheet
if (css.styleSheet) {
css.styleSheet.cssText = rules;
} else {
css.appendChild($.d.createTextNode(rules));
}
// add stylesheet to page
if ($.d.h) {
$.d.h.appendChild(css);
} else {
$.d.b.appendChild(css);
}
},
structure: function (script) {
var widgetId = script.getAttribute('data-widget-id');
var structureId = script.getAttribute('data-structure-id');
if (widgetId && structureId) {
$.s = $.d.getElementById(structureId);
if ($.s) {
$.s.className = $.a.k + '_list';
var s = $.d.createElement('SCRIPT');
s.setAttribute('charset', 'utf-8');
s.id = $.a.k + '_ping';
s.src = $.a.endpoint + widgetId + '?callback=' + $.a.k + '.f.ping';
$.d.b.appendChild(s);
}
}
},
init : function () {
$.d.h = $.d.getElementsByTagName('HEAD')[0];
$.d.b = $.d.getElementsByTagName('BODY')[0];
var script = $.d.getElementsByTagName('SCRIPT'), n = script.length, i;
for (i = 0; i < n; i = i + 1) {
if (script[i].src && script[i].src.match($.a.me)) {
$.f.structure(script[i]);
$.f.makeStyleFrom($.a.rules);
$.f.presentation($.v.css);
script[i].parentNode.removeChild(script[i]);
break;
}
}
}
};
}())
};
$.f.init();
}(window, document, {
'k': 'TW_' + new Date().getTime(),
'me': 'twatter.js',
'strip': [
'className', 'rel', 'dir', 'data-expanded-url', 'target', 'title', 'data-scribe'
],
'endpoint': 'https://cdn.syndication.twimg.com/widgets/timelines/',
'rules': {
'ul._list' : {
'width': '510px',
'height': '640px',
'overflow': 'auto',
'border-radius': '3px',
'box-shadow': '0 1px 3px rgba(0, 0, 0, .33)',
'margin': '0',
'padding': '0',
'font-family': 'Times New, monospace',
'*': {
'box-sizing': 'border-box',
'-moz-box-sizing': 'border-box',
'-ms-box-sizing': 'border-box'
},
'li._item': {
'list-style': 'none',
'margin': '0',
'padding': '0',
'overflow': 'auto',
'width': '100%',
'padding': '10px',
'border-bottom': '1px solid #eee',
'font-size': '14px',
'position': 'relative',
'a': {
'text-decoration': 'none',
'&::hover': {
'text-decoration': 'underline'
}
},
'a._nameLink, a._timeLink': {
'display': 'block'
},
'a._nameLink': {
'font-weight': 'bold'
},
'a._timeLink': {
'font-size': '12px'
}
}
}
}
}));