Skip to content

Instantly share code, notes, and snippets.

@monjudoh
Created September 22, 2008 02:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monjudoh/11927 to your computer and use it in GitHub Desktop.
Save monjudoh/11927 to your computer and use it in GitHub Desktop.
//本体
Twittelien = {};
Twittelien.entryFilters = {};
Twittelien.template = {};
Twittelien.classes = {};
(function($){
function TableUpdator(params){
this._parseRules = params['parseRules'] || {};
this._table = params['table'] || new TAFFY([]);
};
// entriesはjQueryオブジェクト
TableUpdator.prototype.append = function(entries){
var self = this;
var filter = self._filter(self._table);
entries = entries.filter(filter);
var records = this._parse(entries);
this._sort(records);
this._insert(records);
};
TableUpdator.prototype._filter = function(index){
return this;
};
TableUpdator.prototype._parse = function(entries){
var parseRules = this._parseRules;
var log = this._log;
var self = this;
return new TAFFY(
entries
.map(function(){
var thisEntry = $(this);
var entry ={};
for(var key in parseRules){
try{
entry[key] = parseRules[key](thisEntry,$);
}catch(e){
self._log(['Parse error occurred.\n','rule name:',key,'\nhtml:',$('<div/>').append(thisEntry.clone()).html()].join(''));
return null;
}
}
if(!entry.status_id){
self._log('entry id is null');
return null;
}
return entry;
})
.get()
);
};
TableUpdator.prototype._sort = function(records){
records.orderBy('status_id');
};
TableUpdator.prototype._insert = function(records){
var table = this._table;
records
.forEach(function(record){table.insert(record);});
};
TableUpdator.prototype._log = function(){};
Twittelien.TableUpdator = TableUpdator;
})(jQuery);
(function($){
function Appender(params){
var self = this;
if(typeof params.scrape != 'function'){
throw new Error('scrape isn\'t function;');
}
var scrape = params.scrape;
this._updator = params['updator'];
var isStopped = false;
this.stop = function(){isStopped = true;};
this.start = function(){
var func = arguments.callee;
var started = new Date();
$.ajax({
type:'GET',
url:self.url,
dataType:'text',
success:function(script){
var Element =
{
replace:function(id,html){
if(id!='timeline')return;
this.html = html;
throw new Error();
}
};
try{
eval(script);
}catch(e){}
var entries = scrape(Element.html);
self._updator.append(entries);
},
error:function(xhr,textStatus){
var win = window.open();
setTimeout(function(){win.location.href=win.location.href;},10*1000);
},
complete:function(xhr,textStatus){
if(isStopped){
isStopped = false;
return;
}
setTimeout(func,self.interval);
}
});
};
};
Appender.prototype.log = function(){};
Appender.prototype.url = 'http://twitter.com/home';
Appender.prototype.interval = 30*1000;
Twittelien.Appender = Appender;
})(jQuery);
// 関数設定((不要なもの外してOK)
parseRules = {
'status_id' : function(entry){return entry.attr('id');},
'user_name' : function(entry){return entry.find('.status-body>strong>a').text();},
'nick_name' : function(entry){return entry.find('#profile-image').attr('alt');},
'profile_image' : function(entry){return entry.find('#profile-image').attr('src');}
,'entry_content' : function(entry,$){
var content = entry.find('.entry-content').get(0).childNodes;
content = $.map(content,function(n,i){
var nodeType = n.nodeType;
if(nodeType == 1/*Node.ELEMENT_NODE */ && n.nodeName =='A'){
var link = $(n);
if(link.attr('href').startsWith('/')){
return {type:'reply',user_name:$.trim(link.text())};
}else{
return {type:'link',text:$.trim(link.text()),href:link.attr('href')};
}
}else if(nodeType == 3/*Node.TEXT_NODE */){
return {type:'text',text:$.trim(n.nodeValue)};
}else{
return undefined;
}
});
return content;
}
,'published' : function(entry){
try{
var published = entry
.find('.published')
.attr('title')
.replace(/-/g,'/')
.replace('T',' ')
.replace('+',' GMT+');
return new Date(Date.parse(published));
}catch(e){
return false;
}
}
,'twitter_client':function(entry){
var link = entry.find('.entry-meta>a:not(.entry-date,[href^="http://twitter.com/"])');
return link.size() ? {name:link.text(),url:link.attr('href')} : false;
}
,'is_protected':function(entry){
return !!entry.find('img[alt="Icon_red_lock"]').size();
}
,'reply-url':function(entry){
var link = entry.children(':not(.entry-date)[href^="http://twitter.com/"]');
return link.size() ? link.attr('href') : false;
}
};
// 重複判定
(function($){
Twittelien.entryFilters.uniq = function(table){
return function(index){
return table.get({status_id:$(this).attr('id')}).length < 1;
};
}
})(jQuery);
(function($){
function scrape(html){
var temp = $('<div/>');
temp.get(0).innerHTML = html;
return temp.find('tr.hentry');
};
updator = new Twittelien.TableUpdator({'parseRules':parseRules});
updator._filter = Twittelien.entryFilters.uniq;
recent = new Twittelien.Appender({'scrape':scrape,'updator':updator});
var entries = $('tr');
updator.append(entries);
$('#container #timeline').empty();
recent.start();
})(jQuery);
(function($){
var tag = $.browser.opera ? '&#8203;' : '<wbr />';
var pattern = new RegExp('(&[a-z]+;|.)', 'g');
function linkWrapper(text) {
return $('<span/>').text(text).html().replace(pattern, '$1' + tag);
};
window.linkWrapper = ($.browser.opera && parseFloat($.browser.version) >= 9.5) ? function(text){return $('<span/>').text(text).html();}: linkWrapper;
})(jQuery);
// 自動更新開始
var viewHelper = [
['user_url',function(data){return 'http://twitter.com/' + data['user_name'];}]
,['entry_id',function(data){return data['status_id'].replace('status_','');}]
,['entry_url',function(data){return ['http://twitter.com/',data['user_name'],'/statuses/',data['entry_id']].join('');}]
,['entry_content',function(data){return data['entry_content'] || {};}]
];
(function($){
contexT = {
'':function(elem,data){elem.attr('id',data['status_id']);}
,'.url':function(elem,data){elem.attr('href',data['user_url']);}
,'.url>img':function(elem,data){elem.attr('src',data['profile_image']).attr('alt',data['nick_name']);}
,'.content>strong>a':function(elem,data){elem.attr('href',data['user_url']).attr('title',data['nick_name']).text(data['user_name']);}
,'.entry-date':function(elem,data){elem.attr('href',data['entry_url']);}
,'.published':function(elem,data){
elem.text([data['published'].getHours(),data['published'].getMinutes(),data['published'].getSeconds()].join(':'));
}
,'.status_actions':function(elem,data){elem.attr('id','status_actions_'+data['entry_id']);}
,'.entry-content':function(elem,data){
jQuery.each(data['entry_content'],function(i,value){
switch(value['type']){
case 'text':
elem.append( linkWrapper( value['text'] ) );
break;
case 'reply':
elem
.append( $('<a target="_blank"/>').html(linkWrapper( value['user_name'] )).attr('href','/'.concat(value['user_name'])) )
.append( document.createTextNode(' ') );
break;
case 'link':
var linkUrl = value['href'];
elem
.append( $('<a target="_blank"/>').html(linkWrapper( linkUrl ) ).attr('href',linkUrl) )
.append( document.createTextNode(' ') );
break;
}
});
}
,'#__twitter_client':function(elem,data){
if(data['twitter_client']){
elem
.attr('href',data['twitter_client'].url)
.removeAttr('id')
.text(data['twitter_client'].name);
}else{
elem.replaceWith(elem.text());
}
}
};
})(jQuery);
Twittelien.template.entry = new Templalien([
'<tr class="hentry">'
,' <td class="thumb vcard author">'
,' <a class="url"><img id="profile-image" class="photo fn" style="width:48px;height:48px;"/></a>'
,' </td>'
,' <td class="content">'
,' <strong><a></a></strong>'
,' <span class="entry-content"></span>'
,' <span class="meta entry-meta">'
,' <a rel="bookmark" class="entry-date"><abbr class="published"></abbr></a>'
,' from <a id="__twitter_client">web</a>'
,' </span>'
,' </td>'
,' <td width="10" align="right">'
,' <div class="status_actions" >'
// 中身だけtoggleさせればいいんじゃね?
,' <a href="#">'
,' <img border="0" title="Favorite this update" src="http://assets2.twitter.com/images/icon_star_empty.gif" id="status_star_809356512" alt="Icon_star_empty"/>'
,' </a>'
,' <a href="#" id="__reply">'
,' <img border="0" title="reply to " src="http://assets1.twitter.com/images/reply.png" alt="reply to "/>'
,' </a>'
,' </div>'
,' </td>'
,'</tr>'
].join('')
,{viewHelper:viewHelper,context:contexT,events:{}}
);
//createEntryData(record)
//entryDataとentryTmplと値設定は一セットだと思う
//ただし、イベントを貼り付けるのは別
Twittelien.template.entry.setEvents([
[
'#__reply'
,'click'
,function(e){
replyTo(e.data.user_name);
e.preventDefault();
}
]
]);
(function($){
function recordToEntry(record){
return Twittelien.template.entry.merge(record);
}
prepend = function(record){
var timeline = $('#container #timeline');
timeline
.prepend(recordToEntry(record));
}
append = function(record){
var entry = recordToEntry(record);
if($('tr:last').size()){
$('tr:last')
.after(entry);
}else{
$('#container #timeline')
.append(entry);
}
}
})(jQuery);
(function($){
$('#timeline')
.nextAll().remove().end()
.prevAll().remove().end()
.after( ['<div style="text-align:right">'
,' <a id="prev" class="section_links" href="javascript:void(0);">prev100</a>'
,'</div>'].join('') )
.before( ['<div style="text-align:right">'
,' <a id="latest" class="section_links" href="javascript:void(0);">new100</a>'
,' <a id="next" class="section_links" href="javascript:void(0);">next100</a>'
,'</div>'].join('') );
})(jQuery);
(function($,updator){
$('#next').bind('click',function(e){
var entries = updator._table;
var statusId = $('.hentry:first').attr('id');
var startIndex = 0;
if($('.hentry').size()){
var indexes = entries.find({status_id:statusId});
if(indexes.length){
if(indexes[0] < entries.getLength()){
startIndex = indexes[0] + 1;
}else{
return;
}
}
}else{
startIndex = entries.getLength() > 100 ? entries.getLength() - 100 : 0;
}
var endIndex = startIndex + 100;
endIndex = entries.getLength() >= endIndex ? endIndex : entries.getLength() + 1;
if(startIndex == endIndex){
return;
}
var filterIndexes = $.map(new Array(endIndex - startIndex),function(i,n){return n + startIndex;});
try{
$.each(entries.get(filterIndexes),function(i,n){if(n){prepend(n);}});
}catch(e){
$('.hentry:gt(149)').remove();
//updator._log(e);
}
$('.hentry:gt(149)').remove();
if(statusId){
setTimeout(function(){
location.hash=statusId;
},100);
}
});
})(jQuery,updator);
//latest
(function($,updator){
var timeline = $('#container #timeline');
$('#latest').bind('click',function(e){
var entries = updator._table;
timeline.empty();
var startIndex = entries.getLength();
var endIndex = startIndex - 100;
endIndex = endIndex > 0 ? endIndex : 0;
var filterIndexes = $.map(new Array(startIndex - endIndex),function(i,n){return n + endIndex;});
try{
$.each(entries.get(filterIndexes),function(i,n){if(n){prepend(n);}});
}catch(e){
updator._log(e);
}
});
})(jQuery,updator);
(function($,updator){
$('#prev').bind('click',function(e){
var entries = updator._table;
var statusId = $('tr:last').attr('id');
var startIndex = 0;
if($('tr').size()){
var indexes = entries.find({status_id:statusId});
if(indexes.length){
if(indexes[0] > 0){
startIndex = indexes[0] - 1;
}else{
return;
}
}
}else{
startIndex = entries.getLength() + 1;
}
var endIndex = startIndex - 100;
endIndex = endIndex > 0 ? endIndex : 0;
if(startIndex == endIndex){
return;
}
var filterIndexes = $.map(new Array(startIndex - endIndex),function(i,n){return n + endIndex;});
try{
$.each(entries.get(filterIndexes).reverse(),function(i,n){if(n){append(n);}});
}catch(e){
//updator._log(e);
}
$(['tr:eq(', $('tr').size() > 150 ? $('tr').size() - 150 : 0 ,')'].join('')).prevAll().remove();
if(statusId){
location.hash=statusId;
}
});
})(jQuery,updator);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment