Merge branch 'master' into blog_v3

This commit is contained in:
Fred Tempez 2020-09-24 18:01:34 +02:00
commit 78259f3da6
262 changed files with 1769 additions and 1076 deletions

0
.htaccess Executable file → Normal file
View File

View File

@ -11,11 +11,46 @@
- Suppression des commentaires en masse.
- Limiter l'édition des articles et des commentaires à l'id de l'éditeur
- Approbation des commentaires
- Corrections :
- Bloquage de l'incrémentation de l'id de page lorsque deux pages ont le même nom.
- Login : l'option "Se souvenir de moi" est fonctionnelle.
- Menu : déplacement de la classe "active".
- Le titre dans la configuration du module non affiché si le titre de la page est masqué.
- Masque de saisie : formulaire validé malgré la présence d'une notice d'erreur
- Classe jsonDb, suppression de la réinitialisation de la structure de données en cas d'absence du fichier.
- Modifications :
- Noyau :
- Mise en cache des données des modules.
- Module recherche :
- La recherche dans le site devient un module externe plutôt qu'un module interne ;
- Diverses corrections optimisations permettant une recherche à l'aide de plusieurs mot-clés.
- Module galerie :
- Les données du thème de galerie sont désormais stockées de manière unique, un seul thème par site pour toutes les galeries d'un même site.
- Configuration du site :
- Pages 403 (accès interdit) et 404 (page introuvable) personnalisables
- Sauvegarde du site dans une archive : animation d'attente avec message de confirmation ou d'erreur ; le nom de l'archive prend le nom du sous-domaine s'il existe.
- Captcha : addition présentée en lettres sous la forme d'images, réponse en chiffres ; correction du nom de la fonction (capcha en captcha).
- Page :
- Duplication d'une page.
- Mise à jour :
- Script favicon-switcher 1.2.2
## version 10.2.09
- Correction :
- Sécurisation de la fonction d'enregistrement des données.
## version 10.2.08
- Correction :
- Bug pageId, régression corrigée.
## version 10.2.07
- Correction :
- Défaut de chargement de flatpickr dans le module formulaire qui passe en version 2.4
## version 10.2.06
- Corrections :
- Anticipation de la dépréciation de l'option de cookie samesite=none.
- Warning : absence de fichier map dans le thème TinyMCE lightgray
- Warning : absence de fichier map dans le thème TinyMCE lightgray.
## version 10.2.05
- Correction :

0
core/class/.htaccess Executable file → Normal file
View File

0
core/class/SitemapGenerator.class.php Executable file → Normal file
View File

0
core/class/autoload.php Executable file → Normal file
View File

6
core/class/helper.class.php Executable file → Normal file
View File

