tranphuhien514
New member
Description of the /manager File – HTML Editor with Live Preview
This is a customized content management tool that allows users to create and edit blog posts using raw HTML. It replaces the traditional Markdown editor with an HTML-based editor and includes a Preview button for live visualization of the content.
Key Features:
- Full support for editing and formatting content using HTML.
- Integrated CodeMirror editor for a better coding experience with syntax highlighting, auto-closing tags, and line numbers.
- A Preview button lets users instantly see the rendered HTML output, allowing for more accurate content creation.
- Supports creating new articles, editing existing ones, and deleting posts by ID.
- Category selection is required when posting, with built-in validation for title and content length.
- User authentication is required to access this manager, ensuring only logged-in users can use it.
How to Use:
- Access the editor through the URL path: /manager (or any custom path you choose, such as /editor, /abcd, etc.)
- Use the form to input the title, select a category, write HTML content, and preview it before publishing.
- The same file can be renamed and used under any route, as long as you remember its path.
{% use '_blocks' %}
{% set title = 'Dashboard' %}
{% from '_func' import is_login %}
{% if is_login()|trim != 'true' %}{{redirect('/')}}{% endif %}
{{block('header')}}
<article>
{% set uri = get_uri_segments() %}
{% if uri[1] == 'post' %}
{% if get_data_count('category') < 1 %}
{{redirect('/manager/category')}}
{% endif %}
{% set blogid = get_uri_segments()[2] %}
{% if blogid and check_data('blog', blogid|trim) %}
{% if get_get('action') == 'delete' %}
{% do delete_data_by_id('blog', blogid|trim) %}
{{redirect('/')}}
{% endif %}
{% set blogdata = get_data_by_id('blog', blogid|trim).data %}
{% set name, category, content = get_post('title')|trim|default(blogdata.title), get_post('category')|trim|default(blogdata.category), get_post('content')|trim|default(blogdata.content) %}
{% set error = null %}
{% if request_method()|lower == 'post' %}
{% if name|length not in 5..200 %}
{% set error = 'Invalid title. (length 5..200)' %}
{% elseif content|length not in 5..10000 %}
{% set error = 'Invalid content. (length 5..10000)' %}
{% else %}
{% set slug = slug(name) %}
{% do update_data_by_id('blog', blogid|trim, {'category': category, 'title': name, 'slug': slug, 'content': content}) %}
{{redirect('/view/'~slug~'-'~blogid|trim~'.html')}}
{% endif %}
{% endif %}
{% else %}
{% set error = null %}
{% if request_method()|lower == 'post' %}
{% set name, category, content = get_post('title')|trim, get_post('category')|trim, get_post('content')|trim %}
{% if name|length not in 5..200 %}
{% set error = 'Invalid title. (length 5..200)' %}
{% elseif content|length not in 5..10000 %}
{% set error = 'Invalid content. (length 5..10000)' %}
{% else %}
{% set slug = slug(name) %}
{% do save_data('blog', {'category': category, 'title': name, 'slug': slug, 'content': content}) %}
{{redirect('/')}}
{% endif %}
{% endif %}
{% endif %}
<div class="card" style="margin-bottom:8px">
<div class="card-header">
<i class="fa fa-pencil" aria-hidden="true"></i> {% if blogid and check_data('blog', blogid|trim) %}Edit article{% else %}Publish new articles{% endif %}
</div>
<div class="card-body">
{% if error %}<p class="alert alert-warning">{{error|raw}}</p>{% endif %}
<form name="form" action method="post">
<p><input name="title" type="text" value="{{name}}" placeholder="Title" maxlength="300" class="form-control" required/></p>
<p>
<select name="category" class="form-select" required>
<option value="">Select category</option>
{% for cat in get_data('category') %}{% set data = cat.data %}
<option value="{{cat['id']}}"{% if cat['id'] == category %} selected{% endif %}>{{data['name']}}</option>
{% endfor %}
</select>
</p>
<p>
<textarea id="content" name="content" rows="15" class="form-control" placeholder="Nhập HTML ở đây...">{{content|raw}}</textarea>
</p>
<p>
<input type="submit" name="submit" value="{% if blogid and check_data('blog', blogid|trim) %}Republished{% else %}Publish{% endif %}" style="width:100%" class="btn btn-success btn-block"/>
</p><p>
<button type="button" class="btn btn-secondary" onclick="togglePreview()">Preview</button>
</p>
<div id="preview" style="display:none; padding:15px; border:1px solid #ccc; background:#f9f9f9;"></div>
</form>
</div>
{% else %}
<div class="card list-group">
<div class="card-header">
<i class="fa fa-tachometer" aria-hidden="true"></i> Dashboard
</div>
<div class="list-group-item">
<a href="/manager/category">Manage category</a>
</div>
<div class="list-group-item">
<a href="/manager/post" title="Publish new articles">Publish new articles</a>
</div>
<div class="list-group-item">
<a href="/logout" title="Logout account">Logout</a>
</div>
</div>
{% endif %}
</article>
{{block('footer')}}
<!-- CodeMirror CSS -->
<script>
function togglePreview() {
const editor = document.querySelector('.CodeMirror').CodeMirror;
const preview = document.getElementById('preview');
const editorArea = document.querySelector('.CodeMirror');
const content = editor.getValue();
if (preview.style.display === 'none') {
preview.style.display = 'block';
editorArea.style.display = 'none';
preview.innerHTML = content;
} else {
preview.style.display = 'none';
editorArea.style.display = 'block';
}
}
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/theme/eclipse.min.css">
<!-- CodeMirror JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/htmlmixed/htmlmixed.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/xml/xml.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/javascript/javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/css/css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/edit/closetag.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
CodeMirror.fromTextArea(document.getElementById("content"), {
mode: "htmlmixed",
theme: "eclipse",
lineNumbers: true,
lineWrapping: true,
autoCloseTags: true,
tabSize: 2,
indentUnit: 2
});
});
</script>
<style>
.CodeMirror {
height: 500px;
border: 1px solid #ccc;
font-size: 14px;
}
</style>

