AJAX на MaxSite CMS

1 октября 2009 г. Просмотров: 5250 RSS 2
MaxSite CMS » Основы

Использование Аякса всегда имеет некоторые сложности, потому что требуется сразу решить несколько задач: HTML + CSS, PHP и JS. Сегодня я расскажу как можно создать небольшое приложение на MaxSite CMS.

Назвал я его «Крестики-нолики» по аналогии с одноименной игрой. Правда я не стал реализовывать алгоритм поиска верных ходов и анализ выигрышних комбинаций. Эта часть довольно трудоёмкая, и при желании, вы можете её самостоятельно сделать.

Для начала, как обычно, нужно составить небольшое ТЗ.

  • У нас будет приложение, которое мы оформим в виде шаблона MaxSite CMS. Пусть он называется «cross».
  • Нужно оформить внешний вид в виде клеток 3x3.
  • Нужно использовать анимацию для красоты.
  • Нужно запретить ставить ходы на уже занятые клетки.
  • Ответ сервера будет генерироваться случайным образом из пустых клеток.
  • Ответ сервера нужно получать без перезагрузки страницы по AJAX.

Итак приступаем.

Делаем каталог «cross» и в нем располагаем файлы index.php и info.php. Поскольку у нас будет только одна страница, то в index.php мы подключим основной файл нашего приложения cross.php:

require('cross.php');

Почему мы делаем подключение еще одного файла, а не сразу программируем в index.php? Всё просто: я стараюсь использовать «классический» вариант построения шаблона MaxSite CMS, где index.php выполняет роль диспетчера типов данных. То есть, если у вас возникнет потребность что-то добавить, то это легко сделать именно в index.php.

По этой же причине мы оформим наш HTML в виде файлов:

  • main-start.php
  • header.php
  • main-end.php
  • style.css

Описывать разметку нет смысла, потому что дизайн будет зависеть от ваших потребностей, просто остановлюсь на нескольких моментах.

Прежде всего еще раз напомню как происходит подключение файлов. В index.php мы подключаем cross.php. Этот файл в свою очередь выполняется так:

require(getinfo('template_dir') . 'main-start.php');
тут наш код
require(getinfo('template_dir') . 'main-end.php');

В main-start.php мы подключаем header.php. Таким образом наш шаблон разбит на секцию HEAD, начальную часть, выполняемую и конечную.

В header.php мы должны подключить jQuery, поскольку js-часть будет использовать именно эту библиотеку. Кроме этого мы вынесем свою часть js в отдельный файл (my.js).

<?= mso_load_jquery() ?>
<?= mso_load_jquery('ui/effects.core.packed.js') ?>
<?= mso_load_jquery('ui/effects.highlight.packed.js') ?>
<script type="text/javascript" src="<?= getinfo('stylesheet_url') ?>js/my.js"></script>

В первой строчке подключаем jQuery. Во второй и третьей подключаем эффекты. Последней - наш скрипт.

Теперь давайте перейдем к cross.php. Я решил не усложнять задачу, поэтому наше поле 3x3 оформил в виде обычной таблицы, где каждой ячейке прописал свой class. Поскольку код очень маленький, то я привожу полный листинг файла:

<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); 
  
# начальная часть шаблона
require(getinfo('template_dir') . 'main-start.php');
?>
  
<table>
  
<tr>
<td class="r1"></td>
<td class="r2"></td>
<td class="r3"></td>
</tr>
  
<tr>
<td class="r4"></td>
<td class="r5"></td>
<td class="r6"></td>
</tr>
  
<tr>
<td class="r7"></td>
<td class="r8"></td>
<td class="r9"></td>
</tr>
  
</table>
  
<?php
# конечная часть шаблона
require(getinfo('template_dir') . 'main-end.php');
?>

Оформление я вынес в style.css.

Уверен, что никаких сложностей с пониманием этого кода у вас не возникнет. В браузере это будет выглядеть так:

Теперь переходим к самому интересному: определим алгоритм работы. У нас есть уникальные ячейки (td.class) - по ним мы можем отследить какой был клик/ход. На сервер нам нужно передавать не только последний ход посетителя, но и всю таблицу. Сделать это можно получив js-свойство text() каждой ячейки и сформировав строчку вида: «r1 - - X - 0 - - - -». Где элементы разделены пробелом; если «-», значит клетка пустая; «X» - ход посетителя; «0» - ход сервера.

Эту строчку мы передаем на сервер, что-то с ней делаем и отдаем обратно в виде массива (в формате JSON). JS-скрипт обходит этот массив и устанавливает тексты ячеек таблицы в соответствии с массивом. В массиве от сервера мы также передадим и номер хода - он потребуется для анимации.

Теперь перейдем непосредственно к js. В файле my.js вначале подключим jQuery.

$(function(){
тут js-код
});

Все дальнейшие действия мы будем проводить внутри этого блока.

Для начала определимся с анимацией. Я выбрал «вспышку», которая будет происходить когда курсор мыши находится над ячейкой таблицы:

