Skip to content

Instantly share code, notes, and snippets.

@tanamako
Created September 19, 2012 14:20
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 tanamako/3749928 to your computer and use it in GitHub Desktop.
Save tanamako/3749928 to your computer and use it in GitHub Desktop.
forked: simple twitter search
html{
background:#fff;
}
html,body,ul,li,p,form{
margin:0;
padding:0;
}
html,body{
}
.highlight-word{
background-color:#ffff80;
}
a img{
border:none;
}
a{
text-decoration:none;
}
a:hover{
text-decoration:underline;
}
.twsrrlt{
overflow:auto;
width:90%;
padding:0 5px;
position:fixed;/* for Opera*/
}
* html .twsrrlt{
position:relative;
}
.twsrrlt ul.twl{
list-style-type:none;
}
.twsrrlt .twl li{
margin:6px 0;
padding:6px;
position:relative;
background-image:none;
-moz-border-radius:6px;
border-radius:6px;
color:#222;
border:2px solid #fff;
}
.twsrrlt .twl li.new{
border-color:#ffff80;
}
.twsrrlt .twl li.odd{
background-color: #eee;
}
.twsrrlt .twl li.even{
background-color: #ddd;
}
.twsrrlt .twl li a.usr{
width:50px;
position:absolute;
top:5px;
}
* html .twsrrlt .twl li a.usr{
width:50px;
}
.twsrrlt .twl li a.usr{
height:50px;
overflow:hidden;
}
.twsrrlt .twl li a.usr:hover{
height:auto;
overflow:visible;
width:auto;
min-width:50px;
}
.twsrrlt .twl li a.usr:hover span{
padding:2px 6px;
background:#fff;
-moz-border-radius:4px;
border-radius:4px;
word-break: keep-all;
word-wrap: normal;
}
.twsrrlt .twl li p{
margin:0;
display:inline-block;
}
* html .twsrrlt .twl li p{
display:block;
}
.twsrrlt .twl li p.entry{
min-height:55px;
margin-left:52px;
}
* html .twsrrlt .twl li p.entry{
height:55px;
}
.twsrrlt .twl li div.time{
display:block;
text-align:right;
background:#fafafa;
-moz-border-radius:4px;
border-radius:4px;
padding:2px;
margin:6px 0 0;
}
.twsrrlt .twl li div.time a{
padding:0 2px;
}
#timer{
position:absolute;
display:inline;
display:inline-block;
top:0px;
right:0px;
font-size:150%;
color:#444;
background:#ccc;
-moz-border-radius:4px;
border-radius:4px;
padding:4px;
}
<form id="searchform">
<input type="search" id="searchvalue" value="JavaScript">
<select id="searchlang">
<option value="all">all</option>
<option value="ja">ja</option>
</select>
<input type="submit" value="検索">
</form>
<div id="search-result" class="twsrrlt"></div>
<div id="timer"></div>
<ul id="search-tmpl" style="display:none;">
<li>
<a class="usr">
<img width="48" height="48"><br>
<span></span>
</a>
<p class="entry"></p>
<div class="time">
<a class="source"></a>
<a class="username"></a>
<a class="timelink"></a>
</div>
</li>
</ul>
// forked from os0x's "simple twitter search" http://jsdo.it/os0x/search.twitter
/*
* シンプルなTwitter検索
*/
if (!window.XMLHttpRequest){
XMLHttpRequest = function () {
try {
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
} catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
} catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
}
var tmpl = document.getElementById('search-tmpl').getElementsByTagName('li')[0];
var timeline = document.getElementById('search-result');
var tree;
var prev_result;
function TwitterCallback(data){
if (prev_result){
write_timeline(data);
} else {
clear();
write_timeline(data);
start_timer();
}
prev_result = data;
}
function clear(){
if(tree){
timeline.removeChild(tree);
tree = null;
}
}
document.body.onclick = function(e){
var evt = e || window.event;
var target = evt.target || evt.srcElement;
if (target.href && target.innerHTML.indexOf('#') === 0) {
searchvalue.value = target.innerHTML;
searchform.onsubmit();
return false;
}
};
function write_timeline(data){
var keyword = searchvalue.value;
var results = data.results;
if (!tree) {
tree = document.createElement('ul');
tree.className = 'twl';
}
var items = tree.childNodes.length;
results.reverse();
if(prev_result){
for (var i = 0, len = prev_result.results.length;i < len; i++){
var _li = tree.childNodes[i];
_li.className = _li.className.replace(/(\s)+new(\s*|$)/,'');
}
}
for (i = 0, len = results.length;i < len; i++){
var usr = results[i];
var user = usr.from_user;
/* 要素を作る */
var li = tmpl.cloneNode(true);
var link = li.getElementsByTagName('a')[0];
var icon = link.getElementsByTagName('img')[0];
var name = link.getElementsByTagName('span')[0];
var entry = li.getElementsByTagName('p')[0];
var time = li.getElementsByTagName('div')[0];
var source = time.getElementsByTagName('a')[0];
var username = time.getElementsByTagName('a')[1];
var timelink = time.getElementsByTagName('a')[2];
/* CSS用にclassを設定 */
li.className = (((i+1+items)%2) ? 'odd' : 'even') + ' new';
/* リンクや画像などの属性を設定 */
username.href = link.href = 'http://twitter.com/' + user;
var src = usr.profile_image_url;
if (src.indexOf('http') === 0) {
icon.src = src;
}
icon.width = 48;
icon.height = 48;
timelink.href = 'http://twitter.com/' +
user +'/status/' + usr.id;
var d = new Date(usr.created_at);
var date = d.getFullYear() + '/' + (d.getMonth()+1) +
'/' + d.getDate() + ' ' + d.getHours() + ':' +
('0'+d.getMinutes()).slice(-2);
/* テキストノードの挿入 */
var node = document.createTextNode(usr.text.replace(/&(lt|gt|quot|amp);/g,function(_$,_1){
return {lt:'<', gt:'>', quot:'"', amp:'&'}[_1];
}));
entry.appendChild(node);
linkfy(entry, '@(\\w+)', '[^\\w@]|$', 'http://twitter.com/');
linkfy(entry, '#(\\w+)', '[^\\w#]|$', 'http://search.twitter.com/search?q=%23');
linkfy(entry, '(https?://.*)', '[  \\)\\]\'\"\n]|$', '');
expandUrl(entry);
highlight(entry, keyword);
if (usr.source){
var match = usr.source.match(/&quot;(http.*?)&quot;/);
if(match){
source.href = match[1];
source.appendChild(document.createTextNode('from '+usr.source.match(/&gt;(.*?)&lt;/)[1]));
}
}
username.appendChild(document.createTextNode('@' + user));
timelink.appendChild(document.createTextNode(date));
name.appendChild(document.createTextNode(user));
/* 要素の組み立て */
tree.insertBefore(li, tree.firstChild);
}
/* 画面に反映 */
if (!tree.parentNode || !tree.parentNode.parentNode){
timeline.appendChild(tree);
}
}
function highlight(element, keyword){
for (var i =0,l = element.childNodes.length;i < l;i++){
var node = element.childNodes[i];
if(node.nodeType !== 3){
continue;
}
var keywordExp = new RegExp(keyword,'i');
var keywordLength = keyword.length;
if (node.nodeValue.search(keywordExp) >= 0) {
var text = node.nodeValue, index;
var parent = node.parentNode;
while (text && (index=text.search(keywordExp)) >= 0 ){
// テキストを分割し、後ろ側のノードを取得
var _txt = node.splitText(index);
// キーワードの終わりで再度分割
var __txt = _txt.splitText(keywordLength);
var s = document.createElement('span');
s.className ='highlight-word';
s.appendChild(_txt);
if (!__txt.nodeValue || !__txt.parentNode){
parent.appendChild(__txt);
} else {
parent.insertBefore(s, __txt);
}
// ループ用に初期化
text = __txt.nodeValue;
node = __txt;
}
}
}
}
function linkfy(element, start, end, prefix){
for (var i =0,l = element.childNodes.length;i < l;i++){
var node = element.childNodes[i];
if(node.nodeType !== 3){
continue;
}
if (node.nodeValue.search(start) >= 0) {
var text = node.nodeValue, index;
var parent = node.parentNode;
while (text && (index=text.search(start)) >= 0 ){
// テキストを分割し、後ろ側のノードを取得
var _txt = node.splitText(index);
// キーワードの終わりで再度分割
var _end = _txt.nodeValue.search(end);
var __txt = _txt.splitText(_end);
var a = document.createElement('a');
a.href = prefix + _txt.nodeValue.match(start)[1];
a.target = '_blank';
a.appendChild(_txt);
if (!__txt.nodeValue || !__txt.parentNode){
parent.appendChild(a);
} else {
parent.insertBefore(a, __txt);
}
// ループ用に初期化
text = __txt.nodeValue;
node = __txt;
}
}
}
}
function expandUrl(element){
var links = element.getElementsByTagName('a');
for (var i =0,l = links.length;i < l;i++){
var a = links[i];
if (a.href.length < 30 && a.host !== 'twitter.com'){
getCrossSiteXhrOrJsonP(a);
}
}
}
function getCrossSiteXhrOrJsonP(a){
var same_origin = location.hostname === 'ss-o.net' && (location.port==='' || location.port==='80') && location.protocol === 'http:';
var xhr;
var onload = function(){
var data = JSON.parse(xhr.responseText);
if (data.url && data.url !== a.href){
a.textContent = data.url;
a.href = data.url;
}
};
if (same_origin) {
xhr = new XMLHttpRequest();
} else if(window.XDomainRequest){
xhr = new XDomainRequest();
} else if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
if (!('withCredentials' in xhr)){
xhr = {
open:function(method, url){
var s = xhr.__script = document.createElement('script');
var callback = ('JSONP_' + new Date().getTime() + Math.random()).replace(/\W/,'');
s.src = url + '&callback=' + callback;
window[callback] = function(data){
xhr.responseText = JSON.stringify(data);
onload();
document.body.removeChild(s);
delete window[callback];
};
},
send:function(){
document.body.appendChild(xhr.__script);
}
};
}
}
xhr.open('GET', 'http://ss-o.net/api/reurl.json?url=' + encodeURIComponent(a.href), true);
if (!('onload' in xhr)){
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
onload();
}
};
} else {
xhr.onload = onload;
};
xhr.send(null);
}
var searchform = document.getElementById('searchform');
var searchvalue= document.getElementById('searchvalue');
var searchlang = document.getElementById('searchlang');
var timer = document.getElementById('timer');
var lang = '';
function getJSONP(query){
var script = document.createElement('script');
script.src = 'http://search.twitter.com/search.json' + query;
document.body.appendChild(script);
}
searchform.onsubmit=function(){
prev_result = null;
clearInterval(timerID);
lang = searchlang.value;
getJSONP('?callback=TwitterCallback&lang='+lang+'&q=' + encodeURIComponent(searchvalue.value));
// submitをキャンセル(ページ遷移させない)
return false;
};
/*
var addEvent = (document.addEventListener) ?
function(node,type,handler){
node.addEventListener(type,handler,false);
}
: function(node,type,handler){
node.attachEvent('on' + type, function(evt){
handler.call(node, evt);
});
};
addEvent(searchform, 'submit', function(evt){
prev_result = null;
clearInterval(timerID);
lang = searchlang.value;
getJSONP('?callback=TwitterCallback&lang='+lang+'&q=' +
encodeURIComponent(searchvalue.value));
// submitをキャンセル(ページ遷移させない)
if (evt.preventDefault) {
evt.preventDefault();
} else {
evt.returnValue = false;
}
});
*/
var TIME = 60, timerID;
function start_timer(){
var time = TIME;
timerID = setInterval(function(){
time--;
timer.innerHTML = time;
if(time === 0){
time = TIME;
if (prev_result){
getJSONP(prev_result.refresh_url+'&callback=TwitterCallback&lang='+lang);
}
}
}, 1000);
}
window.onresize = function(){
timeline.style.height = (document.documentElement.clientHeight - searchform.offsetHeight) + 'px';
};
window.onresize();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment