Skip to content
Browse files

initial commit based on 1.0 of snapbird

  • Loading branch information...
0 parents commit 2d24de1634fef0a8ba7a8156e09607af0b5d0e49 @remy committed
1 .gitignore
@@ -0,0 +1 @@
+auth/
3 .gitmodules
@@ -0,0 +1,3 @@
+[submodule "twitterlib"]
+ path = twitterlib
+ url = git://github.com/remy/twitterlib.git
BIN images/ajax-loader-grey.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/background.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/bang.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/button-bg.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/divider.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/dots.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/footer-no-results.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/footer-results.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/header.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/main-bg.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN images/submit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
150 index.php
@@ -0,0 +1,150 @@
+<?php
+include('auth/secret.php');
+include('auth/php/EpiCurl.php');
+include('auth/php/EpiOAuth.php');
+include('auth/php/EpiTwitter.php');
+
+$twitterObj = new EpiTwitter(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET);
+$twitterInfo = null;
+
+if ($_COOKIE['token'] && file_exists('auth/oauth/' . $_COOKIE['token'])) {
+ $username = file_get_contents('auth/oauth/' . $_COOKIE['token']);
+ $userToken = $_COOKIE['token'];
+ $userSecret = file_get_contents('auth/oauth/' . $username . '-sec');
+
+ $twitterObj->setToken($userToken, $userSecret);
+ $twitterInfo = $twitterObj->get_accountVerify_credentials();
+
+ if (!$twitterInfo->screen_name) {
+ // reset
+ $twitterObj = new EpiTwitter(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET);
+ $twitterInfo = null;
+ }
+}
+
+$screen_name = isset($_GET['screen_name']) ? $_GET['screen_name'] : '';
+$search = isset($_GET['search']) ? $_GET['search'] : '';
+$type = isset($_GET['type']) ? $_GET['type'] : 'tweets';
+
+?>
+<!DOCTYPE html>
+<!--
+ I wrote this app because the search on Twitter sucks (7 days history).
+ I knew that there something I needed to find in my timeline but couldn't
+ find it. Or it might be favourited but again I couldn't find it - so
+ this app does it for me :-)
+
+ - Remy @rem
+-->
+<html lang="en">
+<head>
+<title>Snap Bird - re-finding the ones that got away</title>
+<meta charset="utf-8" />
+<link rel="shortcut icon" href="/images/snapbird-icon.png" />
+<link rel="apple-touch-icon" href="/images/snapbird-icon.png" />
+<!--[if IE]>
+ <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+<![endif]-->
+<link rel="stylesheet" href="/snapbird.css" type="text/css" />
+</head>
+<body>
+ <header>
+ <h1><a href="/">Snap Bird</a></h1>
+ <p>Re-finding the ones that got away</p>
+ </header>
+ <article id="main">
+ <p>Can&rsquo;t remember who said that thing that time?</p>
+ <ul class="plain">
+ <li>Search <strong>beyond</strong> Twitter&rsquo;s 10-day search archive</li>
+ <li>Search <strong>tweets, lists, friends &amp; favourites</strong></li>
+ </ul>
+ <form action="/">
+ <fieldset class="who">
+ <legend>Where to search</legend>
+ <div>
+ <label for="screen_name">Search</label>
+ <?php if ($twitterInfo != null) : ?>
+ <span title="Searching friends is limited to your screen name" class="input" id="auth_screen_name"><?= $twitterInfo->screen_name ?></span>
+ <?php endif ?>
+ <input type="text" name="screen_name" value="<?=$screen_name?>" id="screen_name" placeholder="screen name" />
+ <span>&rsquo;s</span>
+ </div>
+ <div class="radiogroup">
+ <input type="radio" name="source" <?php if ($type == 'tweets') echo 'checked="checked" '; ?>value="timeline" id="timeline" /><label for="timeline">tweets</label>
+ <input type="radio" name="source" <?php if ($type == 'favs') echo 'checked="checked" '; ?>value="favs" id="favs" /><label for="favs">favourites</label>
+ <input type="radio" name="source" <?php if ($type == 'withfriends') echo 'checked="checked" '; ?>value="friends" id="withfriends" /><label for="withfriends">friends&rsquo; tweets</label>
+ </div>
+ </fieldset>
+ <fieldset class="for">
+ <legend>What to search for</legend>
+ <div>
+ <label for="search">for</label>
+ <input type="text" name="search" value="<?=$search?>" id="search" />
+ <p class="note">You can do all the usual search stuff like <br />wrapping &ldquo;phrases in quotes&rdquo; and using OR, etc.</p>
+ </div>
+ <input type="submit" class="submit" value="Search" />
+ </fieldset>
+ </form>
+ </article>
+ <div id="mainFooter"></div>
+ <article id="tweets">
+ <aside>
+ <p><a id="permalink" href="http://snapbird.org/">&raquo; Permalink to results</a></p>
+ <div id="status">
+ <p>Searched 200 tweets.</p>
+ <p>Read back to: <strong>12:15 AM Oct 16th</strong></p>
+ </div>
+ <input type="button" class="search button" value="Search back further" />
+ </aside>
+
+<ul>
+</ul>
+
+ <input type="button" class="search button" value="Search back further" />
+ </article>
+ <footer>
+ <nav>
+ <ul id="navlinks">
+ <li><a href="/">Search</a></li>
+ <!-- <li><a href="/about">About</a></li> --> <!-- Coming soon -->
+ <li><a href="http://github.com/remy/twitter-search-js">Developers</a></li>
+ <?php if ($twitterInfo != null) : ?>
+ <li><a id="logout" href="/">Logout</a></li>
+ <?php endif ?>
+ </ul>
+ </nav>
+ <ul id="credit">
+ <li><a href="http://twitter.com/rem">Built by @rem</a></li>
+ <li><a href="http://twitter.com/nicepaul">Designed by @nicepaul</a></li>
+ <li><a href="http://twitter.com/stompfrog">bird by @stompfrog</a></li>
+ </ul>
+ </footer>
+ <div id="auth">
+ <div id="overlay"></div>
+ <!-- nasty triple nesting, but necessary for what I'm trying to achieve...I think -->
+ <div id="login">
+ <div>
+ <div>
+ <p>We can only search within your own friends&rsquo; tweets, and you need to tell Twitter it&rsquo;s OK for us to search.</p>
+ <p>Log in to Twitter and on the next screen press &ldquo;allow&rdquo;.</p>
+ <p><a class="button" href="<?= $twitterObj->getAuthorizationUrl() ?>">Go to Twitter.com</a> <a class="button cancel" href="#">Cancel</a></p>
+ </div>
+ </div>
+ </div>
+ </div>
+<!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> -->
+<script src="/jquery.js"></script>
+<!-- <script src="/twitter-search.js"></script> -->
+<script src="/twitterlib.js"></script>
+<script src="/snapbird.js?2009-12-10"></script>
+<script>
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script>
+try {
+var pageTracker = _gat._getTracker("UA-1656750-19");
+pageTracker._trackPageview();
+} catch(err) {}</script>
+</body>
+</html>
399 snapbird.css
@@ -0,0 +1,399 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+
+section, article, aside, header, footer {
+ display: block;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ background: #b0d349 url(/images/background.jpg) repeat-x top left;
+ font-family: helvetica, arial;
+ font-size: 18px;
+}
+
+header {
+ background: url(/images/header.jpg) no-repeat top center;
+ height: 223px;
+ display: block;
+ min-width: 780px;
+ margin: 0 auto;
+}
+
+header p {
+ display: none;
+}
+
+header h1 a {
+ opacity: 0;
+ -moz-opacity: 0;
+ filter:alpha(opacity=0);
+ position: absolute;
+ text-indent: -9999px;
+ overflow: hidden;
+ display: block;
+ top: 100px;
+ left: 0;
+ height: 100px;
+ width: 100%;
+/* margin: 200px 300px;*/
+}
+
+#mainFooter {
+ width: 780px;
+ margin: 0 auto;
+ height: 7px;
+ background: url(/images/footer-no-results.jpg) no-repeat top left;
+}
+
+.results #mainFooter {
+ background-image: url(/images/footer-results.jpg);
+}
+
+#tweets {
+ display: none;
+}
+
+.results #tweets {
+ display: block;
+}
+
+#main {
+ background: url(/images/main-bg.jpg) no-repeat;
+ height: 295px;
+ width: 690px;
+ margin: 0 auto;
+ color: #F2F2F2;
+ padding: 45px;
+}
+
+#main p, #main li, #main label {
+ text-shadow: rgba(0,0,0,0.6) 1px 1px 2px;
+}
+
+footer {
+ font-size: 14px;
+ width: 780px;
+ margin: 0 auto;
+ position: relative;
+}
+
+footer ul {
+ position: absolute;
+ right: 0;
+ padding: 25px 0;
+}
+
+footer nav ul {
+ left: 0;
+}
+
+#credit {
+ text-transform: lowercase;
+}
+
+footer li {
+ background: url(/images/divider.gif) no-repeat center left;
+ padding: 5px 15px;
+ float: left;
+ display: block;
+}
+
+footer ul li:first-child {
+ background: none;
+}
+
+footer a {
+ color: #E6FFE1;
+ text-decoration: none;
+}
+
+footer nav a {
+ font-weight: bold;
+}
+
+ul.plain {
+/* list-style: none;*/
+ font-weight: normal;
+ font-size: 15px;
+ margin-left: 35px;
+}
+
+ul.plain li {
+ margin: 5px 0;
+}
+
+form {
+ margin: 45px 35px;
+}
+
+fieldset {
+ border: 0px solid #000;
+ padding: 0;
+ width: 400px;
+ margin-bottom: 30px;
+/* position: relative;*/
+}
+
+fieldset legend {
+ display: none;
+}
+
+input[type=text], span.input {
+ padding: 5px;
+ background: #fff;
+ width: 200px;
+ font-family: helvetica, arial;
+ font-size: 18px;
+ border: 1px solid #6b4a2d;
+/* shadow: #000 10px 10px 10px;*/
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -o-border-radius: 3px;
+ border-radius: 3px;
+}
+
+span.input {
+ color: #999;
+ display: none;
+}
+
+span.input:after {
+ content: ' (locked)';
+}
+
+.radiogroup {
+ padding: 10px;
+ padding-left: 60px;
+}
+
+.radiogroup label {
+ font-size: 14px;
+ opacity: 0.6;
+ -moz-opacity: 0.6;
+ filter:alpha(opacity=60);
+ padding: 5px 20px 5px 5px;
+}
+
+.note {
+ line-height: 14px;
+ font-size: 11px;
+ text-align: center;
+ width: 270px;
+}
+
+.for div {
+ float: left;
+}
+
+.submit, .button {
+ cursor: pointer;
+ background: url(/images/button-bg.gif) repeat-x bottom left;
+ display: block;
+ color: #fff;
+ text-shadow: rgba(0,0,0,0.8) 1px 1px 2px;
+ font-size: 15px;
+ font-weight: bold;
+ padding: 10px;
+ border: 1px solid #000;
+ border-style: groove;
+ margin-top: 10px;
+ -webkit-border-radius: 10px;
+ -moz-border-radius: 10px;
+}
+
+.submit {
+ float: right;
+ font-size: 22px;
+ height: 50px;
+ width: 125px;
+ -webkit-border-radius: 12px;
+ -moz-border-radius: 12px;
+ -webkit-rotate: 5px;
+ -webkit-transform: rotate(5deg);
+ -moz-transform: rotate(5deg);
+}
+
+#bang {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: url(/images/bang.png) no-repeat center;
+}
+
+#tweets {
+ width: 758px;
+ margin: 0 auto;
+ background: #fff;
+ padding-bottom: 22px;
+ padding-left: 22px;
+ -webkit-border-bottom-left-radius: 15px;
+ -webkit-border-bottom-right-radius: 15px;
+ -moz-border-radius-bottomleft: 15px;
+ -moz-border-radius-bottomright: 15px;
+ position: relative;
+}
+
+#tweets ul {
+ min-height: 120px;
+ width: 520px;
+ padding-top: 22px;
+ padding-right: 22px;
+ margin: 0;
+}
+
+#tweets aside {
+ position: absolute;
+ margin-left: 538px;
+ width: 170px;
+ padding: 15px;
+ margin-top: 22px;
+ background: #d7e9a4;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+}
+
+#tweets aside.fixed {
+ position: fixed;
+ top: 0;
+}
+
+/* twitter styles */
+#tweets li {
+ background: url(/images/dots.gif) repeat-x left bottom;
+ font-size: 14px;
+}
+
+#tweets a {
+ color: #2277bb;
+}
+
+#tweets a:hover, #tweets a:active, #tweets a:focus, #tweets a {
+ text-decoration: none;
+}
+
+#tweets a:hover {
+ text-decoration: underline;
+}
+
+#tweets a img {
+ border: 0;
+}
+
+#tweets li {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.tweet {
+ clear: left;
+ min-height: 48px;
+ padding: 9px;
+ line-height: 1.1;
+ position: relative;
+}
+
+#tweets li.searchterm {
+ font-size: 22px;
+ padding: 20px 0;
+}
+
+.vcard {
+ float: left;
+}
+
+.hentry {
+ margin-left: 58px;
+}
+
+.hentry .meta {
+ color: #999;
+ font-size: 0.764em;
+ margin: 3px 0 0;
+ display: block;
+}
+
+#tweets .meta a {
+ color: #999;
+}
+
+.tweet:hover {
+ background-color: #F7F7F7;
+}
+
+#status {
+ font-size: 14px;
+ color: #565d42;
+}
+
+#status p {
+ margin: 5px 0 15px 0;
+}
+
+#status p strong {
+ display: block;
+}
+
+#auth {
+ display: none;
+}
+
+.auth #auth {
+ display: block;
+}
+
+#overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: #000;
+ opacity: 0.4;
+ -moz-opacity: 0.4;
+ filter:alpha(opacity=40);
+}
+
+#login {
+ width: 500px;
+ margin: 0 auto;
+}
+
+#login > div {
+/* border: 10px solid rgba(0,0,0,0.5);*/
+ -webkit-border-radius: 10px;
+ -moz-border-radius: 10px;
+ background: rgba(0,0,0,0.4);
+ position: absolute;
+ top: 200px;
+ width: 500px;
+ padding: 10px;
+}
+
+#login div div {
+ color: #fff;
+ padding: 10px 30px;
+ background: #000;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+#login p {
+ line-height: 28px;
+ margin: 20px 0;
+}
+
+#login a {
+ text-decoration: none;
+ display: inline;
+}
+
+#permalink {
+ font-size: 14px;
+}
410 snapbird.js
@@ -0,0 +1,410 @@
+var ify = function() {
+ return {
+ link: function(t) {
+ return t.replace(/[a-z]+:\/\/[a-z0-9-_]+\.[a-z0-9-_:~%&\?\/.=]+[^:\.,\)\s*$]/ig, function(m) {
+ return '<a href="' + m + '">' + ((m.length > 25) ? m.substr(0, 24) + '...' : m) + '</a>';
+ });
+ },
+ at: function(t) {
+ return t.replace(/(^|[^\w]+)\@([a-zA-Z0-9_]{1,15}(\/[a-zA-Z0-9-_]+)*)/g, function(m, m1, m2) {
+ return m1 + '@<a href="http://twitter.com/' + m2 + '">' + m2 + '</a>';
+ });
+ },
+ hash: function(t) {
+ return t.replace(/(^|[^\w'"]+)\#([a-zA-Z0-9_]+)/g, function(m, m1, m2) {
+ return m1 + '#<a href="http://search.twitter.com/search?q=%23' + m2 + '">' + m2 + '</a>';
+ });
+ },
+ clean: function(tweet) {
+ return this.hash(this.at(this.link(tweet)));
+ }
+ };
+}();
+
+var store = (function () {
+ var useStorage = !!window.localStorage;
+
+ return {
+ get: function (key) {
+ var value, ca, c, i;
+
+ if (useStorage) {
+ value = window.localStorage.getItem(key);
+ } else {
+ ca = document.cookie.split(';');
+ for (i=0; i < ca.length; i++) {
+ c = ca[i];
+ while (c.charAt(0)==' ') {
+ c = c.substring(1, c.length);
+ }
+ if (c && c.indexOf(key) == 0) {
+ value = c.substring(key.length,c.length);
+ break;
+ }
+ }
+ }
+
+ if (value == null) {
+ value == "";
+ }
+
+ return value;
+ },
+ set: function (key, value) {
+ if (useStorage) {
+ try {
+ window.localStorage.setItem(key, value);
+ } catch (e) {
+ // could be a QUOTA_EXCEEDED_ERR (for some reason Webkit is giving me this, just needs a restart and it goes away...)
+ }
+ } else {
+ document.cookie = key + "=" + value + "; path=/";
+ }
+ }
+ };
+})();
+
+// very hacky code - sorry!
+var $tweets = $('#tweets ul'), screen_name = '', url = '', page = 1, state = '', total_tweets = 0, statusTop = null;
+
+$('input.search').live('click', function () {
+ $('form').submit();
+ return false;
+});
+
+$(function () {
+ var msie6 = $.browser == 'msie' && $.browser.version < 7;
+ if (!msie6) {
+ $(window).scroll(function (event) {
+ var y;
+ // what the y position of the scroll is
+ if (statusTop != null) {
+ y = $(this).scrollTop();
+
+ // whether that's below the form
+ if (y >= statusTop) {
+ // if so, ad the fixed class
+ $('#tweets aside').addClass('fixed');
+ } else {
+ // otherwise remove it
+ $('#tweets aside').removeClass('fixed');
+ }
+ }
+ });
+ }
+});
+
+$('input[type=radio]').bind('click change', function () {
+ var withfriends = $('#withfriends').is(':checked');
+ var auth = $('#auth_screen_name').length;
+ if (withfriends && !auth) {
+ // show lightbox
+ $('body').addClass('auth');
+ } else if (withfriends) {
+ $('#auth_screen_name').css('display', 'inline-block');
+ $('#screen_name').hide();
+ } else { // not checked
+ $('#auth_screen_name').css('display', 'none');
+ $('#screen_name').show();
+ }
+});
+
+$('form').submit(function (e) {
+ e.preventDefault();
+ screen_name = $('#screen_name').val();
+
+ var newstate = $(this).serialize(),
+ timeline = 'http://twitter.com/statuses/user_timeline/' + screen_name + '.json',
+ favs = 'http://twitter.com/favorites/' + screen_name + '.json',
+ friends = '/friends.php',
+ type_string = 'tweets',
+ type = 'tweets',
+ list = '',
+ search = $('#search').val();
+
+ if (state != newstate) {
+ state = newstate;
+ store.set('screen_name', screen_name);
+
+ if ( $('#favs').is(':checked') ) {
+ url = favs;
+ type_string = 'favourites';
+ type = 'favs';
+ } else if ($('#withfriends').is(':checked')) {
+ url = friends;
+ type_string = 'friends&rsquo; tweets';
+ type = 'withfriends';
+ } else {
+ list = screen_name.match(/^(.*?)\/(.*?)$/);
+ if (list != null) {
+ // then we're a list
+ timeline = 'http://api.twitter.com/1/' + list[1] + '/lists/' + list[2] + '/statuses.json';
+ type_string = 'member tweets';
+ }
+ url = timeline;
+ }
+
+
+ page = 1;
+ total_tweets = 0;
+ $tweets.empty();
+
+ $('#permalink').attr('href', '/' + screen_name + '/' + type + '/' + encodeURIComponent(search));
+
+ $tweets.append('<li class="searchterm">Searching <em><strong>' + screen_name + '</strong>&rsquo;s ' + type_string + '</em> for <strong>' + search.replace(/<>/g, function (m) { return m == '<' ? '&lt;' : '&gt;'; }) + '</strong></li>');
+
+ // need a way to cancel all outstanding API requests - bespoke $.getJSONP on it's way!
+ }
+ // else { don't need page++ happens automatically in the success function }
+
+ getTweets();
+});
+
+function getTweets() {
+ var search = $('#search').val(), s = twitterSearch.formatSearch(search);
+
+ if (search) {
+ $('#status').html('<p>Searched ' + total_tweets + ' tweets.</p><p>Requesting more...</p>');
+
+ $.ajax({
+ url: url + '?count=200&per_page=200&page=' + page,
+ dataType: 'jsonp',
+ success: function (json) {
+ // update the page so that searching again requests the next page
+ page++;
+
+ var i = 0, j = 0, t, r, scrollPos = null, searches = s.and.concat(s.or).join('|');
+ total_tweets += json.length;
+ for (i = 0; i < json.length; i++) {
+ if (twitterSearch.filter(json[i], search)) {
+ t = tweet(json[i], i);
+ $tweets.append(t);
+
+ // really tricky code here, we're finding *this* and all nested text nodes
+ // then replacing them with our new <strong>text</strong> elements
+ $tweets.find('.entry-content:last, .entry-content:last *').contents().filter(function () {
+ return this.nodeName == '#text';
+ }).each(function () {
+ // ignore blank lines
+ // make matches bold
+ var change = '';
+ if (/[^\s]/.test(this.nodeValue)) {
+ // encoding of entities happens here, so we need to reverse back out
+ change = this.nodeValue.replace(/[<>&]/g, function (m) {
+ var r = '&amp;';
+ if (m == '<') {
+ r = '&lt;';
+ } else if (m == '>') {
+ r = '&gt;';
+ }
+ return r;
+ }).replace(new RegExp('(' + searches + ')', "gi"), "<strong>$1</strong>");
+ // need to convert this textNode to tags and text
+ $(this).replaceWith(change);
+ }
+ });
+
+
+ if (scrollPos == null) {
+ scrollPos = $tweets.find('li').offset().top;
+ }
+ }
+
+ if (scrollPos != null) {
+ console.log(scrollPos);
+ // $('body').animate({ scrollTop: scrollPos }, 500, function () {
+ // console.log('finished');
+ // });
+ }
+ }
+ $('#status').html('<p>Searched ' + total_tweets + ' tweets.</p><p>Read back to: <strong>' + twitter_time(json[json.length - 1].created_at).replace(/ (AM|PM)/, function (a, m) { return m.toLowerCase() + ','; }) + '</strong></p>');
+
+ if ($tweets.find('li').length == 0) {
+ // keep searching
+ // getTweets();
+ } else {
+ $('body').addClass('results');
+ if (statusTop == null) {
+ statusTop = $('#tweets aside').offset().top - parseFloat($('#tweets aside').css('margin-top').replace(/auto/, 0));
+ }
+ }
+ }
+ });
+ } else {
+ $('#status').html('Nothing to search for.');
+ }
+}
+
+function formatTime(date) {
+ var hour = date.getHours(),
+ min = date.getMinutes() + "",
+ ampm = 'AM';
+
+ if (hour == 0) {
+ hour = 12;
+ } else if (hour > 12) {
+ hour -= 12;
+ ampm = 'PM';
+ }
+
+ if (min.length == 1) {
+ min = '0' + min;
+ }
+
+ return hour + ':' + min + ' ' + ampm;
+}
+
+function formatDate(date) {
+ var ds = date.toDateString().split(/ /),
+ mon = ds[1],
+ day = ds[2],
+ dayi = ~~(day),
+ year = date.getFullYear(),
+ thisyear = (new Date()).getFullYear(),
+ th = 'th';
+
+ // anti-'th' - but don't do the 11th, 12th or 13th
+ if ((dayi % 10) == 1 && day.substr(0, 1) != '1') {
+ th = 'st';
+ } else if ((dayi % 10) == 2 && day.substr(0, 1) != '1') {
+ th = 'nd';
+ } else if ((dayi % 10) == 3 && day.substr(0, 1) != '1') {
+ th = 'rd';
+ }
+
+ if (day.substr(0, 1) == '0') {
+ day = day.substr(1);
+ }
+
+ return mon + ' ' + day + th + (thisyear != year ? ', ' + year : '');
+}
+
+function twitter_time(time_value) {
+ var values = time_value.split(" "),
+ parsed_date = Date.parse(values[1] + " " + values[2] + ", " + values[5] + " " + values[3]),
+ date = new Date(parsed_date),
+ relative_to = (arguments.length > 1) ? arguments[1] : new Date(),
+ delta = ~~((relative_to.getTime() - parsed_date) / 1000),
+ r = '';
+
+
+ delta = delta + (relative_to.getTimezoneOffset() * 60);
+
+ if (delta < 5) {
+ r = 'less than 5 seconds ago';
+ } else if (delta < 30) {
+ r = 'half a minute ago';
+ } else if (delta < 60) {
+ r = 'less than a minute ago';
+ } else if (delta < 120) {
+ r = '1 minute ago';
+ } else if (delta < (45*60)) {
+ r = (~~(delta / 60)).toString() + ' minutes ago';
+ } else if (delta < (2*90*60)) { // 2* because sometimes read 1 hours ago
+ r = 'about 1 hour ago';
+ } else if (delta < (24*60*60)) {
+ r = 'about ' + (~~(delta / 3600)).toString() + ' hours ago';
+ } else {
+ if (delta < (48*60*60)) {
+ r = formatTime(date) + ' yesterday';
+ } else {
+ r = formatTime(date) + ' ' + formatDate(date);
+ }
+ }
+
+ return r;
+}
+
+function tweet(data, i) {
+ var html = '<li><div class="tweet';
+ if (i == 0) {
+ html += ' first';
+ }
+
+ html += '"><div class="vcard"><a href="http://twitter.com/' + data.user.screen_name + '" class="url"><img alt="' + data.user.name + '" class="photo fn" height="48" src="' + data.user.profile_image_url + '" width="48" /></a></div>';
+
+ html += '<div class="hentry"><strong><a href="http://twitter.com/';
+ html += data.user.screen_name + '" ';
+ html += 'title="' + data.user.name + '">' + data.user.screen_name + '</a></strong> ';
+ html += '<span class="entry-content">';
+ html += ify.clean(data.text);
+ html += '</span> <span class="meta entry-meta"><a href="http://twitter.com/' + data.user.screen_name;
+ html += '/status/' + data.id + '" class="entry-date" rel="bookmark"><span class="published" title="';
+ html += data.created_at + '">' + twitter_time(data.created_at) + '</span></a> <span>from ';
+ html += data.source;
+ html += '</span></span></div></div></li>';
+
+ return html;
+}
+
+function getQuery(s) {
+ var query = {};
+
+ s.replace(/\b([^&=]*)=([^&=]*)\b/g, function (m, a, d) {
+ if (typeof query[a] != 'undefined') {
+ query[a] += ',' + d;
+ } else {
+ query[a] = d;
+ }
+ });
+
+ return query;
+}
+
+$('input[type=reset]').click(function () {
+ $tweets.empty();
+});
+
+if ( !$('#screen_name').val() ) {
+ $('#screen_name').val(store.get('screen_name'));
+}
+
+// check location.search to see if we need to prepopulate
+if (window.location.search) {
+ var query = getQuery(window.location.search.substr(1));
+ if (query.screen_name) {
+ $('#screen_name').val(decodeURIComponent(query.screen_name));
+ }
+ if (query.search) {
+ $('#search').val(decodeURIComponent(query.search));
+ }
+ if (query.favs) {
+ $('#favs').attr('checked', 'checked');
+ }
+}
+
+var $ref = $('<div>M</div>').css({
+ 'visibility' : 'hidden',
+ 'font-size': '10px',
+ 'line-height': '10px',
+ 'margin': 0,
+ padding: 0,
+ overflow: 'hidden'
+}).appendTo('body'), oh = 10;
+
+var timer = setInterval(function () {
+ var h = $ref.height();
+ if (h != oh && !$('#bang').length) {
+ // show exploded page
+ $('<div id="bang" />').appendTo('body');
+ } else if (h == oh && $('#bang').length) {
+ $('#bang').remove();
+ }
+}, 500);
+
+$('#auth .cancel').click(function () {
+ $('input[type=radio]:first').click();
+ $('body').removeClass('auth');
+});
+
+$('#logout').click(function () {
+ document.cookie = 'token=; path=/';
+});
+
+if ($('#screen_name').val() && $('#search').val()) {
+ try {
+ $('form').submit();
+ } catch (e) {
+ // why is this throwing in FF?
+ }
+}
1 twitterlib
@@ -0,0 +1 @@
+Subproject commit 891319a6d8bc81a13544f363c81491f17da8d215

0 comments on commit 2d24de1

Please sign in to comment.
Something went wrong with that request. Please try again.