Современная, быстрая и удобная система управления сайтом

AJAX на MaxSite CMS

Архив записейКомментарии: 3Просмотров: 5270

Использование Аякса всегда имеет некоторые сложности, потому что требуется сразу решить несколько задач: 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]);
	};
  
	$("td.r" + t[0]).effect("highlight", {color: "#40FF40"}, 1500);
	$("td.r" + t[10]).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']);
		
		# $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]); 
			
			# пустая клетка?
			if ($ar[$n] === '') 
			{
				$ar[$n] = '0'; // да, ставим свой ход
				break; // выходим из цикла
			}
		}
		
		# наш ход в $ar[10]
		$ar[] = $n;
  
		# отправляем данные
		echo json_encode($ar);
	}
?>

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

Комментариев: 3 RSS

2Сергей26-11-2011 07:48

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

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

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

3Дмитрий05-06-2013 15:48

Работаю с ajax все отправка данных работает отлично и проверка в php тоже.

Но есть одно но, пытаюсь сделать ответ из базы данных обратно в ajax и тут не чего не выходит. Что можно здесь сделать?

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

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

Вы можете войти под своим логином или зарегистрироваться на сайте.

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