Ответ 1
Я уверен, что есть много способов снять это, но здесь мое решение. Я использую Smarty Template Engine, но этот метод также должен работать с HTML-ванили.
Во-первых, вот пример некоторого HTML, хранящегося в моем файле шаблона с именем "dog_fleas.tpl":
<script type="text/javascript" src="/js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="/js/admin/mycms.js"></script>
<div>
<div id="flea-blurb" tpl="/templates/dog_fleas.tpl" contenteditable="true">
<h1>My Dog Has Fleas</h1>
<p>This text is editable via the CMS!</p>
</div>
<p>This text is not editable</p>
</div>
javascript (mycms.js) для обработки встроенного редактирования:
$(document).ready(function() {
CKEDITOR.disableAutoInline = true;
$("div[contenteditable='true']" ).each(function( index ) {
var content_id = $(this).attr('id');
var tpl = $(this).attr('tpl');
CKEDITOR.inline( content_id, {
on: {
blur: function( event ) {
var data = event.editor.getData();
var request = jQuery.ajax({
url: "/admin/cms-pages/inline-update",
type: "POST",
data: {
content : data,
content_id : content_id,
tpl : tpl
},
dataType: "html"
});
}
}
} );
});
});
Вышеприведенный код делает несколько вещей:
- Он преобразует любой тег div с атрибутом contenteditable = "true" в inline-editable.
- После редактирования содержимого (при размывании) идентификатор редактируемого элемента, имя файла tpl и отредактированный контент отправляются на сервер через вызов ajax.
В моей ситуации атрибут tpl необходим для идентификации редактируемого файла. Идентификатор элемента указывает, какой элемент был изменен.
Хотя мой пример содержит только один редактируемый регион, этот код поддерживает несколько редактируемых областей в одном файле.
На стороне сервера, здесь мой PHP-код. Я использую фреймворк, поэтому мои функции $this → _ POST() могут выглядеть немного необычно, но, надеюсь, вы получите идею:
// Get the posted parameters
$new_content = $this->_POST('content');
$content_id = $this->_POST('content_id');
$tpl_filename = $this->_POST('tpl');
// Get the contents of the .tpl file to edit
$file_contents = file_get_contents(APPPATH . 'views' . $tpl_filename);
// create revision as a backup in case of emergency
$revised_filename = str_replace('/', '.', $tpl_filename);
$revised_filename = ltrim ($revised_filename, '.');
file_put_contents(APPPATH . 'views/templates/revisions/' . $revised_filename . '.' . time(), $file_contents);
// Prepare to match the DIV tag
// Credit to: http://stackoverflow.com/questions/5355452/using-a-regular-expression-to-match-a-div-block-having-a-specific-id
$re = '% # Match a DIV element having id="content".
<div\b # Start of outer DIV start tag.
[^>]*? # Lazily match up to id attrib.
\bid\s*+=\s*+ # id attribute name and =
([\'"]?+) # $1: Optional quote delimiter.
\b' . $content_id . '\b # specific ID to be matched.
(?(1)\1) # If open quote, match same closing quote
[^>]*+> # remaining outer DIV start tag.
( # $2: DIV contents. (may be called recursively!)
(?: # Non-capture group for DIV contents alternatives.
# DIV contents option 1: All non-DIV, non-comment stuff...
[^<]++ # One or more non-tag, non-comment characters.
# DIV contents option 2: Start of a non-DIV tag...
| < # Match a "<", but only if it
(?! # is not the beginning of either
/?div\b # a DIV start or end tag,
| !-- # or an HTML comment.
) # Ok, that < was not a DIV or comment.
# DIV contents Option 3: an HTML comment.
| <!--.*?--> # A non-SGML compliant HTML comment.
# DIV contents Option 4: a nested DIV element!
| <div\b[^>]*+> # Inner DIV element start tag.
(?2) # Recurse group 2 as a nested subroutine.
</div\s*> # Inner DIV element end tag.
)*+ # Zero or more of these contents alternatives.
) # End 2$: DIV contents.
</div\s*> # Outer DIV end tag.
%isx';
if (preg_match($re, $file_contents, $matches))
{
$content_to_replace = $matches[0];
$replacement_content = $content_to_replace;
// Replace the inner content of $replacement_content with $new_content
$replacement_content = preg_replace('/(<div(?:.*?)>)(?:.*)(<\/div>)/msi',"$1" . $new_content . "$2", $replacement_content);
// Now replace the content_to_replace with $replacement content in the HTML
$new_file_contents = str_replace($content_to_replace, $replacement_content, $file_contents);
// write out the new .tpl file
file_put_contents(APPPATH . 'views' . $tpl_filename, $new_file_contents);
}
PHP-код, приведенный выше, в основном загружает HTML, размещает тег div соответствующим идентификатором, а затем заменяет содержимое этого тега div содержимым, отправленным с помощью вызова ajax. Затем HTML повторно сохраняется на сервере. Я также включаю в себя некоторый код для хранения резервных копий на всякий случай, если все идет ужасно неправильно.
Я понимаю, что регулярные выражения не всегда являются лучшим решением. В моем случае было трудно использовать PHP Object Object Model, потому что мой HTML-контент недействителен HTML. Вместо этого вы можете изучить модель объекта-объекта, если ваша система проще, чем моя.
Надеюсь, это поможет!