Создание собственной ленты как в твиттере.

20-03-2010

Все кто есть или хотя бы видел твиттер, наверное заметили ленту где отображаются все твитты. Сейчас мы попробуем создать примерно такой же! Итак начнем!
Если вы хотите запустить демо версию на вашем собственном сайте вам придется создать MySQL таблицу где будут сохроняются все ваши твитты. Вы можете запустить следующий SQL код через phpMyAdmin. На всякий случай, таблица должна быть создана в той базе данных которую вы в будущем будете подключать к скрипту.

table.php

CREATE TABLE `demo_twitter_timeline` (
  `id` int(10) NOT NULL auto_increment,
  `tweet` varchar(140) collate utf8_unicode_ci NOT NULL default '',
  `dt` datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Благодоря Css и jQuery, наш Html код не очень сложный. Вот следующий файл который вам следует создать:

inde.php

<div id="twitter-container">
	<form id="tweetForm" action="submit.php" method="post">

		<span class="counter">140</span>
		<label for="inputField">What are you doing?</label>
		<textarea name="inputField" id="inputField" tabindex="1"rows="2" cols="40"></textarea>
		<input class="submitButton inact" name="submit" type="submit" value="update" />

		<span class="latest"><strong>Latest: </strong><span id="lastTweet"><?=?></span></span>

		<div class="clear"></div>
	</form>

	<h3 class="timeline">Timeline</h3>
	<ul class="statuses"><?=?></ul>
</div>

Наша лента расположена между двумя дивами (div) с id twitter-container. Его css описание рассмотрено ниже.
Ниже мы имеем форму с id tweetForm. Внутри формы мы имеем специальный span элемент который выступает в качестве счетчика, который показывает текущее количество символов в форме ввода текста. Как и в тыиттере лимитом будет 140 символов. Далее мы имеем форму ввода текста нашего твитта, и кнопку отправки твитта по умолчанию она неактивна (сделано это с помощью jQuery и специального Css класса inact, это мы рассмотрим позже).
После чего у нас расположен последний твитт, и наконец сама лента последних твиттов.

timeline

Теперь посмотрим на наш файл со стилями

demo.css:

/* Page styles */

body,h1,h2,h3,p,td,quote,small,form,input,ul,li,ol,label{
	margin:0px;
	padding:0px;
}

body{
	margin-top:20px;
	color:#51555C;
}

/* Form & timeline styles */

#twitter-container{
	-moz-border-radius:12px;
	-khtml-border-radius: 12px;
	-webkit-border-radius: 12px;
	border-radius:12px;

	border:6px solid #f5f5f5;

	padding:10px;
	width:600px;

	font-size:11px;
	font-family:'Lucida Grande',sans-serif;
	color:#333333;
}

label{
	font-size:20px;
	display:block;
}

.counter{
	color:#CCCCCC;
	float:right;
	font-family:Georgia,serif;
	font-size:32px;
	font-weight:bold;
	height:40px;
	overflow:hidden;
}

textarea{
	width:594px;
	height:38px;
	margin:5px 0 10px 0;

	border:1px solid #AAAAAA;
	padding: 4px 2px;

	font-family:'Lucida Grande',sans-serif;
	overflow:auto;
	font-size:14px;
}

.clear{
	clear:both;
}

.submitButton{
	color:#666666;
	font-size:14px;
	height:32px;
	width:115px;

	-moz-border-radius:6px;
	-khtml-border-radius: 6px;
	-webkit-border-radius: 6px;
	border-radius:6px;

	border:1px solid #cccccc;
	background:url(img/button_bg.gif) repeat-x #f5f5f5;

	cursor:pointer;
	float:right;
}

.submitButton:hover{
	background-position:bottom;
	border-color:#dddddd;
	color:#333333;
}

.inact,.inact:hover{
	background:#f5f5f5;
	border:1px solid #eeeeee;
	color:#aaaaaa;
	cursor:auto;
}

.latest{
	color: #666666;
}

ul.statuses{
	margin:10px 0;
}

ul.statuses li {
	position:relative;
	border-bottom:1px dashed #D2DADA;
	padding:15px 15px 15px 10px;
	list-style:none;
	font-size:14px;
}

