Autosave function

This commit is contained in:
Diego Najar 2018-05-08 00:15:40 +02:00
parent c06295a41f
commit eb6966723d
18 changed files with 336 additions and 44 deletions

View File

@ -26,4 +26,4 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// ============================================================================
// Title of the page
$layout['title'] .= ' - '.$Language->g('New content');
$layout['title'] = $Language->g('New content').' - '.$layout['title'];

View File

@ -3,6 +3,18 @@ html {
font-size: 0.9em;
}
/*
ALERT
*/
#alert {
display: none;
position: absolute;
right: 0px;
padding: 16px 90px;
border-radius: 0px;
border: 0;
}
/*
SIDEBAR
*/

View File

@ -0,0 +1,17 @@
<!-- Alert -->
<script>
function showAlert(text) {
$("#alert").html(text);
$("#alert").slideDown().delay(3500).slideUp();
}
<?php if (Alert::defined()): ?>
setTimeout(function(){ showAlert("<?php echo Alert::get() ?>") }, 500);
<?php endif; ?>
$(window).click(function() {
$("#alert").hide();
});
</script>
<div id="alert" class="alert <?php echo (Alert::status()==ALERT_STATUS_FAIL)?'alert-danger':'alert-success' ?>"></div>

View File

@ -3,9 +3,11 @@
$listOfFiles = Filesystem::listFiles(PATH_UPLOADS_THUMBNAILS, '*', '*', $GLOBALS['BLUDIT_MEDIA_MANAGER_SORT_BY_DATE'], false);
$listOfFilesByPage = array_chunk($listOfFiles, $GLOBALS['BLUDIT_MEDIA_MANAGER_AMOUNT_OF_FILES']);
$preLoadFiles = array();
if (!empty($listOfFilesByPage[0])) {
foreach ($listOfFilesByPage[0] as $file) {
array_push($preLoadFiles, basename($file));
}
}
// Amount of pages for the paginator
$amountOfPages = count($listOfFilesByPage);
?>
@ -42,7 +44,7 @@ $amountOfPages = count($listOfFilesByPage);
<h3 class="mt-4 mb-3">Manage</h3>
<!-- Table for list files -->
<table id="jsbluditMediaTable" class="table"></table>
<table id="jsbluditMediaTable" class="table">There are not images.</table>
<!-- Paginator -->
<nav>
@ -90,7 +92,7 @@ function displayFiles(files) {
'<td class="information">'+
'<div>'+filename+'</div>'+
'<div>'+
'<button onClick="insertMedia(\''+filename+'\'); closeMediaManager();" type="button" class="btn btn-link p-0 mr-2">Insert</button>'+
'<button onClick="editorInsertMedia(\''+filename+'\'); closeMediaManager();" type="button" class="btn btn-link p-0 mr-2">Insert</button>'+
'<button onClick="deleteMedia(\''+filename+'\')" type="button" class="btn btn-link p-0 mr-2">Delete</button>'+
'</div>'+
'</td>'+

View File

@ -28,6 +28,13 @@
));
?>
<!-- Javascript -->
<?php
echo '<script>';
include(PATH_CORE_JS.'bludit-ajax.php');
echo '</script>';
?>
<!-- Plugins -->
<?php Theme::plugins('adminHead') ?>
</head>
@ -37,7 +44,10 @@
<?php Theme::plugins('adminBodyBegin') ?>
<!-- Javascript variables generated by PHP -->
<?php include(PATH_JS.'variables.php') ?>
<?php include(PATH_CORE_JS.'variables.php') ?>
<!-- Alert -->
<?php include('html/alert.php'); ?>
<!-- TOPBAR -->
<?php include('html/topbar.php'); ?>

View File