@ -98,7 +98,9 @@ class helper {
public static function autoBackup($folder, $filter = ['backup','tmp'] ) {
// Creation du ZIP
$fileName = 'ZwiiCMS-backup'. date('Y-m-d-h-i-s', time()) . '.zip';
$baseName = str_replace('/','',helper::baseUrl(false,false));
$baseName = empty($baseName) ? 'ZwiiCMS' : $baseName;
$fileName = $baseName . '-backup-' . date('Y-m-d-h-i-s', time()) . '.zip';
$zip = new ZipArchive();
$zip->open($folder . $fileName, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$directory = 'site/';
@ -185,7 +187,7 @@ class helper {
* @return string
*/
public static function getOnlineVersion() {
return (helper::urlGetContents('http://zwiicms.com/update/'. common::ZWII_UPDATE_CHANNEL . '/version'));
return (helper::urlGetContents('http://zwiicms.fr/update/'. common::ZWII_UPDATE_CHANNEL . '/version'));
}

0
core/class/jsondb/Dot.class.php Executable file → Normal file
View File

36
core/class/jsondb/JsonDb.class.php Executable file → Normal file
View File

@ -22,10 +22,10 @@ class JsonDb extends \Prowebcraft\Dot
public function __construct($config = [])
{
$this->config = array_merge([
'name' => 'data.json',
'backup' => 5,
'name' => 'data.json',
'backup' => 5,
'dir' => getcwd(),
'template' => getcwd() . DIRECTORY_SEPARATOR . 'data.template.json'
'template' => getcwd() . DIRECTORY_SEPARATOR . 'data.template.json'
], $config);
$this->loadData();
parent::__construct();
@ -36,7 +36,7 @@ class JsonDb extends \Prowebcraft\Dot
*
* @param mixed $key Path or array of paths and values
* @param mixed|null $value Value to set if path is not an array
* @param bool $save Сохранить данные в базу
* @param bool $save Save data to database
* @return $this
*/
public function set($key, $value = null, $save = true)
@ -49,10 +49,10 @@ class JsonDb extends \Prowebcraft\Dot
/**
* Add value or array of values to path
*
* @param mixed $key Path or array of paths and values
* @param mixed $key Path or array of paths and values
* @param mixed|null $value Value to set if path is not an array
* @param boolean $pop Helper to pop out last key if value is an array
* @param bool $save Сохранить данные в базу
* @param boolean $pop Helper to pop out last key if value is an array
* @param bool $save Save data to database
* @return $this
*/
public function add($key, $value = null, $pop = false, $save = true)
@ -65,8 +65,8 @@ class JsonDb extends \Prowebcraft\Dot
/**
* Delete path or array of paths
*
* @param mixed $key Path or array of paths to delete
* @param bool $save Сохранить данные в базу
* @param mixed $key Path or array of paths to delete
* @param bool $save Save data to database
* @return $this
*/
public function delete($key, $save = true)
@ -81,8 +81,8 @@ class JsonDb extends \Prowebcraft\Dot
* optionally format path if it doesn't exist
*
* @param mixed|null $key Path or array of paths to clean
* @param boolean $format Format option
* @param bool $save Сохранить данные в базу
* @param boolean $format Format option
* @param bool $save Save data to database
* @return $this
*/
public function clear($key = null, $format = false, $save = true)
@ -94,14 +94,15 @@ class JsonDb extends \Prowebcraft\Dot
/**
* Загрузка локальной базы данных
* @param bool $reload
* Перезагрузить данные?
* Local database upload
* @param bool $reload Reboot data?
* @return array|mixed|null
*/
protected function loadData($reload = false) {
if ($this->data === null || $reload) {
$this->db = $this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'];
// $this->db = $this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'];
$this->db = $this->config['dir'] . $this->config['name'];
/*
if (!file_exists($this->db)) {
$templateFile = $this->config['template'];
if (file_exists($templateFile)) {
@ -118,6 +119,7 @@ class JsonDb extends \Prowebcraft\Dot
}
}
}
*/
$this->data = json_decode(file_get_contents($this->db), true);
if (!$this->data === null) {
throw new \InvalidArgumentException('Database file ' . $this->db
@ -128,11 +130,9 @@ class JsonDb extends \Prowebcraft\Dot
}
/**
* Сохранение в локальную базу
* Saving to local database
*/
public function save() {
file_put_contents($this->db, json_encode($this->data, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));
}
}

0
core/class/phpmailer/.htaccess Executable file → Normal file
View File

0
core/class/phpmailer/Exception.class.php Executable file → Normal file
View File

0
core/class/phpmailer/PHPMailer.class.php Executable file → Normal file
View File

0
core/class/phpmailer/SMTP.class.php Executable file → Normal file
View File

24
core/class/template.class.php Executable file → Normal file
View File

@ -33,12 +33,12 @@ class template {
}
/**
* Crée un champ capcha
* Crée un champ captcha
* @param string $nameId Nom et id du champ
* @param array $attributes Attributs ($key => $value)
* @return string
*/
public static function capcha($nameId, array $attributes = []) {
public static function captcha($nameId, array $attributes = []) {
// Attributs par défaut
$attributes = array_merge([
'class' => '',
@ -48,15 +48,18 @@ class template {
'name' => $nameId,
'value' => ''
], $attributes);
// Génère deux nombres pour le capcha
$firstNumber = mt_rand(1, 15);
$secondNumber = mt_rand(1, 15);
// Génère deux nombres pour le captcha
$numbers = array(0,1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20);
$letters = array('u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a');
$firstNumber = rand ( 0 , count($letters)-1 );
$secondNumber = rand ( 0 , count($letters)-1 );
// Début du wrapper
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
// Label
$html .= self::label($attributes['id'], $firstNumber . ' + ' . $secondNumber . ' = ?', [
'help' => $attributes['help']
]);
$html .= self::label($attributes['id'],
'<img class="captchaNumber" src="core/vendor/zwiico/png/'.$letters[$firstNumber] . '.png" /> + <img class="captchaNumber" src="core/vendor/zwiico/png/' . $letters[$secondNumber] . '.png" /> = en chiffres ?', [
'help' => $attributes['help']
]);
// Notice
$notice = '';
if(array_key_exists($attributes['id'], common::$inputNotices)) {
@ -64,7 +67,7 @@ class template {
$attributes['class'] .= ' notice';
}
$html .= self::notice($attributes['id'], $notice);
// Capcha
// captcha
$html .= sprintf(
'<input type="text" %s>',
helper::sprintAttributes($attributes)
@ -241,7 +244,7 @@ class template {
'value' => $attributes['value']
]);
// Champ d'upload
$html .= '<div>';
$html .= '<div class="inputFileManagerWrapper">';
$html .= sprintf(
'<a
href="' .
@ -249,7 +252,6 @@ class template {
'?relative_url=1' .
'&field_id=' . $attributes['id'] .
'&type=' . $attributes['type'] .
//'&akey=' . md5_file('site/data/'.'core.json') .
'&akey=' . md5_file(core::DATA_DIR.'core.json') .
($attributes['extensions'] ? '&extensions=' . $attributes['extensions'] : '')
. '"

26
core/core.js.php Executable file → Normal file
View File

@ -7,7 +7,7 @@
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
var core = {};
@ -346,8 +346,8 @@ core.start = function() {
var ratio = width / height;
if ( ($(window).width() / ratio) <= height) {
$("header").height( $(window).width() / ratio );
$("header").css("line-height", $(window).width() / ratio + "px");
}
$("header").css("line-height", $(window).width() / ratio + "px");
}
}
}).trigger("resize");
@ -389,7 +389,7 @@ core.relativeLuminanceW3C = function(rgba) {
$(document).ready(function(){
/**
* Affiche le sous-menu quand il est sticky
* Affiche le sous-menu quand il est sticky
*/
$("nav").mouseenter(function(){
$("#navfixedlogout .navLevel2").css({ 'pointer-events' : 'auto' });
@ -414,7 +414,7 @@ $(document).ready(function(){
// on récupère la valeur data-speed si elle existe
var toggleSpeed = accordion.attr('data-speed') || 100;
// fonction pour afficher un élément
// fonction pour afficher un élément
function open(item, speed) {
// on récupère tous les éléments, on enlève l'élément actif de ce résultat, et on les cache
accordion.find('.accordion-item').not(item).removeClass('active')
@ -428,32 +428,32 @@ $(document).ready(function(){
.find('.accordion-content').slideUp(speed);
}
// on initialise l'accordéon, sans animation
// on initialise l'accordéon, sans animation
open(accordion.find('.active:first'), 0);
// au clic sur un titre...
accordion.on('click', '.accordion-title', function(ev) {
ev.preventDefault();
ev.preventDefault();
// Masquer l'élément déjà actif
if ($(this).closest('.accordion-item').hasClass('active')) {
close($(this).closest('.accordion-item'), toggleSpeed);
} else {
// ...on lance l'affichage de l'élément, avec animation
open($(this).closest('.accordion-item'), toggleSpeed);
// ...on lance l'affichage de l'élément, avec animation
open($(this).closest('.accordion-item'), toggleSpeed);
}
});
});
/**
* Icône du Menu Burger
* Icône du Menu Burger
*/
$("#toggle").click(function() {
$("#toggle").click(function() {
var changeIcon = $('#toggle').children("span");
if ( $(changeIcon).hasClass('zwiico-menu') ) {
$(changeIcon).removeClass('zwiico-menu').addClass('zwiico-cancel');
}
else {
else {
$(changeIcon).addClass('zwiico-menu');
};
});
});
});

201
core/core.php Executable file → Normal file
View File

@ -10,7 +10,7 @@
* @license GNU General Public License, version 3
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
class common {
@ -43,7 +43,7 @@ class common {
const ACCESS_TIMER = 1800;
// Numéro de version
const ZWII_VERSION = '10.3.00';
const ZWII_VERSION = '10.4.00';
const ZWII_UPDATE_CHANNEL = "v10";
public static $actions = [];
@ -52,7 +52,6 @@ class common {
'install',
'maintenance',
'page',
'search',
'sitemap',
'theme',
'user'
@ -150,8 +149,11 @@ class common {
];
public static $timezone;
private $url = '';
// Données de site
private $user = [];
private $page = '';
private $page = [];
private $module = [];
/**
* Constructeur commun
@ -191,8 +193,9 @@ class common {
$this->user = $this->getData(['user', $this->getInput('ZWII_USER_ID')]);
}
// Mise en cache des pages
$this->page = $this->getPageCache();
// Mise en cache des pages et des modules
$this->page = $this->getCache('page');
$this->module = $this->getCache('module');
// Construit la liste des pages parents/enfants
if($this->hierarchy['all'] === []) {
@ -323,12 +326,9 @@ class common {
//Retourne une chaine contenant le dossier à créer
$folder = $this->dirData ($keys[0],'fr');
// Constructeur JsonDB
//require_once "core/vendor/jsondb/Dot.php";
//require_once "core/vendor/jsondb/JsonDb.php";
$db = new \Prowebcraft\JsonDb([
'name' => $keys[0] . '.json',
'dir' => $folder,
'template' => self::TEMP_DIR . 'data.template.json'
'dir' => $folder
]);
switch(count($keys)) {
case 1:
@ -370,10 +370,14 @@ class common {
public function getData($keys = []) {
if (count($keys) >= 1) {
// Lecture d'une donnée de page en cache
if ($keys[0] === 'page') {
/**
* Lecture dans le cache, page et module
*/
if ($keys[0] === 'page' ||
$keys[0] === 'module' ) {
// Décent dans les niveaux de la variable $data
$data = $this->page;
$data = array_merge ($this->page , $this->module);
foreach($keys as $key) {
// Si aucune donnée n'existe retourne null
if(isset($data[$key]) === false) {
@ -387,13 +391,16 @@ class common {
// Retourne les données
return $data;
}
/**
* Lecture directe
*/
//Retourne une chaine contenant le dossier à créer
$folder = $this->dirData ($keys[0],'fr');
// Constructeur JsonDB
$db = new \Prowebcraft\JsonDb([
'name' => $keys[0] . '.json',
'dir' => $folder,
'template' => self::TEMP_DIR . 'data.template.json'
'dir' => $folder
]);
switch(count($keys)) {
case 1:
@ -427,19 +434,15 @@ class common {
* Lecture des fichiers de données de page et mise ne cache
* @param @return string données des pages
*/
public function getPageCache() {
// Trois tentatives
for($i = 0; $i < 3; $i++) {
$data =json_decode(file_get_contents(self::DATA_DIR.'fr/page.json'), true);
if($data) {
return($data);
}
elseif($i === 2) {
exit('Erreur fatale : impossible d\'accéder aux pages');
}
// Pause de 10 millisecondes
usleep(10000);
}
public function getCache($data) {
$folder = $this->dirData ($data,'fr');
// Constructeur JsonDB
$db = new \Prowebcraft\JsonDb([
'name' => $data . '.json',
'dir' => $folder
]);
$tempData = $db->get($data);
return [$data => $tempData];
}
/*
@ -595,7 +598,7 @@ class common {
break;
}
elseif($i === 2) {
exit('Impossible de lire les données à importer.');
throw new \ErrorException('Import des données impossible.');
}
// Pause de 10 millisecondes
usleep(10000);
@ -950,8 +953,9 @@ class common {
*/
public function setData($keys = []) {
// Pas d'enregistrement lorsqu'une notice est présente
if (!empty(self::$inputNotices)) {
// Pas d'enregistrement lorsqu'une notice est présente ou tableau transmis vide
if (!empty(self::$inputNotices
OR empty($keys))) {
return false;
}
@ -960,8 +964,7 @@ class common {
// Constructeur JsonDB
$db = new \Prowebcraft\JsonDb([
'name' => $keys[0] . '.json',
'dir' => $folder,
'template' => self::TEMP_DIR . 'data.template.json'
'dir' => $folder
]);
switch(count($keys)) {
@ -1012,8 +1015,7 @@ class common {
// Constructeur JsonDB
$db = new \Prowebcraft\JsonDb([
'name' => $module . '.json',
'dir' => $folder,
'template' => self::TEMP_DIR . 'data.template.json'
'dir' => $folder
]);
if ($sampleSite === true) {
$db->set($module,init::$siteData[$module]);
@ -1355,12 +1357,57 @@ class common {
if ($this->getData(['core', 'dataVersion']) < 10201) {
// Options de barre de membre simple
$this->setData(['theme','footer','displayMemberBar',false]);
$this->setData(['theme','menu','memberBar',true]);
$this->deleteData(['theme','footer','displayMemberAccount']);
$this->deleteData(['theme','footer','displayMemberLogout']);
$this->setData(['core', 'dataVersion', 10201]);
}
// Version 10.3.00
if ($this->getData(['core', 'dataVersion']) < 10300) {
// Options de barre de membre simple
$this->setData(['config','page404','none']);
$this->setData(['config','page403','none']);
// Module de recherche
// Suppression du dossier search
if (is_dir('core/module/search')) {
$dir = getcwd();
chdir('core/module/search');
$files = glob('*');
foreach($files as $file) unlink($file);
chdir($dir);
rmdir ('core/module/search/');
}
// Désactivation de l'option dans le pied de page
$this->setData(['theme','footer','displaySearch',false]);
// Inscription des nouvelles variables
$this->setData(['config','searchPageId','']);
// Mettre à jour les données des galeries
$pageList = array();
foreach ($this->getHierarchy(null,null,null) as $parentKey=>$parentValue) {
$pageList [] = $parentKey;
foreach ($parentValue as $childKey) {
$pageList [] = $childKey;
}
}
// Mise à jour des données de thème de la galerie
// Les données de thème sont communes au site
foreach ($pageList as $parentKey => $parent) {
//La page a une galerie
if ($this->getData(['page',$parent,'moduleId']) === 'gallery' ) {
foreach ( $this->getData(['module', $parent]) as $galleryKey => $galleryItem) {
// Transfert du theme dans une structure unique
if ( is_array($this->getdata(['theme',$parent])) ) {
$this->setdata(['theme','gallery',$this->getdata(['theme',$parent])]);
}
}
$this->deleteData(['theme',$parent]);
}
}
// Mise à jour du numéro de version
$this->setData(['core', 'dataVersion', 10300]);
}
// Version 10.4.00
if ($this->getData(['core', 'dataVersion']) < 10300) {
// Ajouter le prénom comme pseudo et le pseudo comme signature
foreach($this->getData(['user']) as $userId => $userIds){
@ -1399,7 +1446,7 @@ class common {
}
}
}
$this->setData(['core', 'dataVersion', 10300]);
$this->setData(['core', 'dataVersion', 10400]);
}
}
}
@ -1713,7 +1760,7 @@ class core extends common {
// Déconnexion
$user = new user;
$user->logout();
// Rédirection
// Redirection
http_response_code(302);
header('Location:' . helper::baseUrl() . 'maintenance');
exit();
@ -1753,11 +1800,11 @@ class core extends common {
foreach($this->getData(['user']) as $userId => $userIds){
$t = explode('/',$this->getData(['user', $userId, 'accessUrl']));
if ( $this->getuser('id') &&
$userId !== $this->getuser('id') &&
$this->getData(['user', $userId,'accessUrl']) === $this->getUrl() &&
array_intersect($t,self::$accessList) &&
array_intersect($t,self::$accessExclude) !== false &&
time() < $this->getData(['user', $userId,'accessTimer']) + self::ACCESS_TIMER
$userId !== $this->getuser('id') &&
$this->getData(['user', $userId,'accessUrl']) === $this->getUrl() &&
array_intersect($t,self::$accessList) &&
array_intersect($t,self::$accessExclude) !== false &&
time() < $this->getData(['user', $userId,'accessTimer']) + self::ACCESS_TIMER
) {
$access = false;
$accessInfo['userName'] = $this->getData(['user', $userId, 'lastname']) . ' ' . $this->getData(['user', $userId, 'firstname']);
@ -1990,20 +2037,31 @@ class core extends common {
'title' => 'Accès verrouillé',
'content' => template::speech('La page <strong>' . $accessInfo['pageId'] . '</strong> est ouverte par l\'utilisateur <strong>' . $accessInfo['userName'] . '</strong>')
]);
} else {
if ( $this->getData(['config','page403']) !== 'none'
AND $this->getData(['page',$this->getData(['config','page403'])]))
{
header('Location:' . helper::baseUrl() . $this->getData(['config','page403']));
} else {
$this->addOutput([
'title' => 'Erreur 403',
'content' => template::speech('Vous n\'êtes pas autorisé à accéder à cette page...')
]);
}
}
} elseif ($this->output['content'] === '') {
http_response_code(404);
if ( $this->getData(['config','page404']) !== 'none'
AND $this->getData(['page',$this->getData(['config','page404'])]))
{
header('Location:' . helper::baseUrl() . $this->getData(['config','page404']));
} else {
$this->addOutput([
'title' => 'Erreur 403',
'content' => template::speech('Vous n\'êtes pas autorisé à accéder à cette page...')
'title' => 'Erreur 404',
'content' => template::speech('Oups ! La page demandée est introuvable...')
]);
}
}
elseif($this->output['content'] === '') {
http_response_code(404);
$this->addOutput([
'title' => 'Erreur 404',
'content' => template::speech('Oups ! La page demandée est introuvable...')
]);
}
// Mise en forme des métas
if($this->output['metaTitle'] === '') {
if($this->output['title']) {
@ -2088,12 +2146,12 @@ class layout extends common {
AND (
$this->getData(['page', $this->getUrl(0)]) === null
OR $this->getData(['page', $this->getUrl(0), 'hideTitle']) === false
OR $this->getUrl(1) === 'config'
)
) {
echo '<h1 id="sectionTitle">' . $this->core->output['title'] . '</h1>';
}
echo $this->core->output['content'];
}
@ -2162,7 +2220,7 @@ class layout extends common {
$items .= '>Motorisé&nbsp;par&nbsp;</span>';
// Toujours afficher le nom du CMS
$items .= '<span id="footerZwiiCMS">';
$items .= '<a href="http://zwiicms.com/" onclick="window.open(this.href);return false" data-tippy-content="Zwii CMS sans base de données, très léger et performant">ZwiiCMS</a>';
$items .= '<a href="https://zwiicms.fr/" onclick="window.open(this.href);return false" data-tippy-content="Zwii CMS sans base de données, très léger et performant">ZwiiCMS</a>';
$items .= '</span>';
// Affichage du numéro de version
$items .= '<span id="footerDisplayVersion"';
@ -2177,7 +2235,7 @@ class layout extends common {
// Affichage du module de recherche
$items .= '<span id="footerDisplaySearch"';
$items .= $this->getData(['theme','footer','displaySearch']) === false ? ' class="displayNone"' : '';
$items .= '><wbr>&nbsp;|&nbsp;<a href="' . helper::baseUrl() . 'search" data-tippy-content="Rechercher dans le site" >Rechercher</a>';
$items .= '><wbr>&nbsp;|&nbsp;<a href="' . helper::baseUrl() . $this->getData(['config','searchPageId']) . '" data-tippy-content="Rechercher dans le site" >Recherche</a>';
$items .= '</span>';
// Affichage des mentions légales
$items .= '<span id="footerDisplayLegal"';
@ -2288,7 +2346,8 @@ class layout extends common {
file_exists(self::FILE_DIR.'source/' . $faviconDark)
) {
echo '<link rel="shortcut icon" media="(prefers-color-scheme:dark)" href="' . helper::baseUrl(false) . self::FILE_DIR.'source/' . $faviconDark . '">';
echo '<script src="https://unpkg.com/favicon-switcher@1.2.0/dist/index.js" crossorigin="anonymous" type="application/javascript"></script>';
//echo '<script src="https://unpkg.com/favicon-switcher@1.2.2/dist/index.js" crossorigin="anonymous" type="application/javascript"></script>';
echo '<script src="' . helper::baseUrl(false) . 'core/vendor/favicon-switcher/favicon-switcher.js" crossorigin="anonymous" type="application/javascript"></script>';
}
}
@ -2303,7 +2362,7 @@ class layout extends common {
foreach($this->getHierarchy() as $parentPageId => $childrenPageIds) {
// Passer les entrées masquées
// Propriétés de l'item
$active = ($parentPageId === $currentPageId OR in_array($currentPageId, $childrenPageIds)) ? ' class="active"' : '';
$active = ($parentPageId === $currentPageId OR in_array($currentPageId, $childrenPageIds)) ? 'active ' : '';
$targetBlank = $this->getData(['page', $parentPageId, 'targetBlank']) ? ' target="_blank"' : '';
// Mise en page de l'item
$items .= '<li>';
@ -2313,7 +2372,7 @@ class layout extends common {
{$items .= '<a class="' . $parentPageId . '" href="'.$this->getUrl(1).'">';
} else {
$items .= '<a class="' . $parentPageId . '" href="' . helper::baseUrl() . $parentPageId . '"' . $active . $targetBlank . '>';
$items .= '<a class="' . $active . $parentPageId . '" href="' . helper::baseUrl() . $parentPageId . '"' . $targetBlank . '>';
}
switch ($this->getData(['page', $parentPageId, 'typeMenu'])) {
@ -2359,7 +2418,7 @@ class layout extends common {
$items .= '<ul class="navLevel2">';
foreach($childrenPageIds as $childKey) {
// Propriétés de l'item
$active = ($childKey === $currentPageId) ? ' class="active"' : '';
$active = ($childKey === $currentPageId) ? 'active ' : '';
$targetBlank = $this->getData(['page', $childKey, 'targetBlank']) ? ' target="_blank"' : '';
// Mise en page du sous-item
$items .= '<li>';
@ -2367,7 +2426,7 @@ class layout extends common {
AND $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') ) {
$items .= '<a class="' . $parentPageId . '" href="'.$this->getUrl(1).'">';
} else {
$items .= '<a class="' . $parentPageId . '" href="' . helper::baseUrl() . $childKey . '"' . $active . $targetBlank . '>';
$items .= '<a class="' . $active . $parentPageId . '" href="' . helper::baseUrl() . $childKey . '"' . $targetBlank . '>';
}
switch ($this->getData(['page', $childKey, 'typeMenu'])) {
@ -2467,7 +2526,7 @@ class layout extends common {
continue;
}
// Propriétés de l'item
$active = ($parentPageId === $currentPageId OR in_array($currentPageId, $childrenPageIds)) ? ' class="active"' : '';
$active = ($parentPageId === $currentPageId OR in_array($currentPageId, $childrenPageIds)) ? 'active ' : '';
$targetBlank = $this->getData(['page', $parentPageId, 'targetBlank']) ? ' target="_blank"' : '';
// Mise en page de l'item;
// Ne pas afficher le parent d'une sous-page quand l'option est sélectionnée.
@ -2477,7 +2536,7 @@ class layout extends common {
AND $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') ) {
$items .= '<a href="'.$this->getUrl(1).'">';
} else {
$items .= '<a href="' . helper::baseUrl() . $parentPageId . '"' . $active . $targetBlank . '>';
$items .= '<a href="' . $active . helper::baseUrl() . $parentPageId . '"' . $targetBlank . '>';
}
$items .= $this->getData(['page', $parentPageId, 'title']);
$items .= '</a>';
@ -2490,7 +2549,7 @@ class layout extends common {
}
// Propriétés de l'item
$active = ($childKey === $currentPageId) ? ' class="active"' : '';
$active = ($childKey === $currentPageId) ? 'active ' : '';
$targetBlank = $this->getData(['page', $childKey, 'targetBlank']) ? ' target="_blank"' : '';
// Mise en page du sous-item
$itemsChildren .= '<li class="menuSideChild">';
@ -2499,7 +2558,7 @@ class layout extends common {
AND $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') ) {
$itemsChildren .= '<a href="'.$this->getUrl(1).'">';
} else {
$itemsChildren .= '<a href="' . helper::baseUrl() . $childKey . '"' . $active . $targetBlank . '>';
$itemsChildren .= '<a href="' .$active . helper::baseUrl() . $childKey . '"' . $targetBlank . '>';
}
$itemsChildren .= $this->getData(['page', $childKey, 'title']);
@ -2663,6 +2722,7 @@ class layout extends common {
if ($this->getData(['page', $this->getUrl(0),'moduleId'])) {
$leftItems .= '<li><a href="' . helper::baseUrl() . $this->getUrl(0) . '/config' . '" data-tippy-content="Configurer le module">' . template::ico('gear') . '</a></li>';
}
$leftItems .= '<li><a id="pageDuplicate" href="' . helper::baseUrl() . 'page/duplicate/' . $this->getUrl(0) . '&csrf=' . $_SESSION['csrf'] . '" data-tippy-content="Dupliquer la page">' . template::ico('clone') . '</a></li>';
$leftItems .= '<li><a id="pageDelete" href="' . helper::baseUrl() . 'page/delete/' . $this->getUrl(0) . '&csrf=' . $_SESSION['csrf'] . '" data-tippy-content="Effacer la page">' . template::ico('trash') . '</a></li>';
}
}
@ -2676,13 +2736,14 @@ class layout extends common {
$rightItems .= '<li><a href="' . helper::baseUrl() . 'theme" data-tippy-content="Personnaliser les thèmes">' . template::ico('brush') . '</a></li>';
$rightItems .= '<li><a href="' . helper::baseUrl() . 'config" data-tippy-content="Configurer le site">' . template::ico('cog-alt') . '</a></li>';
// Mise à jour automatique
$today = mktime(0, 0, 0);
// Une mise à jour est disponible + recherche auto activée + 1 jour de délais
$lastAutoUpdate = mktime(0, 0, 0);
if( $this->getData(['config','autoUpdate']) === true &&
$lastAutoUpdate > $this->getData(['core','lastAutoUpdate']) + 86400 &&
helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL)) {
$this->setData(['core','updateAvailable', true]);
$this->setData(['core','lastAutoUpdate',$lastAutoUpdate]);
if ( $this->getData(['config','autoUpdate']) === true
AND $today > $this->getData(['core','lastAutoUpdate']) + 86400 ) {
if ( helper::checkNewVersion(common::ZWII_UPDATE_CHANNEL) ) {
$this->setData(['core','updateAvailable', true]);
$this->setData(['core','lastAutoUpdate',$today]);
}
}
// Afficher le bouton : Mise à jour détectée + activée
if ( $this->getData(['core','updateAvailable']) === true &&

View File

@ -7,7 +7,7 @@
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
/**

0
core/layout/blank.php Executable file → Normal file
View File

View File

@ -7,7 +7,7 @@
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
/**
@ -207,7 +207,6 @@ Signature dans les articles blog et news
}
.table tbody tr {
background: #F6F7F8;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
.table tbody tr:nth-child(2n + 2) {
@ -357,7 +356,6 @@ td > .col12 {
display: inline-block;
padding: 0 12px;
color: #FFF;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
#bar a:hover {
@ -448,14 +446,14 @@ header .container {
height: 100%;
}
/* Element du header */
/* Element du header
#themeHeaderImage {
font-style: italic;
font-size: 0.9em;
}
}*/
/* Menu
/* Menu
body > nav {
margin: 0 -10px;
}
@ -501,7 +499,6 @@ nav li ul {
width: 200px;
z-index: -1;
opacity: 0;
-webkit-transition: .3s ease-out;
transition: .3s ease-out;
padding-left: 10px;
}
@ -518,7 +515,6 @@ nav li:hover ul {
nav a {
display: inherit;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
@ -702,7 +698,6 @@ footer #footerSocials span {
margin: 0 5px;
display: inline-block;
border-radius: 2px;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
footer #footerSocials .zwiico-facebook {
@ -766,7 +761,6 @@ footer #footerSocials .zwiico-github:hover {
margin: 16px auto;
text-align: left;
border-radius: 2px;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
.speechBubble:before {
@ -792,7 +786,6 @@ footer #footerSocials .zwiico-github:hover {
cursor: pointer;
display: none;
border-radius: 50%;
-webkit-transition: background.3s ease-out;
transition: background .3s ease-out;
}
#backToTop:hover {
@ -822,7 +815,6 @@ footer #footerSocials .zwiico-github:hover {
background: #666;
padding: 4px 8px;
display: inline-block;
-webkit-transition: background.3s ease-out;
transition: background .3s ease-out;
}
#cookieConsentConfirm:hover {
@ -902,7 +894,6 @@ textarea {
width: 100%;
border-radius: 2px;
font-family: inherit;
-webkit-transition: border .3s ease-out;
transition: border .3s ease-out;
}
select {
@ -950,7 +941,6 @@ button {
cursor: pointer;
font-family: inherit;
border-radius: 2px;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
textarea {
@ -982,7 +972,6 @@ label {
user-select: none;
cursor: pointer;
border-radius: 2px;
-webkit-transition: background .3s ease-out;
transition: background .3s ease-out;
}
/* Bouton redimensionnable pour le formulaire*/
@ -1019,6 +1008,16 @@ label {
text-decoration: none;
}
/* Empêche le débordement et les sauts de ligne */
.inputFileManagerWrapper {
display: inline;
}
.inputFileManagerWrapper > .inputFile {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Pagination */
.pagination {
padding: 10px 0;
@ -1358,4 +1357,35 @@ th.col12 {
}
.accordion-content {
padding: 7px;
}
}
/* Captcha
* Taille des images
*/
.captchaNumber {
height: 25px;
vertical-align: bottom;
padding-left: 5px;
padding-right: 5px;
}
/*
* Couleur des icônes + et -
*/
.zwiico-minus-circled,
.zwiico-plus-circled {
color: #D8890B;
font-size: 1.3em !important;
}
.zwiico-minus-circled,
.zwiico-plus-circled {
transition: all 1s ease;
}
.zwiico-minus-circled:hover,
.zwiico-plus-circled:hover {
-webkit-transform:scale(1.25); /* Safari et Chrome */
-moz-transform:scale(1.25); /* Firefox */
-ms-transform:scale(1.25); /* Internet Explorer 9 */
-o-transform:scale(1.25); /* Opera */
transform:scale(1.25);
}

View File

@ -7,7 +7,7 @@
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
/**

0
core/layout/light.php Executable file → Normal file
View File

0
core/layout/mail.php Executable file → Normal file
View File

4
core/layout/main.php Executable file → Normal file
View File

@ -186,7 +186,7 @@
<div class="row siteContainer">
<?php
if ($blockleft !== "") :?>
<div class="<?php echo $blockleft; ?>" id="contentLeft"><?php $layout->showBarContentLeft(); ?></div>
<div class="<?php echo $blockleft; ?>" id="contentLeft"><aside><?php $layout->showBarContentLeft(); ?></aside></div>
<?php endif; ?>
<div class="<?php echo $content; ?>" id="contentSite"><?php $layout->showContent();
if (file_exists(self::DATA_DIR . 'body.inc.html')) {
@ -196,7 +196,7 @@
</div>
<?php
if ($blockright !== "") :?>
<div class="<?php echo $blockright; ?>" id="contentRight"><?php $layout->showBarContentRight(); ?></div>
<div class="<?php echo $blockright; ?>" id="contentRight"><aside><?php $layout->showBarContentRight(); ?></aside></div>
<?php endif; ?>
</div>
<?php }

52
core/module/config/config.php Executable file → Normal file
View File

@ -8,10 +8,10 @@
*
* @author Rémi Jean <remi.jean@outlook.com>
* @copyright Copyright (C) 2008-2018, Rémi Jean
* * @author Frédéric Tempez <frederic.tempez@outlook.com>
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
class config extends common {
@ -246,17 +246,19 @@ class config extends common {
// Creation du ZIP
$filter = $this->getInput('configBackupOption',helper::FILTER_BOOLEAN) === true ? ['backup','tmp'] : ['backup','tmp','file'];
$fileName = helper::autoBackup(self::TEMP_DIR,$filter);
// Téléchargement du ZIP
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize(self::TEMP_DIR . $fileName));
readfile(self::TEMP_DIR . $fileName);
// Créer le répertoire manquant
if (!is_dir(self::FILE_DIR.'source/backup')) {
mkdir(self::FILE_DIR.'source/backup');
}
// Copie dans les fichiers
$success = copy (self::TEMP_DIR . $fileName , self::FILE_DIR.'source/backup/' . $fileName);
// Détruire le temporaire
unlink(self::TEMP_DIR . $fileName);
// Valeurs en sortie
$this->addOutput([
'display' => self::DISPLAY_RAW
'display' => self::DISPLAY_JSON,
'content' => json_encode($success)
]);
unlink(self::TEMP_DIR . $fileName);
} else {
// Valeurs en sortie
$this->addOutput([
@ -406,22 +408,41 @@ class config extends common {
public function index() {
// Soumission du formulaire
if($this->isPost()) {
$success = true;
// Basculement en mise à jour auto
// Remise à 0 du compteur
if ($this->getData(['config','autoUpdate']) === false &&
$this->getInput('configAutoUpdate', helper::FILTER_BOOLEAN) === true) {
$this->setData(['core','lastAutoUpdate',0]);
}
if ($this->getInput('configLegalCheck', helper::FILTER_BOOLEAN) === true ) {
$legalPageId = $this->getInput('configLegalPageId', helper::FILTER_ID);
// Empêcher la modification si défini dans footer
if ( $this->getData(['theme','footer','displaySearch']) === true
AND $this->getInput('configSearchPageId') === ''
){
$searchPageId = $this->getData(['config','searchPageId']);
self::$inputNotices['configSearchPageId'] = 'Désactiver l\'option dans le pied de page';
$success = false;
} else {
$legalPageId = '';
$searchPageId = $this->getInput('configSearchPageId');
}
// Empêcher la modification si défini dans footer
if ( $this->getData(['theme','footer','displayLegal']) === true
AND $this->getInput('configLegalPageId') === ''
){
$legalPageId = $this->getData(['config','legalPageId']);
self::$inputNotices['configLegalPageId'] = 'Désactiver l\'option dans le pied de page';
$success = false;
} else {
$legalPageId = $this->getInput('configLegalPageId');
}
// Sauvegarder
$this->setData([
'config',
[
'homePageId' => $this->getInput('configHomePageId', helper::FILTER_ID, true),
'page404' => $this->getInput('configPage404'),
'page403' => $this->getInput('configPage403'),
'page302' => $this->getInput('configPage302'),
'analyticsId' => $this->getInput('configAnalyticsId'),
'autoBackup' => $this->getInput('configAutoBackup', helper::FILTER_BOOLEAN),
'maintenance' => $this->getInput('configMaintenance', helper::FILTER_BOOLEAN),
@ -440,7 +461,8 @@ class config extends common {
],
'timezone' => $this->getInput('configTimezone', helper::FILTER_STRING_SHORT, true),
'itemsperPage' => $this->getInput('configItemsperPage', helper::FILTER_INT,true),
'legalPageId' => $this->getInput('configLegalPageId'),
'legalPageId' => $legalPageId,
'searchPageId' => $searchPageId,
'metaDescription' => $this->getInput('configMetaDescription', helper::FILTER_STRING_LONG, true),
'title' => $this->getInput('configTitle', helper::FILTER_STRING_SHORT, true),
'autoUpdate' => $this->getInput('configAutoUpdate', helper::FILTER_BOOLEAN),
@ -509,7 +531,7 @@ class config extends common {
$this->addOutput([
'redirect' => helper::baseUrl() . $this->getUrl(),
'notification' => 'Modifications enregistrées',
'state' => true
'state' => $success
]);
}
// Initialisation du screen - APPEL AUTO DESACTIVE POUR EVITER UN RALENTISSEMENT

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -9,7 +9,49 @@
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2020, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.com/
* @link http://zwiicms.fr/
*/
@import url("site/data/admin.css");
@import url("site/data/admin.css");
/**
* Effet d'animation
*/
/* Start by setting display:none to make this hidden.
Then we position it in relation to the viewport window
with position:fixed. Width, height, top and left speak
for themselves. Background we set to 80% white with
our animation centered, and no-repeating */
.modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba( 0, 0, 0, .9 )
url('core/module/config/ressource/ajax-loader.png')
50% 45%
no-repeat;
}
.alertMessage {
color: lightgrey;
display: none;
display: flex;
align-items: center;
justify-content: center;
}
/* When the body has the loading class, we turn
the scrollbar off with overflow:hidden */
body.loading .modal .alertMessage {
overflow: hidden;
}
/* Anytime the body has the loading class, our
modal element will be visible */
body.loading .modal .alertMessage {
display: block;
}