ul.statuses li:first-child{
	border-top:1px dashed #D2DADA;
}

ul.statuses li:hover {
	background-color:#F7F7F7;
}

h3.timeline{
	margin-top:20px;
	color:#999999;
	font-size:20px;
	font-weight:normal;
}

div.tweetTxt{
	float:left;
	width:498px;
	overflow:hidden;
}

ul.statuses a img.avatar{
	float:left;
	margin-right:10px;
	border:1px solid #446600;
}
div.date{
	line-height:18px;
	font-size:12px;
	color:#999999;
}

li a, li a:visited {
	color:#007bc4;
	text-decoration:none;
	outline:none;
}

li a:hover{
	text-decoration:underline;
}

Начнем с определения стилей страницы. Сначала мы онулируем стили нашей страницы (внутренние внешние отступы страницы и некоторых элементов страницы) это нужно сделать потому что разные браузеры иногда добовляют свои стили к некоторым элементам страницы, поэтому практически у каждого грамотного вебмастера имеется свой reset файл который онулирует все стили страницы. После онулирования мы ставим верхний отступ для body и прописываем цвет текста для всей страницы.
В строках от 16 до 19 мы округляем div, который содержит нашу форму и ленту твиттов, подробное создание закругленных углов я описывал в этом уроке.
С 63ей строки мы описываем нашу кнопку, для нее мы снова использовали закругленные углы, другая важная вещь которую нужно отметить это то что мы для нее использовали фоновую картинку вот она. При наведении курсора фон смещается вниз.
На строке 87 описывается класс inact который отключает кнопку только когда страница щещ не загрузилась до конца и если поле ввода пусто.
Со строки 102 до 116 опсываются элементы ленты твиттов. Лента твиттов ничто иное как неупорядоченный список.
Рассмотрим jQuery код вот собственно js файл:

script.js

$(document).ready(function(){

	$('#inputField').bind("blur focus keydown keypress keyup", function(){recount();});
	$('input.submitButton').attr('disabled','disabled');

	$('#tweetForm').submit(function(e){

		tweet();
		e.preventDefault();

	});

});

function recount()
{
	var maxlen=140;
	var current = maxlen-$('#inputField').val().length;
	$('.counter').html(current);

	if(current<0 || current==maxlen)
	{
		$('.counter').css('color','#D40D12');
		$('input.submitButton').attr('disabled','disabled').addClass('inact');
	}
	else
		$('input.submitButton').removeAttr('disabled').removeClass('inact');

	if(current<10)
		$('.counter').css('color','#D40D12');

	else if(current<20)
		$('.counter').css('color','#5C0002');

	else
		$('.counter').css('color','#cccccc');

}

function tweet()
{
	var submitData = $('#tweetForm').serialize();

	$('.counter').html('loading');

	$.ajax({
		type: "POST",
		url: "submit.php",
		data: submitData,
		dataType: "html",
		success: function(msg){

			if(parseInt(msg)!=0)
			{
				$('ul.statuses li:first-child').before(msg);
				$("ul.statuses:empty").append(msg);

				$('#lastTweet').html($('#inputField').val());

				$('#inputField').val('');
				recount();
			}
		}

	});

}

Мы можем разделить этот код на три части. Скрипт который запускается после загрузки страницы. Функция recount() которая заполняет наш span счетчик количеством оставшихся символов. И функция tweet() которая обеспечивает работу AJAX и добавляет в ленту с твиттами обновления.
В первой части, в строке 3 вы можете видеть что мы связываем recount() с рядом событий которые могут произойти в поле ввода текста то есть textarea. Это потому что любое из этих событий не может гарантировать достаточно быстрое обновление счетчика, то есть событие происходит не часто.
На следующей строке мы отключаем кнопку отправки твитта – нам не нужно что бы пользователь мог отправлять пустые твитты.
Затем мы связываем событие формы onsubmit с функцией tweet().
В функции recount() есть ряд вещей о которых стоить упомянуть. В строках 17-19 мы считаем оставшееся количество символов до 140 и в строках 21-36, в зависимости от количества символов устанавливаем цыет счетчику, допустим если количество сиволов в поле ввода текста будет больше 140 то счетчик будет красным.
Мы также постоянно решаем нодо ли отключать кнопку или нет (если нет текста в поле ввода, или его больше 140 символов). Выключение/включение кнопки происходит путем изменения свойств атрибутов нашей кнопки с использованием CSS класса inact который убирает вид русора (рука) и меняет его цвет на светло-серый.
Функция tweet() это та функция в которой происходят чудеса. После нажатия на кнопку отправить, данные будут посланы в submit.php и в зависимости от возвращаемого значения, вставит полученный твитт в ленту твиттов строки 55 и 56. После вставки нового созданного твитта, мы очищаем поле ввода и обнуляем счетчик.
PHP
Наш php код управляет вставкой даных в MySQL базу данных и формированием твиттов в ленте.