@ -10,9 +10,12 @@
<a class="nav-link " id="options-tab" data-toggle="tab" href="#options" role="tab" aria-controls="options" aria-selected="false">Options</a>
</li>
</ul>
<form class="tab-content mt-3" id="dynamicTabContent">
<?php
echo Bootstrap::formOpen(array(
'id'=>'jsform',
'class'=>'tab-content mt-4'
));
// Token CSRF
echo Bootstrap::formInputHidden(array(
'name'=>'tokenCSRF',
@ -25,6 +28,12 @@
'value'=>$page->parent()
));
// UUID
echo Bootstrap::formInputHidden(array(
'name'=>'uuid',
'value'=>$dbPages->generateUUID()
));
// Status = published, draft, sticky, static
echo Bootstrap::formInputHidden(array(
'name'=>'status',
@ -56,9 +65,9 @@
</div>
<div class="form-group mt-2">
<button type="button" class="btn btn-primary">Save</button>
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn" id="jssaveAsDraft">Save as draft</button>
<button type="button" class="btn">Cancel</button>
<a href="<?php echo HTML_PATH_ADMIN_ROOT ?>dashboard" class="btn"><?php echo $L->g('Cancel') ?></a>
</div>
</div>
@ -109,18 +118,15 @@
echo Bootstrap::formSelect(array(
'name'=>'category',
'label'=>'Category',
'selected'=>'',
'options'=>array(
''=>'- Uncategorized -',
'music'=>'Music',
'videos'=>'Videos'
)
'selected'=>$page->categoryKey(),
'options'=>$dbCategories->getKeyNameArray()
));
// Tags
echo Bootstrap::formInputText(array(
'name'=>'tags',
'label'=>'Tags',
'value'=>$page->tags(),
'placeholder'=>'Tags separeted by comma'
));
@ -129,7 +135,8 @@
'name'=>'description',
'label'=>'Description',
'placeholder'=>'Small description about the content',
'rows'=>'4'
'rows'=>'4',
'value'=>$page->description()
));
echo Bootstrap::formTitle(array('title'=>'Advanced'));
@ -146,7 +153,7 @@
echo Bootstrap::formSelect(array(
'name'=>'type',
'label'=>'Type',
'selected'=>'',
'selected'=>$page->status(),
'options'=>array(
''=>'- Default -',
'sticky'=>'Sticky',
@ -158,7 +165,8 @@
echo Bootstrap::formInputText(array(
'name'=>'parentTMP',
'label'=>'Parent',
'placeholder'=>'Start writing the title of the page parent'
'placeholder'=>'Start writing the title of the page parent',
'value'=>($page->parent()?$page->parentMethod('title'):'')
));
// Position
@ -173,6 +181,7 @@
echo Bootstrap::formInputText(array(
'name'=>'slug',
'label'=>'Friendly URL',
'value'=>$page->slug(),
'placeholder'=>'Leave empty for automaticly complete'
));
@ -180,7 +189,8 @@
echo Bootstrap::formInputText(array(
'name'=>'template',
'label'=>'Template',
'placeholder'=>''
'placeholder'=>'',
'value'=>$page->template()
));
?>
@ -202,6 +212,18 @@ $(document).ready(function() {
$("#jsstatus").val(status);
});
// Autosave
setInterval(
function() {
var uuid = $("#jsuuid").val();
var title = $("#jstitle").val();
var content = $("#jscontent").val();
var ajax = new bluditAjax()
ajax.autosave(uuid, title, content);
},
10*1000
);
// Template autocomplete
$('input[name="template"]').autoComplete({
minChars: 2,

View File

@ -10,9 +10,12 @@
<a class="nav-link " id="options-tab" data-toggle="tab" href="#options" role="tab" aria-controls="options" aria-selected="false">Options</a>
</li>
</ul>
<form class="tab-content mt-3" id="dynamicTabContent">
<?php
echo Bootstrap::formOpen(array(
'id'=>'jsform',
'class'=>'tab-content mt-4'
));
// Token CSRF
echo Bootstrap::formInputHidden(array(
'name'=>'tokenCSRF',
@ -25,6 +28,12 @@
'value'=>''
));
// UUID
echo Bootstrap::formInputHidden(array(
'name'=>'uuid',
'value'=>$dbPages->generateUUID()
));
// Status = published, draft, sticky, static
echo Bootstrap::formInputHidden(array(
'name'=>'status',
@ -50,9 +59,9 @@
</div>
<div class="form-group mt-2">
<button type="button" class="btn btn-primary">Save</button>
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn" id="jssaveAsDraft">Save as draft</button>
<button type="button" class="btn">Cancel</button>
<a href="<?php echo HTML_PATH_ADMIN_ROOT ?>dashboard" class="btn"><?php echo $L->g('Cancel') ?></a>
</div>
</div>
@ -97,11 +106,7 @@
'name'=>'category',
'label'=>'Category',
'selected'=>'',
'options'=>array(
''=>'- Uncategorized -',
'music'=>'Music',
'videos'=>'Videos'
)
'options'=>$dbCategories->getKeyNameArray()
));
// Tags
@ -125,7 +130,8 @@
echo Bootstrap::formInputText(array(
'name'=>'date',
'label'=>'Date',
'placeholder'=>'YYYY-MM-DD hh:mm:ss'
'placeholder'=>'YYYY-MM-DD hh:mm:ss',
'value'=>Date::current(DB_DATE_FORMAT)
));
// Type
@ -178,15 +184,36 @@ $(document).ready(function() {
// Button Save as draft
$("#jssaveAsDraft").on("click", function() {
$("#jsstatus").val("draft");
$("#dynamicTabContent").submit();
$("#jsform").submit();
});
// Type selector modiefied the status
// Type selector modified the status hidden field
$("#jstype").on("change", function() {
var status = $("#jstype option:selected").val();
$("#jsstatus").val(status);
});
// Generate slug when the user type the title
$("#jstitle").keyup(function() {
var text = $(this).val();
var parent = $("#jsparent").val();
var currentKey = "";
var ajax = new bluditAjax();
ajax.generateSlug(text, parent, currentKey, $("#jsslug"));
});
// Autosave interval
setInterval(function() {
var uuid = $("#jsuuid").val();
var title = $("#jstitle").val();
var content = editorGetContent();
var ajax = new bluditAjax();
// showAlert is the function to display an alert defined in alert.php
ajax.autosave(uuid, title, content, showAlert);
},
10*1000
);
// Template autocomplete
$('input[name="template"]').autoComplete({
minChars: 2,

View File

@ -22,7 +22,7 @@ echo Bootstrap::pageTitle(array('title'=>$L->g('Settings'), 'icon'=>'cog'));
<?php
echo Bootstrap::formOpen(array(
'id'=>'dynamicTabContent',
'class'=>'tab-content mt-4',
'class'=>'tab-content mt-4'
));
// Token CSRF

View File

@ -0,0 +1,56 @@
<?php defined('BLUDIT') or die('Bludit CMS.');
header('Content-Type: application/json');
// $_POST
// ----------------------------------------------------------------------------
// (string) $_POST['title']
$title = isset($_POST['title']) ? $_POST['title'] : false;
// (string) $_POST['content']
$content = isset($_POST['content']) ? $_POST['content'] : false;
// (string) $_POST['uuid']
$uuid = isset($_POST['uuid']) ? $_POST['uuid'] : false;
// ----------------------------------------------------------------------------
// Check UUID
if (empty($uuid)) {
exit (json_encode(array(
'status'=>1,
'message'=>'Autosave fail. UUID not defined.'
)));
}
// Check content length to create the autosave page
if (Text::length($content)<100) {
exit (json_encode(array(
'status'=>1,
'message'=>'Autosave not completed. The content length is less than 100 characters.'
)));
}
$autosaveUUID = 'autosave-'.$uuid;
$page = array(
'uuid'=>$autosaveUUID,
'key'=>$autosaveUUID,
'slug'=>$autosaveUUID,
'title'=>$title.' [ Autosave ] ',
'content'=>$content,
'status'=>'draft'
);
// Get the page key by the UUID
$pageKey = $dbPages->getByUUID($autosaveUUID);
// if pageKey is empty means the autosave page doesn't exist
if (empty($pageKey)) {
createPage($page);
} else {
editPage($page);
}
exit (json_encode(array(
'status'=>0,
'message'=>'Autosave successfully.',
'uuid'=>$autosaveUUID
)));
?>

View File

@ -23,6 +23,9 @@ if ( in_array( strtolower( ini_get( 'magic_quotes_gpc' ) ), array( '1', 'on' ) )
$_COOKIE = array_map('stripslashes', $_COOKIE);
}
// Boot plugins rules
include(PATH_RULES.'60.plugins.php');
// --- AJAX ---
if ($layout['slug']==='ajax') {
if ($Login->isLogged()) {
@ -34,12 +37,12 @@ if ($layout['slug']==='ajax') {
include(PATH_AJAX.$layout['parameters'].'.php');
}
}
exit(0);
}
// --- ADMIN AREA ---
else
{
// Boot rules
include(PATH_RULES.'60.plugins.php');
include(PATH_RULES.'69.pages.php');
include(PATH_RULES.'99.header.php');
include(PATH_RULES.'99.paginator.php');

View File

@ -31,8 +31,7 @@ define('PATH_ABSTRACT', PATH_KERNEL.'abstract'.DS);
define('PATH_RULES', PATH_KERNEL.'boot'.DS.'rules'.DS);
define('PATH_HELPERS', PATH_KERNEL.'helpers'.DS);
define('PATH_AJAX', PATH_KERNEL.'ajax'.DS);
define('PATH_JS', PATH_KERNEL.'js'.DS);
define('PATH_CSS', PATH_KERNEL.'css'.DS);
define('PATH_CORE_JS', PATH_KERNEL.'js'.DS);
define('PATH_PAGES', PATH_CONTENT.'pages'.DS);
define('PATH_DATABASES', PATH_CONTENT.'databases'.DS);

View File

@ -77,7 +77,9 @@ class dbPages extends dbJSON
$key = $this->generateKey($args['slug'], $args['parent']);
// Generate UUID
if (empty($args['uuid'])) {
$args['uuid'] = $this->generateUUID();
}
// Validate date
if (!Valid::date($args['date'], DB_DATE_FORMAT)) {
@ -535,10 +537,31 @@ class dbPages extends dbJSON
return $a['date']<$b['date'];
}
private function generateUUID() {
function generateUUID() {
return md5( uniqid().time() );
}
// Returns the UUID of a page, by the page key
function getUUID($key)
{
if ($this->exists($key)) {
return $this->db[$key]['uuid'];
}
return false;
}
// Returns the page key by the uuid
function getByUUID($uuid)
{
foreach ($this->db as $key=>$value) {
if ($value['uuid']==$uuid) {
return $key;
}
}
return false;
}
// Returns string without HTML tags and truncated
private function generateSlug($text, $truncateLength=60) {
$tmpslug = Text::removeHTMLTags($text);

View File

@ -394,6 +394,12 @@ function createPage($args) {
global $syslog;
global $Language;
// Check if the autosave page exists for this new page and delete it
$pageKey = $dbPages->getByUUID('autosave-'.$args['uuid']);
if (!empty($pageKey)) {
deletePage($pageKey);
}
// The user is always the one loggued
$args['username'] = Session::get('username');
if ( empty($args['username']) ) {
@ -441,6 +447,12 @@ function editPage($args) {
global $dbPages;
global $syslog;
// Check if the autosave page exists for this new page and delete it
$pageKey = $dbPages->getByUUID('autosave-'.$args['uuid']);
if (!empty($pageKey)) {
deletePage($pageKey);
}
// Check the key is not empty
if (empty($args['key'])) {
Log::set('Function editPage()'.LOG_SEP.'Empty key.');

View File

@ -0,0 +1,69 @@
class bluditAjax {
autosave(uuid, title, content, callBack) {
var ajaxRequest;
if (ajaxRequest) {
ajaxRequest.abort();
}
if (content.length<100) {
return false;
}
ajaxRequest = $.ajax({
type: "POST",
data: {
tokenCSRF: tokenCSRF, // token from env variables
uuid: uuid,
title: title,
content: content
},
url: "<?php echo HTML_PATH_ADMIN_ROOT ?>ajax/save-as-draft"
});
ajaxRequest.done(function (response, textStatus, jqXHR) {
console.log("Bludit AJAX: autosave(): done handler");
callBack("Autosave success");
});
ajaxRequest.fail(function (jqXHR, textStatus, errorThrown) {
console.log("Bludit AJAX: autosave(): fail handler");
callBack("Autosave failure");
});
ajaxRequest.always(function () {
console.log("Bludit AJAX: autosave(): always handler");
});
}
generateSlug(text, parentKey, currentKey, callBack) {
var ajaxRequest;
if (ajaxRequest) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
type: "POST",
data: {
tokenCSRF: tokenCSRF,
text: text,
parentKey: parentKey,
currentKey: currentKey
},
url: "<?php echo HTML_PATH_ADMIN_ROOT.'ajax/generate-slug' ?>"
});
ajaxRequest.done(function (response, textStatus, jqXHR) {
console.log("Bludit AJAX: generateSlug(): done handler");
callBack.val(response["slug"]);
});
ajaxRequest.fail(function (jqXHR, textStatus, errorThrown) {
console.log("Bludit AJAX: generateSlug(): fail handler");
});
ajaxRequest.always(function () {
console.log("Bludit AJAX: generateSlug(): always handler");
});
}
}

View File

@ -2,6 +2,40 @@
var ajaxRequest;
function autosave(title, content) {
var ajaxRequest;
if(ajaxRequest) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
type: "POST",
data: {
tokenCSRF: tokenCSRF, // token from env variables
title: title,
content: content
},
url: "<?php echo HTML_PATH_ADMIN_ROOT.'ajax/save-as-draft' ?>"
});
// Callback handler that will be called on success
ajaxRequest.done(function (response, textStatus, jqXHR){
console.log("Autosave done.");
});
// Callback handler that will be called on failure
ajaxRequest.fail(function (jqXHR, textStatus, errorThrown){
console.log("Autosave error on ajax call.");
});
// Callback handler that will be called regardless
// if the request failed or succeeded
ajaxRequest.always(function () {
console.log("Autosave always.");
});
}
function generateSlug(text, parentKey, currentKey, writeResponse) {
if(ajaxRequest) {
ajaxRequest.abort();

View File

@ -277,7 +277,7 @@ class Page {
return $this->getValue('description');
}
// Returns the tags
// Returns the tags separated by comma
// (boolean) $returnsArray, TRUE to get the tags as an array, FALSE to get the tags separeted by comma
public function tags($returnsArray=false)
{

View File

@ -32,7 +32,7 @@ $script = <<<EOF
var quill;
// Function required for Media Manager to insert a file on the editor
function insertMedia(filename) {
function editorInsertMedia(filename) {
var Delta = Quill.import("delta");
quill.updateContents(new Delta()
.retain(quill.getSelection().index)
@ -40,6 +40,12 @@ function insertMedia(filename) {
);
}
// Function required for Autosave function
// Returns the content of the editor
function editorGetContent() {
return quill.container.firstChild.innerHTML;
}
$(document).ready(function() {
quill = new Quill("#jscontent", {