$('td').mouseover(
		function()
		{
			if ( $(this).text() ) 
				$(this).effect("highlight", {color: "#FFE0E0"}, 500);
			else
				$(this).effect("highlight", {color: "#A0FFA0"}, 500);
		});

Единственный момент - я указал условие «if ( $(this).text() )», которое проверяет есть ли текст внутри ячейки. Если есть, значит в ней ход ставить нельзя и мы подсвечиваем его светло-красным. Если же текста нет, то это пустая ячейка и она подсвечивается светло-зеленым.

Теперь нам нужно определить действия по клику.

$("td").click(function()
	{
	наши действия
	};

Для начала мы должны запретить действия, если ход запрещен. Код вам уже знаком:

if ( $(this).text() ) 
		{
			$(this).effect("highlight", {color: "#FF0000"}, 200);
			return;
		}

Подсвечиваем красным и выходим из функции.

Теперь нам нужно создать строчку, которую мы отправим на сервер. Каждая ячейка может содержать три значения: пусто, X и 0. Я сделал вспомогательную функцию, которая получает какое-то значение текста, а на выходе отдает одно из трех вариантов (пусто заменяем на «-»).

function k(e)
		{
			if (e)
			{ 
				if ( e == "0") m = "0";
					else m = "X";
			}
			else m = "-"; 
			return m;
		}

Составить строчку теперь не составлает труда:

var s = $(this).attr("class") + ' '
			+ k($("td.r1").text()) + ' '
			+ k($("td.r2").text()) + ' '
			+ k($("td.r3").text()) + ' '
			+ k($("td.r4").text()) + ' '
			+ k($("td.r5").text()) + ' '
			+ k($("td.r6").text()) + ' '
			+ k($("td.r7").text()) + ' '
			+ k($("td.r8").text()) + ' '
			+ k($("td.r9").text());

Мы прогоняем через функцию k() каждую ячейку и получаем строчку, разделенную пробелами. Вот эта часть «$(this).attr("class")» возвращает класс нажатой ячейки (r1-r9). То есть на сервере по этому значению мы можем отследить последний ход.

Для того чтобы отправить строчку на сервер используется несколько функций. Я остановился на $.ajax(), которая считается универсальной.

$.ajax({
			type: "POST",
			url: path_ajax,
			data: "cross=" + s,
			dataType: "text",
			success: function(msg)
			{
				ответ сервера в msg
		   	}
		});

Мы отправляем данные как POST. Данные (data) отправляются как поле «cross». Тип - текст.

Ответ сервера помещается в success в виде аргумента функции, в нашем случае это msg.

Теперь самое интересное. Обратите внимание на переменнную path_ajax. Это путь к «приёмному» php-файлу. Здесь я хочу остановиться поподробнее.

Путь к файлу нужно указывать полным в виде адреса. Казалось бы ничего сложного, однако есть маленький нюанс. Если мы напрямую обратимся к php-файлу, то мы не сможем получить доступ к MaxSite CMS! Очень часто нужна работа АЯКСА именно в рамках системы. Например при отправке данных со страницы какой-то записи. Очевидно, что одиночный php-скрипт просто не получит никаких данных об отправляемой странице. Чтобы обойти все эти ограничений в MaxSite CMS используется предопределенный тип данных «ajax» (http://сайт/ajax/). Во втором сегменте (уточнение ниже) нужно указать путь до файла относительно каталога «maxsite».

В нашем примере это будет так:

http://сайт/ajax/templates/cross/cross-post-ajax.php

Получив такой адрес, MaxSite CMS подключит файл

путь_на_сервере/application/maxsite/templates/cross/cross-post-ajax.php

Таким образом обращение к cross-post-ajax.php произойдет уже на уровне системы и мы преспокойно можем использовать все её функции, плагины и т.п.

Однако это еще не всё. Тип «ajax» должен иметь только один сегмент URL. Дело в том, что адреса могут быть самыми разными и иметь разную вложенность («/»). И чтобы не «сбивать» сегменты URL следует кодировать путь к файлу с помощью base64.

Таким образом путь определяется так:

$p = getinfo('ajax') 
	. base64_encode( 'templates/' . getinfo('template') . '/cross-post-ajax.php' );

В итоге получится что-то вроде такого:

http://сайт/ajax/dGVtcGxhdGVzL2Nyb3NzL2Nyb3NzLXBvc3QucGhw

Система автоматически декодирует эту строчку и подключит нужный файл.

В последних версиях MaxSite CMS в целях безопасности имя ajax-файла должно иметь формат «имя-ajax.php». Только в этом случае произойдет его подключение.

Ну вот, когда мы определились с путями для Аякса, нам следует передать имя файла в наш js-скрипт. Очевидно, что php выполнять в js-файле не получится, поэтому мы с помощью php сгенерируем js-код, где в качестве переменной path_ajax укажем путь к файлу.

Перед подключением my.js в header.php допишем:

<script type="text/javascript">
	var path_ajax = "<?= getinfo('ajax') . base64_encode( 'templates/' . getinfo('template') . '/cross-post-ajax.php' ) ?>";
</script>

Как видите всё очень просто.

Что делать если нужно оправлять несколько Аякс-запросов к разным файлам? В принципе можно задать для них разные переменные, вроде path_ajax, path_ajax1, path_ajax2 и т.д. Но можно воспользорваться и одним. В этом случае в «приёмном» файле следует отслеживать входные данные (в $.ajax это data) и от этого подключать другие php-файлы.

Последняя часть работы с js - получив ответ сервера, изменить тексты ячеек. Сервер будет отдавать массив, где ключи совпадают с номером ячейки, а значения - с текстом. Таким образом мы просто обходим массив и расставляем тексты в ячейки.

...
success: function(msg)
{
	var t = eval('(' + msg + ')');
  
	for (var i = 1; i < 10; i++)
	{
		$("td.r" + i).text(t[i]<img src="http://maxsite.org/uploads/smiles/wink.gif" width="19" height="19" alt="wink" style="border:0;" class="smiley">;
	};
  
	$("td.r" + t[0]<img src="http://maxsite.org/uploads/smiles/wink.gif" width="19" height="19" alt="wink" style="border:0;" class="smiley">.effect("highlight", {color: "#40FF40"}, 1500);
	$("td.r" + t[10]<img src="http://maxsite.org/uploads/smiles/wink.gif" width="19" height="19" alt="wink" style="border:0;" class="smiley">.effect("highlight", {color: "#FFA080"}, 1500);
}

Первая строчка - преобразование JSON-данных в обычный js-массив. Дальше мы запускаем цикл for с 1 по 9 и выставляем тексты. Последние две строчки - анимация. В нулевом элементе у нас хранится последний ход посетителя, в 10-м - ход сервера.

С js покончено, переходим к php-части. Как вы уже поняли из описаний выше, наш «приёмный» файл это cross-post-ajax.php.

Работа в нем организуется аналогично обработке обычной формы, а результат нужно отдать по echo, предварительно кодировав его в формат JSON.

Дальше я привожу полный листинг с комментариями.

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  
	mso_checkreferer(); // защищаем реферер
  
	if ( $post = mso_check_post(array('cross')) )
	{
		# разобьем строку в массив
		$ar = explode(' ', $post['cross']<img src="http://maxsite.org/uploads/smiles/wink.gif" width="19" height="19" alt="wink" style="border:0;" class="smiley">;
		
		# $ar[0] - это только что выбранная ячейка
		# $ar[1]...$ar[9] - клетки
		# если «-» - пустая
		# если «X» - ход посетителя
		# если «0» - ход сайта
		
		# заменим - на ''
		foreach ($ar as $key => $val) if ($ar[$key] == '-') $ar[$key] = '';
		
		# добавим X в новый ход
		# сразу преобразуем в число - это номер ячейки
		$ar[0] = substr($ar[0], 1, 1);
		$ar[ $ar[0] ] = 'X';
		
		
		# после выбираем свой ход случайно из пустых
		
		# сделаем массив от 1 до 9
		$my_hod = array_fill(1, 9, '0');
		
		while($my_hod)
		{
			# случайный элемент
			$n = array_rand($my_hod);
			
			# удалим его, чтобы повторно не обращаться
			unset($my_hod[$n]<img src="http://maxsite.org/uploads/smiles/wink.gif" width="19" height="19" alt="wink" style="border:0;" class="smiley">; 
			
			# пустая клетка?
			if ($ar[$n] === '') 
			{
				$ar[$n] = '0'; // да, ставим свой ход
				break; // выходим из цикла
			}
		}
		
		# наш ход в $ar[10]
		$ar[] = $n;
  
		# отправляем данные
		echo json_encode($ar);
	}
?>

Скачать «Крестики-нолики» 147 (ок. 23КБ.)


twitter.com facebook.com vkontakte.ru odnoklassniki.ru mail.ru friendfeed.com google.com yandex.ru
Комментариев: 2
  1. Тест.

  2. 2011-11-26 в 09:48:09 | Сергей

    Спасибо, все работает, но:

    при ошибке возвращает 200 ОК со всеми вытекающими последствиями, если вместо die

    {header("HTTP/1.0 404 Not Found"); die();}
    и добавить еще строчку чтобы если файл не существует, также возвращало ошибку.

Оставьте комментарий!

grin LOL cheese smile wink smirk rolleyes confused surprised big surprise tongue laugh tongue rolleye tongue wink raspberry blank stare long face ohh grrr gulp oh oh downer red face sick shut eye hmmm mad angry zipper kiss shock cool smile cool smirk cool grin cool hmm cool mad cool cheese vampire snake excaim question

Комментарий будет опубликован после проверки

(войти без комментирования)

Имя и сайт используются только при регистрации

Авторизация: Loginza.

(обязательно)