submit.php

define('INCLUDE_CHECK',1);
require "functions.php";
require "connect.php";

if(ini_get('magic_quotes_gpc'))
$_POST['inputField']=stripslashes($_POST['inputField']);

$_POST['inputField'] = mysql_real_escape_string(strip_tags($_POST['inputField']),$link);

if(mb_strlen($_POST['inputField']) < 1 || mb_strlen($_POST['inputField'])>140)
die("0");

mysql_query("INSERT INTO demo_twitter_timeline SET tweet='".$_POST['inputField']."',dt=NOW()");

if(mysql_affected_rows($link)!=1)
die("0");

echo formatTweet($_POST['inputField'],time());

Сперва мы проверяем данные $_POST['inputField'] на длину и вставляем строку в базу данных. Затем выводи сформированный твитт с помощью formattweet, затем возврощаем функции tweet() как переменную msg.

Function.php

if(!defined('INCLUDE_CHECK')) die('You are not allowed to execute this file directly');

function relativeTime($dt,$precision=2)
{
	$times=array(	365*24*60*60	=> "year",
				30*24*60*60		=> "month",
				7*24*60*60		=> "week",
				24*60*60		=> "day",
				60*60			=> "hour",
				60				=> "minute",
				1				=> "second");

	$passed=time()-$dt;

	if($passed<5)
	{
		$output='less than 5 seconds ago';
	}
	else
	{
		$output=array();
		$exit=0;
		foreach($times as $period=>$name)
		{
			if($exit>=$precision || ($exit>0 && $period<60)) 	break;
			$result = floor($passed/$period);

			if($result>0)
			{
				$output[]=$result.' '.$name.($result==1?'':'s');
				$passed-=$result*$period;
				$exit++;
			}

			else if($exit>0) $exit++;

		}
		$output=implode(' and ',$output).' ago';
	}

	return $output;
}

function formatTweet($tweet,$dt)
{
	if(is_string($dt)) $dt=strtotime($dt);

	$tweet=htmlspecialchars(stripslashes($tweet));

	return'
	<li><a href="#"><img class="avatar" src="img/avatar.jpg" width="48" height="48" alt="avatar" /></a>
	<div class="tweetTxt">
	<strong><a href="#">demo</a></strong> '. preg_replace('/((?:http|https|ftp):\/\/(?:[A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?[^\s\"\']+)/i','<a href="$1" rel="nofollow" target="blank">$1</a>',).'
	<div class="date">'.relativeTime().'</div>
	</div>
	<div class="clear"></div>
	</li>';
}

Здесь вы можете увидеть 2функции. Первая relativetime() котрая отображает относительный период который прошел с тех пор как твитт был опудликованн. Вторая функция просто формирует твитт использую набранный текст и временную переменную.

timeline

Теперь давайте посмотрим как наша лента твиттов создается:

index.php

define('INCLUDE_CHECK',1);

require "functions.php";
require "connect.php";

// remove tweets older than 1 hour to prevent spam
mysql_query("DELETE FROM demo_twitter_timeline WHERE id>1 AND dt

Этот код нужно расположить в перед html кодом. Ну вот вроде и все! Демо версию я не стал делать так как она требует использование базы данных, а мне не хочется дополнительно нагружать сервер, но так как я урок переводил то вот демо