diff --git a/admin/controller/editor/editor.php b/admin/controller/editor/editor.php
index ecd7d22..6137b93 100755
--- a/admin/controller/editor/editor.php
+++ b/admin/controller/editor/editor.php
@@ -36,6 +36,8 @@
use Vvveb\System\Sites;
class Editor extends Base {
+ use GlobalTrait;
+
protected $revisionDateFormat = 'Y-m-d_H:i:s';
private $themeConfig = [];
@@ -62,13 +64,15 @@ function oEmbedProxy() {
$this->response->output($result);
}
- function getThemeFolder() {
- $theme = $this->request->get['theme'] ?? Sites::getTheme() ?? 'default';
+ private function getTheme() {
+ return $theme = sanitizeFileName($this->request->get['theme'] ?? Sites::getTheme() ?? 'default');
+ }
- return DIR_THEMES . DS . $theme;
+ private function getThemeFolder() {
+ return DIR_THEMES . $this->getTheme();
}
- function loadThemeConfig() {
+ private function loadThemeConfig() {
$config = $this->getThemeFolder() . DS . 'theme.php';
if (file_exists($config)) {
@@ -78,16 +82,16 @@ function loadThemeConfig() {
}
}
- function loadTemplateList() {
+ private function loadTemplateList($theme = null) {
$list = $this->themeConfig['pages'] ?? [];
- $pages = $list + \Vvveb\getTemplateList();
+ $pages = $list + \Vvveb\getTemplateList($theme);
list($pages) = Event::trigger(__CLASS__, __FUNCTION__, $pages);
return $pages;
}
- function loadEditorData() {
+ private function loadEditorData() {
$data = [];
//menu list
@@ -104,7 +108,7 @@ function loadEditorData() {
/*
Load theme sections, components and inputs
*/
- function loadThemeAssets() {
+ private function loadThemeAssets() {
$themeFolder = $this->getThemeFolder();
$view = &$this->view;
$themeJs = [];
@@ -136,9 +140,11 @@ function loadThemeAssets() {
}
function index() {
+ $theme = sanitizeFileName($this->request->get['theme'] ?? false);
+ $themeParam = ($theme ? '&theme=' . $theme : '');
$view = View::getInstance();
- $view->themeBaseUrl = PUBLIC_PATH . 'themes/' . (Sites::getTheme() ?? 'default') . '/';
- $view->pages = $this->loadTemplateList();
+ $view->themeBaseUrl = PUBLIC_PATH . 'themes/' . ($this->getTheme() ?? 'default') . '/';
+ $view->pages = $this->loadTemplateList($theme);
$this->loadThemeAssets();
@@ -155,45 +161,51 @@ function index() {
$name = 'homepage-live';
}
- $current_page = ['name' => $name, 'file' => $file, 'url' => $url, 'title' => $title, 'folder' => '', 'className' => 'page'];
+ $current_page = ['name' => $name,
+ 'file' => $file,
+ 'url' => $url . ($theme ? '?theme=' . $theme : ''),
+ 'title' => $title,
+ 'folder' => '',
+ 'className' => 'page', ];
+
$view->pages = [$name => $current_page] + $view->pages;
}
$admin_path = \Vvveb\adminPath();
$mediaControllerPath = $admin_path . 'index.php?module=media/media';
- $controllerPath = $admin_path . 'index.php?module=editor/editor';
- $revisionsPath = $admin_path . 'index.php?module=editor/revisions';
+ $controllerPath = $admin_path . 'index.php?module=editor/editor' . $themeParam;
+ $revisionsPath = $admin_path . 'index.php?module=editor/revisions' . $themeParam;
+ $reusablePath = $admin_path . 'index.php?module=editor/reusable' . $themeParam;
$this->view->scanUrl = "$mediaControllerPath&action=scan";
$this->view->uploadUrl = "$mediaControllerPath&action=upload";
$this->view->saveUrl = "$controllerPath&action=save";
$this->view->deleteUrl = "$controllerPath&action=delete";
$this->view->renameUrl = "$controllerPath&action=rename";
- $this->view->saveReusableUrl = "$controllerPath&action=saveReusable";
+ $this->view->saveReusableUrl = "$reusablePath&action=save";
$this->view->oEmbedProxyUrl = "$controllerPath&action=oEmbedProxy";
$this->view->revisionsUrl = "$revisionsPath&action=revisions";
- $this->view->revisionLoadUrl = "$revisionsPath&action=revisionLoad";
- $this->view->revisionDeleteUrl = "$revisionsPath&action=revisionDelete";
+ $this->view->revisionLoadUrl = "$revisionsPath&action=load";
+ $this->view->revisionDeleteUrl = "$revisionsPath&action=delete";
- $view->templates = \Vvveb\getTemplateList();
- $view->folders = \Vvveb\getThemeFolderList();
+ $view->templates = \Vvveb\getTemplateList($theme);
+ $view->folders = \Vvveb\getThemeFolderList($theme);
$view->data = $this->loadEditorData();
}
- function getComponent($html, $options) {
- }
-
- function backup($page) {
+ private function backup($page) {
$themeFolder = $this->getThemeFolder() . DS;
$backupFolder = $themeFolder . 'backup' . DS;
$page = str_replace('.html', '', sanitizeFileName($page));
- $backupName = str_replace(DS, '-', $page) . '|' . date($this->revisionDateFormat) . '.html';
+ $backupName = str_replace(DS, '-', $page) . '@' . str_replace(':',';', date($this->revisionDateFormat)) . '.html';
$file = $themeFolder . $page . '.html';
if (is_dir($backupFolder)) {
if (file_exists($file)) {
$content = file_get_contents($themeFolder . $page . '.html');
+ $base = str_replace('/admin', '', PUBLIC_THEME_PATH) . 'themes/' . $this->getTheme() . '/';
+ $content = preg_replace('//', '', $content);
return file_put_contents($backupFolder . $backupName, $content);
}
@@ -202,7 +214,7 @@ function backup($page) {
return false;
}
- function saveElements($elements) {
+ private function saveElements($elements) {
$products = new ProductSQL();
$posts = new PostSQL();
$components = [];
@@ -313,36 +325,16 @@ function rename() {
$this->response->output($message);
}
- function saveReusable() {
- $name = slugify(sanitizeFileName($this->request->post['name']));
- $type = $this->request->post['type'];
- $html = $this->request->post['html'];
-
- $themeFolder = $this->getThemeFolder();
- $folder = $themeFolder . DS . $type . 's' . DS . 'reusable' . DS;
- $file = "$name.html";
-
- @mkdir($folder);
-
- if (file_put_contents($folder . $file, $html)) {
- $message = ['success' => true, 'message' => __('Element saved!')];
- } else {
- $message = ['success' => false, 'message' => __('Error saving!')];
- }
-
- $this->response->setType('json');
- $this->response->output($message);
- }
-
function save() {
$file = $this->request->post['file'] ?? '';
$folder = $this->request->post['folder'] ?? '';
$startTemplateUrl = $this->request->post['startTemplateUrl'] ?? '';
$name = $this->request->post['name'] ?? '';
$content = $this->request->post['content'] ?? 'Lorem ipsum';
- $type = $this->request->post['type'] ?? false;
- $addMenu = $this->request->post['add-menu'] ?? false;
- $menu_id = $this->request->post['menu_id'] ?? false;
+ $type = $this->request->post['type'] ?? false;
+ $addMenu = $this->request->post['add-menu'] ?? false;
+ $menu_id = $this->request->post['menu_id'] ?? false;
+ $theme = sanitizeFileName($this->request->get['theme'] ?? false);
$url = '';
$file = sanitizeFileName(str_replace('.html', '', $file)) . '.html';
@@ -369,7 +361,8 @@ function save() {
'content' => $content,
'language_id' => $this->global['language_id'],
]],
- ] + $this->global, ] + $this->global);
+ ] + $this->global,
+ 'site_id' => [$this->global['site_id']], ] + $this->global);
if ($result['post']) {
$success = true;
@@ -398,7 +391,8 @@ function save() {
'content' => $content,
'language_id' => $this->global['language_id'],
]],
- ] + $this->global, ] + $this->global);
+ ] + $this->global,
+ 'site_id' => [$this->global['site_id']], ] + $this->global);
if ($result['product']) {
$success = true;
@@ -419,8 +413,8 @@ function save() {
$success = false;
$text = '';
+ $baseUrl = '/themes/' . $this->getTheme() . '/' . ($folder ? $folder . '/' : '');
$themeFolder = $this->getThemeFolder();
- $baseUrl = '/themes/' . (Sites::getTheme() ?? 'default') . '/' . ($folder ? $folder . '/' : '');
if ($startTemplateUrl) {
$content = file_get_contents($themeFolder . DS . $startTemplateUrl);
@@ -478,6 +472,8 @@ function save() {
$fileName = $themeFolder . DS . ($folder ? $folder . DS : '') . $file;
}
+ $this->saveGlobalElements($content);
+
if (file_put_contents($fileName, $content)) {
$success = true;
$text .= __('File saved!');
diff --git a/admin/controller/editor/global-trait.php b/admin/controller/editor/global-trait.php
new file mode 100644
index 0000000..52659a0
--- /dev/null
+++ b/admin/controller/editor/global-trait.php
@@ -0,0 +1,102 @@
+.
+ *
+ */
+
+namespace Vvveb\Controller\Editor;
+
+use Vvveb\System\Core\View;
+
+trait GlobalTrait {
+ private function saveGlobalElements($content) {
+ $document = new \DomDocument();
+ $document->preserveWhiteSpace = false;
+ $document->recover = true;
+ $document->strictErrorChecking = false;
+ $document->formatOutput = false;
+ $document->resolveExternals = false;
+ $document->validateOnParse = false;
+ $document->xmlStandalone = true;
+
+ $view = View::getInstance();
+ libxml_use_internal_errors(true);
+
+ @$document->loadHTML($content);
+
+ $xpath = new \DOMXpath($document);
+
+ $elements = $xpath->query('//*[ @data-v-save-global ]');
+
+ if ($elements && $elements->length) {
+ $toDocument = new \DomDocument();
+ $toDocument->preserveWhiteSpace = false;
+ $toDocument->recover = true;
+ $toDocument->strictErrorChecking = false;
+ $toDocument->formatOutput = false;
+ $toDocument->resolveExternals = false;
+ $toDocument->validateOnParse = false;
+ $toDocument->xmlStandalone = true;
+
+ $themeFolder = $this->getThemeFolder();
+
+ foreach ($elements as $element) {
+ $attribute = $element->getAttribute('data-v-save-global');
+
+ if (strpos($attribute, ',') !== false) {
+ list($file, $selector) = explode(',',$attribute);
+
+ $file = html_entity_decode($file);
+ $selector = html_entity_decode($selector);
+ $file = $themeFolder . DS . $file;
+
+ $toDocument->loadHTMLFile($file);
+
+ $toXpath = new \DOMXpath($toDocument);
+
+ $toElements = $toXpath->query(\Vvveb\cssToXpath($selector));
+
+ $count = 0;
+
+ if ($elements && $elements->length) {
+ foreach ($toElements as $externalNode) {
+ $parent = $externalNode->parentNode;
+
+ $importedNode = $toDocument->importNode($element, true);
+
+ if ($parent) {
+ if ($count) {
+ $parent->appendChild($importedNode);
+ } else {
+ $parent->replaceChild($importedNode, $externalNode);
+ }
+ $externalNode = $importedNode;
+ $parent = $externalNode->parentNode;
+ $count++;
+ }
+ }
+
+ $html= $toDocument->saveHTML();
+ file_put_contents($file, $html);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/admin/controller/editor/reusable.php b/admin/controller/editor/reusable.php
new file mode 100644
index 0000000..23a1a22
--- /dev/null
+++ b/admin/controller/editor/reusable.php
@@ -0,0 +1,133 @@
+.
+ *
+ */
+
+namespace Vvveb\Controller\Editor;
+
+use function Vvveb\__;
+use Vvveb\Controller\Base;
+use function Vvveb\humanReadable;
+use function Vvveb\sanitizeFileName;
+use function Vvveb\slugify;
+use Vvveb\System\Sites;
+
+class Reusable extends Base {
+ private $sectionTemplate = <<request->get['theme'] ?? Sites::getTheme() ?? 'default');
+ }
+
+ private function regenerate($type) {
+ $themeFolder = $this->getThemeFolder();
+
+ $folder = $themeFolder . DS . $type . 's' . DS;
+ $htmlFolder = $folder . 'reusable' . DS;
+ $template = ($type == 'section') ? $this->sectionTemplate : $this->blockTemplate;
+
+ $js = '';
+
+ foreach (scandir($htmlFolder) as $file) {
+ if (strpos($file, '.html') === false) {
+ continue;
+ }
+ $name = str_replace('.html','', $file);
+ $title = humanReadable($name);
+ $content = file_get_contents($htmlFolder . DS . $file);
+
+ $data = compact('name', 'title', 'content');
+ $reusable = $template;
+
+ foreach ($data as $key => $value) {
+ $reusable = str_replace('{' . $key . '}', $value, $reusable);
+ }
+
+ $js .= $reusable;
+ }
+
+ $jsFile = $folder . $type . 's.js';
+ $typeName = ucfirst($type);
+ $jsContent = '';
+
+ if (file_exists($jsFile)) {
+ $jsContent = file_get_contents($jsFile);
+
+ //remove old reusable
+ $regex = '\s*Vvveb\.\w+?\.add\([\'"]reusable.+?`\s*\}\);?|' .
+ '\s*Vvveb\.\w+?Group\[["\']Reusable["\']\]\s*\.push\([^\)]+\);?\s*|' .
+ '\s*Vvveb\.\w+?Group\[["\']Reusable["\']\]\s*=\s*\[[^\]]*?\];?\s*';
+
+ $jsContent = preg_replace("/$regex/ms", '', $jsContent);
+ }
+
+ //append new reusable
+ $jsContent = $jsContent . "\n\nVvveb." . $typeName . "sGroup[\"Reusable\"] = [];\n" . $js;
+
+ return file_put_contents($jsFile, $jsContent);
+ }
+
+ function save() {
+ $name = slugify(sanitizeFileName($this->request->post['name']));
+ $type = $this->request->post['type'];
+ $html = $this->request->post['html'];
+ $message = ['success' => false, 'message' => __('Error saving!')];
+
+ if (($type == 'section' || $type == 'block') && $html) {
+ $themeFolder = $this->getThemeFolder();
+ $folder = $themeFolder . DS . $type . 's' . DS . 'reusable' . DS;
+ $file = "$name.html";
+
+ @mkdir($folder, 0755 & ~umask(), true);
+
+ if (file_put_contents($folder . $file, $html)) {
+ if ($this->regenerate($type)) {
+ $message = ['success' => true, 'message' => __('Element saved!')];
+ }
+ } else {
+ }
+ }
+
+ $this->response->setType('json');
+ $this->response->output($message);
+ }
+}
diff --git a/admin/controller/editor/revisions.php b/admin/controller/editor/revisions.php
index 8821425..7d96807 100644
--- a/admin/controller/editor/revisions.php
+++ b/admin/controller/editor/revisions.php
@@ -22,52 +22,94 @@
namespace Vvveb\Controller\Editor;
+use function Vvveb\__;
use Vvveb\Controller\Base;
use function Vvveb\friendlyDate;
use function Vvveb\sanitizeFileName;
use Vvveb\System\Sites;
class Revisions extends Base {
- private function backupFolder() {
+ function getThemeFolder() {
$theme = $this->request->get['theme'] ?? Sites::getTheme() ?? 'default';
- return DIR_THEMES . DS . $theme . DS . 'backup' . DS;
+ return $theme;
+ }
+
+ private function sanitizeBackupFileName($fileName) {
+ return str_replace(['.', '/', '\\'], '', $fileName);
+ }
+
+ private function backupFolder() {
+ $theme = $this->getThemeFolder();
+
+ return DIR_THEMES . $theme . DS . 'backup' . DS;
}
function delete() {
+ $file = $this->request->post['file'] ?? false;
+
+ if ($file) {
+ $file = $this->backupFolder() . $this->sanitizeBackupFileName($file) . '.html';
+
+ $text = __('Error deleting file!' . $file);
+ $success = false;
+
+ if (file_exists($file)) {
+ $success = unlink($file);
+
+ if ($success) {
+ $text = __('File deleted!');
+ }
+ }
+
+ $data = ['success' => $success, 'message' => $text];
+
+ $this->response->setType('json');
+ $this->response->output($data);
+ }
}
function load() {
- $template = $this->request->get['template'] ?? false;
+ $file = $this->request->post['file'] ?? false;
- $this->view->text = $text;
- $this->response->setType('text');
- }
+ if ($file) {
+ $file = $this->backupFolder() . $this->sanitizeBackupFileName($file) . '.html';
- function preview() {
+ if (file_exists($file)) {
+ $this->response->setType('text');
+ $this->response->output(file_get_contents($file));
+ }
+ }
}
function revisions() {
+ $theme = $this->getThemeFolder();
$template = $this->request->get['template'] ?? false;
$backupFolder = $this->backupFolder();
$revisions = [];
if ($template) {
- $template = str_replace(['/', '.html'], ['-', ''], sanitizeFileName($template));
+ $templateName = str_replace(['/', '.html'], ['-', ''], sanitizeFileName($template));
+ $path = '//' . $_SERVER['HTTP_HOST'] . PUBLIC_PATH . "/themes/$theme/";
- $glob = glob("$backupFolder/$template|*.html");
+ $glob = glob("$backupFolder/$templateName@*.html");
foreach ($glob as &$file) {
$file = basename($file, '.html');
- list($name, $date) = explode('|', $file);
- $date = str_replace('_', ' ', $date);
+ $url = $path . "backup/$file.html";
+ list($name, $date) = explode('@', $file);
+ $date = str_replace(['_', ';'], [' ', ':'], $date);
$date_friendly = friendlyDate($date);
/*
$time = date_parse_from_format($this->revisionDateFormat, $date);
unset($time['warnings'], $time['warning_count'], $time['errors'], $time['error_count']);
*/
- $revisions[] = compact(['file', 'date', 'date_friendly', 'name'/*, 'time'*/]);
+ $revisions[$date] = compact(['url', 'file', 'date', 'date_friendly', 'name'/*, 'time'*/]);
}
+
+ krsort($revisions);
+
+ //$revisions[0] = ['url' => $path . $template, 'file' => $template, '' => '', 'date_friendly' => 'Live', 'date' => '', 'name' => ''];
}
$this->response->setType('json');