Здесь нам нужно добавить js скрипт и немного скорректировать форму. Находим:
{literal}
<script language="JavaScript" type="text/javascript">
document.addEvent('domready', function() {
new Autocompleter.Request.HTML($('topic_tags'), DIR_WEB_ROOT+'/include/ajax/tagAutocompleter.php', {
'indicatorClass': 'autocompleter-loading', // class added to the input during request
'minLength': 2, // We need at least 1 character
'selectMode': 'pick', // Instant completion
'multiple': true // Tag support, by default comma separated
});
});
</script>
{/literal}
Меняем на (комментарии в коде):
{literal}
<script language="JavaScript" type="text/javascript">
document.addEvent('domready', function() {
new Autocompleter.Request.HTML($('topic_tags'), DIR_WEB_ROOT+'/include/ajax/tagAutocompleter.php', {
'indicatorClass': 'autocompleter-loading', // class added to the input during request
'minLength': 2, // We need at least 1 character
'selectMode': 'pick', // Instant completion
'multiple': true // Tag support, by default comma separated
});
});
// Создаем функцию для автосохранения черновика
autosave = function(){
// Если пользователь не запретил автосохранение, то
// формируем и отправляем ajax-запрос
if(!$('draft_autosave_disabled').get('checked')) {
// Отправляем запрос
JsHttpRequest.query(
DIR_WEB_ROOT+'/include/ajax/autosaveTopic.php',
{ params: $('form_topic').toQueryString() },
function(result, errors)
{
if (!result) {
msgErrorBox.alert('Error','Please try again later');
}
if (result.bStateError) {
msgErrorBox.alert(result.sMsgTitle,result.sMsg);
} else {
msgNoticeBox.alert('Автосохранение','Черновик успешно сохранен');
// Указываем пользователю на время сохранения
$('autosave_time').innerHTML = "Последнее автосохранение: "+result.sTime;
$('autosave_time').style.display="block";
// Добавляем в форму информацию о идентификаторе черновика
if(result.sId) {
$('draft_id').setProperty('value', result.sId);
}
}
},
true
);
}
};
// Вызываем выполнение функции каждые 30 секунд
// Настроить по своему усмотрению
autosave.periodical(30000);
</script>
{/literal}
Теперь находим форму для создания топика и вносим следующие коррективы.
(Это сделано для того, чтобы пользователь мог создавая запись, вручную отключить автосохранения — ему достаточно для этого поставить в этом поле галочку.)
2. Создаем файл /include/ajax/autosaveTopic.php
Это файл будет обрабатывать запрос на сохранение и возвращать ответ. Скачиваем файл здесь. Комментарии к действиям по коду расставлены достаточно обильно.
(С удовольствием бы выложил код в записи, но там 200 строк, и не эстетично, и редактор не позволяет :))
3. Файл /classes/actions/ActionTopic.class.php
Далее, есть несколько путей реализации. Я выбрал наиболее простой, с той целью, чтобы не трогать структуру базы и не переписывать все Event`ы по другому.
Для того, чтобы понять, что мы делаем в этом action`е, давайте представим сам процесс работы пользователя с новой записью.
а) Открывается страничка «создать» («редактировать», в данный момент не важно).
б) На ней создается форма, в которой указан идентификатор autosave-черновика = 0.
в) При отправке ajax запроса на автосохранение, система создаст новый черновик, вернет его идентификатор, который будет занесен в поле draft_id.
г) Каждый следующий запрос автосохранения будет обновлять этот черновик.
д) Далее, существует два варианта: первая, пользователь не смог по каким-то причинам сохранить запись в черновики или опубликовать — тогда наше автосохранение ему очень поможет (храниться со всеми черновиками), вторая — пользователь сохранил запись или опубликовал ее. В этом случае, мы просто удаляем autosave-черновик, закрепленный за записью. Останется либо новый черновик пользователя, либо публикация, либо autosave создастся заново (в случае, когда запись не прошла валидацию и возвращена системой «на доработку»).
Есть и другие схемы работы, но о них позже. Давайте сначала реализуем это.
Находим
protected function SubmitAdd() {
/**
* Проверяем отправлена ли форма с данными(хотяб одна кнопка)
*/
if (!isset($_REQUEST['submit_topic_publish']) and !isset($_REQUEST['submit_topic_save'])) {
return false;
}
И добавляем после этих строк
/**
* Здесь мы проверяем, если есть прикрепленный autosave,
* то удаляем его. В случае, если заметка не пройдет валидацию,
* autosave-черновик будет создан заново
*/
if( $sDraftId = getRequest('draft_id',0) ) {
@$this->Topic_DeleteTopic($sDraftId);
}
Находим
protected function SubmitEdit($oTopic) {
И добавляем после этой строки
/**
* Здесь мы проверяем, если есть прикрепленный autosave,
* то удаляем его. В случае, если заметка не пройдет валидацию,
* autosave-черновик будет создан заново
*/
if( $sDraftId = getRequest('draft_id',0) ) {
@$this->Topic_DeleteTopic($sDraftId);
}
На этом наши приключения закончились, можете тестировать. Если о чем-то забыл, пишите в комментариях.
Теперь, о других схемах. Вообще, предполагаю, что будет недовольство из-за увеличения количество запросов на базу данных и объема хранимой информации. Но…
В WordPress действует система «ревизии» записи. Каждое автосохранение, если оно чем-то отличается от предыдущего будет записано в базу отдельной строкой, с пометкой review. Плюс в том, что ревизии живут своей отдельной жизнью, и можно вернуть свою запись к состоянию любой из них. Минус также очевиден, очень большой объем дополнительной информации. В блоге одного человека это может быть некритичным, а вот на блогоплатформе так играться, наверное, не стоит. Тем более, такое решение вынуждает нас менять структуру базы — автосейв в этом случае должен иметь особый статус и привязку к родительской заметке.
Такое решение не подходит.
Можно было бы поступить так: при передачи запроса на публикацию, при существующем autosave-черновике доставать из базы этот черновик и update`ить его, а не создавать новую запись, удаляя черновик. Но, приводит к необходимости почти полностью переписывать все Event, связанные с добавлением, редактированием и обработкой отправленных форм (submit). Вся проблема в том, что запись может и не пройти валидацию. Тогда нам нужно учитывать это, перепривязывая черновик от одной страницы до другой…
Сильно переписывать module не хочется, тем более один из центральных. Будут потом проблемы при апгрейдах.
В общем, если кто-то придумает простой выход, как оптимизировать работу с черновиками, пишите в комментариях. Будем разбираться.
С этим как раз проблем нет. Если топик не прошел валидацию, то все данные в форме останутся на месте. Ничего не пропадет, а через 30 секунд как обычно контент формы будет помещен в новосозданный авто-черновик.
У меня БД сейчас пестрит черновичками, и у меня два вопроса:
а) черновики так и будут висеть мёртвым грузом до бесконечности?
б) Кроме как через БД никак не вернуться к сохраняемым периодически версиям (как это реализовано в WordPress, где можно перейти к той или иной версии и её восстановить)?
Согласен… Тоже не удаляется автоматом. Надо просто подобрать, очевидно, какой-то такой интервал между автосохранениями, чтобы не каждые 30 сек. навая запись в таблице появлялась. Поставил 3 минуты. Но просто сколько будет хлама, если юзер, предположим, час пишет топик. С другой стороны, можно и 10 мин. поставить, но это много. В идеале, если это возможно, здорово было бы как-то крона настроить, чтоб, например, искал черновики и при наличии >=5 черновиков для одного топика за один день, сносил бы, например, в 00:00 четыре, оставляя последний. Ну как-то так…
У меня только что вылетела Опера вместе с результатом четырёхчасового мозгового штурма…
Вместо того, чтобы беситься — пошёл на лайвстрит.ру, вбил «автосохранение» в поиск и радуюсь найденному.
Непременно поставлю. Функция необходима в базовой поставке!
Ахтунг!
Пользователь расстроен. А расстроен вот почему:
'topic_create_text_error_unique' => 'Вы уже писали топик с таким содержанием'
Я пытаюсь разобраться, почему оное выскакивает, но такого топика (опубликованного) нет! Но в базу много записей от автосохранения черновика. Поможите, пожалуйста, что бы это могло быть?
проблема в том что автосохранение не знает что этот топик уже сохранен, сохраняет его снова и только тогда записывает в /> что топик сохранен под таким-то номером.
проблема в том что автосохранение не знает что этот топик уже сохранен, сохраняет его снова и только тогда записывает в <input type=«hidden» name=«draft_id» value=«0» id=«draft_id»/> что топик сохранен под таким-то номером.
решается это так: <input type=«hidden» name=«draft_id» value="{$_aRequest.topic_id}" id=«draft_id»/>
22 комментария
а) черновики так и будут висеть мёртвым грузом до бесконечности?
б) Кроме как через БД никак не вернуться к сохраняемым периодически версиям (как это реализовано в WordPress, где можно перейти к той или иной версии и её восстановить)?
Вместо того, чтобы беситься — пошёл на лайвстрит.ру, вбил «автосохранение» в поиск и радуюсь найденному.
Непременно поставлю. Функция необходима в базовой поставке!
Авторы, СПАСИБО!
Пользователь расстроен. А расстроен вот почему:
Я пытаюсь разобраться, почему оное выскакивает, но такого топика (опубликованного) нет! Но в базу много записей от автосохранения черновика. Поможите, пожалуйста, что бы это могло быть?
Помогает только удаление всех черновиков и быстрая отправка топика.
Я сейчас сделал в add.tpl:
, вроде бы работает, хотя могут быть неожиданности, не дружу пока с MooTools.
Ещё хорошо бы добавить проверку, были ли внесены изменения с последнего сохранения, но сейчас уже совсем нет на это времени(
решается это так: />
решается это так: <input type=«hidden» name=«draft_id» value="{$_aRequest.topic_id}" id=«draft_id»/>