Merge branch '114_dev'

This commit is contained in:
Fred Tempez 2022-05-03 16:08:13 +02:00
commit 188dd6b17d
70 changed files with 3495 additions and 2318 deletions

19
.gitignore vendored
View File

@ -1,19 +0,0 @@
# Fichiers du site
site/*
# Dossiers vides dans GitHub
!.gitkeep
/.git
# PHPStorm
.idea/
# Trucs
core/vendor/tinymce/link_list.json
.vscode/*
sitemap.xml.gz
sitemap.xml
robots.txt
.DS_Store
# Service de mise à jour
gitupdate.sh

View File

@ -32,5 +32,5 @@ Options -Indexes
Options -MultiViews
</IfModule>
# Attention, surtout ne rien modifier ci-dessous !
# ne pas supprimer la ligne URL rewriting !
# URL rewriting

View File

@ -1,5 +1,33 @@
# Changelog
## Version 11.4.00
### Nouveautés :
- Compatibilité avec PHP 8.1
- Prise en charge des fontes Web Safe. Les fontes initiales sont transférées dans les fontes optionnelles, donc effaçables.
- Toutes les fontes en ligne sont désormais acceptées quel que soit le CDN, Google Fonte (avec preconnect), CDN Fontes ou autres.
- Désormais, les URL internes sont relatives, cela signifie qu'elles ne contiendront plus le domaine et le chemin d'accès au site. Cela permettra le déplacement d'un site d'un hébergement à un autre, d'un dossier d'hébergement à un autre, sans avoir à convertir les adresses internes. Les données d'un site mis à jour et importées d'une version antérieures sont automatiquement converties. En conséquence, le bloc de conversion de la fenêtre d'import est supprimé.
- Suppression temporaire de l'option d'installation d'un module, il faudra passer par une connexion FTP pour cela. Cette fonctionnalité a été réécrite pour la version 11.2.
### Améliorations :
- Configuration de la bannière, modalité d'affichage de la taille d'image recommandée et affichage des dimensions de l'image.
- Edition d'une page, le nom court se complète automatiquement.
- Configuration de la connexion, une option autorise l'affichage de la page de connexion lorsqu'une page de gestion du site est demandée: 'user', 'theme', 'config', 'edit', 'translate', 'addon'.
- L'option de réécriture d'URL n'est pas plus active avec le serveur Nginx.
- Galerie, version 3.5 :
- Nouvelle structure anticipée sur la version 12, le formulaire d'ajout de la galerie est séparé de la liste des galeries du module.
- Lorsque la galerie n'en contient qu'**une seule galerie**, elle peut être affichée directement, la liste des galeries étant ignorée. Pour cela, activer cette option dans les options de la galerie.
- Le contenu de la page peut désormais être affiché avec le contenu de la galerie sélectionnée. Ce paramètre ce gère au niveau de chaque galerie.
- Déplacement du bouton de retour à la liste des galeries en bas de l'écran.
### Corrections :
- URL Rewrite Apache, bug d'interprétation d'activation de la réécriture d'URL lorsque des données ont été inscrites après la ligne servant de délimiteur *# URL rewriting* dans le fichier htaccess.
- Module Galerie : correction de bugs, tri des images, erreurs d'affectation.
- Module Blog : taille recommandée de l'image erronée lorsque la largeur de l'écran est réglée sur fluide (100%).
- Gestion des pages : positionnement dans le menu accessoire ou dans le menu standard.
- Safari sur Mac, bug avec les cookies qui ne sont pas stockés.
- Nettoyage du code.
### Mise à jour :
- TableDND, script JQUERY de tri de tables utilisé par la galerie passe en version 1.0.5
- PHPMailer 6.6.0
## Version 11.3.07
### Correction :
- Module galerie, option plein écran inopérante.
@ -16,7 +44,6 @@
- Sauvegarde des fontes avec le thème.
- Une fonte Websafe remplace une fonte locale dont le fichier n'est pas disponible.
## Version 11.3.05
### Correction :
- Dossier du fichier de fontes non créé empêchant la création du fichier des appels de fontes.

View File

@ -1,4 +1,4 @@
# ZwiiCMS 11.3.07
# ZwiiCMS 11.4.00
Zwii est un CMS sans base de données (flat-file) qui permet de créer et gérer facilement un site web sans aucune connaissance en programmation.

View File

@ -86,7 +86,7 @@ class helper {
* @param string $sort Type de tri à appliquer au tableau (SORT_ASC, SORT_DESC, ou null)
* @return array
*/
public static function arrayCollumn($array, $column, $sort = null) {
public static function arrayColumn($array, $column, $sort = null) {
$newArray = [];
if(empty($array) === false) {
$newArray = array_map(function($element) use($column) {
@ -104,6 +104,14 @@ class helper {
return $newArray;
}
/**
* Compatibilité avec les anciens modules
*/
public static function arrayCollumn($array, $column, $sort = null) {
return (helper::arrayColumn($array, $column, $sort));
}
/**
* Génère un backup des données de site
@ -255,11 +263,15 @@ class helper {
* @return bool
*/
public static function checkRewrite() {
if(self::$rewriteStatus === null) {
// N'interroge que le serveur Apache
if (strpos($_SERVER["SERVER_SOFTWARE"], 'Apache') > 0) {
self::$rewriteStatus === false;
} elseif(self::$rewriteStatus === null) {
// Ouvre et scinde le fichier .htaccess
$htaccess = explode('# URL rewriting', file_get_contents('.htaccess'));
// Retourne un boolean en fonction du contenu de la partie réservée à l'URL rewriting
self::$rewriteStatus = (empty($htaccess[1]) === false);
//self::$rewriteStatus = (empty($htaccess[1]) === false);
self::$rewriteStatus = (strpos($htaccess[1], 'RewriteEngine on') > 0) ? true : false;
}
return self::$rewriteStatus;
}

View File

@ -31,6 +31,16 @@ class JsonDb extends \Prowebcraft\Dot
parent::__construct();
}
/**
* Reload data from file
* @return $this
*/
public function reload()
{
$this->loadData(true);
return $this;
}
/**
* Set value or array of values to path
*

View File

@ -1,4 +1,5 @@
<?php
/**
* PHPMailer Exception class.
* PHP Version 5.5.
@ -9,7 +10,7 @@
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
* @author Brent R. Matzelle (original founder)
* @copyright 2012 - 2017 Marcus Bointon
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
@ -34,6 +35,6 @@ class Exception extends \Exception
*/
public function errorMessage()
{
return '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n";
return '<strong>' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "</strong><br />\n";
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
<?php
/**
* PHPMailer RFC821 SMTP email transport class.
* PHP Version 5.5.
@ -9,7 +10,7 @@
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
* @author Brent R. Matzelle (original founder)
* @copyright 2012 - 2019 Marcus Bointon
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
@ -34,7 +35,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.1.5';
const VERSION = '6.6.0';
/**
* SMTP line break constant.
@ -185,6 +186,8 @@ class SMTP
'Amazon_SES' => '/[\d]{3} Ok (.*)/',
'SendGrid' => '/[\d]{3} Ok: queued as (.*)/',
'CampaignMonitor' => '/[\d]{3} 2.0.0 OK:([a-zA-Z\d]{48})/',
'Haraka' => '/[\d]{3} Message Queued \((.*)\)/',
'Mailjet' => '/[\d]{3} OK queued as (.*)/',
];
/**
@ -311,17 +314,11 @@ class SMTP
*/
public function connect($host, $port = null, $timeout = 30, $options = [])
{
static $streamok;
//This is enabled by default since 5.0.0 but some providers disable it
//Check this once and cache the result
if (null === $streamok) {
$streamok = function_exists('stream_socket_client');
}
// Clear errors to avoid confusion
//Clear errors to avoid confusion
$this->setError('');
// Make sure we are __not__ connected
//Make sure we are __not__ connected
if ($this->connected()) {
// Already connected, generate error
//Already connected, generate error
$this->setError('Already connected to a server');
return false;
@ -329,18 +326,66 @@ class SMTP
if (empty($port)) {
$port = self::DEFAULT_PORT;
}
// Connect to the SMTP server
//Connect to the SMTP server
$this->edebug(
"Connection: opening to $host:$port, timeout=$timeout, options=" .
(count($options) > 0 ? var_export($options, true) : 'array()'),
self::DEBUG_CONNECTION
);
$this->smtp_conn = $this->getSMTPConnection($host, $port, $timeout, $options);
if ($this->smtp_conn === false) {
//Error info already set inside `getSMTPConnection()`
return false;
}
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
//Get any announcement
$this->last_reply = $this->get_lines();
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
$responseCode = (int)substr($this->last_reply, 0, 3);
if ($responseCode === 220) {
return true;
}
//Anything other than a 220 response means something went wrong
//RFC 5321 says the server will wait for us to send a QUIT in response to a 554 error
//https://tools.ietf.org/html/rfc5321#section-3.1
if ($responseCode === 554) {
$this->quit();
}
//This will handle 421 responses which may not wait for a QUIT (e.g. if the server is being shut down)
$this->edebug('Connection: closing due to error', self::DEBUG_CONNECTION);
$this->close();
return false;
}
/**
* Create connection to the SMTP server.
*
* @param string $host SMTP server IP or host name
* @param int $port The port number to connect to
* @param int $timeout How long to wait for the connection to open
* @param array $options An array of options for stream_context_create()
*
* @return false|resource
*/
protected function getSMTPConnection($host, $port = null, $timeout = 30, $options = [])
{
static $streamok;
//This is enabled by default since 5.0.0 but some providers disable it
//Check this once and cache the result
if (null === $streamok) {
$streamok = function_exists('stream_socket_client');
}
$errno = 0;
$errstr = '';
if ($streamok) {
$socket_context = stream_context_create($options);
set_error_handler([$this, 'errorHandler']);
$this->smtp_conn = stream_socket_client(
$connection = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
@ -348,7 +393,6 @@ class SMTP
STREAM_CLIENT_CONNECT,
$socket_context
);
restore_error_handler();
} else {
//Fall back to fsockopen which should work in more places, but is missing some features
$this->edebug(
@ -356,17 +400,18 @@ class SMTP
self::DEBUG_CONNECTION
);
set_error_handler([$this, 'errorHandler']);
$this->smtp_conn = fsockopen(
$connection = fsockopen(
$host,
$port,
$errno,
$errstr,
$timeout
);
restore_error_handler();
}
// Verify we connected properly
if (!is_resource($this->smtp_conn)) {
restore_error_handler();
//Verify we connected properly
if (!is_resource($connection)) {
$this->setError(
'Failed to connect to server',
'',
@ -381,22 +426,19 @@ class SMTP
return false;
}
$this->edebug('Connection: opened', self::DEBUG_CONNECTION);
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
//SMTP server can take longer to respond, give longer timeout for first read
//Windows does not have support for this timeout function
if (strpos(PHP_OS, 'WIN') !== 0) {
$max = (int) ini_get('max_execution_time');
// Don't bother if unlimited
if (0 !== $max && $timeout > $max) {
$max = (int)ini_get('max_execution_time');
//Don't bother if unlimited, or if set_time_limit is disabled
if (0 !== $max && $timeout > $max && strpos(ini_get('disable_functions'), 'set_time_limit') === false) {
@set_time_limit($timeout);
}
stream_set_timeout($this->smtp_conn, $timeout, 0);
stream_set_timeout($connection, $timeout, 0);
}
// Get any announcement
$announce = $this->get_lines();
$this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
return true;
return $connection;
}
/**
@ -420,7 +462,7 @@ class SMTP
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}
// Begin encrypted connection
//Begin encrypted connection
set_error_handler([$this, 'errorHandler']);
$crypto_ok = stream_socket_enable_crypto(
$this->smtp_conn,
@ -441,7 +483,7 @@ class SMTP
* @param string $username The user name
* @param string $password The password
* @param string $authtype The auth type (CRAM-MD5, PLAIN, LOGIN, XOAUTH2)
* @param OAuth $OAuth An optional OAuth instance for XOAUTH2 authentication
* @param OAuthTokenProvider $OAuth An optional OAuthTokenProvider instance for XOAUTH2 authentication
*
* @return bool True if successfully authenticated
*/
@ -458,11 +500,11 @@ class SMTP
}
if (array_key_exists('EHLO', $this->server_caps)) {
// SMTP extensions are available; try to find a proper authentication method
//SMTP extensions are available; try to find a proper authentication method
if (!array_key_exists('AUTH', $this->server_caps)) {
$this->setError('Authentication is not allowed at this stage');
// 'at this stage' means that auth may be allowed after the stage changes
// e.g. after STARTTLS
//'at this stage' means that auth may be allowed after the stage changes
//e.g. after STARTTLS
return false;
}
@ -506,12 +548,15 @@ class SMTP
}
switch ($authtype) {
case 'PLAIN':
// Start authentication
//Start authentication
if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
return false;
}
// Send encoded username and password
if (!$this->sendCommand(
//Send encoded username and password
if (
//Format from https://tools.ietf.org/html/rfc4616#section-2
//We skip the first field (it's forgery), so the string starts with a null byte
!$this->sendCommand(
'User & Password',
base64_encode("\0" . $username . "\0" . $password),
235
@ -521,7 +566,7 @@ class SMTP
}
break;
case 'LOGIN':
// Start authentication
//Start authentication
if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
return false;
}
@ -533,17 +578,17 @@ class SMTP
}
break;
case 'CRAM-MD5':
// Start authentication
//Start authentication
if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
return false;
}
// Get the challenge
//Get the challenge
$challenge = base64_decode(substr($this->last_reply, 4));
// Build the response
//Build the response
$response = $username . ' ' . $this->hmac($challenge, $password);
// send encoded credentials
//send encoded credentials
return $this->sendCommand('Username', base64_encode($response), 235);
case 'XOAUTH2':
//The OAuth instance must be set up prior to requesting auth.
@ -552,7 +597,7 @@ class SMTP
}
$oauth = $OAuth->getOauth64();
// Start authentication
//Start authentication
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
return false;
}
@ -582,15 +627,15 @@ class SMTP
return hash_hmac('md5', $data, $key);
}
// The following borrowed from
// http://php.net/manual/en/function.mhash.php#27225
//The following borrowed from
//http://php.net/manual/en/function.mhash.php#27225
// RFC 2104 HMAC implementation for php.
// Creates an md5 HMAC.
// Eliminates the need to install mhash to compute a HMAC
// by Lance Rushing
//RFC 2104 HMAC implementation for php.
//Creates an md5 HMAC.
//Eliminates the need to install mhash to compute a HMAC
//by Lance Rushing
$bytelen = 64; // byte length for md5
$bytelen = 64; //byte length for md5
if (strlen($key) > $bytelen) {
$key = pack('H*', md5($key));
}
@ -613,7 +658,7 @@ class SMTP
if (is_resource($this->smtp_conn)) {
$sock_status = stream_get_meta_data($this->smtp_conn);
if ($sock_status['eof']) {
// The socket is valid but we are not connected
//The socket is valid but we are not connected
$this->edebug(
'SMTP NOTICE: EOF caught while checking if connected',
self::DEBUG_CLIENT
@ -623,7 +668,7 @@ class SMTP
return false;
}
return true; // everything looks good
return true; //everything looks good
}
return false;
@ -641,7 +686,7 @@ class SMTP
$this->server_caps = null;
$this->helo_rply = null;
if (is_resource($this->smtp_conn)) {
// close the connection and cleanup
//Close the connection and cleanup
fclose($this->smtp_conn);
$this->smtp_conn = null; //Makes for cleaner serialization
$this->edebug('Connection: closed', self::DEBUG_CONNECTION);
@ -651,7 +696,7 @@ class SMTP
/**
* Send an SMTP DATA command.
* Issues a data command and sends the msg_data to the server,
* finializing the mail transaction. $msg_data is the message
* finalizing the mail transaction. $msg_data is the message
* that is to be send with the headers. Each header needs to be
* on a single line followed by a <CRLF> with the message headers
* and the message body being separated by an additional <CRLF>.
@ -676,7 +721,7 @@ class SMTP
* NOTE: this does not count towards line-length limit.
*/
// Normalize line breaks before exploding
//Normalize line breaks before exploding
$lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data));
/* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
@ -722,7 +767,8 @@ class SMTP
//Send the lines to the server
foreach ($lines_out as $line_out) {
//RFC2821 section 4.5.2
//Dot-stuffing as per RFC5321 section 4.5.2
//https://tools.ietf.org/html/rfc5321#section-4.5.2
if (!empty($line_out) && $line_out[0] === '.') {
$line_out = '.' . $line_out;
}
@ -756,7 +802,16 @@ class SMTP
public function hello($host = '')
{
//Try extended hello first (RFC 2821)
return $this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host);
if ($this->sendHello('EHLO', $host)) {
return true;
}
//Some servers shut down the SMTP service here (RFC 5321)
if (substr($this->helo_rply, 0, 3) == '421') {
return false;
}
return $this->sendHello('HELO', $host);
}
/**
@ -946,12 +1001,12 @@ class SMTP
$this->client_send($commandstring . static::LE, $command);
$this->last_reply = $this->get_lines();
// Fetch SMTP code and possible error code explanation
//Fetch SMTP code and possible error code explanation
$matches = [];
if (preg_match('/^([\d]{3})[ -](?:([\d]\\.[\d]\\.[\d]{1,2}) )?/', $this->last_reply, $matches)) {
$code = (int) $matches[1];
$code_ex = (count($matches) > 2 ? $matches[2] : null);
// Cut off error code from each response line
//Cut off error code from each response line
$detail = preg_replace(
"/{$code}[ -]" .
($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . '/m',
@ -959,7 +1014,7 @@ class SMTP
$this->last_reply
);
} else {
// Fall back to simple parsing if regex fails
//Fall back to simple parsing if regex fails
$code = (int) substr($this->last_reply, 0, 3);
$code_ex = null;
$detail = substr($this->last_reply, 4);
@ -1058,8 +1113,10 @@ class SMTP
{
//If SMTP transcripts are left enabled, or debug output is posted online
//it can leak credentials, so hide credentials in all but lowest level
if (self::DEBUG_LOWLEVEL > $this->do_debug &&
in_array($command, ['User & Password', 'Username', 'Password'], true)) {
if (
self::DEBUG_LOWLEVEL > $this->do_debug &&
in_array($command, ['User & Password', 'Username', 'Password'], true)
) {
$this->edebug('CLIENT -> SERVER: [credentials hidden]', self::DEBUG_CLIENT);
} else {
$this->edebug('CLIENT -> SERVER: ' . $data, self::DEBUG_CLIENT);
@ -1113,7 +1170,7 @@ class SMTP
if (!$this->server_caps) {
$this->setError('No HELO/EHLO was sent');
return;
return null;
}
if (!array_key_exists($name, $this->server_caps)) {
@ -1125,7 +1182,7 @@ class SMTP
}
$this->setError('HELO handshake was used; No information about server extensions available');
return;
return null;
}
return $this->server_caps[$name];
@ -1152,7 +1209,7 @@ class SMTP
*/
protected function get_lines()
{
// If the connection is bad, give up straight away
//If the connection is bad, give up straight away
if (!is_resource($this->smtp_conn)) {
return '';
}
@ -1166,24 +1223,52 @@ class SMTP
$selW = null;
while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
//Must pass vars in here as params are by reference
if (!stream_select($selR, $selW, $selW, $this->Timelimit)) {
//solution for signals inspired by https://github.com/symfony/symfony/pull/6540
set_error_handler([$this, 'errorHandler']);
$n = stream_select($selR, $selW, $selW, $this->Timelimit);
restore_error_handler();
if ($n === false) {
$message = $this->getError()['detail'];
$this->edebug(
'SMTP -> get_lines(): select failed (' . $message . ')',
self::DEBUG_LOWLEVEL
);
//stream_select returns false when the `select` system call is interrupted
//by an incoming signal, try the select again
if (stripos($message, 'interrupted system call') !== false) {
$this->edebug(
'SMTP -> get_lines(): retrying stream_select',
self::DEBUG_LOWLEVEL
);
$this->setError('');
continue;
}
break;
}
if (!$n) {
$this->edebug(
'SMTP -> get_lines(): select timed-out in (' . $this->Timelimit . ' sec)',
self::DEBUG_LOWLEVEL
);
break;
}
//Deliberate noise suppression - errors are handled afterwards
$str = @fgets($this->smtp_conn, self::MAX_REPLY_LENGTH);
$this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL);
$data .= $str;
// If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
// or 4th character is a space or a line break char, we are done reading, break the loop.
// String array access is a significant micro-optimisation over strlen
//If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
//or 4th character is a space or a line break char, we are done reading, break the loop.
//String array access is a significant micro-optimisation over strlen
if (!isset($str[3]) || $str[3] === ' ' || $str[3] === "\r" || $str[3] === "\n") {
break;
}
// Timed-out? Log and break
//Timed-out? Log and break
$info = stream_get_meta_data($this->smtp_conn);
if ($info['timed_out']) {
$this->edebug(
@ -1192,7 +1277,7 @@ class SMTP
);
break;
}
// Now check if reads took too long
//Now check if reads took too long
if ($endtime && time() > $endtime) {
$this->edebug(
'SMTP -> get_lines(): timelimit reached (' .

View File

@ -0,0 +1,38 @@
<?php
/**
* French PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* Some French punctuation requires a thin non-breaking space (U+202F) character before it,
* for example before a colon or exclamation mark.
* There is one of these characters between these quotes: ""
* @see http://unicode.org/udhr/n/notes_fra.html
*/
$PHPMAILER_LANG['authenticate'] = 'Erreur SMTP: échec de lauthentification.';
$PHPMAILER_LANG['buggy_php'] = 'Votre version de PHP est affectée par un bug qui peut entraîner des messages corrompus. Pour résoudre ce problème, passez à lenvoi par SMTP, désactivez loption mail.add_x_header dans le fichier php.ini, passez à MacOS ou Linux, ou passez PHP à la version 7.0.17+ ou 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Erreur SMTP: impossible de se connecter au serveur SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Erreur SMTP: données incorrectes.';
$PHPMAILER_LANG['empty_message'] = 'Corps du message vide.';
$PHPMAILER_LANG['encoding'] = 'Encodage inconnu: ';
$PHPMAILER_LANG['execute'] = 'Impossible de lancer lexécution: ';
$PHPMAILER_LANG['extension_missing'] = 'Extension manquante: ';
$PHPMAILER_LANG['file_access'] = 'Impossible daccéder au fichier: ';
$PHPMAILER_LANG['file_open'] = 'Ouverture du fichier impossible: ';
$PHPMAILER_LANG['from_failed'] = 'Ladresse dexpéditeur suivante a échoué: ';
$PHPMAILER_LANG['instantiate'] = 'Impossible dinstancier la fonction mail.';
$PHPMAILER_LANG['invalid_address'] = 'Adresse courriel non valide: ';
$PHPMAILER_LANG['invalid_header'] = 'Nom ou valeur de len-tête non valide';
$PHPMAILER_LANG['invalid_hostentry'] = 'Entrée dhôte non valide: ';
$PHPMAILER_LANG['invalid_host'] = 'Hôte non valide: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' client de messagerie non supporté.';
$PHPMAILER_LANG['provide_address'] = 'Vous devez fournir au moins une adresse de destinataire.';
$PHPMAILER_LANG['recipients_failed'] = 'Erreur SMTP:les destinataires suivants ont échoué: ';
$PHPMAILER_LANG['signing'] = 'Erreur de signature: ';
$PHPMAILER_LANG['smtp_code'] = 'Code SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Informations supplémentaires SMTP: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'La fonction SMTP connect() a échouée.';
$PHPMAILER_LANG['smtp_detail'] = 'Détails: ';
$PHPMAILER_LANG['smtp_error'] = 'Erreur du serveur SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Impossible dinitialiser ou de réinitialiser une variable: ';
$PHPMAILER_LANG['extension_missing'] = 'Extension manquante: ';

View File

@ -612,19 +612,17 @@ class template {
'label' => '',
'name' => $nameId,
'selected' => '',
'fonts' => false
'fonts' => []
], $attributes);
// Stocker les fontes et remettre à zéro le tableau des fontes transmis pour éviter une erreur de sprintAttributes
if (empty($attributes['fonts']) === false) {
$fonts = $attributes['fonts'];
$attributes['fonts'] = [];
}
// Sauvegarde des données en cas d'erreur
if($attributes['before'] AND array_key_exists($attributes['id'], common::$inputBefore)) {
$attributes['selected'] = common::$inputBefore[$attributes['id']];
}
// Liste des polices à intégrer
//var_dump(core::$fonts);
if ($attributes['fonts'] === true) {
foreach (core::$fonts as $fontId => $font) {
echo "<link href='https://fonts.cdnfonts.com/css/" . $fontId . "' rel='stylesheet' type='text/css'>\n";
}
}
// Début du wrapper
$html = '<div id="' . $attributes['id'] . 'Wrapper" class="inputWrapper ' . $attributes['classWrapper'] . '">';
// Label
@ -645,12 +643,14 @@ class template {
helper::sprintAttributes($attributes)
);
foreach($options as $value => $text) {
$html .= $attributes['fonts'] === true ? sprintf(
// Select des liste de fontes
$html .= isset($fonts) ? sprintf(
'<option value="%s"%s style="font-family: %s;">%s</option>',
$value,
$attributes['selected'] == $value ? ' selected' : '', // Double == pour ignorer le type de variable car $_POST change les types en string
core::$fonts[$value],
$fonts[$value],
$text
// Select standard
) : sprintf(
'<option value="%s"%s>%s</option>',
$value,

View File

@ -215,8 +215,7 @@ core.start = function() {
// Variables des cookies
var getUrl = window.location;
var domain = "domain=" + getUrl.host + ";";
var path = "path=" + getUrl.pathname.split('/')[1] + ";";
//var path = "path=" + getUrl.pathname.split('/')[1] + ";";
var e = new Date();
e.setFullYear(e.getFullYear() + 1);
var expires = "expires=" + e.toUTCString();
@ -229,14 +228,14 @@ core.start = function() {
if ($("#googleAnalytics").is(":checked")) {
// L'URL du serveur faut TRUE
document.cookie = "ZWII_COOKIE_GA_CONSENT=true;samesite=strict;" + domain + path + expires;
document.cookie = "ZWII_COOKIE_GA_CONSENT=true;samesite=strict;" + domain + expires;
} else {
document.cookie = "ZWII_COOKIE_GA_CONSENT=false;samesite=strict;" + domain + path + expires;
document.cookie = "ZWII_COOKIE_GA_CONSENT=false;samesite=strict;" + domain + expires;
}
}
// Stocke le cookie d'acceptation
document.cookie = "ZWII_COOKIE_CONSENT=true;samesite=strict;" + domain + path + expires;
document.cookie = "ZWII_COOKIE_CONSENT=true;samesite=strict;" + domain + expires;
});

View File

@ -45,7 +45,7 @@ class common {
// Numéro de version
const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/update/raw/branch/master/';
const ZWII_VERSION = '11.3.07';
const ZWII_VERSION = '11.4.00';
const ZWII_UPDATE_CHANNEL = "v11";
public static $actions = [];
@ -65,8 +65,8 @@ class common {
'theme',
'config',
'edit',
'config',
'translate'
'translate',
'addon'
];
public static $accessExclude = [
'login',
@ -183,39 +183,80 @@ class common {
];
// Fontes
public static $fonts = [
'abril-fatface' => 'Abril Fatface',
'arimo' => 'Arimo',
'arvo' => 'Arvo',
'berkshire-swash' => 'Berkshire Swash',
'dancing-script' => 'Dancing Script',
'droid-sans-2' => 'Droid Sans',
'droid-serif-2' => 'Droid Serif',
'fira-sans' => 'Fira Sans',
'genera' => 'Genera',
'inconsolata-2' => 'Inconsolata',
'indie-flower' => 'Indie Flower',
'josefin-sans-std' => 'Josefin Sans',
'liberation-sans' => 'Liberation Sans',
'liberation-serif' => 'Liberation Serif',
'lobster-2' => 'Lobster',
'lora' => 'Lora',
'lato' => 'Lato',
'montserrat-ace' => 'Montserrat Ace',
'old-standard-tt-3' => 'Old Standard TT',
'open-sans' => 'Open Sans',
'oswald-4' => 'Oswald',
'pt-mono' => 'PT Mono',
'pt-serif' => 'PT Serif',
'raleway-5' => 'Raleway',
'rancho' => 'Rancho',
'roboto' => 'Roboto',
'signika' => 'Signika',
'ubuntu' => 'Ubuntu',
'vollkorn' => 'Vollkorn'
public static $fontsWebSafe = [
'arial' => [
'name' => 'Arial',
'font-family' => 'Arial, Helvetica, sans-serif',
'resource' => 'websafe'
],
'arvo'=> [
'name' => 'Arvo',
'font-family' => 'Arvo, sans-serif',
'resource' => 'websafe'
],
'courrier-new' => [
'name' => 'Courier New',
'font-family' => '\'Courier New\', Courier, monospace',
'resource' => 'websafe'
],
'garamond' => [
'name' => 'Garamond',
'font-family' => 'Garamond, serif',
'resource' => 'websafe'
],
'georgia' => [
'name' => 'Geogia',
'font-family' => 'Georgia, serif',
'resource' => 'websafe'
],
'impact' => [
'name' => 'Impact',
'font-family' => 'Impact, Charcoal, sans-serif',
'resource' => 'websafe'
],
'lora'=> [
'name' => 'Lora',
'font-family' => 'Lora, serif',
'resource' => 'websafe'
],
'lucida' => [
'name' => 'Lucida',
'font-family' => '\'Lucida Sans Unicode\', \'Lucida Grande\', sans-serif',
'resource' => 'websafe'
],
'roboto'=> [
'name' => 'Roboto',
'font-family' => 'Roboto, sans-serif',
'resource' => 'websafe'
],
'tahoma' => [
'name' => 'Tahoma',
'font-family' => 'Tahoma, Geneva, sans-serif',
'resource' => 'websafe'
],
'times-new-roman' => [
'name' => 'Times New Roman',
'font-family' => '\'Times New Roman\', \'Liberation Serif\', serif',
'resource' => 'websafe'
],
'trebuchet' => [
'name' => 'Trebuchet',
'font-family' => '\'Trebuchet MS\', Arial, Helvetica, sans-serif',
'resource' => 'websafe'
],
'tahoma' => [
'name' => 'Tahoma',
'font-family' => 'Tahoma, Geneva, sans-serif',
'resource' => 'websafe'
],
'verdana' => [
'name' => 'Verdana',
'font-family' => 'Verdana, Geneva, sans-serif;',
'resource' => 'websafe'
]
];
/**
* Constructeur commun
*/
@ -250,7 +291,6 @@ class common {
]);;
}
// Import version 9
if (file_exists(self::DATA_DIR . 'core.json') === true &&
$this->getData(['core','dataVersion']) < 10000) {
@ -267,7 +307,9 @@ class common {
// La langue d'installation par défaut est fr
foreach ($this->dataFiles as $stageId => $item) {
$folder = $this->dataPath ($stageId, self::$i18n);
if (file_exists($folder . $stageId .'.json') === false) {
if ( file_exists($folder . $stageId .'.json') === false ||
$this->getData([$stageId]) === NULL
) {
$this->initData($stageId, self::$i18n);
common::$coreNotices [] = $stageId ;
}
@ -517,7 +559,6 @@ class common {
if (
$this->getData(['page', $page, 'content']) !== ''
&& file_exists(self::DATA_DIR . $lang . '/content/' . $this->getData(['page', $page, 'content']))
&& is_file(self::DATA_DIR . $lang . '/content/' . $this->getData(['page', $page, 'content']))
) {
return file_get_contents(self::DATA_DIR . $lang . '/content/' . $this->getData(['page', $page, 'content']));
} else {
@ -825,10 +866,9 @@ class common {
/**
* Génère un fichier json avec la liste des pages
*
* Génère la liste des pages pour le plugin Link de TinyMCE
*/
public function pages2Json() {
public function listPages() {
// Sauve la liste des pages pour TinyMCE
$parents = [];
$rewrite = (helper::checkRewrite()) ? '' : '?';
@ -914,8 +954,6 @@ class common {
public function createSitemap($command = "all") {
//require_once "core/vendor/sitemap/SitemapGenerator.php";
$timezone = $this->getData(['config','timezone']);
$outputDir = getcwd();
$sitemap = new \Icamys\SitemapGenerator\SitemapGenerator(helper::baseurl(false),$outputDir);
@ -1080,6 +1118,7 @@ class common {
$layout = ob_get_clean();
$mail = new PHPMailer\PHPMailer\PHPMailer;
$mail->CharSet = 'UTF-8';
$mail->setLanguage('fr', 'core/class/phpmailer/phpmailer.lang-fr.php');
// Mail
try{
// Paramètres SMTP
@ -1129,10 +1168,10 @@ class common {
else {
return $mail->ErrorInfo;
}
} catch (phpmailerException $e) {
return $e->errorMessage();
} catch (Exception $e) {
return $e->getMessage();
echo $e->errorMessage();
} catch (\Exception $e) {
echo $e->getMessage();
}
}
@ -1254,7 +1293,7 @@ class common {
$item .= '<h3>'. $this->getData(['locale', 'cookies', 'titleLabel']) . '</h3>';
$item .= '<p>' . $this->getData(['locale', 'cookies', 'mainLabel']) . '</p>';
// Formulaire de réponse
$item .= '<form method="POST" action="" id="cookieForm">';
$item .= '<form method="POST" action="' . helper::baseUrl(false, true) . '" id="cookieForm">';
$analytics = $this->getData(['config', 'seo', 'analyticsId']);
$stateCookieGA = $this->getInput('ZWII_COOKIE_GA_CONSENT') === 'true' ? 'checked="checked"' : '';
if( $analytics !== null AND $analytics !== '' ) {
@ -1342,9 +1381,6 @@ class common {
*/
echo '<div class="'. $content . '" id="contentSite">';
$this->showContent();
if (file_exists(self::DATA_DIR . 'body.inc.html')) {
include(self::DATA_DIR . 'body.inc.html');
}
echo '</div>';
/**
* Barre droite
@ -1646,7 +1682,7 @@ class common {
) {
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.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>';
echo '<script src="' . helper::baseUrl(false) . 'core/vendor/favicon-switcher/favicon-switcher.js" crossorigin="anonymous"></script>';
}
}
@ -2121,14 +2157,18 @@ class common {
// Import des styles liés à la page
if($this->output['style']) {
echo '<base href="' . helper::baseUrl(true) .'">';
// Import de la feuille de style des pages admin
if (strpos($this->output['style'], 'admin.css') >= 1 ) {
echo '<link rel="stylesheet" href="' . self::DATA_DIR . 'admin.css?' . md5_file(self::DATA_DIR .'admin.css') . '">';
}
echo '<style type="text/css">' . helper::minifyCss($this->output['style']) . '</style>';
}
// Import des fontes liées au thème
if (file_exists(self::DATA_DIR.'fonts/fonts.html')) {
include_once(self::DATA_DIR.'fonts/fonts.html');
// Import des fontes
if ( file_exists(self::DATA_DIR . 'fonts/fonts.html') ){
include_once(self::DATA_DIR . 'fonts/fonts.html');
}
if ( file_exists(self::DATA_DIR . 'fonts/fonts.css') ){
echo '<link rel="stylesheet" href="' . helper::baseUrl(false) . self::DATA_DIR . 'fonts/fonts.css?' . md5_file(self::DATA_DIR .'fonts/fonts.css') . '">';
}
}
@ -2214,7 +2254,7 @@ class common {
}
echo '<li>';
echo '<a href="' . helper::baseUrl() . 'translate/i18n/' . $key . '/' . $this->getData(['config', 'i18n',$key]) . '/' . $this->getUrl(0) . '"><img ' . $select . ' class="flag" alt="' . $value . '" src="' . helper::baseUrl(false) . 'core/vendor/i18n/png/' . $key . '.png"/></a>';
echo '<a href="' . helper::baseUrl() . 'translate/i18n/' . $key . '/' . $this->getData(['config', 'i18n',$key]) . '/' . $this->getUrl(0) . '"><img ' . $select . ' alt="' . $value . '" src="' . helper::baseUrl(false) . 'core/vendor/i18n/png/' . $key . '.png"/></a>';
echo '</li>';
}
}
@ -2277,17 +2317,6 @@ class core extends common {
}
}
// Importe les polices personnalisées
$fontsImported = $this->getData(['fonts', 'imported']);
if (is_array($fontsImported) &&
!empty ($fontsImported)
) {
// Fusionner les fonts avec les fontes installées
self::$fonts = array_merge(self::$fonts, $fontsImported);
// Tri Alphabétique
asort(self::$fonts);
}
// Crée le fichier de personnalisation avancée
if(file_exists(self::DATA_DIR.'custom.css') === false) {
file_put_contents(self::DATA_DIR.'custom.css', file_get_contents('core/module/theme/resource/custom.css'));
@ -2303,6 +2332,7 @@ class core extends common {
file_put_contents(self::DATA_DIR.'admin.css', '');
chmod(self::DATA_DIR.'admin.css', 0755);
}
// Check la version rafraichissement du theme
$cssVersion = preg_split('/\*+/', file_get_contents(self::DATA_DIR.'theme.css'));
if(empty($cssVersion[1]) OR $cssVersion[1] !== md5(json_encode($this->getData(['theme'])))) {
@ -2311,55 +2341,24 @@ class core extends common {
/**
* Import des polices de caractères
* A partir du CDN ou dans le dossier site/file/source/fonts
*/
$fonts = [ $this->getData(['theme', 'text', 'font']),
$this->getData(['theme', 'title', 'font']),
$this->getData(['theme', 'header', 'font']),
$this->getData(['theme', 'menu', 'font']),
$this->getData(['theme', 'footer', 'font'])
];
// Suppression des polices identiques
$fonts = array_unique($fonts);
// Lire le fichier des fontes locales
$localFonts = $this->getData(['fonts', 'files']);
/**
* Chargement des polices en ligne dans un fichier séparé
*/
$fontFile = '';
foreach ($fonts as $fontId) {
if (!array_key_exists($fontId, $localFonts) ) {
$fontFile .= '<link href="https://fonts.cdnfonts.com/css/' . $fontId .'" rel="stylesheet">';
// Supprimer l'élément des fontes chargées en ligne
unset($fonts[$fontId]);
$f ['files'] = $this->getData(['fonts', 'files']);
$f ['imported'] = $this->getData(['fonts', 'imported']);
$f ['websafe'] = self::$fontsWebSafe;
// Construit un tableau avec leur ID et leur famille
foreach(['websafe', 'imported', 'files'] as $type) {
if (is_array($f[$type])) {
foreach ($f[$type] as $fontId => $fontValue ) {
$fonts[$fontId] = $fontValue['font-family'];
}
}
/**
* Fontes installées localement
*/
if ( !empty($localFonts)
) {
foreach ($localFonts as $fontId => $fontName) {
// Validité du tableau :
if ( array_key_exists($fontId, self::$fonts) ||
file_exists(self::DATA_DIR . 'fonts/' . $fontName) ) {
// Chargement de la police
$css .= '@font-face {font-family:"' . self::$fonts[$fontId] . '";';
$css .= 'src: url("' . helper::baseUrl(false) . self::DATA_DIR . 'fonts/' . $fontName . '");}';
} else {
// Le fichier de font n'est pas disponible, fonte par défaut
$fonts [$fontId] = 'verdana';
}
}
}
// Fond du body
$colors = helper::colorVariants($this->getData(['theme', 'body', 'backgroundColor']));
// Body
$css .= 'body{font-family:"' . self::$fonts[$this->getData(['theme', 'text', 'font'])] . '",sans-serif}';
$css .= 'body{font-family:' . $fonts[$this->getData(['theme', 'text', 'font'])] . ';}';
if($themeBodyImage = $this->getData(['theme', 'body', 'image'])) {
// Image dans html pour éviter les déformations.
$css .= 'html {background-image:url("../file/source/' . $themeBodyImage . '");background-position:' . $this->getData(['theme', 'body', 'imagePosition']) . ';background-attachment:' . $this->getData(['theme', 'body', 'imageAttachment']) . ';background-size:' . $this->getData(['theme', 'body', 'imageSize']) . ';background-repeat:' . $this->getData(['theme', 'body', 'imageRepeat']) . '}';
@ -2377,7 +2376,7 @@ class core extends common {
$colors = helper::colorVariants($this->getData(['theme', 'text', 'linkColor']));
$css .= 'a{color:' . $colors['normal'] . '}';
// Couleurs de site dans TinyMCe
$css .= 'div.mce-edit-area {font-family:"' . self::$fonts[$this->getData(['theme', 'text', 'font'])] . '",sans-serif}';
$css .= 'div.mce-edit-area {font-family:' . $fonts[$this->getData(['theme', 'text', 'font'])] . ';}';
// Site dans TinyMCE
$css .= '.editorWysiwyg {background-color:' . $this->getData(['theme', 'site', 'backgroundColor']) . ';}';
$css .= 'span.mce-text{background-color: unset !important;}';
@ -2418,7 +2417,7 @@ class core extends common {
$css .= '.helpButton span:hover{color:' . $colors['darken'] . '}';
$css .= '.button:active,button[type=\'submit\']:active,.pagination a:active{background-color:' . $colors['veryDarken'] . '}';
$colors = helper::colorVariants($this->getData(['theme', 'title', 'textColor']));
$css .= 'h1,h2,h3,h4,h5,h6,h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:' . $colors['normal'] . ';font-family:"' . self::$fonts[$this->getData(['theme', 'title', 'font'])] . '",sans-serif;font-weight:' . $this->getData(['theme', 'title', 'fontWeight']) . ';text-transform:' . $this->getData(['theme', 'title', 'textTransform']) . '}';
$css .= 'h1,h2,h3,h4,h5,h6,h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:' . $colors['normal'] . ';font-family:' . $fonts[$this->getData(['theme', 'title', 'font'])] . ';font-weight:' . $this->getData(['theme', 'title', 'fontWeight']) . ';text-transform:' . $this->getData(['theme', 'title', 'textTransform']) . '}';
$css .= 'h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover{color:' . $colors['darken'] . '}';
// Les blocs
$colors = helper::colorVariants($this->getData(['theme', 'block', 'backgroundColor']));
@ -2452,7 +2451,7 @@ class core extends common {
$css .= 'header{background-image:url("../file/source/' . $themeHeaderImage . '");background-position:' . $this->getData(['theme', 'header', 'imagePosition']) . ';background-repeat:' . $this->getData(['theme', 'header', 'imageRepeat']) . '}';
}
$colors = helper::colorVariants($this->getData(['theme', 'header', 'textColor']));
$css .= 'header span{color:' . $colors['normal'] . ';font-family:"' . self::$fonts[$this->getData(['theme', 'header', 'font'])] . '",sans-serif;font-weight:' . $this->getData(['theme', 'header', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'header', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'header', 'textTransform']) . '}';
$css .= 'header span{color:' . $colors['normal'] . ';font-family:' . $fonts[$this->getData(['theme', 'header', 'font'])] . ';font-weight:' . $this->getData(['theme', 'header', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'header', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'header', 'textTransform']) . '}';
}
// Bannière au contenu personnalisé
@ -2501,7 +2500,7 @@ class core extends common {
$css .= 'nav{padding:0 10px;}';
}
$css .= '#toggle span,#menu a{padding:' . $this->getData(['theme', 'menu', 'height']) .';font-family:"' . self::$fonts[$this->getData(['theme', 'menu', 'font'])] . '",sans-serif;font-weight:' . $this->getData(['theme', 'menu', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'menu', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'menu', 'textTransform']) . '}';
$css .= '#toggle span,#menu a{padding:' . $this->getData(['theme', 'menu', 'height']) .';font-family:' . $fonts[$this->getData(['theme', 'menu', 'font'])] . ';font-weight:' . $this->getData(['theme', 'menu', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'menu', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'menu', 'textTransform']) . '}';
// Pied de page
$colors = helper::colorVariants($this->getData(['theme', 'footer', 'backgroundColor']));
@ -2511,7 +2510,7 @@ class core extends common {
$css .= 'footer{padding:0}';
}
$css .= 'footer span, #footerText > p {color:' . $this->getData(['theme', 'footer', 'textColor']) . ';font-family:"' . self::$fonts[$this->getData(['theme', 'footer', 'font'])] . '",sans-serif;font-weight:' . $this->getData(['theme', 'footer', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'footer', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'footer', 'textTransform']) . '}';
$css .= 'footer span, #footerText > p {color:' . $this->getData(['theme', 'footer', 'textColor']) . ';font-family:' . $fonts[$this->getData(['theme', 'footer', 'font'])] . ';font-weight:' . $this->getData(['theme', 'footer', 'fontWeight']) . ';font-size:' . $this->getData(['theme', 'footer', 'fontSize']) . ';text-transform:' . $this->getData(['theme', 'footer', 'textTransform']) . '}';
$css .= 'footer {background-color:' . $colors['normal'] . ';color:' . $this->getData(['theme', 'footer', 'textColor']) . '}';
$css .= 'footer a{color:' . $this->getData(['theme', 'footer', 'textColor']) . '}';
$css .= 'footer #footersite > div {margin:' . $this->getData(['theme', 'footer', 'height']) . ' 0}';
@ -2522,12 +2521,6 @@ class core extends common {
$css .= '#footerText > p {text-align:' . $this->getData(['theme', 'footer', 'textAlign']) . '}';
$css .= '#footerCopyright{text-align:' . $this->getData(['theme', 'footer', 'copyrightAlign']) . '}';
// Enregistre les fontes
if (!is_dir(self::DATA_DIR . 'fonts')) {
mkdir(self::DATA_DIR . 'fonts');
}
file_put_contents(self::DATA_DIR . 'fonts/fonts.html', $fontFile);
// Enregistre la personnalisation
file_put_contents(self::DATA_DIR.'theme.css', $css);
@ -2548,52 +2541,25 @@ class core extends common {
/**
* Import des polices de caractères
* A partir du CDN ou dans le dossier site/file/source/fonts
*/
$fonts = [ $this->getData(['admin', 'fontText']),
$this->getData(['admin', 'fontTitle']),
];
// Suppression des polices identiques
$fonts = array_unique($fonts);
// Lire le fichier des fontes locales
$localFonts = $this->getData(['fonts', 'files']);
/**
* Chargement des polices en ligne
*/
foreach ($fonts as $fontId) {
if (!array_key_exists($fontId, $localFonts) ) {
$css .= '@import url("https://fonts.cdnfonts.com/css/' . $fontId . '");';
// Supprimer l'élément des fontes chargées en ligne
unset($fonts[$fontId]);
$f ['files'] = $this->getData(['fonts', 'files']);
$f ['imported'] = $this->getData(['fonts', 'imported']);
$f ['websafe'] = self::$fontsWebSafe;
// Construit un tableau avec leur ID et leur famille
foreach(['websafe', 'imported', 'files'] as $type) {
if (is_array($f[$type])) {
foreach ($f[$type] as $fontId => $fontValue ) {
$fonts[$fontId] = $fontValue['font-family'];
}
}
/**
* Fontes installées localement
*/
if ( !empty($localFonts)
) {
foreach ($localFonts as $fontId => $fontName) {
// Validité du tableau :
if ( array_key_exists($fontId, self::$fonts) ||
file_exists(self::DATA_DIR . 'fonts/' . $fontName) ) {
// Chargement de la police
$css .= '@font-face {font-family:"' . self::$fonts[$fontId] . '";';
$css .= 'src: url("' . helper::baseUrl(false) . self::DATA_DIR . 'fonts/' . $fontName . '");}';
} else {
// Le fichier de font n'est pas disponible, fonte par défaut
$fonts [$fontId] = 'verdana';
}
}
}
// Thème Administration
$colors = helper::colorVariants($this->getData(['admin','backgroundColor']));
$css .= '#site{background-color:' . $colors['normal']. ';}';
$css .= '.row > div {font:' . $this->getData(['admin','fontSize']) . ' "' . self::$fonts[$this->getData(['admin','fontText'])] . '", sans-serif;}';
$css .= 'body h1, h2, h3, h4 a, h5, h6 {font-family:"' . self::$fonts[$this->getData(['admin','fontTitle'])] . '", sans-serif;color:' . $this->getData(['admin','colorTitle' ]) . ';}';
$css .= '.row > div {font:' . $fonts[$this->getData(['admin','fontText'])] . ';font-size:' . $this->getData(['admin','fontSize']) .'}';
$css .= 'body h1, h2, h3, h4 a, h5, h6 {font-family:' . $fonts[$this->getData(['admin','fontTitle'])] . ';color:' . $this->getData(['admin','colorTitle' ]) . ';}';
// TinyMCE
$css .= 'body:not(.editorWysiwyg),span .zwiico-help {color:' . $this->getData(['admin','colorText']) . ';}';
@ -3032,6 +2998,13 @@ 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 {
// Redirige vers la page de connexion si page de gestion demandée
if ( $this->getData(['config', 'connect', 'redirectLogin']) === true
&& in_array($this->geturl(0), self::$accessList) ) {
http_response_code(302);
header('Location:' . helper::baseUrl() . 'user/login/');
exit();
} else {
if ( $this->getData(['locale','page403']) !== 'none'
AND $this->getData(['page',$this->getData(['locale','page403'])]))
@ -3044,6 +3017,7 @@ class core extends common {
]);
}
}
}
} elseif ($this->output['content'] === '') {
http_response_code(404);
if ( $this->getData(['locale','page404']) !== 'none'

View File

@ -481,7 +481,7 @@ if ($this->getData(['core', 'dataVersion']) < 10400) {
foreach ($pageList as $parentKey => $parent) {
//La page est un blog
if ($this->getData(['page',$parent,'moduleId']) === 'blog' ) {
$articleIds = array_keys(helper::arrayCollumn($this->getData(['module', $parent, 'posts']), 'publishedOn', 'SORT_DESC'));
$articleIds = array_keys(helper::arrayColumn($this->getData(['module', $parent, 'posts']), 'publishedOn', 'SORT_DESC'));
foreach ($articleIds as $key => $article) {
// Droits les deux groupes
$this->setData(['module', $parent, 'posts', $article,'editConsent', 3]);
@ -809,7 +809,8 @@ if ($this->getData(['core', 'dataVersion']) < 11303) {
$this->setData(['core', 'dataVersion', 11303]);
}
// Version 11.3.06
// Version 11.3.06
if ($this->getData(['core', 'dataVersion']) < 11306) {
// Supprime les fontes déclarées en double par la version précédentes
@ -822,3 +823,162 @@ if ($this->getData(['core', 'dataVersion']) < 11306) {
// Mise à jour
$this->setData(['core', 'dataVersion', 11306]);
}
// Version 11.4.00
if ($this->getData(['core', 'dataVersion']) < 11400) {
$fonts = [
'arimo'=> [
'name' => 'Arimo',
'font-family' => 'Arimo, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/arimo'
],
'dancing-script' => [
'name' => 'Dancing Script',
'font-family' => '\'Dancing Script\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/dancing-script'
],
'droid-sans-2'=> [
'name' => 'Droid Sans',
'font-family' => '\'Droid Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/droid-sans-2'
],
'droid-serif-2'=> [
'name' => 'Droid Serif',
'font-family' => '\'Droid Serif\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/droid-serif-2'
],
'indie-flower'=> [
'name' => 'Indie Flower',
'font-family' => '\'Indie Flower\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/indie-flower'
],
'fira-sans' => [
'name' => 'Fira Sans',
'font-family' => '\'Fira Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/fira-sans'
],
'liberation-sans'=> [
'name' => 'Liberation Sans',
'font-family' => '\'Liberation Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/liberation-sans'
],
'liberation-serif'=> [
'name' => 'Liberation Serif',
'font-family' => '\'Liberation Serif\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/liberation-serif'
],
'lobster-2'=> [
'name' => 'Lobster',
'font-family' => 'Lobster, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/lobster-2'
],
'lato'=> [
'name' => 'lato',
'font-family' => 'Lato, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/lato'
],
'old-standard-tt-3'=> [
'name' => 'Old Standard TT',
'font-family' => '\'Old Standard TT\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/old-standard-tt-3'
],
'open-sans' => [
'name' => 'Open Sans',
'font-family' => '\'Open Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/open-sans'
],
'oswald-4'=> [
'name' => 'Oswald',
'font-family' => 'Oswald, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/oswald-4'
],
'pt-mono'=> [
'name' => 'PT Mono',
'font-family' => '\'PT Mono\', monospace',
'resource' => 'https://fonts.cdnfonts.com/css/pt-mono'
],
'pt-serif'=> [
'name' => 'PR Serif',
'font-family' => '\'PT Serif\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/pt-serif'
],
'rancho'=> [
'name' => 'Rancho',
'font-family' => 'Rancho, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/rancho'
],
'ubuntu'=> [
'name' => 'Ubuntu',
'font-family' => 'Ubuntu, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/ubuntu'
],
'vollkorn'=> [
'name' => 'Vollkorn',
'font-family' => 'Vollkorn, serif',
'resource' => 'https://fonts.cdnfonts.com/css/vollkorn'
]
];
// Conversion des fontes locales
$files = $this->getData(['fonts', 'files']);
if (is_array($files)) {
foreach ($files as $fontId => $fontName) {
if ( gettype($fontName) === 'string'
&& file_exists(self::DATA_DIR . 'fonts/' . $fontName)) {
$this->setData(['fonts', 'files', $fontId, [
'name' => ucfirst($fontId),
'font-family'=> '\'' . ucfirst($fontId) . '\', sans-serif',
'resource' => $fontName
]]);
}
}
}
// Consersion des fontes importées
$imported = $this->getData(['fonts', 'imported']);
if (is_array($imported)) {
foreach ($imported as $fontId => $fontUrl) {
if ( gettype($fontUrl) === 'string' ) {
$this->setData(['fonts', 'imported', $fontId, [
'name' => ucfirst($fontId),
'font-family'=> '\'' . ucfirst($fontId) . '\', sans-serif',
'resource' => 'https:\\fonts.cdnfonts.com\css' . $fontUrl
]]);
}
}
}
// Importation des fontes exemples
$template = $fonts;
foreach ($template as $fontId => $fontValue) {
$this->setData(['fonts', 'imported', $fontId, $fontValue]);
}
// Redirection des pages d'administration vers la bannière de connexion
$this->setData(['config', 'connect', 'redirectLogin', true]);
// Transforme les URL en références relatives
/*
$baseUrl = $this->getData(['core', 'baseUrl']);
$baseUrl2 = str_replace('?', '', $baseUrl);
foreach ($this->getHierarchy(null,null,null) as $parentKey=>$parentValue) {
$pageList [] = $parentKey;
foreach ($parentValue as $childKey) {
$pageList [] = $childKey;
}
}
foreach ($pageList as $parentKey => $parent) {
$s = $this->getPage( $parent, self::$i18n);
// Suppression des sous-dossiers
$s = str_replace ($baseUrl, './', $s);
$s = str_replace ($baseUrl2, './', $s);
$this->setPage( $parent, $s, self::$i18n);
}
*/
// Suppression de la variable URL dans core
$this->deleteData(['core', 'baseUrl']);
// Mise à jour
$this->setData(['core', 'dataVersion', 11400]);
}

View File

@ -13,7 +13,8 @@
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/common.css">
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/blank.css">
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>theme.css?<?php echo md5_file(self::DATA_DIR.'theme.css'); ?>">
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>custom.css?<?php echo md5_file(self::DATA_DIR.'custom.css'); ?>"></head>
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>custom.css?<?php echo md5_file(self::DATA_DIR.'custom.css'); ?>">
</head>
<body>
<?php $this->showContent(); ?>
<?php $this->showScript(); ?>

View File

@ -13,6 +13,7 @@
<link rel="stylesheet" href="<?php echo helper::baseUrl(false); ?>core/layout/common.css?<?php echo md5_file('core/layout/common.css');?>">
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>theme.css?<?php echo md5_file(self::DATA_DIR.'theme.css'); ?>">
<link rel="stylesheet" href="<?php echo helper::baseUrl(false) . self::DATA_DIR; ?>custom.css?<?php echo md5_file(self::DATA_DIR.'custom.css'); ?>">
<!-- Détection RSS -->
<?php if ( ( $this->getData(['page', $this->getUrl(0), 'moduleId']) === 'blog'
OR $this->getData(['page', $this->getUrl(0), 'moduleId']) === 'news' )
@ -20,6 +21,7 @@
<link rel="alternate" type="application/rss+xml" href="'<?php echo helper::baseUrl(). $this->getUrl(0) . '/rss';?>" title="fLUX rss">
<?php endif; ?>
<?php $this->showStyle(); ?>
<!-- Script perso dans le header -->
<?php if (file_exists(self::DATA_DIR .'head.inc.html')) {
include(self::DATA_DIR .'head.inc.html');
}?>
@ -86,10 +88,9 @@
<?php echo $this->getData(['theme','header','featureContent']);?>
</div>
<?php endif; ?>
<?php echo ($this->getData(['theme','header','linkHomePage']) && $this->getData(['theme','header','feature']) === 'wallpaper' ) ? '</a>' : '';?>
</header>
<?php echo ( $this->getData(['theme','header','linkHomePage']) && $this->getData(['theme','header','feature']) === 'wallpaper' ) ? '</a>' : ''; ?>
<?php endif; ?>
<!-- Menu dans le fond du site après la bannière -->
<?php if($this->getData(['theme', 'menu', 'position']) === 'body-second'): ?>
@ -187,6 +188,10 @@
<?php $this->showCookies(); ?>
<!-- Les scripts -->
<?php $this->showScript();?>
<!-- Script perso dans body -->
<?php if (file_exists(self::DATA_DIR . 'body.inc.html')) {
include(self::DATA_DIR . 'body.inc.html');
}
?>
</body>
</html>

View File

@ -293,7 +293,7 @@ class addon extends common {
// Modules installés
$infoModules = helper::getModules();
// Clés moduleIds dans les pages
$inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC');
$inPages = helper::arrayColumn($this->getData(['page']),'moduleId', 'SORT_DESC');
foreach( $inPages as $key=>$value){
$inPagesTitle[ $this->getData(['page', $key, 'title' ]) ] = $value;
}
@ -364,7 +364,7 @@ class addon extends common {
$infoModules = helper::getModules();
// Clés moduleIds dans les pages
$inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC');
$inPages = helper::arrayColumn($this->getData(['page']),'moduleId', 'SORT_DESC');
foreach( $inPages as $key=>$value){
$inPagesTitle[ $this->getData(['page', $key, 'title' ]) ] = $value;
}
@ -430,7 +430,7 @@ class addon extends common {
mkdir($tmpFolder, 0755);
}
// Clés moduleIds dans les pages
$inPages = helper::arrayCollumn($this->getData(['page']),'moduleId', 'SORT_DESC');
$inPages = helper::arrayColumn($this->getData(['page']),'moduleId', 'SORT_DESC');
// Parcourir les pages utilisant le module
foreach (array_keys($inPages,$this->getUrl(2)) as $pageId) {
// Export des pages hébergeant le module

View File

@ -1,8 +0,0 @@
<h3>MODULES INSTALLES</h3>
Les modules installés sont listés dans le tableau avec leur nom usuel (alias) et leur numéro de version.
Si le module est utilisé le nom de la page ou des pages apparaît, dans le cas contraire une icône permet de le supprimer.
<h3>EXPORTER IMPORTER</h3>
<p>Exporter produit une archive au nom du module contenant les pages concernées ainsi que les données et ressources utilisées par le module dans ces pages.</p>
<p>Vous pouvez vous en servir comme d'une sauvegarde partielle ou pour transférer les pages et les données du module vers un autre site.</p>
<p>Une fois le module installé l'import permet de restaurer les pages et les données sauvegardées. Vous devrez avoir au préalable transféré le fichier zip d'un export sur votre serveur par 'Gérer les fichiers'.
Si une page de même nom existe sur votre site vous serez invité à modifier son nom.</p>

View File

@ -16,18 +16,12 @@
'class' => 'buttonHelp'
]); ?>
</div>
<div class="col2 offset4">
<div class="col2 offset6">
<?php echo template::button('configModulesStore', [
'href' => helper::baseUrl() . 'addon/store',
'value' => 'Catalogue en ligne'
]); ?>
</div>
<div class="col2">
<?php echo template::button('configStoreUpload', [
'href' => helper::baseUrl() . 'addon/upload',
'value' => 'Installer'
]); ?>
</div>
</div>
<!-- Aide à propos de la gestion des modules, view index -->
<div class="helpDisplayContent">

View File

@ -2,7 +2,7 @@
<div class="col2">
<?php echo template::button('configStoreBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'addon/upload',
'href' => helper::baseUrl() . 'addon',
'ico' => 'left',
'value' => 'Retour'
]); ?>

View File

@ -20,7 +20,7 @@ class config extends common {
'backup' => self::GROUP_ADMIN,
'copyBackups'=> self::GROUP_ADMIN,
'configMetaImage' => self::GROUP_ADMIN,
'generateFiles' => self::GROUP_ADMIN,
'siteMap' => self::GROUP_ADMIN,
'index' => self::GROUP_ADMIN,
'restore' => self::GROUP_ADMIN,
'updateBaseUrl' => self::GROUP_ADMIN,
@ -28,8 +28,7 @@ class config extends common {
'logReset' => self::GROUP_ADMIN,
'logDownload'=> self::GROUP_ADMIN,
'blacklistReset' => self::GROUP_ADMIN,
'blacklistDownload' => self::GROUP_ADMIN,
'blacklistDownload' => self::GROUP_ADMIN
];
public static $timezones = [
@ -203,17 +202,15 @@ class config extends common {
* Sitemap compressé et non compressé
* Robots.txt
*/
public function generateFiles() {
public function siteMap() {
// Mettre à jour le site map
$successSitemap=$this->createSitemap();
// Valeurs en sortie
$this->addOutput([
/*'title' => 'Configuration',
'view' => 'index',*/
'redirect' => helper::baseUrl() . 'config',
'notification' => $successSitemap ? 'Mises à jour des fichiers sitemap et robots.txt' : 'Echec d\'écriture, le site map n\'a pas été mis à jour',
'notification' => $successSitemap ? 'La carte du site a été mise à jour' : 'Echec d\'écriture, la carte du site n\'a pas été mise à jour',
'state' => $successSitemap
]);
}
@ -279,8 +276,6 @@ class config extends common {
}
// Valeurs en sortie
$this->addOutput([
/*'title' => 'Configuration',
'view' => 'index',*/
'redirect' => helper::baseUrl() . 'config',
'notification' => $success === false ? 'Service inaccessible ou erreur d\'écriture de l\'image' : 'Image générée avec succès',
'state' => $success === false ? false : true
@ -510,7 +505,8 @@ class config extends common {
'captchaStrong' => $this->getInput('connectCaptchaStrong',helper::FILTER_BOOLEAN),
'autoDisconnect' => $this->getInput('connectAutoDisconnect',helper::FILTER_BOOLEAN),
'captchaType' => $this->getInput('connectCaptchaType'),
'showPassword' => $this->getInput('connectShowPassword',helper::FILTER_BOOLEAN)
'showPassword' => $this->getInput('connectShowPassword',helper::FILTER_BOOLEAN),
'redirectLogin' => $this->getInput('connectRedirectLogin',helper::FILTER_BOOLEAN)
],
'i18n' => [
'enable' => $this->getInput('localei18n',helper::FILTER_BOOLEAN),
@ -551,17 +547,21 @@ class config extends common {
AND helper::checkRewrite() === false
) {
// Ajout des lignes dans le .htaccess
file_put_contents(
'.htaccess',
PHP_EOL .
$fileContent = file_get_contents('.htaccess');
$rewriteData = PHP_EOL .
'# URL rewriting' . PHP_EOL .
'<IfModule mod_rewrite.c>' . PHP_EOL .
"\tRewriteEngine on" . PHP_EOL .
"\tRewriteBase " . helper::baseUrl(false, false) . PHP_EOL .
"\tRewriteCond %{REQUEST_FILENAME} !-f" . PHP_EOL .
"\tRewriteCond %{REQUEST_FILENAME} !-d" . PHP_EOL .
"\tRewriteRule ^(.*)$ index.php?$1 [L]" . PHP_EOL .
'</IfModule>',
FILE_APPEND
'</IfModule>'. PHP_EOL .
'# URL rewriting' . PHP_EOL ;
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
file_put_contents(
'.htaccess',
$fileContent
);
// Change le statut de la réécriture d'URL (pour le helper::baseUrl() de la redirection)
helper::$rewriteStatus = true;
@ -572,16 +572,19 @@ class config extends common {
AND helper::checkRewrite()
) {
// Suppression des lignes dans le .htaccess
$htaccess = explode('# URL rewriting', file_get_contents('.htaccess'));
file_put_contents('.htaccess', $htaccess[0] . '# URL rewriting');
$fileContent = file_get_contents('.htaccess');
$fileContent = explode('# URL rewriting', $fileContent);
$fileContent = $fileContent[0] . '# URL rewriting' . $fileContent[2];
file_put_contents(
'.htaccess',
$fileContent
);
// Change le statut de la réécriture d'URL (pour le helper::baseUrl() de la redirection)
helper::$rewriteStatus = false;
}
// Met à jour la baseUrl
$this->setData(['core', 'baseUrl', helper::baseUrl(true,false) ]);
}
// Générer robots.txt et sitemap
$this->generateFiles();
$this->siteMap();
// Valeurs en sortie
$this->addOutput([
'title' => 'Configuration',
@ -652,59 +655,6 @@ class config extends common {
]);
}
/**
* Met à jour les données de site avec l'adresse transmise
*/
public function updateBaseUrl () {
// Supprimer l'information de redirection
$old = str_replace('?','',$this->getData(['core', 'baseUrl']));
$new = helper::baseUrl(false,false);
$c3 = 0;
$success = false ;
// Boucler sur les pages
foreach($this->getHierarchy(null,null,null) as $parentId => $childIds) {
$content = $this->getPage($parentId, self::$i18n);
$titre = $this->getData(['page', $parentId, 'title']);
$content = $titre . ' ' . $content ;
$replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ;
$replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ;
if ($c1 > 0 || $c2 > 0) {
$success = true;
$this->setPage($parentId, $replace, self::$i18n);
$c3 += $c1 + $c2;
}
foreach($childIds as $childId) {
$content = $this->getPage($childId, self::$i18n);
$content = $titre . ' ' . $content ;
$replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ;
$replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ;
if ($c1 > 0 || $c2 > 0) {
$success = true;
$this->setPage($childId, $replace, self::$i18n);
$c3 += $c1 + $c2;
}
}
}
// Traiter les modules dont la redirection
$content = $this->getdata(['module']);
$replace = $this->recursive_array_replace('href="' . $old , 'href="'. $new, $content, $c1);
$replace = $this->recursive_array_replace('src="' . $old , 'src="'. $new, $replace, $c2);
if ($content !== $replace) {
$this->setdata(['module',$replace]);
$c3 += $c1 + $c2;
$success = true;
}
// Mettre à jour la base URl
$this->setData(['core','baseUrl',helper::baseUrl(true,false)]);
// Valeurs en sortie
$this->addOutput([
'title' => 'Restaurer',
'view' => 'restore',
'notification' => $success ? $c3. ' conversion' . ($c3 > 1 ? 's' : '') . ' effectuée' . ($c3 > 1 ? 's' : '') : 'Aucune conversion',
'state' => $success ? true : false
]);
}
/**
* Vider le fichier de log

View File

@ -9,39 +9,31 @@
</a>
</span>
</h4>
<div class="row">
<div class="col3">
<?php echo template::checkbox('connectCaptcha', true, 'Captcha à la connexion', [
'checked' => $this->getData(['config', 'connect','captcha'])
]); ?>
<?php echo template::checkbox('connectCaptchaStrong', true, 'Captcha complexe', [
'checked' => $this->getData(['config', 'connect', 'captchaStrong']),
'help' => 'Option recommandée pour sécuriser la connexion. S\'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha complexe utilise quatre opérations de nombres de 0 à 20. Activation recommandée.'
<div class="col4">
<?php echo template::checkbox('connectShowPassword', true, 'Dévoiler le mot de passe', [
'checked' => $this->getData(['config', 'connect', 'showPassword']),
'help' => 'Le survom d\'une icône de l\'écran de connexion affiche temporairement le mot de passe.'
]); ?>
</div>
<div class="col3">
<?php echo template::select('connectCaptchaType', $module::$captchaTypes , [
'label' => 'Type de captcha',
'selected' => $this->getData(['config', 'connect', 'captchaType'])
]); ?>
</div>
<div class="col3">
<div class="col4">
<?php echo template::checkbox('connectAutoDisconnect', true, 'Déconnexion automatique', [
'checked' => $this->getData(['config', 'connect', 'autoDisconnect']),
'help' => 'Déconnecte les sessions ouvertes précédemment sur d\'autres navigateurs ou terminaux. Activation recommandée.'
]); ?>
</div>
<div class="col3">
<?php echo template::checkbox('connectShowPassword', true, 'Dévoiler le mot de passe', [
'checked' => $this->getData(['config', 'connect', 'showPassword']),
'help' => 'Dans l\'écran de connexion, active une icône dont le survol affiche temporairement le mot de passe.'
<div class="col4">
<?php echo template::checkbox('connectRedirectLogin', true, 'Redirection vers la connexion', [
'checked' => $this->getData(['config', 'connect', 'redirectLogin']),
'help' => 'Cette redirection ne concerne que les pages d\'administration du site.'
]); ?>
</div>
</div>
<div class="row">
<div class="col3">
<?php echo template::select('connectAttempt', $module::$connectAttempt , [
'label' => 'Connexions successives',
'label' => 'Limitation des tentatives',
'selected' => $this->getData(['config', 'connect', 'attempt'])
]); ?>
</div>
@ -73,6 +65,25 @@
]); ?>
</div>
</div>
<div class="row">
<div class="col3">
<?php echo template::checkbox('connectCaptcha', true, 'Captcha à la connexion', [
'checked' => $this->getData(['config', 'connect','captcha'])
]); ?>
</div>
<div class="col3">
<?php echo template::checkbox('connectCaptchaStrong', true, 'Captcha complexe', [
'checked' => $this->getData(['config', 'connect', 'captchaStrong']),
'help' => 'Option recommandée pour sécuriser la connexion. S\'applique à tous les captchas du site. Le captcha simple se limite à une addition de nombres de 0 à 10. Le captcha complexe utilise quatre opérations de nombres de 0 à 20. Activation recommandée.'
]); ?>
</div>
<div class="col3">
<?php echo template::select('connectCaptchaType', $module::$captchaTypes , [
'label' => 'Type de captcha',
'selected' => $this->getData(['config', 'connect', 'captchaType'])
]); ?>
</div>
</div>
</div>
</div>
</div>

View File

@ -57,21 +57,21 @@
</h4>
<div class="row">
<div class="col4">
<?php echo template::select('localeHomePageId', helper::arrayCollumn($module::$pagesList, 'title', 'SORT_ASC'), [
<?php echo template::select('localeHomePageId', helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC'), [
'label' => 'Accueil du site',
'selected' =>$this->getData(['locale', 'homePageId']),
'help' => 'La première page que vos visiteurs verront.'
]); ?>
</div>
<div class="col4">
<?php echo template::select('localePage403', array_merge(['none' => 'Page par défaut'],helper::arrayCollumn($module::$orphansList, 'title', 'SORT_ASC')), [
<?php echo template::select('localePage403', array_merge(['none' => 'Page par défaut'],helper::arrayColumn($module::$orphansList, 'title', 'SORT_ASC')), [
'label' => 'Accès interdit, erreur 403',
'selected' =>$this->getData(['locale', 'page403']),
'help' => 'Cette page ne doit pas apparaître dans l\'arborescence du menu. Créez une page orpheline.'
]); ?>
</div>
<div class="col4">
<?php echo template::select('localePage404', array_merge(['none' => 'Page par défaut'],helper::arrayCollumn($module::$orphansList, 'title', 'SORT_ASC')), [
<?php echo template::select('localePage404', array_merge(['none' => 'Page par défaut'],helper::arrayColumn($module::$orphansList, 'title', 'SORT_ASC')), [
'label' => 'Page inexistante, erreur 404',
'selected' =>$this->getData(['locale', 'page404']),
'help' => 'Cette page ne doit pas apparaître dans l\'arborescence du menu. Créez une page orpheline.'
@ -80,14 +80,14 @@
</div>
<div class="row">
<div class="col4">
<?php echo template::select('localeLegalPageId', array_merge(['none' => 'Aucune'] , helper::arrayCollumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
<?php echo template::select('localeLegalPageId', array_merge(['none' => 'Aucune'] , helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
'label' => 'Mentions légales',
'selected' => $this->getData(['locale', 'legalPageId']),
'help' => 'Les mentions légales sont obligatoires en France. Une option du pied de page ajoute un lien discret vers cette page.'
]); ?>
</div>
<div class="col4">
<?php echo template::select('localeSearchPageId', array_merge(['none' => 'Aucune'] , helper::arrayCollumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
<?php echo template::select('localeSearchPageId', array_merge(['none' => 'Aucune'] , helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
'label' => 'Recherche dans le site',
'selected' => $this->getData(['locale', 'searchPageId']),
'help' => 'Sélectionnez une page contenant le module \'Recherche\'. Une option du pied de page ajoute un lien discret vers cette page.'
@ -95,7 +95,7 @@
</div>
<div class="col4">
<?php
echo template::select('localePage302', array_merge(['none' => 'Page par défaut'],helper::arrayCollumn($module::$orphansList, 'title', 'SORT_ASC')), [
echo template::select('localePage302', array_merge(['none' => 'Page par défaut'],helper::arrayColumn($module::$orphansList, 'title', 'SORT_ASC')), [
'label' => 'Site en maintenance',
'selected' =>$this->getData(['locale', 'page302']),
'help' => 'Cette page ne doit pas apparaître dans l\'arborescence du menu. Créez une page orpheline.'

View File

@ -38,46 +38,4 @@
</div>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Conversion après la restauration<?php echo template::help('Conversion des URL des ressources multimédia entre deux sites aux arborescences différentes.');?></h4>
<div class="row">
<div class="col4 offset1">
<?php
if (is_null($this->getData(['core', 'baseUrl'])) ) {
$baseUrlValue = 'Pas de donnée dans la sauvegarde';
$buttonClass = 'disabled';
} elseif ($this->getData(['core', 'baseUrl']) === '') {
$baseUrlValue = '/';
$buttonClass = helper::baseUrl(false,false) !== $this->getData(['core', 'baseUrl']) ? '' : 'disabled';
} else {
$baseUrlValue = str_replace('?','',$this->getData(['core', 'baseUrl']));
$buttonClass = helper::baseUrl(false,false) !== $baseUrlValue ? '' : 'disabled';
}
echo template::text('configRestoreBaseURLToConvert', [
'label' => 'Dossier de l\'archive' ,
'value' => $baseUrlValue,
'readonly' => true,
'help' => 'Le dossier de base du site est stockée dans la sauvegarde.'
]); ?>
</div>
<div class="col4">
<?php echo template::text('configRestoreCurrentURL', [
'label' => 'Dossier du site actuel',
'value' => helper::baseUrl(false,false),
'readonly' => true
]); ?>
</div>
<div class="col2 verticalAlignMiddle">
<?php echo template::button('configRestoreUpdateBaseURLButton', [
'href' => helper::baseUrl() . 'config/updateBaseUrl',
'class' => $buttonClass,
'value' => 'convertir'
]); ?>
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>

View File

@ -42,9 +42,10 @@
]); ?>
</div>
<div class="col6">
<?php echo template::checkbox('configRewrite', true, 'URL intelligentes', [
<?php echo template::checkbox('configRewrite', true, 'Apache URL intelligentes', [
'checked' => helper::checkRewrite(),
'help' => 'Supprime ? dans les URL et redirige sur le protocole HTTPS.'
'help' => 'Supprime le point d\'interrogation dans les URL, l\'option est indisponible avec les autres serveurs Web',
'disabled' => strpos($_SERVER["SERVER_SOFTWARE"], 'Apache') > 0 ? true : false
]); ?>
</div>
</div>

View File

@ -23,7 +23,7 @@
<div class="row">
<div class="col12">
<?php echo template::button('socialSiteMap', [
'href' => helper::baseUrl() . 'config/generateFiles',
'href' => helper::baseUrl() . 'config/siteMap',
'value' => 'Générer sitemap.xml et robots.txt'
]); ?>
</div>

View File

@ -121,10 +121,6 @@ class install extends common {
if (!is_dir(self::DATA_DIR . 'fonts')) {
mkdir(self::DATA_DIR . 'fonts');
}
// Stocker le dossier d'installation
$this->setData(['core', 'baseUrl', helper::baseUrl(false,false) ]);
// Créer sitemap
$this->createSitemap();
// Installation du thème sélectionné
$dataThemes = file_get_contents('core/module/install/ressource/themes/themes.json');
@ -153,7 +149,12 @@ class install extends common {
// Récupération de la liste des thèmes
$dataThemes = file_get_contents('core/module/install/ressource/themes/themes.json');
$dataThemes = json_decode($dataThemes, true);
self::$themes = helper::arrayCollumn($dataThemes, 'name');
self::$themes = helper::arrayColumn($dataThemes, 'name');
// Créer sitemap
$this->createSitemap();
// Mise à jour de la liste des pages pour TinyMCE
$this->listPages();
// Valeurs en sortie
$this->addOutput([
@ -251,19 +252,23 @@ class install extends common {
$success = true;
$rewrite = $this->getInput('data');
// Réécriture d'URL
if ($rewrite === "true") {
$success = (file_put_contents(
'.htaccess',
PHP_EOL .
if ($rewrite === "true") { // Ajout des lignes dans le .htaccess
$fileContent = file_get_contents('.htaccess');
$rewriteData = PHP_EOL .
'# URL rewriting' . PHP_EOL .
'<IfModule mod_rewrite.c>' . PHP_EOL .
"\tRewriteEngine on" . PHP_EOL .
"\tRewriteBase " . helper::baseUrl(false, false) . PHP_EOL .
"\tRewriteCond %{REQUEST_FILENAME} !-f" . PHP_EOL .
"\tRewriteCond %{REQUEST_FILENAME} !-d" . PHP_EOL .
"\tRewriteRule ^(.*)$ index.php?$1 [L]" . PHP_EOL .
'</IfModule>',
FILE_APPEND
) !== false);
'</IfModule>'. PHP_EOL .
'# URL rewriting' . PHP_EOL ;
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
file_put_contents(
'.htaccess',
$fileContent
);
}
// Recopie htaccess
if ($this->getData(['config','autoUpdateHtaccess']) &&
@ -271,7 +276,7 @@ class install extends common {
) {
// L'écraser avec le backup
$success = copy( '.htaccess.bak' ,'.htaccess' );
// Effacer l ebackup
// Effacer le backup
unlink('.htaccess.bak');
}
// Valeurs en sortie

View File

@ -38,7 +38,8 @@ class init extends common {
'captchaStrong' => false,
"captchaType" => 'num',
'autoDisconnect' => true,
'showPassword' => true
'showPassword' => true,
'redirectLogin' => true
],
'i18n' => [
'enable'=> true,
@ -56,12 +57,11 @@ class init extends common {
]
],
'core' => [
'dataVersion' => 11300,
'dataVersion' => 11400,
'lastBackup' => 0,
'lastClearTmp' => 0,
'lastAutoUpdate' => 0,
'updateAvailable' => false,
'baseUrl' => ''
'updateAvailable' => false
],
'locale' => [
'homePageId' => 'accueil',
@ -87,7 +87,108 @@ class init extends common {
],
'fonts' => [
'files' => [],
'imported' => []
'imported'=> [
'arimo'=> [
'name' => 'Arimo',
'font-family' => 'Arimo, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/arimo'
],
'arvo'=> [
'name' => 'Arvo',
'font-family' => 'Arvo, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/arvo'
],
'dancing-script' => [
'name' => 'Dancing Script',
'font-family' => '\'Dancing Script\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/dancing-script'
],
'droid-sans-2'=> [
'name' => 'Droid Sans',
'font-family' => '\'Droid Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/droid-sans-2'
],
'droid-serif-2'=> [
'name' => 'Droid Serif',
'font-family' => '\'Droid Serif\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/droid-serif-2'
],
'indie-flower'=> [
'name' => 'Indie Flower',
'font-family' => '\'Indie Flower\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/indie-flower'
],
'liberation-sans'=> [
'name' => 'Liberation Sans',
'font-family' => '\'Liberation Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/liberation-sans'
],
'liberation-serif'=> [
'name' => 'Liberation Serif',
'font-family' => '\'Liberation Serif\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/liberation-serif'
],
'lobster-2'=> [
'name' => 'Lobster',
'font-family' => 'Lobster, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/lobster-2'
],
'lato'=> [
'name' => 'lato',
'font-family' => 'Lato, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/lato'
],
'lora'=> [
'name' => 'Lora',
'font-family' => 'Lora, serif',
'resource' => 'https://fonts.cdnfonts.com/css/lora'
],
'old-standard-tt-3'=> [
'name' => 'Old Standard TT',
'font-family' => '\'Old Standard TT\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/old-standard-tt-3'
],
'open-sans' => [
'name' => 'Open Sans',
'font-family' => '\'Open Sans\', sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/open-sans'
],
'oswald-4'=> [
'name' => 'Oswald',
'font-family' => 'Oswald, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/oswald-4'
],
'pt-mono'=> [
'name' => 'PT Mono',
'font-family' => '\'PT Mono\', monospace',
'resource' => 'https://fonts.cdnfonts.com/css/pt-mono'
],
'pt-serif'=> [
'name' => 'PR Serif',
'font-family' => '\'PT Serif\', serif',
'resource' => 'https://fonts.cdnfonts.com/css/pt-serif'
],
'rancho'=> [
'name' => 'Rancho',
'font-family' => 'Rancho, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/rancho'
],
'roboto'=> [
'name' => 'Roboto',
'font-family' => 'Roboto, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/roboto'
],
'ubuntu'=> [
'name' => 'Ubuntu',
'font-family' => 'Ubuntu, sans-serif',
'resource' => 'https://fonts.cdnfonts.com/css/ubuntu'
],
'vollkorn'=> [
'name' => 'Vollkorn',
'font-family' => 'Vollkorn, serif',
'resource' => 'https://fonts.cdnfonts.com/css/vollkorn'
]
]
],
'page' => [
'accueil' => [
@ -132,7 +233,7 @@ class init extends common {
],
'footer' => [
'backgroundColor' => 'rgba(255, 255, 255, 1)',
'font' => 'open-sans',
'font' => 'georgia',
'fontSize' => '.8em',
'fontWeight' => 'normal',
'height' => '5px',
@ -159,7 +260,7 @@ class init extends common {
],
'header' => [
'backgroundColor' => 'rgba(32, 59, 82, 1)',
'font' => 'oswald-4',
'font' => 'arial',
'fontSize' => '2em',
'fontWeight' => 'normal',
'height' => '150px',
@ -182,7 +283,7 @@ class init extends common {
'menu' => [
'backgroundColor' => 'rgba(32, 59, 82, 1)',
'backgroundColorSub' => 'rgba(32, 59, 82, 1)',
'font' => 'open-sans',
'font' => 'arial',
'fontSize' => '1em',
'fontWeight' => 'normal',
'height' => '15px 10px',
@ -213,13 +314,13 @@ class init extends common {
'borderColor' => 'rgba(236, 239, 241, 1)'
],
'text' => [
'font' => 'open-sans',
'font' => 'georgia',
'fontSize' => '13px',
'textColor' => 'rgba(33, 34, 35, 1)',
'linkColor' => 'rgba(74, 105, 189, 1)'
],
'title' => [
'font' => 'oswald-4',
'font' => 'arial',
'fontWeight' => 'normal',
'textColor' => 'rgba(74, 105, 189, 1)',
'textTransform' => 'none'
@ -231,9 +332,9 @@ class init extends common {
],
'admin' => [
'backgroundColor' => 'rgba(255, 255, 255, 1)',
'fontText' => 'open-sans',
'fontText' => 'georgia',
'fontSize' => '13px',
'fontTitle' => 'oswald-4',
'fontTitle' => 'arial',
'colorText' => 'rgba(33, 34, 35, 1)',
'colorTitle' => 'rgba(74, 105, 189, 1)',
'backgroundColorButton' => 'rgba(74, 105, 189, 1)',

View File

@ -146,7 +146,7 @@ class page extends common {
'group' => self::GROUP_VISITOR,
'targetBlank' => false,
'title' => $pageTitle,
'shortTitle' => $pageTitle,
'shortTitle' => '',
'block' => '12',
'barLeft' => '',
'barRight' => '',
@ -164,6 +164,8 @@ class page extends common {
$this->setPage($pageId, '<p>Contenu de votre nouvelle page.</p>', self::$i18n);
// Met à jour le site map
$this->createSitemap('all');
// Mise à jour de la liste des pages pour TinyMCE
$this->listPages();
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . $pageId,
@ -289,6 +291,8 @@ class page extends common {
$this->deleteData(['module', $url[0]]);
// Met à jour le site map
$this->createSitemap('all');
// Mise à jour de la liste des pages pour TinyMCE
$this->listPages();
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl(false),
@ -388,9 +392,13 @@ class page extends common {
$lastPosition = 1;
$hierarchy = $this->getInput('pageEditParentPageId') ? $this->getHierarchy($this->getInput('pageEditParentPageId')) : array_keys($this->getHierarchy());
$position = $this->getInput('pageEditPosition', helper::FILTER_INT);
$extraPosition = $this->getinput('pageEditExtraPosition', helper::FILTER_BOOLEAN);
foreach($hierarchy as $hierarchyPageId) {
// Ne traite que les pages du menu sélectionné
if ($this->getData(['page', $hierarchyPageId, 'extraPosition']) === $extraPosition ) {
// Ignore la page en cours de modification
if($hierarchyPageId === $this->getUrl(2)) {
if($hierarchyPageId === $this->getUrl(2) ) {
continue;
}
// Incrémente de +1 pour laisser la place à la position de la page en cours de modification
@ -402,6 +410,8 @@ class page extends common {
// Incrémente pour la prochaine position
$lastPosition++;
}
}
if ($this->getinput('pageEditBlock') !== 'bar') {
$barLeft = $this->getinput('pageEditBarLeft');
$barRight = $this->getinput('pageEditBarRight');
@ -476,7 +486,7 @@ class page extends common {
'hideMenuSide' => $this->getinput('pageEditHideMenuSide', helper::FILTER_BOOLEAN),
'hideMenuHead' => $this->getinput('pageEditHideMenuHead', helper::FILTER_BOOLEAN),
'hideMenuChildren' => $this->getinput('pageEditHideMenuChildren', helper::FILTER_BOOLEAN),
'extraPosition' => $this->getinput('pageEditExtraPosition', helper::FILTER_BOOLEAN)
'extraPosition' => $extraPosition
]
]);
@ -487,9 +497,11 @@ class page extends common {
$content = empty($this->getInput('pageEditContent', null)) ? '<p></p>' : str_replace('<p></p>', '<p>&nbsp;</p>', $this->getInput('pageEditContent', null));
$this->setPage($pageId , $content, self::$i18n);
// Met à jour le site map
$this->createSitemap('all');
// Mise à jour de la liste des pages pour TinyMCE
$this->listPages();
// Redirection vers la configuration
if(
$this->getInput('pageEditModuleRedirect', helper::FILTER_BOOLEAN)
@ -510,7 +522,7 @@ class page extends common {
}
}
}
self::$moduleIds = array_merge( ['' => 'Aucun'] , helper::arrayCollumn(helper::getModules(),'realName','SORT_ASC')); // Pages sans parent
self::$moduleIds = array_merge( ['' => 'Aucun'] , helper::arrayColumn(helper::getModules(),'realName','SORT_ASC')); // Pages sans parent
foreach($this->getHierarchy() as $parentPageId => $childrenPageIds) {
if($parentPageId !== $this->getUrl(2)) {
self::$pagesNoParentId[$parentPageId] = $this->getData(['page', $parentPageId, 'title']);
@ -523,8 +535,6 @@ class page extends common {
self::$pagesBarId[$parentPageId] = $this->getData(['page', $parentPageId, 'title']);
}
}
// Mise à jour de la liste des pages pour TinyMCE
$this->pages2Json();
// Valeurs en sortie
$this->addOutput([
'title' => $this->getData(['page', $this->getUrl(2), 'title']),

View File

@ -514,6 +514,12 @@ pageTypeMenuDOM.on("change", function() {
}
});
/**
* Duplication du champ Title dans Short title
*/
$("#pageEditTitle").on("input", function() {
$("#pageEditShortTitle").val($(this).val());
});
/**
* Actualise la liste de pages lorsque le menu accessoire est sélectionné

View File

@ -42,8 +42,8 @@ class sitemap extends common
!empty($this->getData(['module',$parentId, 'posts' ]))) {
$items .= '<ul>';
// Ids des articles par ordre de publication
$articleIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $parentId,'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayCollumn($this->getData(['module', $parentId, 'posts']), 'state', 'SORT_DESC');
$articleIdsPublishedOns = helper::arrayColumn($this->getData(['module', $parentId,'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayColumn($this->getData(['module', $parentId, 'posts']), 'state', 'SORT_DESC');
$articleIds = [];
foreach ($articleIdsPublishedOns as $articleId => $articlePublishedOn) {
if ($articlePublishedOn <= time() and $articleIdsStates[$articleId]) {
@ -78,8 +78,8 @@ class sitemap extends common
!empty($this->getData(['module', $childId, 'posts' ]))) {
$items .= '<ul>';
// Ids des articles par ordre de publication
$articleIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $childId,'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayCollumn($this->getData(['module', $childId, 'posts']), 'state', 'SORT_DESC');
$articleIdsPublishedOns = helper::arrayColumn($this->getData(['module', $childId,'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayColumn($this->getData(['module', $childId, 'posts']), 'state', 'SORT_DESC');
$articleIds = [];
foreach ($articleIdsPublishedOns as $articleId => $articlePublishedOn) {
if ($articlePublishedOn <= time() and $articleIdsStates[$articleId]) {

View File

@ -32,6 +32,7 @@ class theme extends common {
'save' => self::GROUP_ADMIN,
'fonts' => self::GROUP_ADMIN,
'fontAdd' => self::GROUP_ADMIN,
'fontEdit' => self::GROUP_ADMIN,
'fontDelete' => self::GROUP_ADMIN
];
public static $aligns = [
@ -231,7 +232,10 @@ class theme extends common {
// Variable pour construire la liste des pages du site
public static $pagesList = [];
// Variable pour construire la liste des fontes installées
public static $fontsList = [];
public static $fontsNames= [];
public static $fonts = [];
// Variable pour détailler les fontes installées
public static $fontsDetail = [];
/**
* Thème des écrans d'administration
@ -262,6 +266,10 @@ class theme extends common {
'state' => true
]);
}
// Lire les fontes installées
$this->enumFonts();
// Toutes les fontes installées sont chargées
$this->setFonts('all');
// Valeurs en sortie
$this->addOutput([
'title' => 'Administration',
@ -396,7 +404,10 @@ class theme extends common {
unset(self::$pagesList[$page]);
}
}
// Lire les fontes installées
$this->enumFonts();
// Toutes les fontes installées sont chargées
$this->setFonts('all');
// Valeurs en sortie
$this->addOutput([
'title' => 'Personnalisation du pied de page',
@ -416,7 +427,7 @@ class theme extends common {
if($this->isPost()) {
// Modification des URL des images dans la bannière perso
$featureContent = $this->getInput('themeHeaderText', null);
$featureContent = str_replace(helper::baseUrl(false,false), './', $featureContent);
//$featureContent = str_replace(helper::baseUrl(false,false), './', $featureContent);
/**
* Stocker les images incluses dans la bannière perso dans un tableau
@ -475,6 +486,10 @@ class theme extends common {
'state' => true
]);
}
// Lire les fontes installées
$this->enumFonts();
// Toutes les fontes installées sont chargées
$this->setFonts('all');
// Valeurs en sortie
$this->addOutput([
'title' => 'Personnalisation de la bannière',
@ -490,6 +505,10 @@ class theme extends common {
* Accueil de la personnalisation
*/
public function index() {
// Restaurer les fontes utilisateurs
$this->setFonts('user');
// Valeurs en sortie
$this->addOutput([
'title' => 'Personnalisation des thèmes',
@ -534,6 +553,10 @@ class theme extends common {
'state' => true
]);
}
// Lire les fontes installées
$this->enumFonts();
// Toutes les fontes installées sont chargées
$this->setFonts('all');
// Valeurs en sortie
$this->addOutput([
'title' => 'Personnalisation du menu',
@ -549,8 +572,8 @@ class theme extends common {
*/
public function fonts() {
// Polices trouvées dans la configuration
$fonts = $this->getData(['fonts']);
// Toutes les fontes installées sont chargées
$this->setFonts('all');
// Polices liées au thème
$used = [
@ -563,32 +586,48 @@ class theme extends common {
'Admin (texte)' => $this->getData (['admin', 'fontText' ])
];
// Parcourir les fontes installées et construire le tableau pour le formulaire
foreach (self::$fonts as $fontId => $fontName) {
// Récupérer le détail des fontes installées
//$f = $this->getFonts();
$f ['files'] = $this->getData(['fonts', 'files']);
$f ['imported'] = $this->getData(['fonts', 'imported']);
$f ['websafe'] = self::$fontsWebSafe;
// Fontes utilisées par le thème
// Parcourir les fontes disponibles et construire le tableau pour le formulaire
foreach ($f as $type => $typeValue) {
if (is_array($typeValue)) {
foreach ($typeValue as $fontId => $fontValue) {
// Fontes utilisées par les thèmes
$fontUsed[$fontId] = '';
foreach ($used as $key => $value) {
if ( $value === $fontId) {
$fontUsed[$fontId] .= $key . '<br/>';
}
}
self::$fontsList [] = [
$fontName,
self::$fontsDetail [] = [
$fontId,
'<span style="font-family:' . $f[$type][$fontId]['font-family'] . '">' . $f[$type][$fontId]['name'] . '</span>' ,
$f[$type][$fontId]['font-family'],
$fontUsed[$fontId],
//array_key_exists($fontId, $fonts['imported']) ? 'Importée' : '',
array_key_exists($fontId, $fonts['files']) ? $fonts['files'][$fontId] : 'CDN Fonts',
array_key_exists($fontId, $fonts['imported']) || array_key_exists($fontId, $fonts['files'])
? template::button('themeFontDelete' . $fontId, [
$type,
$type !== 'websafe' ? template::button('themeFontEdit' . $fontId, [
'class' => 'themeFontEdit',
'href' => helper::baseUrl() . $this->getUrl(0) . '/fontEdit/' . $type . '/' . $fontId . '/' . $_SESSION['csrf'],
'value' => template::ico('pencil'),
'disabled' => !empty($fontUsed[$fontId])
])
: '',
$type !== 'websafe' ? template::button('themeFontDelete' . $fontId, [
'class' => 'themeFontDelete buttonRed',
'href' => helper::baseUrl() . $this->getUrl(0) . '/fontDelete/' . $fontId . '/' . $_SESSION['csrf'],
'href' => helper::baseUrl() . $this->getUrl(0) . '/fontDelete/' . $type . '/' . $fontId . '/' . $_SESSION['csrf'],
'value' => template::ico('cancel'),
'disabled' => !empty($fontUsed[$fontId])
])
: ''
];
}
}
}
sort(self::$fontsDetail);
// Valeurs en sortie
$this->addOutput([
'title' => 'Gestion des fontes',
@ -602,55 +641,45 @@ class theme extends common {
public function fontAdd() {
// Soumission du formulaire
if ($this->isPost()) {
$fontId = $this->getInput('fontAddFontId', helper::FILTER_STRING_SHORT, true);
$fontName = $this->getInput('fontAddFontName',helper::FILTER_STRING_SHORT, true);
$filePath = $this->getInput('fontAddFile', helper::FILTER_STRING_SHORT);
// Type d'import en ligne ou local
$type = $this->getInput('fontAddFontImported', helper::FILTER_BOOLEAN) ? 'imported' : 'files';
$e = explode ('/', $filePath);
$file = $e[count($e) - 1 ];
$typeFlip = $type === 'files' ? 'imported' : 'files';
$ressource = $type === 'imported' ? $this->getInput('fontAddUrl', null) : $this->getInput('fontAddFile', null);
$fontId = $this->getInput('fontAddFontId', null, true);
$fontName = $this->getInput('fontAddFontName', null, true);
$fontFamilyName = $this->getInput('fontAddFontFamilyName', null, true);
// Vérifier l'existence de fontId et validité de family name si usage en ligne de cdnFonts
$data = helper::getUrlContents('https://www.cdnfonts.com/' . $fontId . '.font');
// Remplace les doubles quotes par des simples quotes
$fontFamilyName = str_replace('"', '\'', $fontFamilyName);
if ( $filePath === ''
&& $fontName !== ''
&& strpos($data, $fontName) === false
) {
// Supprime la fonte si elle existe dans le type inverse
if (is_array($this->getData(['fonts', $typeFlip, $fontId])) ) {
$this->deleteData(['fonts', $typeFlip, $fontId ]);
}
// Stocker la fonte
$this->setData(['fonts',
$type,
$fontId, [
'name' => $fontName,
'font-family' => $fontFamilyName,
'resource' => $ressource
]]);
// Valeurs en sortie
$this->addOutput([
'notification' => 'Erreur de nom de fonte ou d\'identifiant',
'redirect' => helper::baseUrl() . 'theme/fontAdd',
'state' => false
]);
} else {
// Concaténation dans les tableaux existants
switch ($type) {
case 'imported':
$imported = $this->getData(['fonts', 'imported']);
$imported = array_merge([$fontId => $fontName], $imported);
$this->setData(['fonts', 'imported', $imported ]);
break;
case 'files':
$files = $this->getData(['fonts', 'files']);
$files = array_merge([$fontId => $file], $files);
$this->setData(['fonts', 'files', $files ]);
// Copier la fonte si le nom du fichier est fourni
copy ( self::FILE_DIR . 'source/' . $filePath, self::DATA_DIR . 'fonts/' . $file );
break;
if ( $type === 'files' &&
file_exists(self::FILE_DIR . 'source/' . $ressource)
) {
copy ( self::FILE_DIR . 'source/' . $ressource, self::DATA_DIR . 'fonts/' . $ressource );
}
// Valeurs en sortie
$this->addOutput([
'notification' => 'La fonte a été importée',
'notification' => 'La fonte a été créée',
'redirect' => helper::baseUrl() . 'theme/fonts',
'state' => true
]);
}
}
// Valeurs en sortie
$this->addOutput([
'title' => 'Ajouter une fonte',
@ -658,12 +687,63 @@ class theme extends common {
]);
}
/**
* Ajouter une fonte
*/
public function fontEdit() {
// Soumission du formulaire
if ($this->isPost()) {
// Type d'import en ligne ou local
$type = $this->getInput('fontEditFontImported', helper::FILTER_BOOLEAN) ? 'imported' : 'files';
$typeFlip = $type === 'files' ? 'imported' : 'files';
$ressource = $type === 'imported' ? $this->getInput('fontEditUrl', null) : $this->getInput('fontEditFile', null);
$fontId = $this->getInput('fontEditFontId', null, true);
$fontName = $this->getInput('fontEditFontName', null , true);
$fontFamilyName = $this->getInput('fontEditFontFamilyName', null, true);
// Remplace les doubles quotes par des simples quotes
$fontFamilyName = str_replace('"', '\'', $fontFamilyName);
// Supprime la fonte si elle existe dans le type inverse
if (is_array($this->getData(['fonts', $typeFlip, $fontId])) ) {
$this->deleteData(['fonts', $typeFlip, $fontId ]);
}
// Stocker les fontes
$this->setData(['fonts',
$type,
$fontId, [
'name' => $fontName,
'font-family' => $fontFamilyName,
'resource' => $ressource
]]);
// Copier la fonte si le nom du fichier est fourni
if ( $type === 'files' &&
file_exists(self::FILE_DIR . 'source/' . $ressource)
) {
copy ( self::FILE_DIR . 'source/' . $ressource, self::DATA_DIR . 'fonts/' . $ressource );
}
// Valeurs en sortie
$this->addOutput([
'notification' => 'La fonte a été actualisée',
'redirect' => helper::baseUrl() . 'theme/fonts',
'state' => true
]);
}
// Valeurs en sortie
$this->addOutput([
'title' => 'Editer une fonte',
'view' => 'fontEdit'
]);
}
/**
* Effacer une fonte
*/
public function fontDelete() {
// Jeton incorrect
if ($this->getUrl(3) !== $_SESSION['csrf']) {
if ($this->getUrl(4) !== $_SESSION['csrf']) {
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'theme/fonts',
@ -673,26 +753,19 @@ class theme extends common {
// Suppression
else {
// Charger les données des fontes
$files = $this->getData(['fonts', 'files']);
$imported = $this->getData(['fonts', 'imported']);
// Effacer la fonte de la base
$this->deleteData(['fonts', $this->getUrl(2), $this->getUrl(3)]);
// Effacer le fichier existant
if ( file_exists(self::DATA_DIR . $files[$this->getUrl(2)]) ) {
unlink(self::DATA_DIR . $files[$this->getUrl(2)]);
if ( $this->getUrl(2) === 'file' &&
file_exists(self::DATA_DIR . $this->getUrl(2)) ) {
unlink(self::DATA_DIR . $this->getUrl(2));
}
// Supprimer les entrées
unset($files[$this->getUrl(2)]);
unset($imported[$this->getUrl(2)]);
// Mettre à jour le fichier des fontes
$this->setData(['fonts', 'files', $files ]);
$this->setData(['fonts', 'imported', $imported ]);
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . 'theme/fonts',
'notification' => 'Fonte supprimée',
'notification' => 'La fonte a été supprimée',
'state' => true
]);
}
@ -782,6 +855,10 @@ class theme extends common {
'state' => true
]);
}
// Lire les fontes installées
$this->enumFonts();
// Toutes les fontes installées sont chargées
$this->setFonts('all');
// Valeurs en sortie
$this->addOutput([
'title' => 'Personnalisation du site',
@ -1002,7 +1079,6 @@ class theme extends common {
$zip->addFile(self::DATA_DIR .'fonts/fonts.html', self::DATA_DIR .'fonts/fonts.html');
}
break;
}
$ret = $zip->close();
@ -1011,7 +1087,8 @@ class theme extends common {
}
/**
* Subsitution des fontes de Google Fonts vers CdnFont grâce à un tableau de conversion
* Substitution des fontes de Google Fonts vers CdnFont grâce à un tableau de conversion
* Cette fonction est utilisée par l'import.
* @param string $file, nom du fichier json à convertir
* @return int nombre de substitution effectuées
*/
@ -1063,4 +1140,103 @@ class theme extends common {
return ($count);
}
// Retourne un tableau simple des fonts installées idfont avec le nom
// Cette fonction est utile aux sélecteurs de fonts dans les formulaires.
public function enumFonts() {
/**
* Récupère la liste des fontes installées et construit deux tableaux
* id - nom
* id - font-family - resource
*/
$f ['files'] = $this->getData(['fonts', 'files']);
$f ['imported'] = $this->getData(['fonts', 'imported']);
$f ['websafe'] = self::$fontsWebSafe;
// Construit un tableau avec leur ID et leur famille
foreach(['websafe', 'imported', 'files'] as $type) {
if (is_array($f[$type])) {
foreach ($f[$type] as $fontId => $fontValue ) {
self::$fonts['name'][$fontId] = $fontValue['name'];
self::$fonts['family'][$fontId] = $fontValue['font-family'];
}
}
}
// Liste des fontes pour les sélecteurs
ksort(self::$fonts['name']);
ksort(self::$fonts['family']);
}
/**
* Création d'un fichier de liens d'appel des fontes
* @param string $scope vaut all pour toutes les fontes ; 'user' pour les fontes utilisateurs
*/
private function setFonts($scope = 'all') {
// Filtrage par fontes installées
$fontsInstalled = [ $this->getData(['theme', 'text', 'font']),
$this->getData(['theme', 'title', 'font']),
$this->getData(['theme', 'header', 'font']),
$this->getData(['theme', 'menu', 'font']),
$this->getData(['theme', 'footer', 'font']),
$this->getData(['admin', 'fontText']),
$this->getData(['admin', 'fontTitle']),
];
// Compression
$fontsInstalled = array_unique($fontsInstalled);
/**
* Chargement des polices en ligne dans un fichier fonts.html inclus dans main.php
*/
$gf = false;
$fileContent = '<!-- Fontes personnalisées -->';
foreach ($this->getData(['fonts', 'imported']) as $fontId => $fontValue) {
if (
( $scope === 'user' && in_array($fontId, $fontsInstalled) )
|| $scope === 'all'
) {
//Pré chargement à revoir
//$fileContent .= '<link rel="preload" href="' . $fontValue['resource'] . '" crossorigin="anonymous" as="style">';
$fileContent .= '<link href="' . $fontValue['resource'] .'" rel="stylesheet">';
// Pré connect pour api.google
$gf = strpos($fontValue['resource'], 'fonts.googleapis.com') === false ? $gf || false : $gf || true;
}
}
// Ajoute le préconnect des fontes Googles.
$fileContent = $gf ? '<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>' . $fileContent
: $fileContent;
/**
* Fontes installées localement
*/
$fileContentCss = '';
foreach ($this->getData(['fonts', 'files']) as $fontId => $fontValue) {
if (
( $scope === 'user' && in_array($fontId, $fontsInstalled) )
|| $scope === 'all'
) {
if (file_exists(self::DATA_DIR . 'fonts/' . $fontValue['resource']) ) {
// Extension
$path_parts = pathinfo(helper::baseUrl(false) . self::DATA_DIR . 'fonts/' . $fontValue['resource']);
// Chargement de la police
$fileContentCss .= '@font-face {' ;
$fileContentCss .= 'font-family:"' . $fontId . '";';
$fileContentCss .= 'src: url("' . $fontValue['resource'] . '") format("' . $path_parts['extension'] . '");';
$fileContentCss .= '}' ;
// Préchargement
//$fileContent = '<link rel="preload" href="' . self::DATA_DIR . 'fonts/' . $fontValue['resource'] . '" type="font/woff" crossorigin="anonymous" as="font">' . $fileContent;
}
}
}
// Enregistre la personnalisation
file_put_contents(self::DATA_DIR.'fonts/fonts.html', $fileContent);
// Enregistre la personnalisation
file_put_contents(self::DATA_DIR.'fonts/fonts.css', $fileContentCss);
}
}

View File

@ -128,10 +128,10 @@
<h4>Mise en forme du texte</h4>
<div class="row">
<div class="col4">
<?php echo template::select('adminFontText', self::$fonts, [
<?php echo template::select('adminFontText', $module::$fonts['name'], [
'label' => 'Police du texte',
'selected' => $this->getData(['admin', 'fontText']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
<div class="col4">
@ -141,10 +141,10 @@
]); ?>
</div>
<div class="col4">
<?php echo template::select('adminFontTitle', self::$fonts, [
<?php echo template::select('adminFontTitle', $module::$fonts['name'], [
'label' => 'Police des titres',
'selected' => $this->getData(['admin', 'fontTitle']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
</div>

View File

@ -15,7 +15,8 @@
*/
$(document).ready(function(){
$('input[name=fontAddFontImported]').prop('checked', true);
$('#fontAddFileWrapper').hide();
$('input[name=fontAddFontUrl]').prop('checked', false);
$('#containerFontAddFile').hide();
});
@ -28,7 +29,8 @@ $("input[name=fontAddFontImported]").on("click", function() {
} else {
$('input[name=fontAddFontFile]').prop('checked', true);
}
$('#fontAddFileWrapper').hide();
$('#containerFontAddFile').hide();
$('#containerFontAddUrl').show();
});
$("input[name=fontAddFontFile]").on("click", function() {
@ -37,5 +39,6 @@ $("input[name=fontAddFontFile]").on("click", function() {
} else {
$('input[name=fontAddFontImported]').prop('checked', true);
}
$('#fontAddFileWrapper').show();
$('#containerFontAddFile').show();
$('#containerFontAddUrl').hide();
});

View File

@ -1,23 +1,21 @@
<?php echo template::formOpen('fontAddForm'); ?>
<div class="row">
<div class="col2">
<div class="col1">
<?php echo template::button('fontAddBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'theme/fonts',
'ico' => 'left',
'value' => 'Retour'
'value' => template::ico('left')
]); ?>
</div>
<div class="col2">
<?php echo template::button('pageEditHelp', [
<div class="col1">
<?php echo template::button('fontAddHelp', [
'href' => 'https://doc.zwiicms.fr/fontes#add',
'target' => '_blank',
'ico' => 'help',
'value' => 'Aide',
'value' => template::ico('help'),
'class' => 'buttonHelp'
]); ?>
</div>
<div class="col2 offset6">
<div class="col2 offset8">
<?php echo template::submit('fontAddPublish', [
'value' => 'Valider',
'uniqueSubmission' => true
@ -30,14 +28,10 @@
<h4>Identité de la fonte</h4>
<div class="row">
<div class="col6">
<?php echo template::checkbox('fontAddFontImported', true, 'Fonte téléchargée sur <a href="https://cdnfonts.com" target="_blank">cdnFonts</a>', [
'help' => 'Police utilisée en ligne, se connecter sur cdnFonts pour récupérer les informations nécessaires.'
]); ?>
<?php echo template::checkbox('fontAddFontImported', true, 'Fonte en ligne', []); ?>
</div>
<div class="col6">
<?php echo template::checkbox('fontAddFontFile', true,'Fonte installée', [
'help' => 'Sélectionnez un fichier de fonte au format WOFF.'
]); ?>
<?php echo template::checkbox('fontAddFontFile', true,'Fonte installée', []); ?>
</div>
</div>
<div class="row">
@ -45,7 +39,7 @@
<?php echo template::text('fontAddFontId', [
'autocomplete' => 'off',
'label' => 'Identifiant (sans espace ni majuscule)',
'placeholder' => 'perry-gothic'
'placeholder' => 'big-marker-extrude'
]); ?>
</div>
@ -58,10 +52,26 @@
</div>
</div>
<div class="row">
<div class="col12">
<?php echo template::text('fontAddFontFamilyName', [
'autocomplete' => 'off',
'label' => 'Famille',
'placeholder' => "'Big Marker Extrude', sans-serif"
]); ?>
</div>
</div>
<div class="row" id="containerFontAddFile">
<div class="col12">
<?php echo template::file('fontAddFile', [
'label' => 'Fichier de police (Format WOFF)',
'placeholder' => 'https://fonts.cdnfonts.com/s/7896/PERRYGOT.woff'
'label' => 'Fichier de fonte (Format WOFF)'
]); ?>
</div>
</div>
<div class="row" id="containerFontAddUrl">
<div class="col12">
<?php echo template::text('fontAddUrl', [
'label' => 'Url du fichier de fonte',
'placeholder' => 'https://fonts.cdnfonts.com/css/big-marker-extrude'
]); ?>
</div>
</div>

View File

@ -0,0 +1,18 @@
/**
* This file is part of Zwii.
*
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @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>
* @copyright Copyright (C) 2018-2022, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/** NE PAS EFFACER
* admin.css
*/

View File

@ -0,0 +1,59 @@
/**
* This file is part of Zwii.
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @author Frédéric Tempez <frederic.tempez@outlook.com>
* @copyright Copyright (C) 2018-2022, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/**
* Option par défaut du sélecteur de mode
*/
$(document).ready(function(){
if( $('input[name=fontEditFontImported]').is(':checked') ){
$('#containerfontEditFile').hide();
$('#containerfontEditUrl').show();
$('#fontEditFontFileWrapper').hide();
$('input[name=fontEditFontImported]').attr('disabled', 'disabled');
}
if( $('input[name=fontEditFontFile]').is(':checked') ){
$('#containerfontEditFile').show();
$('#containerfontEditUrl').hide();
$('#fontEditFontImportedWrapper').hide();
$('input[name=fontEditFontFile]').attr('disabled', 'disabled');
}
});
/**
* Mode téléchargement en ligne de la fonte ou installation locale
$("input, select").on("change", function() {
if( $('input[name=fontEditFontImported]').is(':checked') ){
$('input[name=fontEditFontFile]').prop('checked', false);
$('#containerfontEditFile').hide();
$('#containerfontEditUrl').show();
} else {
}
if( $('input[name=fontEditFontFile]').is(':checked') ){
$('input[name=fontEditFontImported]').prop('checked', false);
$('#containerfontEditFile').show();
$('#containerfontEditUrl').hide();
} else {
$('input[name=fontEditFontImported]').prop('checked', true);
}
});
*/

View File

@ -0,0 +1,85 @@
<?php echo template::formOpen('fontEditForm'); ?>
<div class="row">
<div class="col1">
<?php echo template::button('fontEditBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'theme/fonts',
'value' => template::ico('left')
]); ?>
</div>
<div class="col1">
<?php echo template::button('fontEditHelp', [
'href' => 'https://doc.zwiicms.fr/fontes#add',
'target' => '_blank',
'value' => template::ico('help'),
'class' => 'buttonHelp'
]); ?>
</div>
<div class="col2 offset8">
<?php echo template::submit('fontEditPublish', [
'value' => 'Valider',
'uniqueSubmission' => true
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Identité de la fonte</h4>
<div class="row">
<div class="col6">
<?php echo template::checkbox('fontEditFontImported', true, 'Fonte en ligne', [
'checked' => $this->getUrl(2) === 'imported' ? true : false
]); ?>
</div>
<div class="col6">
<?php echo template::checkbox('fontEditFontFile', true,'Fonte installée', [
'checked' => $this->getUrl(2) === 'files' ? true : false
]); ?>
</div>
</div>
<div class="row">
<div class="col6">
<?php echo template::text('fontEditFontId', [
'autocomplete' => 'off',
'label' => 'Identifiant (sans espace ni majuscule)',
'value' => $this->getUrl(3)
]); ?>
</div>
<div class="col6">
<?php echo template::text('fontEditFontName', [
'autocomplete' => 'off',
'label' => 'Nom',
'value' => $this->getData(['fonts', $this->getUrl(2), $this->getUrl(3), 'name'])
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<?php echo template::text('fontEditFontFamilyName', [
'autocomplete' => 'off',
'label' => 'Famille',
'value' => stripslashes($this->getData(['fonts', $this->getUrl(2), $this->getUrl(3), 'font-family']))
]); ?>
</div>
</div>
<div class="row" id="containerfontEditFile">
<div class="col12">
<?php echo template::file('fontEditFile', [
'label' => 'Fichier de fonte (Format WOFF)',
'value' => $this->getUrl(2) === 'files' ? $this->getData(['fonts', $this->getUrl(2), $this->getUrl(3), 'resource']) : ''
]); ?>
</div>
</div>
<div class="row" id="containerfontEditUrl">
<div class="col12">
<?php echo template::text('fontEditUrl', [
'label' => 'Url du fichier de fonte',
'value' => $this->getUrl(2) === 'imported' ? $this->getData(['fonts', $this->getUrl(2), $this->getUrl(3), 'resource']) : ''
]); ?>
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>

View File

@ -1,22 +1,20 @@
<div class="row">
<div class="col2">
<div class="col1">
<?php echo template::button('themeFontBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'theme',
'ico' => 'left',
'value' => 'Retour'
'value' => template::ico('left')
]); ?>
</div>
<div class="col2">
<div class="col1">
<?php echo template::button('pageEditHelp', [
'href' => 'https://doc.zwiicms.fr/fontes',
'target' => '_blank',
'ico' => 'help',
'value' => 'Aide',
'value' => template::ico('help'),
'class' => 'buttonHelp'
]); ?>
</div>
<div class="col2 offset6">
<div class="col2 offset8">
<?php echo template::button('themeFontAdd', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/fontAdd',
'ico' => 'plus',
@ -24,8 +22,8 @@
]); ?>
</div>
</div>
<?php if($module::$fontsList): ?>
<?php echo template::table([3, 3, 3, 3, 1], $module::$fontsList, ['Family Name', 'Font Id', 'Affectation', 'Ressource', 'Effacer']); ?>
<?php if($module::$fontsDetail): ?>
<?php echo template::table([2, 2, 3, 2, 1, 1, 1], $module::$fontsDetail, ['FontId', 'Nom', 'Famille', 'Affectation', 'Origine', '', '']); ?>
<?php else: ?>
<?php echo template::speech('Aucune fonte !'); ?>
<?php endif; ?>

View File

@ -133,7 +133,7 @@
]); ?>
</div>
<div class="col3">
<?php echo template::select('configLegalPageId', array_merge(['none' => 'Aucune'] , helper::arrayCollumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
<?php echo template::select('configLegalPageId', array_merge(['none' => 'Aucune'] , helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
'label' => 'Page "Mentions légales" ' . template::flag('site', '20px'),
'selected' => $this->getData(['locale', 'legalPageId'])
]); ?>
@ -147,7 +147,7 @@
]); ?>
</div>
<div class="col3">
<?php echo template::select('configSearchPageId', array_merge(['none' => 'Aucune'] , helper::arrayCollumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
<?php echo template::select('configSearchPageId', array_merge(['none' => 'Aucune'] , helper::arrayColumn($module::$pagesList, 'title', 'SORT_ASC') ) , [
'label' => 'Page "Rechercher" ' . template::flag('site', '20px'),
'selected' => $this->getData(['locale', 'searchPageId'])
]); ?>
@ -171,10 +171,10 @@
<h4>Mise en forme du texte</h4>
<div class="row">
<div class="col3">
<?php echo template::select('themeFooterFont', self::$fonts, [
'label' => 'Police',
<?php echo template::select('themeFooterFont', $module::$fonts['name'], [
'label' => 'Fonte',
'selected' => $this->getData(['theme', 'footer', 'font']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
<div class="col3">

View File

@ -47,9 +47,9 @@ $("input, select").on("change", function() {
var tmpImg = new Image();
tmpImg.onload = function() {
// Informations affichées
$("#themeHeaderImageHeight").val(tmpImg.height + " px");
$("#themeHeaderImageWidth").val(tmpImg.width + " px");
$("#themeHeaderImageRatio").val(tmpImg.width / tmpImg.height);
$("#themeHeaderImageHeight").html(tmpImg.height + "px");
$("#themeHeaderImageWidth").html(tmpImg.width + "px");
$("#themeHeaderImageRatio").html(tmpImg.width / tmpImg.height);
// Limiter la hauteur à 600 px
if (tmpImg.height > 600) {
@ -69,6 +69,9 @@ $("input, select").on("change", function() {
$("#themeHeaderHeight option:eq(0)").val(tmpImgHeight + "px");
// Modifier l'option
$("#themeHeaderHeight option:eq(0)").html("Hauteur de l\'image sélectionnée (" + tmpImgHeight + "px)");
$("#themeHeaderImageInfo").show();
} else {
$("#themeHeaderImageInfo").hide();
}
};
@ -207,10 +210,10 @@ $("input, select").on("change", function() {
// Affiche / Cache les options de l'image du fond
$("#themeHeaderImage").on("change", function() {
if($(this).val()) {
$("#themeHeaderImageOptions").slideDown();
$(".themeHeaderImageOptions").slideDown();
}
else {
$("#themeHeaderImageOptions").slideUp(function() {
$(".themeHeaderImageOptions").slideUp(function() {
$("#themeHeaderTextHide").prop("checked", false).trigger("change");
});
}

View File

@ -106,10 +106,10 @@
]); ?>
</div>
<div class="col4">
<?php echo template::select('themeHeaderFont', self::$fonts, [
'label' => 'Police',
<?php echo template::select('themeHeaderFont', $module::$fonts['name'], [
'label' => 'Fonte',
'selected' => $this->getData(['theme', 'header', 'font']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
<div class="col4">
@ -154,40 +154,20 @@
$imageFile = file_exists(self::FILE_DIR.'source/'.$this->getData(['theme', 'header', 'image'])) ?
$this->getData(['theme', 'header', 'image']) : "";
echo template::file('themeHeaderImage', [
'help' => 'Sélectionner une image aux dimensions recommandées ci-dessous :',
'label' => 'Image',
'type' => 1,
'value' => $imageFile
]); ?>
<span class="themeHeaderImageOptions displayNone" id="themeHeaderImageInfo">
Largeur de l'image : <span id="themeHeaderImageWidth"></span> (largeur de site : <?php echo $this->getData(['theme', 'site', 'width']); ?>)
-
Hauteur de l'image : <span id="themeHeaderImageHeight"></span>
-
Ratio : <span id="themeHeaderImageRatio"></span>
</span>
</div>
</div>
<div class="row">
<div class="col3 textAlignRight">
Informations sur l'image :
</div>
<div class="col2">
<?php echo template::text('themeHeaderImageWidth', [
'label' => 'Largeur',
'class' => 'textAlignCenter',
'disable' => true
]); ?>
</div>
<div class="col2">
<?php echo template::text('themeHeaderImageHeight', [
'label' => 'Hauteur',
'class' => 'textAlignCenter',
'disable' => true
]); ?>
</div>
<div class="col2">
<?php echo template::text('themeHeaderImageRatio', [
'label' => 'Ratio (L/H)',
'class' => 'textAlignCenter',
'disable' => true
]); ?>
</div>
</div>
<div id="themeHeaderImageOptions" class="displayNone">
<div class="themeHeaderImageOptions" class="displayNone">
<div class="row">
<div class="col3">
<?php echo template::select('themeHeaderImageRepeat', $module::$repeats, [

View File

@ -15,7 +15,7 @@
</div>
<div class="col2">
<?php echo template::button('themeHelp', [
'href' => 'https://doc.zwiicms.fr/theme-2',
'href' => 'https://doc.zwiicms.fr/gestion-du-theme',
'target' => '_blank',
'ico' => 'help',
'value' => 'Aide',
@ -73,7 +73,7 @@
</div>
<div class="col2">
<?php echo template::button('themeHelp', [
'href' => 'https://doc.zwiicms.fr/theme-2',
'href' => 'https://doc.zwiicms.fr/gestion-du-theme',
'target' => '_blank',
'ico' => 'help',
'value' => 'Aide',

View File

@ -183,10 +183,10 @@
<h4>Mise en forme du texte</h4>
<div class="row">
<div class="col6">
<?php echo template::select('themeMenuFont', self::$fonts, [
'label' => 'Police',
<?php echo template::select('themeMenuFont', $module::$fonts['name'], [
'label' => 'Fonte',
'selected' => $this->getData(['theme', 'menu', 'font']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
<div class="col6">

View File

@ -11,8 +11,6 @@
* @link http://zwiicms.fr/
*/
/**
* Aperçu en direct
*/
@ -28,21 +26,19 @@ $("input, select").on("change",function() {
$("#themeSiteMarginWrapper").show();
}
/**
* Aperçu dans la boîte
*/
// Import des polices de caractères
// Import des polices de caractères pour l'aperçu en temps réel
var titleFont = $("#themeTitleFont :selected").val();
var titleFontText = $("#themeTitleFont :selected").text();
var textFont = $("#themeTextFont :selected").val();
var textFontText = $("#themeTextFont :selected").text();
console.log(textFontText);
var css = "@import url('https://fonts.cdnfonts.com/css/" + titleFont + "');";
var css = "@import url('https://fonts.cdnfonts.com/css/" + textFont + "');";
// Couleurs des boutons
var colors = core.colorVariants($("#themeButtonBackgroundColor").val());
css += ".button.buttonSubmitPreview{background-color:" + colors.normal + ";}";
var css = ".button.buttonSubmitPreview{background-color:" + colors.normal + ";}";
css += ".button.buttonSubmitPreview:hover{background-color:" + colors.darken + "}";
css += ".button.buttonSubmitPreview{color:" + colors.text + ";}";
@ -114,5 +110,4 @@ $("input, select").on("change",function() {
.attr("id", "themePreview")
.text(css)
.appendTo("head");
}).trigger("change");

View File

@ -141,7 +141,8 @@
<div class="row">
<div class="col12">
<div class="block preview">
<h4 class="preview">Bloc</h4> <p class="textPreview">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<h4 class="preview">Bloc</h4>
<p class="textPreview">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p><a href="#" class="urlPreview">Lorem ipsum dolor sit amet.</a></p>
</div>
</div>
@ -158,10 +159,11 @@
<h4>Mise en forme du texte</h4>
<div class="row">
<div class="col6">
<?php echo template::select('themeTextFont', self::$fonts, [
'label' => 'Police',
<?php
echo template::select('themeTextFont', $module::$fonts['name'], [
'label' => 'Fonte',
'selected' => $this->getData(['theme', 'text', 'font']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
<div class="col6">
@ -179,10 +181,10 @@
<h4>Mise en forme des titres</h4>
<div class="row">
<div class="col4">
<?php echo template::select('themeTitleFont', self::$fonts, [
'label' => 'Police',
<?php echo template::select('themeTitleFont', $module::$fonts['name'] , [
'label' => 'Fonte',
'selected' => $this->getData(['theme', 'title', 'font']),
'fonts' => true
'fonts' => $module::$fonts['family']
]); ?>
</div>
<div class="col4">

View File

@ -336,7 +336,7 @@ class user extends common {
* Liste des utilisateurs
*/
public function index() {
$userIdsFirstnames = helper::arrayCollumn($this->getData(['user']), 'firstname');
$userIdsFirstnames = helper::arrayColumn($this->getData(['user']), 'firstname');
ksort($userIdsFirstnames);
foreach($userIdsFirstnames as $userId => $userFirstname) {
if ($this->getData(['user', $userId, 'group'])) {
@ -397,7 +397,7 @@ class user extends common {
]
]);
// Verrouillage des IP
$ipBlackList = helper::arrayCollumn($this->getData(['blacklist']), 'ip');
$ipBlackList = helper::arrayColumn($this->getData(['blacklist']), 'ip');
if ( $this->getData(['blacklist',$userId,'connectFail']) >= $this->getData(['config', 'connect', 'attempt'])
AND in_array($this->getData(['blacklist',$userId,'ip']),$ipBlackList) ) {
$logStatus = 'Compte inconnu verrouillé';

View File

@ -3,8 +3,8 @@ $version = "9.14.0";
if (session_id() == '') session_start();
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
mb_http_input('UTF-8');
mb_http_output();
mb_http_input();
mb_language('uni');
if (function_exists('mb_regex_encoding')) {
mb_regex_encoding('UTF-8');

View File

@ -114,7 +114,7 @@ tinymce.init({
// Active l'onglet avancé lors de l'ajout d'une image
image_advtab: true,
// Urls absolues
relative_urls: false,
relative_urls: true,
// Url de base
document_base_url: baseUrl,
// Gestionnaire de fichiers
@ -294,7 +294,7 @@ tinymce.init({
// Active l'onglet avancé lors de l'ajout d'une image
image_advtab: true,
// Urls absolues
relative_urls: false,
relative_urls: true,
// Url de base
document_base_url: baseUrl,
// Contenu du bouton formats

View File

@ -140,8 +140,8 @@ class blog extends common {
$feeds->setDate(date('r',time()));
$feeds->addGenerator();
// Corps des articles
$articleIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'posts']), 'state', 'SORT_DESC');
$articleIdsPublishedOns = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayColumn($this->getData(['module', $this->getUrl(0),'posts']), 'state', 'SORT_DESC');
foreach( $articleIdsPublishedOns as $articleId => $articlePublishedOn ) {
if( $articlePublishedOn <= time() AND $articleIdsStates[$articleId] ) {
// Miniature
@ -230,7 +230,7 @@ class blog extends common {
]);
}
// Liste des utilisateurs
self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname');
self::$users = helper::arrayColumn($this->getData(['user']), 'firstname');
ksort(self::$users);
foreach(self::$users as $userId => &$userFirstname) {
$userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']);
@ -259,7 +259,7 @@ class blog extends common {
'value' => 'Tout effacer'
]);
// Ids des commentaires par ordre de création
$commentIds = array_keys(helper::arrayCollumn($comments, 'createdOn', 'SORT_DESC'));
$commentIds = array_keys(helper::arrayColumn($comments, 'createdOn', 'SORT_DESC'));
// Pagination
$pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) );
// Liste des pages
@ -416,7 +416,7 @@ class blog extends common {
]);
} else {
// Ids des articles par ordre de publication
$articleIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'));
$articleIds = array_keys(helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'));
// Gestion des droits d'accès
$filterData=[];
foreach ($articleIds as $key => $value) {
@ -448,7 +448,7 @@ class blog extends common {
// Articles en fonction de la pagination
for($i = $pagination['first']; $i < $pagination['last']; $i++) {
// Nombre de commentaires à approuver et approuvés
$approvals = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'comment' ]),'approval', 'SORT_DESC');
$approvals = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'comment' ]),'approval', 'SORT_DESC');
if ( is_array($approvals) ) {
$a = array_values($approvals);
$toApprove = count(array_keys($a,false));
@ -595,7 +595,7 @@ class blog extends common {
]);
}
// Liste des utilisateurs
self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname');
self::$users = helper::arrayColumn($this->getData(['user']), 'firstname');
ksort(self::$users);
foreach(self::$users as $userId => &$userFirstname) {
// Les membres ne sont pas éditeurs, les exclure de la liste
@ -709,7 +709,7 @@ class blog extends common {
// Ligne suivante si affichage du nombre total de commentaires approuvés sous l'article
self::$nbCommentsApproved = count($commentsApproved);
}
$commentIds = array_keys(helper::arrayCollumn($commentsApproved, 'createdOn', 'SORT_DESC'));
$commentIds = array_keys(helper::arrayColumn($commentsApproved, 'createdOn', 'SORT_DESC'));
// Pagination
$pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']),'#comment');
// Liste des pages
@ -749,8 +749,8 @@ class blog extends common {
// Liste des articles
else {
// Ids des articles par ordre de publication
$articleIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC');
$articleIdsPublishedOns = helper::arrayColumn($this->getData(['module', $this->getUrl(0),'posts']), 'publishedOn', 'SORT_DESC');
$articleIdsStates = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC');
$articleIds = [];
foreach($articleIdsPublishedOns as $articleId => $articlePublishedOn) {
if($articlePublishedOn <= time() AND $articleIdsStates[$articleId]) {

View File

@ -20,7 +20,7 @@
<div class="col2">
<?php echo template::submit('blogEditSubmit', [
'value' => 'Publier',
'uniqueSubmission' => true,
'uniqueSubmission' => true
]); ?>
</div>
</div>
@ -39,7 +39,7 @@
<div class="row">
<div class="col6">
<?php echo template::file('blogEditPicture', [
'help' => 'Taille optimale de l\'image de couverture : ' . ((int) substr($this->getData(['theme', 'site', 'width']), 0, -2) - (20 * 2)) . ' x 350 pixels.',
'help' => $this->getData(['theme', 'site', 'width']) !== '100%' ? 'Taille optimale de l\'image de couverture : ' . ((int) substr($this->getData(['theme', 'site', 'width']), 0, -2) - (20 * 2)) . ' x 350 pixels.' : '',
'label' => 'Image de couverture',
'type' => 1,
'value' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(2), 'picture'])

View File

@ -80,7 +80,7 @@ class form extends common {
*/
public function config() {
// Liste des utilisateurs
$userIdsFirstnames = helper::arrayCollumn($this->getData(['user']), 'firstname');
$userIdsFirstnames = helper::arrayColumn($this->getData(['user']), 'firstname');
ksort($userIdsFirstnames);
self::$listUsers [] = '';
foreach($userIdsFirstnames as $userId => $userFirstname) {

View File

@ -69,7 +69,7 @@ function position() {
var inputUid = 0;
var inputs = <?php echo json_encode($this->getData(['module', $this->getUrl(0), 'input'])); ?>;
if(inputs) {
var inputsPerPosition = <?php echo json_encode(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'input']), 'position', 'SORT_ASC')); ?>;
var inputsPerPosition = <?php echo json_encode(helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'input']), 'position', 'SORT_ASC')); ?>;
$.each(inputsPerPosition, function(id) {
add(inputUid, inputs[id]);
inputUid++;

View File

@ -17,7 +17,7 @@
class gallery extends common {
const VERSION = '3.4';
const VERSION = '3.5';
const REALNAME = 'Galerie';
const DELETE = true;
const UPDATE = '0.0';
@ -51,7 +51,9 @@ class gallery extends common {
'sortGalleries' => self::GROUP_MODERATOR,
'sortPictures' => self::GROUP_MODERATOR,
'edit' => self::GROUP_MODERATOR,
'add' => self::GROUP_MODERATOR,
'theme' => self::GROUP_MODERATOR,
'option' => self::GROUP_MODERATOR,
'index' => self::GROUP_VISITOR
];
@ -151,7 +153,6 @@ class gallery extends common {
*/
private function update() {
// Initialisation du module, créer les données si elles sont manquantes.
$this->init();
@ -264,7 +265,7 @@ class gallery extends common {
*
*/
public function sortGalleries() {
if($_POST['response']) {
if( isset($_POST['response']) ){
$data = explode('&',$_POST['response']);
$data = str_replace('galleryTable%5B%5D=','',$data);
for($i=0;$i<count($data);$i++) {
@ -275,7 +276,8 @@ class gallery extends common {
'homePicture' => $this->getData(['module',$this->getUrl(0), 'content', $data[$i],'config','homePicture']),
'sort' => $this->getData(['module',$this->getUrl(0), 'content', $data[$i],'config','sort']),
'position'=> $i,
'fullScreen' => $this->getData(['module',$this->getUrl(0), 'content',$data[$i],'config','fullScreen'])
'fullScreen' => $this->getData(['module',$this->getUrl(0), 'content',$data[$i],'config','fullScreen']),
'showPageContent' => $this->getData(['module',$this->getUrl(0), 'content',$data[$i],'config','showPageContent'])
],
'legend' => $this->getData(['module',$this->getUrl(0), 'content', $data[$i],'legend']),
@ -290,22 +292,22 @@ class gallery extends common {
*
*/
public function sortPictures() {
if($_POST['response']) {
if( isset($_POST['response']) ) {
$galleryName = $_POST['gallery'];
$data = explode('&',$_POST['response']);
$data = str_replace('galleryTable%5B%5D=','',$data);
// Sauvegarder
$this->setData(['module', $this->getUrl(0), 'content', $galleryName, [
'config' => [
'name' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','name']),
'directory' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','directory']),
'homePicture' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','homePicture']),
'sort' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','sort']),
'position' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','position']),
'fullScreen' => $this->getData(['module',$this->getUrl(0),$galleryName,'config','fullScreen'])
'name' => $this->getData(['module',$this->getUrl(0), 'content', $galleryName,'config','name']),
'directory' => $this->getData(['module',$this->getUrl(0),'content',$galleryName,'config','directory']),
'homePicture' => $this->getData(['module',$this->getUrl(0),'content',$galleryName,'config','homePicture']),
'sort' => $this->getData(['module',$this->getUrl(0),'content',$galleryName,'config','sort']),
'position' => $this->getData(['module',$this->getUrl(0),'content',$galleryName,'config','position']),
'fullScreen' => $this->getData(['module',$this->getUrl(0),'content',$galleryName,'config','fullScreen'])
],
'legend' => $this->getData(['module',$this->getUrl(0),$galleryName,'legend']),
'legend' => $this->getData(['module',$this->getUrl(0), 'content', $galleryName,'legend']),
'positions' => array_flip($data)
]]);
}
@ -322,7 +324,7 @@ class gallery extends common {
//Affichage de la galerie triée
$g = $this->getData(['module', $this->getUrl(0), 'content']);
$p = helper::arrayCollumn(helper::arrayCollumn($g,'config'),'position');
$p = helper::arrayColumn(helper::arrayColumn($g,'config'),'position');
asort($p,SORT_NUMERIC);
$galleries = [];
foreach ($p as $positionId => $item) {
@ -343,7 +345,7 @@ class gallery extends common {
}
// Met en forme le tableau
self::$galleries[] = [
template::ico('sort'),
$gallery['config']['position'] + 1,
$gallery['config']['name'],
$gallery['config']['directory'],
template::button('galleryConfigEdit' . $galleryId , [
@ -385,9 +387,10 @@ class gallery extends common {
'name' => $this->getInput('galleryConfigName'),
'directory' => $this->getInput('galleryConfigDirectory', helper::FILTER_STRING_SHORT, true),
'homePicture' => $homePicture,
'sort' => self::SORT_ASC,
'position' => $this->getData(['module', $this->getUrl(0), 'content', $galleryId,'config','position']),
'fullScreen' => false
'sort' => $this->getInput('galleryConfigSort'),
'position' => count($this->getData(['module', $this->getUrl(0), 'content'])) + 1,
'fullScreen' => $this->getInput('galleryConfigFullscreen', helper::FILTER_BOOLEAN),
'showPageContent' => $this->getInput('galleryConfigShowPageContent', helper::FILTER_BOOLEAN)
],
'legend' => [],
'positions' => []
@ -410,6 +413,58 @@ class gallery extends common {
]);
}
/**
* Ajout d'une galerie
*/
public function add() {
// Soumission du formulaire d'ajout d'une galerie
if($this->isPost()) {
if (!$this->getInput('galleryAddFilterResponse')) {
$galleryId = helper::increment($this->getInput('galleryAddName', helper::FILTER_ID, true), (array) $this->getData(['module', $this->getUrl(0), 'content']));
// définir une vignette par défaut
$directory = $this->getInput('galleryAddDirectory', helper::FILTER_STRING_SHORT, true);
$iterator = new DirectoryIterator($directory);
foreach($iterator as $fileInfos) {
if($fileInfos->isDot() === false AND $fileInfos->isFile() AND @getimagesize($fileInfos->getPathname())) {
// Créer la miniature si manquante
if (!file_exists( str_replace('source','thumb',$fileInfos->getPath()) . '/' . self::THUMBS_SEPARATOR . strtolower($fileInfos->getFilename()))) {
$this->makeThumb($fileInfos->getPathname(),
str_replace('source','thumb',$fileInfos->getPath()) . '/' . self::THUMBS_SEPARATOR . strtolower($fileInfos->getFilename()),
self::THUMBS_WIDTH);
}
// Miniatures
$homePicture = strtolower($fileInfos->getFilename());
break;
}
}
$this->setData(['module', $this->getUrl(0), 'content', $galleryId, [
'config' => [
'name' => $this->getInput('galleryAddName'),
'directory' => $this->getInput('galleryAddDirectory', helper::FILTER_STRING_SHORT, true),
'homePicture' => $homePicture,
'sort' => $this->getInput('galleryAddSort'),
'position' => count($this->getData(['module', $this->getUrl(0), 'content'])) + 1,
'fullScreen' => $this->getInput('galleryAddFullscreen', helper::FILTER_BOOLEAN),
'showPageContent' => $this->getInput('galleryAddShowPageContent', helper::FILTER_BOOLEAN)
],
'legend' => [],
'positions' => []
]]);
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', // '#galleryAddForm'*/,
'notification' => 'Modifications enregistrées',
'state' => true
]);
}
} else {
// Valeurs en sortie
$this->addOutput([
'title' => 'Ajout d\'une galerie',
'view' => 'add'
]);
}
}
/**
* Suppression
*/
@ -510,11 +565,12 @@ class gallery extends common {
// pas de positions, on active le tri alpha
'sort' => $this->getInput('galleryEditSort'),
'position' => $this->getData(['module', $this->getUrl(0), 'content', $galleryId,'config','position']),
'fullScreen' => $this->getInput('galleryEditFullscreen', helper::FILTER_BOOLEAN)
'fullScreen' => $this->getInput('galleryEditFullscreen', helper::FILTER_BOOLEAN),
'showPageContent' => $this->getInput('galleryEditShowPageContent', helper::FILTER_BOOLEAN)
],
'legend' => $legends,
'positions' => empty($oldPositions) ? $this->getdata(['module', $this->getUrl(0), 'content', $galleryId, 'positions']) : $oldPositions
'positions' => empty($oldPositions) ? $this->getData(['module', $this->getUrl(0), 'content', $galleryId, 'positions']) : $oldPositions
]]);
}
// Valeurs en sortie
@ -528,7 +584,6 @@ class gallery extends common {
$directory = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'directory']);
if(is_dir($directory)) {
$iterator = new DirectoryIterator($directory);
foreach($iterator as $fileInfos) {
if($fileInfos->isDot() === false AND $fileInfos->isFile() AND @getimagesize($fileInfos->getPathname())) {
// Créer la miniature RFM si manquante
@ -538,7 +593,7 @@ class gallery extends common {
122);
}
self::$pictures[str_replace('.','',$fileInfos->getFilename())] = [
template::ico('sort'),
$this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'positions', str_replace('.','',$fileInfos->getFilename())]) + 1,
$fileInfos->getFilename(),
template::checkbox( 'homePicture[' . $fileInfos->getFilename() . ']', true, '', [
'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2),'config', 'homePicture']) === $fileInfos->getFilename() ? true : false,
@ -555,7 +610,7 @@ class gallery extends common {
// Tri des images
switch ($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'sort'])) {
case self::SORT_HAND:
$positions = $this->getdata(['module',$this->getUrl(0), $this->getUrl(2),'positions']);
$positions = $this->getData(['module',$this->getUrl(0),'content', $this->getUrl(2),'positions']);
if ($positions) {
foreach ($positions as $key => $value) {
if (array_key_exists($key,self::$pictures)) {
@ -603,7 +658,8 @@ class gallery extends common {
// Mise à jour des données de module
$this->update();
// Une seule galerie, bifurquer sur celle-ci
$gallery = count($this->getData(['module', $this->getUrl(0), 'content'])) === 1
$gallery = $this->getData(['module', $this->getUrl(0), 'theme', 'showUniqueGallery']) === true &&
count($this->getData(['module', $this->getUrl(0), 'content'])) === 1
? array_key_first($this->getData(['module', $this->getUrl(0), 'content']))
: $this->getUrl(1);
// Images d'une galerie
@ -669,7 +725,8 @@ class gallery extends common {
'showBarEditButton' => true,
'title' => $this->getData(['module', $this->getUrl(0), 'content', $gallery, 'config', 'name']),
'view' => 'gallery',
'style' => $this->getData(['module', $this->getUrl(0), 'theme', 'style'])
'style' => $this->getData(['module', $this->getUrl(0), 'theme', 'style']),
'showPageContent' => $this->getData(['module', $this->getUrl(0), 'content', $gallery, 'config', 'showPageContent']),
]);
}
// Pas d'image dans la galerie
@ -686,7 +743,7 @@ class gallery extends common {
else {
// Tri des galeries suivant l'ordre défini
$g = $this->getData(['module', $this->getUrl(0), 'content']);
$p = helper::arrayCollumn(helper::arrayCollumn($g,'config'),'position');
$p = helper::arrayColumn(helper::arrayColumn($g,'config'),'position');
asort($p,SORT_NUMERIC);
$galleries = [];
foreach ($p as $positionId => $item) {
@ -732,7 +789,9 @@ class gallery extends common {
'showBarEditButton' => true,
'showPageContent' => true,
'view' => 'index',
'style' => $this->getData(['module', $this->getUrl(0), 'theme', 'style'])
'style' => file_exists($this->getData(['module', $this->getUrl(0), 'theme', 'style']))
? $this->getData(['module', $this->getUrl(0), 'theme', 'style'])
: ''
]);
}
}
@ -770,7 +829,8 @@ class gallery extends common {
'legendAlign' => $this->getinput('galleryThemeLegendAlign', helper::FILTER_STRING_SHORT),
'legendTextColor' => $this->getinput('galleryThemeLegendTextColor', helper::FILTER_STRING_SHORT),
'legendBgColor' => $this->getinput('galleryThemeLegendBgColor', helper::FILTER_STRING_SHORT),
'style' => self::DATADIRECTORY . $this->getUrl(0) . '/theme.css'
'showUniqueGallery' => $this->getinput('galleryThemeShowUniqueGallery', helper::FILTER_BOOLEAN),
'style' => self::DATADIRECTORY . $this->getUrl(0) . '/theme.css',
]]);
// Création des fichiers CSS
$content = file_get_contents('module/gallery/ressource/vartheme.css');
@ -808,6 +868,41 @@ class gallery extends common {
]);
}
/**
* Option de configuration de la galerie
*/
public function option() {
// Jeton incorrect
if ($this->getUrl(2) !== $_SESSION['csrf']) {
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config',
'notification' => 'Action non autorisée'
]);
}
// Soumission du formulaire
if($this->isPost()) {
// Dossier de l'instance
if (!is_dir(self::DATADIRECTORY . $this->getUrl(0) )) {
mkdir (self::DATADIRECTORY . $this->getUrl(0), 0755, true);
}
$this->setData(['module', $this->getUrl(0), 'config', [
'showUniqueGallery' => $this->getinput('galleriesOptionShowUniqueGallery', helper::FILTER_BOOLEAN)
]]);
// Valeurs en sortie
$this->addOutput([
'redirect' => helper::baseUrl() . $this->getUrl() . '/option',
'notification' => 'Modifications enregistrées',
'state' => true
]);
}
// Valeurs en sortie
$this->addOutput([
'title' => "Options",
'view' => 'option'
]);
}
}
class galleriesHelper extends helper {

View File

@ -0,0 +1,22 @@
Copyright (c) Denis Howlett <denish@isocra.com>
Copyright 2012 Nick Lombard - nickl- and other contributors
https://github.com/isocra/TableDnD
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1 +1,2 @@
https://github.com/isocra/TableDnD
Version 1.0.5

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,19 @@
/**
* This file is part of Zwii.
*
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @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>
* @copyright Copyright (C) 2018-2022, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/** NE PAS EFFACER
* admin.css
*/

View File

@ -0,0 +1,87 @@
/**
* This file is part of Zwii.
*
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @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>
* @copyright Copyright (C) 2018-2022, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
$( document ).ready(function() {
/**
* Tri de la galerie avec drag and drop
*/
$("#galleryTable").tableDnD({
onDrop: function(table, row) {
$("#galleryAddFilterResponse").val($.tableDnD.serialize());
},
onDragStop : function(table, row) {
// Affiche le bouton de tri après un déplacement
//$(":input[type='submit']").prop('disabled', false);
// Sauvegarde le tri
sortGalleries();
},
// Supprime le tiret des séparateurs
serializeRegexp: ""
});
/**
* Confirmation de suppression
*/
$(".galleryAddDelete").on("click", function() {
var _this = $(this);
return core.confirm("Êtes-vous sûr de vouloir supprimer cette galerie ?", function() {
$(location).attr("href", _this.attr("href"));
});
});
});
/**
* Liste des dossiers
*/
var oldResult = [];
var directoryDOM = $("#galleryAddDirectory");
var directoryOldDOM = $("#galleryAddDirectoryOld");
function dirs() {
$.ajax({
type: "POST",
url: "<?php echo helper::baseUrl() . $this->getUrl(0); ?>/dirs",
success: function(result) {
if($(result).not(oldResult).length !== 0 || $(oldResult).not(result).length !== 0) {
directoryDOM.empty();
for(var i = 0; i < result.length; i++) {
directoryDOM.append(function(i) {
var option = $("<option>").val(result[i]).text(result[i]);
if(directoryOldDOM.val() === result[i]) {
option.prop("selected", true);
}
return option;
}(i))
}
oldResult = result;
}
}
});
}
dirs();
// Actualise la liste des dossiers toutes les trois secondes
setInterval(function() {
dirs();
}, 3000);
/**
* Stock le dossier choisi pour le re-sélectionner en cas d'actualisation ajax de la liste des dossiers
*/
directoryDOM.on("change", function() {
directoryOldDOM.val($(this).val());
});

View File

@ -0,0 +1,68 @@
<?php echo template::formOpen('galleryAddForm'); ?>
<div class="row">
<div class="col2">
<?php echo template::button('galleryAddBack', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/config' ,
'ico' => 'left',
'value' => 'Retour'
]); ?>
</div>
<div class="col2 offset8">
<?php echo template::submit('galleryAddSubmit', [
'ico' => 'plus',
'value' => ' Ajouter',
'class' => 'gallerySubmit'
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Ajouter une galerie</h4>
<div class="row">
<div class="col6">
<?php echo template::text('galleryAddName', [
'label' => 'Nom'
]); ?>
</div>
<div class="col5">
<?php echo template::hidden('galleryAddDirectoryOld', [
'noDirty' => true // Désactivé à cause des modifications en ajax
]); ?>
<?php echo template::select('galleryAddDirectory', [], [
'label' => 'Dossier cible',
'noDirty' => true // Désactivé à cause des modifications en ajax
]); ?>
</div>
</div>
<div class="row">
<div class="col3">
<?php echo template::select('galleryAddSort', $module::$sort, [
'selected' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'sort']),
'label' => 'Tri des images',
'help' => 'Tri manuel : déplacez le images dans le tableau ci-dessous. L\'ordre est sauvegardé automatiquement.'
]); ?>
</div>
<div class="col7 verticalAlignBottom">
<div class="row">
<div class="col12">
<?php echo template::checkbox('galleryAddFullscreen', true, 'Mode plein écran automatique' , [
'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'fullScreen']),
'help' => 'A l\'ouverture de la galerie, la première image est affichée en plein écran.'
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<?php echo template::checkbox('galleryAddShowPageContent', true, 'Afficher le contenu de la page avec la galerie' , [
'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'showPageContent']),
'help' => 'Le contenu de la page est toujours affiché dans la liste des galeries. Quand une seule galerie est disponible, il est possible de l\'afficher directement, cette option est utile dans ce cas précis.'
]); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>

View File

@ -21,69 +21,12 @@ $( document ).ready(function() {
$("#galleryTable").tableDnD({
onDrop: function(table, row) {
$("#galleryConfigFilterResponse").val($.tableDnD.serialize());
},
onDragStop : function(table, row) {
// Affiche le bouton de tri après un déplacement
//$(":input[type='submit']").prop('disabled', false);
// Sauvegarde le tri
sortGalleries();
location.reload();
},
// Supprime le tiret des séparateurs
serializeRegexp: ""
});
/**
* Confirmation de suppression
*/
$(".galleryConfigDelete").on("click", function() {
var _this = $(this);
return core.confirm("Êtes-vous sûr de vouloir supprimer cette galerie ?", function() {
$(location).attr("href", _this.attr("href"));
});
});
});
/**
* Liste des dossiers
*/
var oldResult = [];
var directoryDOM = $("#galleryConfigDirectory");
var directoryOldDOM = $("#galleryConfigDirectoryOld");
function dirs() {
$.ajax({
type: "POST",
url: "<?php echo helper::baseUrl() . $this->getUrl(0); ?>/dirs",
success: function(result) {
if($(result).not(oldResult).length !== 0 || $(oldResult).not(result).length !== 0) {
directoryDOM.empty();
for(var i = 0; i < result.length; i++) {
directoryDOM.append(function(i) {
var option = $("<option>").val(result[i]).text(result[i]);
if(directoryOldDOM.val() === result[i]) {
option.prop("selected", true);
}
return option;
}(i))
}
oldResult = result;
}
}
});
}
dirs();
// Actualise la liste des dossiers toutes les trois secondes
setInterval(function() {
dirs();
}, 3000);
/**
* Stock le dossier choisi pour le re-sélectionner en cas d'actualisation ajax de la liste des dossiers
*/
directoryDOM.on("change", function() {
directoryOldDOM.val($(this).val());
});

View File

@ -1,57 +1,36 @@
<?php echo template::formOpen('galleryConfigForm'); ?>
<div class="row">
<div class="row">
<div class="col2">
<?php echo template::button('galleryConfigBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0),
'ico' => 'left',
'value' => 'Retour'
]); ?>
</div>
<div class="col2 offset8">
<?php echo template::button('galleryConfigBack', [
<div class="col1 offset7">
<?php echo template::button('galleryConfigOption', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/option/' . $_SESSION['csrf'],
'value' => template::ico('sliders')
]); ?>
</div>
<div class="col1">
<?php echo template::button('galleryConfigTheme', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/theme/' . $_SESSION['csrf'],
'value' => template::ico('brush','right') . 'Thème'
'value' => template::ico('brush')
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Ajouter une galerie</h4>
<div class="row">
<div class="col6">
<?php echo template::text('galleryConfigName', [
'label' => 'Nom'
<div class="col1">
<?php echo template::button('galleryAdd', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/add/',
'value' => template::ico('plus')
]); ?>
</div>
<div class="col5">
<?php echo template::hidden('galleryConfigDirectoryOld', [
'noDirty' => true // Désactivé à cause des modifications en ajax
]); ?>
<?php echo template::select('galleryConfigDirectory', [], [
'label' => 'Dossier cible',
'noDirty' => true // Désactivé à cause des modifications en ajax
]); ?>
</div>
<div class="col1 verticalAlignBottom">
<?php echo template::submit('galleryConfigSubmit', [
'ico' => '',
'value' => template::ico('plus'),
'class' => 'gallerySubmit'
]); ?>
</div>
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>
<div class="row">
<div class="col12">
<div class="block">
<h4>Galeries installées</h4>
<?php if($module::$galleries): ?>
<?php echo template::table([1, 4, 5, 1, 1], $module::$galleries, ['','Nom', 'Dossier cible', '', ''], ['id' => 'galleryTable'],$module::$galleriesId); ?>
<?php echo template::table([1, 4, 5, 1, 1], $module::$galleries, ['#','Nom', 'Dossier cible', '', ''], ['id' => 'galleryTable'],$module::$galleriesId); ?>
<?php echo template::hidden('galleryConfigFilterResponse'); ?>
<?php else: ?>
<?php echo template::speech('Aucune galerie.'); ?>

View File

@ -65,11 +65,7 @@ $( document ).ready(function() {
$("#galleryTable").tableDnD({
onDrop: function(table, row) {
$("#galleryEditFormResponse").val($.tableDnD.serialize());
},
onDragStop : function(table, row) {
// Sauvegarde le tri
sortPictures();
$("#galleryEditFormResponse").val("");
},
serializeRegexp: ""
});
@ -103,16 +99,20 @@ $("#galleryEditSort").change(function() {
*/
function sortPictures() {
var url = "<?php echo helper::baseUrl() . $this->getUrl(0); ?>/sortPictures";
var url = "<?php echo helper::baseUrl(true,true) . $this->getUrl(0); ?>/sortPictures";
var d1 = $("#galleryEditFormResponse").val();
var d2 = $("#galleryEditFormGalleryName").val();
//var data = $('#galleryEditForm').serialize();
$.ajax({
type: "POST",
url: url ,
data: {
response : d1,
gallery: d2
},/*
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
*/
});
}

View File

@ -2,7 +2,6 @@
<div class="row">
<div class="col2">
<?php echo template::button('galleryEditBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . $this->getUrl(0) . '/config',
'ico' => 'left',
'value' => 'Retour'
@ -15,15 +14,15 @@
<div class="row">
<div class="col12">
<div class="block">
<h4>Paramètre des images</h4>
<h4>Paramètres de la galerie</h4>
<div class="row">
<div class="col5">
<div class="col6">
<?php echo template::text('galleryEditName', [
'label' => 'Nom',
'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'name'])
]); ?>
</div>
<div class="col4">
<div class="col6">
<?php echo template::hidden('galleryEditDirectoryOld', [
'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'directory']),
'noDirty' => true // Désactivé à cause des modifications en ajax
@ -33,6 +32,8 @@
'noDirty' => true // Désactivé à cause des modifications en ajax
]); ?>
</div>
</div>
<div class="row">
<div class="col3">
<?php echo template::select('galleryEditSort', $module::$sort, [
'selected' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'sort']),
@ -40,7 +41,8 @@
'help' => 'Tri manuel : déplacez le images dans le tableau ci-dessous. L\'ordre est sauvegardé automatiquement.'
]); ?>
</div>
<div clas="row">
<div class="col7 verticalAlignBottom">
<div class="row">
<div class="col12">
<?php echo template::checkbox('galleryEditFullscreen', true, 'Mode plein écran automatique' , [
'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'fullScreen']),
@ -48,10 +50,21 @@
]); ?>
</div>
</div>
<div class="row">
<div class="col12">
<?php echo template::checkbox('galleryEditShowPageContent', true, 'Afficher le contenu de la page avec la galerie' , [
'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'showPageContent']),
'help' => 'Le contenu de la page est toujours affiché dans la liste des galeries. Quand une seule galerie est disponible, il est possible de l\'afficher directement, cette option est utile dans ce cas précis.'
]); ?>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col12">
<?php if($module::$pictures): ?>
<?php echo template::table([1, 4, 1, 5, 1], $module::$pictures, ['','Image', 'Couverture','Légende',''],['id' => 'galleryTable'], $module::$picturesId ); ?>
<?php echo template::table([1, 4, 1, 5, 1], $module::$pictures, ['#','Image', 'Couverture','Légende',''],['id' => 'galleryTable'], $module::$picturesId ); ?>
<?php echo template::hidden('galleryEditFormResponse'); ?>
<?php echo template::hidden('galleryEditFormGalleryName',['value' => $this->getUrl(2)]); ?>
<?php else: ?>
@ -61,8 +74,6 @@
</div>
</div>
</div>
</div>
<div class="moduleVersion">Version
<?php echo $module::VERSION; ?>
</div>

View File

@ -1,16 +1,3 @@
<?php if ( $module::$config['mono'] !== true): ?>
<div class="row">
<div class="col2">
<?php echo template::button('galleryGalleryBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . $this->getUrl(0),
'ico' => 'left',
'value' => 'Retour'
]); ?>
</div>
</div>
<?php endif; ?>
<div id="pictureContainer" class="row galleryRow <?php echo ($module::$config['fullScreen']);?> ">
<?php foreach($module::$pictures as $picture => $legend): ?>
<div class="colPicture">
@ -28,3 +15,14 @@
</div>
<?php endforeach; ?>
</div>
<?php if ( $module::$config['mono'] !== true): ?>
<div class="row">
<div class="col2">
<?php echo template::button('galleryGalleryBack', [
'href' => helper::baseUrl() . $this->getUrl(0),
'ico' => 'left',
'value' => ''
]); ?>
</div>
</div>
<?php endif; ?>

View File

@ -0,0 +1,39 @@
<?php echo template::formOpen('galleriesOptionForm'); ?>
<div class="row">
<div class="col2">
<?php echo template::button('galleriesOptionBack', [
'href' => helper::baseUrl() . $this->getUrl(0) . '/config',
'ico' => 'left',
'value' => 'Retour'
]); ?>
</div>
<div class="col2 offset8">
<?php echo template::submit('galleriesOptionSubmit'); ?>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Galerie unique</h4>
<div class="row">
<div class="col12 verticalAlignBottom">
<?php echo template::checkbox('galleriesOptionShowUniqueGallery', true, 'Masquer l\'index des galeries lorsque le module ne contient qu\'une galerie' , [
'checked' => count($this->getData(['module', $this->getUrl(0), 'content'])) === 1
? $this->getData(['module', $this->getUrl(0), 'theme', 'showUniqueGallery'])
: false,
'disabled' => count($this->getData(['module', $this->getUrl(0), 'content'])) > 1,
'help' => 'Cette option est active lorsque le module ne contient qu\'une seule galerie, elle permet d\'éviter la page listant toutes les galeries et affiche directement la galerie'
]); ?>
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>
<div class="row">
<div class="col12">
<div class="moduleVersion">Version
<?php echo $module::VERSION; ?>
</div>
</div>
</div>

View File

@ -0,0 +1,18 @@
/**
* This file is part of Zwii.
*
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @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>
* @copyright Copyright (C) 2018-2022, Frédéric Tempez
* @license GNU General Public License, version 3
* @link http://zwiicms.fr/
*/
/** NE PAS EFFACER
* admin.css
*/

View File

@ -1,9 +1,7 @@
<?php echo template::formOpen('galleryThemeForm'); ?>
<div class="row">
<div class="row">
<div class="col2">
<?php echo template::button('galleryThemeBack', [
'class' => 'buttonGrey',
'href' => helper::baseUrl() . $this->getUrl(0) . '/config',
'ico' => 'left',
'value' => 'Retour'
@ -12,8 +10,8 @@
<div class="col2 offset8">
<?php echo template::submit('galleryThemeBack'); ?>
</div>
</div>
<div class="row">
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Vignettes
@ -93,8 +91,8 @@
</div>
</div>
</div>
</div>
<div class="row">
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Légendes
@ -133,8 +131,7 @@
</div>
</div>
</div>
</div>
</div>
<?php echo template::formClose(); ?>
<div class="row">
<div class="col12">

View File

@ -112,8 +112,8 @@ class news extends common {
$feeds->setDate(date('r',time()));
$feeds->addGenerator();
// Corps des articles
$newsIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC');
$newsIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC');
$newsIdsPublishedOns = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC');
$newsIdsStates = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC');
foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) {
if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) {
$newsArticle = $feeds->createNewItem();
@ -164,7 +164,7 @@ class news extends common {
]);
}
// Liste des utilisateurs
self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname');
self::$users = helper::arrayColumn($this->getData(['user']), 'firstname');
ksort(self::$users);
foreach(self::$users as $userId => &$userFirstname) {
$userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']);
@ -234,7 +234,7 @@ class news extends common {
]);
} else {
// Ids des news par ordre de publication
$newsIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'));
$newsIds = array_keys(helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'));
// Pagination
$pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) );
// Liste des pages
@ -367,7 +367,7 @@ class news extends common {
]);
}
// Liste des utilisateurs
self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname');
self::$users = helper::arrayColumn($this->getData(['user']), 'firstname');
ksort(self::$users);
foreach(self::$users as $userId => &$userFirstname) {
$userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']);
@ -420,8 +420,8 @@ class news extends common {
} else {
// Affichage index
// Ids des news par ordre de publication
$newsIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC');
$newsIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC');
$newsIdsPublishedOns = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC');
$newsIdsStates = helper::arrayColumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC');
$newsIds = [];
foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) {
$newsIdsPublishedOff = $this->getData(['module', $this->getUrl(0), 'posts', $newsId, 'publishedOff']);