From c2c67b55ffb037096977ea01f3fdc39d6e5f4cf2 Mon Sep 17 00:00:00 2001 From: fredtempez Date: Mon, 5 Apr 2021 08:59:24 +0200 Subject: [PATCH] Modules de v11 --- module/blog/blog.php | 47 +- module/blog/view/config/config.php | 8 + module/download/download.php | 978 ++++++++++++++++ module/download/ressource/feed-icon-16.gif | Bin 0 -> 652 bytes module/download/vendor/FeedWriter/ATOM.php | 38 + module/download/vendor/FeedWriter/Feed.php | 1017 +++++++++++++++++ .../FeedWriter/InvalidOperationException.php | 33 + module/download/vendor/FeedWriter/Item.php | 413 +++++++ module/download/vendor/FeedWriter/README.md | 42 + module/download/vendor/FeedWriter/RSS1.php | 37 + module/download/vendor/FeedWriter/RSS2.php | 37 + module/download/view/add/add.css | 18 + module/download/view/add/add.js.php | 54 + module/download/view/add/add.php | 139 +++ module/download/view/comment/comment.css | 18 + module/download/view/comment/comment.js.php | 62 + module/download/view/comment/comment.php | 22 + module/download/view/config/config.css | 18 + module/download/view/config/config.js.php | 21 + module/download/view/config/config.php | 60 + module/download/view/edit/edit.css | 18 + module/download/view/edit/edit.js.php | 66 ++ module/download/view/edit/edit.php | 159 +++ module/download/view/index/index.css | 69 ++ module/download/view/item/item.css | 63 + module/download/view/item/item.js.php | 43 + module/download/view/list/list.php | 1 + module/download/view/rss/rss.php | 1 + module/download/view/stats/stats.css | 18 + module/download/view/stats/stats.js.php | 22 + module/download/view/stats/stats.php | 36 + module/gallery/gallery.php | 162 ++- module/gallery/ressource/defaultdata.php | 3 +- module/gallery/view/edit/edit.php | 8 +- module/gallery/view/theme/theme.php | 28 +- module/news/news.php | 151 ++- module/news/view/article/article.css | 20 + module/news/view/config/config.php | 54 +- module/news/view/index/index.css | 42 +- module/news/view/index/index.php | 35 +- module/search/ressource/defaultdata.php | 3 +- module/search/search.php | 150 ++- module/search/view/config/config.php | 10 +- module/search/view/index/index.php | 2 +- 44 files changed, 4061 insertions(+), 165 deletions(-) create mode 100644 module/download/download.php create mode 100644 module/download/ressource/feed-icon-16.gif create mode 100644 module/download/vendor/FeedWriter/ATOM.php create mode 100644 module/download/vendor/FeedWriter/Feed.php create mode 100644 module/download/vendor/FeedWriter/InvalidOperationException.php create mode 100644 module/download/vendor/FeedWriter/Item.php create mode 100644 module/download/vendor/FeedWriter/README.md create mode 100644 module/download/vendor/FeedWriter/RSS1.php create mode 100644 module/download/vendor/FeedWriter/RSS2.php create mode 100644 module/download/view/add/add.css create mode 100644 module/download/view/add/add.js.php create mode 100644 module/download/view/add/add.php create mode 100644 module/download/view/comment/comment.css create mode 100644 module/download/view/comment/comment.js.php create mode 100644 module/download/view/comment/comment.php create mode 100644 module/download/view/config/config.css create mode 100644 module/download/view/config/config.js.php create mode 100644 module/download/view/config/config.php create mode 100644 module/download/view/edit/edit.css create mode 100644 module/download/view/edit/edit.js.php create mode 100644 module/download/view/edit/edit.php create mode 100644 module/download/view/index/index.css create mode 100644 module/download/view/item/item.css create mode 100644 module/download/view/item/item.js.php create mode 100644 module/download/view/list/list.php create mode 100644 module/download/view/rss/rss.php create mode 100644 module/download/view/stats/stats.css create mode 100644 module/download/view/stats/stats.js.php create mode 100644 module/download/view/stats/stats.php create mode 100644 module/news/view/article/article.css diff --git a/module/blog/blog.php b/module/blog/blog.php index 7e2b2b30..a4d68c3d 100755 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -15,7 +15,7 @@ class blog extends common { - const VERSION = '4.5'; + const VERSION = '5.0'; const REALNAME = 'Blog'; const DELETE = true; const UPDATE = '0.0'; @@ -75,6 +75,15 @@ class blog extends common { 'right' => 'À droite ', ]; + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + //Paramètre longueur maximale des commentaires en nb de caractères public static $commentLength = [ '500' => '500', @@ -94,7 +103,23 @@ class blog extends common { public static $users = []; - /** + + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Version 5.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '5.0', '<') ) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 6]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','5.0']); + } + } + + + + /** * Flux RSS */ public function rss() { @@ -192,7 +217,7 @@ class blog extends common { 'commentApproved' => $this->getInput('blogAddCommentApproved', helper::FILTER_BOOLEAN), 'commentClose' => $this->getInput('blogAddCommentClose', helper::FILTER_BOOLEAN), 'commentNotification' => $this->getInput('blogAddCommentNotification', helper::FILTER_BOOLEAN), - 'commentGroupNotification' => $this->getInput('blogAddCommentGroupNotification', helper::FILTER_INT) + 'commentGroupNotification' => $this->getInput('blogAddCommentGroupNotification', helper::FILTER_INT), ] ]); // Valeurs en sortie @@ -234,7 +259,7 @@ class blog extends common { // Ids des commentaires par ordre de création $commentIds = array_keys(helper::arrayCollumn($comments, 'createdOn', 'SORT_DESC')); // Pagination - $pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) ); // Liste des pages self::$pages = $pagination['pages']; // Commentaires en fonction de la pagination @@ -371,11 +396,15 @@ class blog extends common { * Configuration */ public function config() { + // Mise à jour des données de module + $this->update(); // Soumission du formulaire if($this->isPost()) { $this->setData(['module', $this->getUrl(0), 'config',[ 'feeds' => $this->getInput('blogConfigShowFeeds',helper::FILTER_BOOLEAN), - 'feedsLabel' => $this->getInput('blogConfigFeedslabel',helper::FILTER_STRING_SHORT) + 'feedsLabel' => $this->getInput('blogConfigFeedslabel',helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('blogConfigItemsperPage', helper::FILTER_INT,true), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) ]]); // Valeurs en sortie $this->addOutput([ @@ -411,7 +440,7 @@ class blog extends common { } $articleIds = $filterData; // Pagination - $pagination = helper::pagination($articleIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($articleIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); // Liste des pages self::$pages = $pagination['pages']; // Articles en fonction de la pagination @@ -590,6 +619,8 @@ class blog extends common { * Accueil (deux affichages en un pour éviter une url à rallonge) */ public function index() { + // Mise à jour des données de module + $this->update(); // Affichage d'un article if( $this->getUrl(1) @@ -678,7 +709,7 @@ class blog extends common { } $commentIds = array_keys(helper::arrayCollumn($commentsApproved, 'createdOn', 'SORT_DESC')); // Pagination - $pagination = helper::pagination($commentIds, $this->getUrl(),$this->getData(['config','itemsperPage']),'#comment'); + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']),'#comment'); // Liste des pages self::$pages = $pagination['pages']; // Signature de l'article @@ -725,7 +756,7 @@ class blog extends common { } } // Pagination - $pagination = helper::pagination($articleIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($articleIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); // Liste des pages self::$pages = $pagination['pages']; // Articles en fonction de la pagination diff --git a/module/blog/view/config/config.php b/module/blog/view/config/config.php index fee5671a..736151c9 100755 --- a/module/blog/view/config/config.php +++ b/module/blog/view/config/config.php @@ -36,6 +36,14 @@ ]); ?> +
+
+ 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
+
diff --git a/module/download/download.php b/module/download/download.php new file mode 100644 index 00000000..7dd08a7c --- /dev/null +++ b/module/download/download.php @@ -0,0 +1,978 @@ + + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +class download extends common { + + const VERSION = '1.2'; + const REALNAME = 'Téléchargement'; + const DELETE = true; + const UPDATE = '0.0'; + const DATADIRECTORY = []; // Contenu localisé inclus par défaut (page.json et module.json) + + // Constantes du module + const EDIT_OWNER = 'owner'; + const EDIT_GROUP = 'group'; + const EDIT_ALL = 'all'; + + public static $actions = [ + 'add' => self::GROUP_MODERATOR, + 'comment' => self::GROUP_MODERATOR, + 'commentApprove' => self::GROUP_MODERATOR, + 'commentDelete' => self::GROUP_MODERATOR, + 'commentDeleteAll' => self::GROUP_MODERATOR, + 'config' => self::GROUP_MODERATOR, + 'delete' => self::GROUP_MODERATOR, + 'edit' => self::GROUP_MODERATOR, + 'stats' => self::GROUP_MODERATOR, + 'statsDeleteAll' => self::GROUP_MODERATOR, + 'index' => self::GROUP_VISITOR, + 'rss' => self::GROUP_VISITOR, + 'downloadFile' => self::GROUP_VISITOR, + 'list' =>self::GROUP_VISITOR + ]; + + public static $items = []; + + // Signature de l'item + public static $itemSignature = ''; + + // Signature du commentaire + public static $editCommentSignature = ''; + + public static $comments = []; + + public static $nbCommentsApproved = 0; + + public static $commentsDelete; + + // Signatures des commentaires déjà saisis + public static $commentsSignature = []; + + public static $pages; + + // Nombre de téléchargements + public static $statSum = 0; + + public static $states = [ + false => 'Brouillon', + true => 'Publié' + ]; + + public static $pictureSizes = [ + '20' => 'Très petite', + '30' => 'Petite', + '40' => 'Grande', + '50' => 'Très Grande', + '100' => 'Pleine largeur', + ]; + + public static $picturePositions = [ + 'left' => 'À gauche', + 'right' => 'À droite ', + ]; + + //Paramètre longueur maximale des commentaires en nb de caractères + public static $commentLength = [ + '500' => '500', + '1000' => '1000', + '2000' => '2000', + '5000' => '5000', + '10000' => '10000' + ]; + + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + + // Permissions d'un item + public static $itemConsent = [ + self::EDIT_ALL => 'Tous les groupes', + self::EDIT_GROUP => 'Groupe du propriétaire', + self::EDIT_OWNER => 'Propriétaire' + ]; + + + public static $itemLicense = [ + 'none'=> 'Non définie', + 'cc' => 'Licence libre Creative Common, partage autorisé', + 'gnu' => 'Licence libre GNU, partage autorisé', + 'mit' => 'Licence libre MIT, partage autorisé', + 'owner' => 'Licence Propriétaire' + ]; + + public static $users = []; + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Version 5.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '1.1', '<') ) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 6]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','1.2']); + } + } + + /** + * Flux RSS + */ + public function rss() { + // Inclure les classes + include_once 'module/news/vendor/FeedWriter/Item.php'; + include_once 'module/news/vendor/FeedWriter/Feed.php'; + include_once 'module/news/vendor/FeedWriter/RSS2.php'; + include_once 'module/news/vendor/FeedWriter/InvalidOperationException.php'; + + date_default_timezone_set('UTC'); + $feeds = new \FeedWriter\RSS2(); + + // En-tête + $feeds->setTitle($this->getData (['page', $this->getUrl(0), 'title'])); + $feeds->setLink(helper::baseUrl() . $this->getUrl(0)); + $feeds->setDescription($this->getData (['page', $this->getUrl(0), 'metaDescription'])); + $feeds->setChannelElement('language', 'fr-FR'); + $feeds->setDate(date('r',time())); + $feeds->addGenerator(); + // Corps des items + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'items']), 'state', 'SORT_DESC'); + foreach($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if($itemPublishedOn <= time() AND $itemIdsStates[$itemId]) { + // Miniature + $parts = explode('/',$this->getData(['module', $this->getUrl(0), 'items', $itemId, 'picture'])); + $thumb = str_replace ($parts[(count($parts)-1)],'mini_' . $parts[(count($parts)-1)], $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'picture'])); + // Créer les items du flux + $newsitem = $feeds->createNewItem(); + // Signature de l'item + $author = $this->signature($this->getData(['module', $this->getUrl(0), 'items', $itemId, 'userId'])); + $newsitem->addElementArray([ + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'title']), + 'link' => helper::baseUrl() .$this->getUrl(0) . '/' . $itemId, + 'description' => '' . $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'title'])
+									 . '' . + $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'content']), + ]); + $newsitem->setAuthor($author,'no@mail.com'); + $newsitem->setId(helper::baseUrl() .$this->getUrl(0) . '/' . $itemId); + $newsitem->setDate(date('r', $this->getData(['module', $this->getUrl(0), 'items', $itemId, 'publishedOn']))); + $imageData = getimagesize(helper::baseUrl(false) . self::FILE_DIR . 'thumb/' . $thumb); + $newsitem->addEnclosure( helper::baseUrl(false) . self::FILE_DIR . 'thumb/' . $thumb, + $imageData[0] * $imageData[1], + $imageData['mime'] + ); + $feeds->addItem($newsitem); + } + } + + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RSS, + 'content' => $feeds->generateFeed(), + 'view' => 'rss' + ]); + } + + /** + * Édition + */ + public function add() { + // Soumission du formulaire + if($this->isPost()) { + // Modification de l'userId + if($this->getUser('group') === self::GROUP_ADMIN){ + $newuserid = $this->getInput('downloadAddUserId', helper::FILTER_STRING_SHORT, true); + } + else{ + $newuserid = $this->getUser('id'); + } + // Incrémente l'id de l'item + $itemId = helper::increment($this->getInput('downloadAddTitle', helper::FILTER_ID), $this->getData(['page'])); + $itemId = helper::increment($itemId, (array) $this->getData(['module', $this->getUrl(0)])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + // Crée l'item + $this->setData(['module', + $this->getUrl(0), + 'items', + $itemId, [ + 'comment' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment']), + 'content' => $this->getInput('downloadAddContent', null), + 'picture' => $this->getInput('downloadAddPicture', helper::FILTER_STRING_SHORT, true), + 'file' => $this->getInput('downloadAddFile', helper::FILTER_STRING_SHORT, true), + 'fileVersion' => $this->getInput('downloadAddFileVersion', helper::FILTER_STRING_SHORT, true), + 'fileDate' => $this->getInput('downloadAddFileDate', helper::FILTER_DATETIME, true), + 'fileLicense' => $this->getInput('downloadAddFileLicense', helper::FILTER_STRING_SHORT, true), + 'fileAuthor' => $this->getInput('downloadAddFileAuthor', helper::FILTER_STRING_SHORT, true), + 'fileStats' => [], + 'publishedOn' => $this->getInput('downloadAddPublishedOn', helper::FILTER_DATETIME, true), + 'state' => $this->getInput('downloadAddState', helper::FILTER_BOOLEAN), + 'title' => $this->getInput('downloadAddTitle', helper::FILTER_STRING_SHORT, true), + 'userId' => $newuserid, + 'editConsent' => $this->getInput('downloadAddConsent') === self::EDIT_GROUP ? $this->getUser('group') : $this->getInput('downloadAddConsent'), + 'commentMaxlength' => $this->getInput('downloadAddCommentMaxlength'), + 'commentApproved' => $this->getInput('downloadAddCommentApproved', helper::FILTER_BOOLEAN), + 'commentClose' => $this->getInput('downloadAddCommentClose', helper::FILTER_BOOLEAN), + 'commentNotification' => $this->getInput('downloadAddCommentNotification', helper::FILTER_BOOLEAN), + 'commentGroupNotification' => $this->getInput('downloadAddCommentGroupNotification', helper::FILTER_INT) + ] + ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Nouvel item créé', + 'state' => true + ]); + } + // Liste des utilisateurs + self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname'); + ksort(self::$users); + foreach(self::$users as $userId => &$userFirstname) { + $userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']); + } + unset($userFirstname); + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Nouvel item', + 'vendor' => [ + 'flatpickr', + 'tinymce' + ], + 'view' => 'add' + ]); + } + + /** + * Liste des commentaires + */ + public function comment() { + $comments = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2),'comment']); + self::$commentsDelete = template::button('downloadCommentDeleteAll', [ + 'class' => 'downloadCommentDeleteAll buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentDeleteAll/' . $this->getUrl(2).'/' . $_SESSION['csrf'] , + 'ico' => 'cancel', + 'value' => 'Tout effacer' + ]); + // Ids des commentaires par ordre de création + $commentIds = array_keys(helper::arrayCollumn($comments, 'createdOn', 'SORT_DESC')); + // Pagination + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // Commentaires en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Met en forme le tableau + $comment = $comments[$commentIds[$i]]; + // Bouton d'approbation + $buttonApproval = ''; + // Compatibilité avec les commentaires des versions précédentes, les valider + $comment['approval'] = array_key_exists('approval', $comment) === false ? true : $comment['approval'] ; + if ( $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2),'commentApproved']) === true) { + $buttonApproval = template::button('downloadCommentApproved' . $commentIds[$i], [ + 'class' => $comment['approval'] === true ? 'downloadCommentRejected buttonGreen' : 'downloadCommentApproved buttonRed' , + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentApprove/' . $this->getUrl(2) . '/' . $commentIds[$i] . '/' . $_SESSION['csrf'] , + 'value' => $comment['approval'] === true ? 'A' : 'R' + ]); + } + self::$comments[] = [ + mb_detect_encoding(strftime('%d %B %Y - %H:%M', $comment['createdOn']), 'UTF-8', true) + ? strftime('%d %B %Y - %H:%M', $comment['createdOn']) + : utf8_encode(strftime('%d %B %Y - %H:%M', $comment['createdOn'])), + $comment['content'], + $comment['userId'] ? $this->getData(['user', $comment['userId'], 'firstname']) . ' ' . $this->getData(['user', $comment['userId'], 'lastname']) : $comment['author'], + $buttonApproval, + template::button('downloadCommentDelete' . $commentIds[$i], [ + 'class' => 'downloadCommentDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/commentDelete/' . $this->getUrl(2) . '/' . $commentIds[$i] . '/' . $_SESSION['csrf'] , + 'value' => template::ico('cancel') + ]) + ]; + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Gestion des commentaires : '. $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'title']), + 'view' => 'comment' + ]); + } + + /** + * Suppression de commentaire + */ + public function commentDelete() { + // Le commentaire n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment/'.$this->getUrl(2), + 'notification' => 'Commentaire supprimé', + 'state' => true + ]); + } + } + + /** + * Suppression de tous les commentaires de l'item $this->getUrl(2) + */ + public function commentDeleteAll() { + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Suppression + else { + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment',[] ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment', + 'notification' => 'Commentaires supprimés', + 'state' => true + ]); + } + } + + /** + * Approbation oou désapprobation de commentaire + */ + public function commentApprove() { + // Le commentaire n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(4) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Inversion du statut + else { + $approved = !$this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'approval']) ; + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), [ + 'author' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'author']), + 'content' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'content']), + 'createdOn' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'createdOn']), + 'userId' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment', $this->getUrl(3), 'userId']), + 'approval' => $approved + ]]); + + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/comment/'.$this->getUrl(2), + 'notification' => $approved ? 'Commentaire approuvé' : 'Commentaire rejeté', + 'state' => $approved + ]); + } + } + + /** + * Configuration + */ + public function config() { + // Mise à jour des données de module + $this->update(); + // Soumission du formulaire + if($this->isPost()) { + $this->setData(['module', $this->getUrl(0), 'config',[ + 'feeds' => $this->getInput('downloadConfigShowFeeds',helper::FILTER_BOOLEAN), + 'feedsLabel' => $this->getInput('downloadConfigFeedslabel',helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('blogConfigItemsperPage', helper::FILTER_INT,true), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) + ]]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } else { + // Ids des items par ordre de publication + $itemIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'publishedOn', 'SORT_DESC')); + // Gestion des droits d'accès + $filterData=[]; + foreach ($itemIds as $key => $value) { + if ( + ( // Propriétaire + $this->getData(['module', $this->getUrl(0), 'items', $value,'editConsent']) === self::EDIT_OWNER + AND ( $this->getData(['module', $this->getUrl(0), 'items', $value,'userId']) === $this->getUser('id') + OR $this->getUser('group') === self::GROUP_ADMIN ) + ) + + OR ( + // Groupe + $this->getData(['module', $this->getUrl(0), 'items', $value,'editConsent']) !== self::EDIT_OWNER + AND $this->getUser('group') >= $this->getData(['module',$this->getUrl(0), 'items', $value,'editConsent']) + ) + OR ( + // Tout le monde + $this->getData(['module', $this->getUrl(0), 'items', $value,'editConsent']) === self::EDIT_ALL + ) + ) { + $filterData[] = $value; + } + } + $itemIds = $filterData; + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // items 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), 'items', $itemIds[$i], 'comment' ]),'approval', 'SORT_DESC'); + if ( is_array($approvals) ) { + $a = array_values($approvals); + $toApprove = count(array_keys($a,false)); + $approved = count(array_keys($a,true)); + } else { + $toApprove = 0; + $approved = count($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i],'comment'])); + } + // Met en forme le tableau + $date = mb_detect_encoding(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])), 'UTF-8', true) + ? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])) + : utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate']))); + $heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])), 'UTF-8', true) + ? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate'])) + : utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileDate']))); + $stat = count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i],'fileStats']), 'time') ) === 0 + ? '0' + : '' . + count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i],'fileStats']), 'time') ) . + ''; + self::$items[] = [ + '' . + $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'title']) . + '', + $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'fileVersion']), + $date .' à '. $heure, + $stat, + self::$states[$this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i], 'state'])], + // Bouton pour afficher les commentaires de l'item + template::button('downloadConfigComment' . $itemIds[$i], [ + 'class' => ($toApprove || $approved ) > 0 ? 'buttonBlue' : 'buttonGrey' , + 'href' => ($toApprove || $approved ) > 0 ? helper::baseUrl() . $this->getUrl(0) . '/comment/' . $itemIds[$i] : '', + 'value' => $toApprove > 0 ? $toApprove . '/' . $approved : $approved + ]), + template::button('downloadConfigEdit' . $itemIds[$i], [ + 'href' => helper::baseUrl() . $this->getUrl(0) . '/edit/' . $itemIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('pencil') + ]), + template::button('downloadConfigDelete' . $itemIds[$i], [ + 'class' => 'downloadConfigDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/delete/' . $itemIds[$i] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]) + ]; + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration du module', + 'view' => 'config' + ]); + } + } + + /** + * Suppression + */ + public function delete() { + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // Suppression + else { + $this->deleteData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Item supprimé', + 'state' => true + ]); + } + } + + /** + * Édition + */ + public function edit() { + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Action non autorisée' + ]); + } + // L'item n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // L'item existe + else { + // Soumission du formulaire + if($this->isPost()) { + if($this->getUser('group') === self::GROUP_ADMIN){ + $newuserid = $this->getInput('downloadEditUserId', helper::FILTER_STRING_SHORT, true); + } + else{ + $newuserid = $this->getUser('id'); + } + $itemId = $this->getInput('downloadEditTitle', helper::FILTER_ID, true); + // Incrémente le nouvel id de l'item + if($itemId !== $this->getUrl(2)) { + $itemId = helper::increment($itemId, $this->getData(['page'])); + $itemId = helper::increment($itemId, $this->getData(['module', $this->getUrl(0),'items'])); + $itemId = helper::increment($itemId, array_keys(self::$actions)); + } + $this->setData(['module', + $this->getUrl(0), + 'items', + $itemId, [ + 'comment' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'comment']), + 'content' => $this->getInput('downloadEditContent', null), + 'picture' => $this->getInput('downloadEditPicture', helper::FILTER_STRING_SHORT, true), + 'file' => $this->getInput('downloadEditFile', helper::FILTER_STRING_SHORT, true), + 'fileVersion' => $this->getInput('downloadEditFileVersion', helper::FILTER_STRING_SHORT, true), + 'fileDate' => $this->getInput('downloadEditFileDate', helper::FILTER_DATETIME, true), + 'fileStats' => $this->getData(['module',$this->getUrl(0), 'items', $this->getUrl(2), 'fileStats']), + 'fileLicense' => $this->getInput('downloadEditFileLicense', helper::FILTER_STRING_SHORT, true), + 'fileAuthor' => $this->getInput('downloadEditFileAuthor', helper::FILTER_STRING_SHORT, true), + 'publishedOn' => $this->getInput('downloadEditPublishedOn', helper::FILTER_DATETIME, true), + 'state' => $this->getInput('downloadEditState', helper::FILTER_BOOLEAN), + 'title' => $this->getInput('downloadEditTitle', helper::FILTER_STRING_SHORT, true), + 'userId' => $newuserid, + 'editConsent' => $this->getInput('downloadEditConsent') === self::EDIT_GROUP ? $this->getUser('group') : $this->getInput('downloadEditConsent'), + 'commentMaxlength' => $this->getInput('downloadEditCommentMaxlength'), + 'commentApproved' => $this->getInput('downloadEditCommentApproved', helper::FILTER_BOOLEAN), + 'commentClose' => $this->getInput('downloadEditCommentClose', helper::FILTER_BOOLEAN), + 'commentNotification' => $this->getInput('downloadEditCommentNotification', helper::FILTER_BOOLEAN), + 'commentGroupNotification' => $this->getInput('downloadEditCommentGroupNotification', helper::FILTER_INT) + ] + ]); + // Supprime l'ancien item + if($itemId !== $this->getUrl(2)) { + $this->deleteData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]); + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'notification' => 'Modifications enregistrées', + 'state' => true + ]); + } + // Liste des utilisateurs + self::$users = helper::arrayCollumn($this->getData(['user']), 'firstname'); + ksort(self::$users); + foreach(self::$users as $userId => &$userFirstname) { + // Les membres ne sont pas éditeurs, les exclure de la liste + if ( $this->getData(['user', $userId, 'group']) < self::GROUP_MODERATOR) { + unset(self::$users[$userId]); + } + $userFirstname = $userFirstname . ' ' . $this->getData(['user', $userId, 'lastname']) . ' (' . self::$groupEdits[$this->getData(['user', $userId, 'group'])] . ')'; + } + unset($userFirstname); + // Valeurs en sortie + $this->addOutput([ + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'title']), + 'vendor' => [ + 'flatpickr', + 'tinymce' + ], + 'view' => 'edit' + ]); + } + } + + /** + * Accueil (deux affichages en un pour éviter une url à rallonge) + */ + public function index() { + // Mise à jour des données de module + $this->update(); + // Affichage d'un item + if( + $this->getUrl(1) + // Protection pour la pagination, un ID ne peut pas être un entier, une page oui + AND intval($this->getUrl(1)) === 0 + ) { + // L'item n'existe pas + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // L'item existe + else { + // Soumission du formulaire + if($this->isPost()) { + // Check la captcha + if( + $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') + //AND $this->getInput('downloaditemcaptcha', helper::FILTER_INT) !== $this->getInput('downloaditemcaptchaFirstNumber', helper::FILTER_INT) + $this->getInput('downloaditemcaptchaSecondNumber', helper::FILTER_INT)) + AND password_verify($this->getInput('downloadItemCaptcha', helper::FILTER_INT), $this->getInput('downloadItemCaptchaResult') ) === false ) + { + self::$inputNotices['downloadItemCaptcha'] = 'Incorrect'; + } + // Crée le commentaire + $commentId = helper::increment(uniqid(), $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment'])); + $content = $this->getInput('downloadItemContent', false); + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentId, [ + 'author' => $this->getInput('downloadItemAuthor', helper::FILTER_STRING_SHORT, empty($this->getInput('downloadItemUserId')) ? TRUE : FALSE), + 'content' => $content, + 'createdOn' => time(), + 'userId' => $this->getInput('downloadItemUserId'), + 'approval' => !$this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentApproved']) // true commentaire publié false en attente de publication + ]]); + // Envoi d'une notification aux administrateurs + // Init tableau + $to = []; + // Liste des destinataires + foreach($this->getData(['user']) as $userId => $user) { + if ($user['group'] >= $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentGroupNotification']) ) { + $to[] = $user['mail']; + $firstname[] = $user['firstname']; + $lastname[] = $user['lastname']; + } + } + // Envoi du mail $sent code d'erreur ou de réussite + $notification = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentApproved']) === true ? 'Commentaire déposé en attente d\'approbation': 'Commentaire déposé'; + if ($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'commentNotification']) === true) { + $error = 0; + foreach($to as $key => $adress){ + $sent = $this->sendMail( + $adress, + 'Nouveau commentaire déposé', + 'Bonjour' . ' ' . $firstname[$key] . ' ' . $lastname[$key] . ',

' . + 'L\'item ' . $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'title']) . ' a reçu un nouveau commentaire.

', + '' + ); + if( $sent === false) $error++; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl() . '#comment', + 'notification' => ($error === 0 ? $notification . '
Une notification a été envoyée.' : $notification . '
Erreur de notification : ' . $sent), + 'state' => ($sent === true ? true : null) + ]); + + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl() . '#comment', + 'notification' => $notification, + 'state' => true + ]); + } + + } + // Ids des commentaires approuvés par ordre de publication + $commentsApproved = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment']); + if ($commentsApproved) { + foreach( $commentsApproved as $key => $value){ + if($value['approval']===false) unset($commentsApproved[$key]); + } + // Ligne suivante si affichage du nombre total de commentaires approuvés sous l'item + self::$nbCommentsApproved = count($commentsApproved); + } + $commentIds = array_keys(helper::arrayCollumn($commentsApproved, 'createdOn', 'SORT_DESC')); + // Pagination + $pagination = helper::pagination($commentIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']),'#comment'); + // Nombre de téléchargements + self::$statSum = count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items',$this->getUrl(1),'fileStats']), 'time') ) === 0 + ? '0' + : count(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1),'fileStats']), 'time') ) ; + // Liste des pages + self::$pages = $pagination['pages']; + // Signature de l'item + self::$itemSignature = $this->signature($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'userId'])); + // Signature du commentaire édité + if($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD')) { + self::$editCommentSignature = $this->signature($this->getUser('id')); + } + // Commentaires en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + // Signatures des commentaires + $e = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i],'userId']); + if ($e) { + self::$commentsSignature[$commentIds[$i]] = $this->signature($e); + } else { + self::$commentsSignature[$commentIds[$i]] = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i],'author']); + } + // Données du commentaire si approuvé + if ($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i],'approval']) === true ) { + self::$comments[$commentIds[$i]] = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'comment', $commentIds[$i]]); + } + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(1), 'title']), + 'vendor' => [ + 'tinymce' + ], + 'view' => 'item' + ]); + } + + } + // Liste des items + else { + // Ids des items par ordre de publication + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'items']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'state', 'SORT_DESC'); + $itemIds = []; + foreach($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if($itemPublishedOn <= time() AND $itemIdsStates[$itemId]) { + $itemIds[] = $itemId; + } + } + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Liste des pages + self::$pages = $pagination['pages']; + // Items en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + self::$items[$itemIds[$i]] = $this->getData(['module', $this->getUrl(0), 'items', $itemIds[$i]]); + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'showPageContent' => true, + 'view' => 'index' + ]); + } + } + + /** + * Retourne la signature d'un utilisateur + */ + private function signature($userId) { + switch ($this->getData(['user', $userId, 'signature'])){ + case 1: + return $userId; + break; + case 2: + return $this->getData(['user', $userId, 'pseudo']); + break; + case 3: + return $this->getData(['user', $userId, 'firstname']) . ' ' . $this->getData(['user', $userId, 'lastname']); + break; + case 4: + return $this->getData(['user', $userId, 'lastname']) . ' ' . $this->getData(['user', $userId, 'firstname']); + break; + default: + return $this->getData(['user', $userId, 'firstname']); + } + } + + /** + * Initie un téléchargement protégé + */ + public function downloadFile() { + + if($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Action non autorisée' + ]); + } + // Téléchargement + else { + $filePath = self::FILE_DIR . 'source/' . $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'file']); + $fileName = $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'file']); + if (file_exists($filePath)) { + // Statistiques de téléchargement + $statId = helper::increment(uniqid(), $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats'])); + $this->setData(['module', + $this->getUrl(0), + 'items', + $this->getUrl(2), + 'fileStats', + $statId, [ + 'time' => time(), + 'ip' => helper::getIp() + ]]); + // Formatage http + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename="' . $fileName . '"'); + header('Content-Length: ' . filesize($filePath)); + readfile( $filePath); + // Valeurs en sortie + $this->addOutput([ + 'display' => self::DISPLAY_RAW + ]); + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Configuration', + 'view' => 'index' + ]); + } else { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Le fichier n\'existe pas', + 'state' => false + ]); + } + } + } + + /** + * Ecran de consultation des données statistiques + */ + + public function stats() { + + // Construction de la page des statistiques + $itemIds = array_keys($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats'])); + // Total des téléchargements + self::$statSum = count ($itemIds); + // Pagination + $pagination = helper::pagination($itemIds, $this->getUrl(), $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + + // Liste des pages + self::$pages = $pagination['pages']; + + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + + // Format des variables + $date = mb_detect_encoding(strftime('%d %B %Y - %H:%M', $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'time'])), 'UTF-8', true) + ? strftime('%d %B %Y - %H:%M',$this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'time'])) + : utf8_encode(strftime('%d %B %Y - %H:%M', $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'time']))); + + // Met en forme le tableau + self::$items[] = [ + $date, + $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', $itemIds[$i], 'ip']) + ]; + + } + $this->addOutput([ + 'title' => 'Statistiques de téléchargement', + 'view' => 'stats' + ]); + } + + public function statsDeleteAll() { + // Validité de la page demandée + if($this->getData(['module', $this->getUrl(0), 'items']) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); + } + // Jeton incorrect + elseif ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0), + 'notification' => 'Action non autorisée' + ]); + } + // Téléchargement + else { + $this->setData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileStats', [] ]); + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/stats/' . $this->getUrl(2), + 'notification' => 'Purge des statistiques', + 'state' => true + ]); + } + } + + /*** + * Retourne une chaîne json contenant la liste des téléchargements disponibles + */ + public function list() { + $itemIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0),'items']), 'publishedOn', 'SORT_DESC'); + $itemIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'items']), 'state', 'SORT_DESC'); + $itemIds = []; + foreach($itemIdsPublishedOns as $itemId => $itemPublishedOn) { + if($itemPublishedOn <= time() AND $itemIdsStates[$itemId]) { + $itemIds[] = $itemId; + } + } + foreach ($itemIds as $key) { + self::$items[$key] = [ + 'title' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'title']), + 'content' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'content']), + 'picture' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'picture']), + 'file' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'file']), + 'fileVersion' => $this->getData(['module', $this->getUrl(0), 'items', $key, 'fileVersion']), + 'fileDate' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'fileDate']), + 'fileAuthor' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'fileAuthor']), + 'fileLicense' =>$this->getData(['module', $this->getUrl(0), 'items', $key, 'fileLicense']), + ]; + } + $this->addOutput([ + 'display' => self::DISPLAY_JSON, + 'content' => self::$items + ]); + } +} \ No newline at end of file diff --git a/module/download/ressource/feed-icon-16.gif b/module/download/ressource/feed-icon-16.gif new file mode 100644 index 0000000000000000000000000000000000000000..26fa274454d016fdafa1b371e6d172030b61ac7d GIT binary patch literal 652 zcmZ?wbhEHb6krfwI9AB;Wun>ZdZS-+EPv0n`Z3e;&({zCe|~<~YVxAe@L9d_w<+eI zdQG2|=)Y_={m^OhuGRS8k57;D^!|N%b}LTnd4>L)F0+RfhHn~;9%Sjhsx^FEY4o_# z@aJ5|7tJR3Qg!}*e0DEi|9+vtokZ=wx3)ekF?ii+`l8kJ-}g^XOY|O<89r|`zE@!I zw8rQ~lgXb$Ew9>5@8;=0sWy6AYxJ_i?AMyOU+0$pSfBZBqR*FQ>F;Kx{5&!HWu4`h zy)%Byb9vwE_-=LQzc;sjE)9COY3j%A(|_+Qe^BcBc}e>FxhY@P6#u!o_50e)zxNOR z`}pkB;X?tj(k`Srkzulr~IeR}rieAnO4Zv4Ey|51V2uYJwG*T+4nasRbB>(}MY z-=|yroMriSlKIDO(^nhX|C0g~f3h%gG1N2YFaQB4P8irutD!|K07BTzlA_-oNcc1hVb)@I$C@&8w%Mnm^}*x>=-$uWM@XE3q3K( z+n30}qshBGH{_PjB8AT4CPx+_eKXyakCM*VXfpa8x!9!W!fBS3&{_Cd#ZQtY`q7^c z42zs*YqCAMQjx5}C&}jgh(nMu*=?1A*RH1rgcN%xD+z}kc=+HAgLSinO~;G`HX#{d V-YAuXg^H}50tyKne}y?1tN}38S(N|) literal 0 HcmV?d00001 diff --git a/module/download/vendor/FeedWriter/ATOM.php b/module/download/vendor/FeedWriter/ATOM.php new file mode 100644 index 00000000..28494501 --- /dev/null +++ b/module/download/vendor/FeedWriter/ATOM.php @@ -0,0 +1,38 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating ATOM feeds + * + * @package UniversalFeedWriter + */ +class ATOM extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::ATOM); + } + +} diff --git a/module/download/vendor/FeedWriter/Feed.php b/module/download/vendor/FeedWriter/Feed.php new file mode 100644 index 00000000..d33a2059 --- /dev/null +++ b/module/download/vendor/FeedWriter/Feed.php @@ -0,0 +1,1017 @@ + + * Copyright (C) 2010-2016 Michael Bemmerl + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Universal Feed Writer class + * + * Generate RSS 1.0, RSS2.0 and ATOM Feeds + * + * @package UniversalFeedWriter + * @author Anis uddin Ahmad + * @link http://www.ajaxray.com/projects/rss + */ +abstract class Feed +{ + // RSS 0.90 Officially obsoleted by 1.0 + // RSS 0.91, 0.92, 0.93 and 0.94 Officially obsoleted by 2.0 + // So, define constants for RSS 1.0, RSS 2.0 and ATOM + + const RSS1 = 'RSS 1.0'; + const RSS2 = 'RSS 2.0'; + const ATOM = 'ATOM'; + + const VERSION = '1.1.0'; + + /** + * Collection of all channel elements + */ + private $channels = array(); + + /** + * Collection of items as object of \FeedWriter\Item class. + */ + private $items = array(); + + /** + * Collection of other version wise data. + * + * Currently used to store the 'rdf:about' attribute and image element of the channel (both RSS1 only). + */ + private $data = array(); + + /** + * The tag names which have to encoded as CDATA + */ + private $CDATAEncoding = array(); + + /** + * Collection of XML namespaces + */ + private $namespaces = array(); + + /** + * Contains the format of this feed. + */ + private $version = null; + + /** + * Constructor + * + * If no version is given, a feed in RSS 2.0 format will be generated. + * + * @param string $version the version constant (RSS1/RSS2/ATOM). + */ + protected function __construct($version = Feed::RSS2) + { + $this->version = $version; + + // Setting default encoding + $this->encoding = 'utf-8'; + + // Setting default value for essential channel element + $this->setTitle($version . ' Feed'); + + // Add some default XML namespaces + $this->namespaces['content'] = 'http://purl.org/rss/1.0/modules/content/'; + $this->namespaces['wfw'] = 'http://wellformedweb.org/CommentAPI/'; + $this->namespaces['atom'] = 'http://www.w3.org/2005/Atom'; + $this->namespaces['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + $this->namespaces['rss1'] = 'http://purl.org/rss/1.0/'; + $this->namespaces['dc'] = 'http://purl.org/dc/elements/1.1/'; + $this->namespaces['sy'] = 'http://purl.org/rss/1.0/modules/syndication/'; + + // Tag names to encode in CDATA + $this->addCDATAEncoding(array('description', 'content:encoded', 'summary')); + } + + // Start # public functions --------------------------------------------- + + /** + * Set the URLs for feed pagination. + * + * See RFC 5005, chapter 3. At least one page URL must be specified. + * + * @param string $nextURL The URL to the next page of this feed. Optional. + * @param string $previousURL The URL to the previous page of this feed. Optional. + * @param string $firstURL The URL to the first page of this feed. Optional. + * @param string $lastURL The URL to the last page of this feed. Optional. + * @link http://tools.ietf.org/html/rfc5005#section-3 + * @return self + * @throws \LogicException if none of the parameters are set. + */ + public function setPagination($nextURL = null, $previousURL = null, $firstURL = null, $lastURL = null) + { + if (empty($nextURL) && empty($previousURL) && empty($firstURL) && empty($lastURL)) + throw new \LogicException('At least one URL must be specified for pagination to work.'); + + if (!empty($nextURL)) + $this->setAtomLink($nextURL, 'next'); + + if (!empty($previousURL)) + $this->setAtomLink($previousURL, 'previous'); + + if (!empty($firstURL)) + $this->setAtomLink($firstURL, 'first'); + + if (!empty($lastURL)) + $this->setAtomLink($lastURL, 'last'); + + return $this; + } + + /** + * Add a channel element indicating the program used to generate the feed. + * + * @return self + * @throws InvalidOperationException if this method is called on an RSS1 feed. + */ + public function addGenerator() + { + if ($this->version == Feed::ATOM) + $this->setChannelElement('atom:generator', 'FeedWriter', array('uri' => 'https://github.com/mibe/FeedWriter')); + else if ($this->version == Feed::RSS2) + $this->setChannelElement('generator', 'FeedWriter'); + else + throw new InvalidOperationException('The generator element is not supported in RSS1 feeds.'); + + return $this; + } + + /** + * Add a XML namespace to the internal list of namespaces. After that, + * custom channel elements can be used properly to generate a valid feed. + * + * @access public + * @param string $prefix namespace prefix + * @param string $uri namespace name (URI) + * @return self + * @link http://www.w3.org/TR/REC-xml-names/ + * @throws \InvalidArgumentException if the prefix or uri is empty or NULL. + */ + public function addNamespace($prefix, $uri) + { + if (empty($prefix)) + throw new \InvalidArgumentException('The prefix may not be emtpy or NULL.'); + if (empty($uri)) + throw new \InvalidArgumentException('The uri may not be empty or NULL.'); + + $this->namespaces[$prefix] = $uri; + + return $this; + } + + /** + * Add a channel element to the feed. + * + * @access public + * @param string $elementName name of the channel tag + * @param string $content content of the channel tag + * @param array array of element attributes with attribute name as array key + * @param bool TRUE if this element can appear multiple times + * @return self + * @throws \InvalidArgumentException if the element name is not a string, empty or NULL. + */ + public function setChannelElement($elementName, $content, array $attributes = null, $multiple = false) + { + if (empty($elementName)) + throw new \InvalidArgumentException('The element name may not be empty or NULL.'); + if (!is_string($elementName)) + throw new \InvalidArgumentException('The element name must be a string.'); + + $entity['content'] = $content; + $entity['attributes'] = $attributes; + + if ($multiple === TRUE) + $this->channels[$elementName][] = $entity; + else + $this->channels[$elementName] = $entity; + + return $this; + } + + /** + * Set multiple channel elements from an array. Array elements + * should be 'channelName' => 'channelContent' format. + * + * @access public + * @param array array of channels + * @return self + */ + public function setChannelElementsFromArray(array $elementArray) + { + foreach ($elementArray as $elementName => $content) { + $this->setChannelElement($elementName, $content); + } + + return $this; + } + + /** + * Get the appropriate MIME type string for the current feed. + * + * @access public + * @return string The MIME type string. + */ + public function getMIMEType() + { + switch ($this->version) { + case Feed::RSS2 : $mimeType = "application/rss+xml"; + break; + case Feed::RSS1 : $mimeType = "application/rdf+xml"; + break; + case Feed::ATOM : $mimeType = "application/atom+xml"; + break; + default : $mimeType = "text/xml"; + } + + return $mimeType; + } + + /** + * Print the actual RSS/ATOM file + * + * Sets a Content-Type header and echoes the contents of the feed. + * Should only be used in situations where direct output is desired; + * if you need to pass a string around, use generateFeed() instead. + * + * @access public + * @param bool FALSE if the specific feed media type should be sent. + * @return void + * @throws \InvalidArgumentException if the useGenericContentType parameter is not boolean. + */ + public function printFeed($useGenericContentType = false) + { + if (!is_bool($useGenericContentType)) + throw new \InvalidArgumentException('The useGenericContentType parameter must be boolean.'); + + $contentType = "text/xml"; + + if (!$useGenericContentType) { + $contentType = $this->getMIMEType(); + } + + // Generate the feed before setting the header, so Exceptions will be nicely visible. + $feed = $this->generateFeed(); + header("Content-Type: " . $contentType . "; charset=" . $this->encoding); + echo $feed; + } + + /** + * Generate the feed. + * + * @access public + * @return string The complete feed XML. + * @throws InvalidOperationException if the link element of the feed is not set. + */ + public function generateFeed() + { + if ($this->version != Feed::ATOM && !array_key_exists('link', $this->channels)) + throw new InvalidOperationException('RSS1 & RSS2 feeds need a link element. Call the setLink method before this method.'); + + return $this->makeHeader() + . $this->makeChannels() + . $this->makeItems() + . $this->makeFooter(); + } + + /** + * Create a new Item. + * + * @access public + * @return Item instance of Item class + */ + public function createNewItem() + { + $Item = new Item($this->version); + + return $Item; + } + + /** + * Add one or more tags to the list of CDATA encoded tags + * + * @access public + * @param array $tags An array of tag names that are merged into the list of tags which should be encoded as CDATA + * @return self + */ + public function addCDATAEncoding(array $tags) + { + $this->CDATAEncoding = array_merge($this->CDATAEncoding, $tags); + + return $this; + } + + /** + * Get list of CDATA encoded properties + * + * @access public + * @return array Return an array of CDATA properties that are to be encoded as CDATA + */ + public function getCDATAEncoding() + { + return $this->CDATAEncoding; + } + + /** + * Remove tags from the list of CDATA encoded tags + * + * @access public + * @param array $tags An array of tag names that should be removed. + * @return void + */ + public function removeCDATAEncoding(array $tags) + { + // Call array_values to re-index the array. + $this->CDATAEncoding = array_values(array_diff($this->CDATAEncoding, $tags)); + } + + /** + * Add a FeedItem to the main class + * + * @access public + * @param Item $feedItem instance of Item class + * @return self + * @throws \InvalidArgumentException if the given item version mismatches. + */ + public function addItem(Item $feedItem) + { + if ($feedItem->getVersion() != $this->version) + { + $msg = sprintf('Feed type mismatch: This instance can handle %s feeds only, but item for %s feeds given.', $this->version, $feedItem->getVersion()); + throw new \InvalidArgumentException($msg); + } + + $this->items[] = $feedItem; + + return $this; + } + + // Wrapper functions ------------------------------------------------------------------- + + /** + * Set the 'encoding' attribute in the XML prolog. + * + * @access public + * @param string $encoding value of 'encoding' attribute + * @return self + * @throws \InvalidArgumentException if the encoding is not a string, empty or NULL. + */ + public function setEncoding($encoding) + { + if (empty($encoding)) + throw new \InvalidArgumentException('The encoding may not be empty or NULL.'); + if (!is_string($encoding)) + throw new \InvalidArgumentException('The encoding must be a string.'); + + $this->encoding = $encoding; + + return $this; + } + + /** + * Set the 'title' channel element + * + * @access public + * @param string $title value of 'title' channel tag + * @return self + */ + public function setTitle($title) + { + return $this->setChannelElement('title', $title); + } + + /** + * Set the date when the feed was lastly updated. + * + * This adds the 'updated' element to the feed. The value of the date parameter + * can be either an instance of the DateTime class, an integer containing a UNIX + * timestamp or a string which is parseable by PHP's 'strtotime' function. + * + * Not supported in RSS1 feeds. + * + * @access public + * @param DateTime|int|string Date which should be used. + * @return self + * @throws \InvalidArgumentException if the given date is not an instance of DateTime, a UNIX timestamp or a date string. + * @throws InvalidOperationException if this method is called on an RSS1 feed. + */ + public function setDate($date) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('The publication date is not supported in RSS1 feeds.'); + + // The feeds have different date formats. + $format = $this->version == Feed::ATOM ? \DATE_ATOM : \DATE_RSS; + + if ($date instanceof DateTime) + $date = $date->format($format); + else if(is_numeric($date) && $date >= 0) + $date = date($format, $date); + else if (is_string($date)) + { + $timestamp = strtotime($date); + if ($timestamp === FALSE) + throw new \InvalidArgumentException('The given date was not parseable.'); + + $date = date($format, $timestamp); + } + else + throw new \InvalidArgumentException('The given date is not an instance of DateTime, a UNIX timestamp or a date string.'); + + if ($this->version == Feed::ATOM) + $this->setChannelElement('updated', $date); + else + $this->setChannelElement('lastBuildDate', $date); + + return $this; + } + + /** + * Set a phrase or sentence describing the feed. + * + * @access public + * @param string $description Description of the feed. + * @return self + */ + public function setDescription($description) + { + if ($this->version != Feed::ATOM) + $this->setChannelElement('description', $description); + else + $this->setChannelElement('subtitle', $description); + + return $this; + } + + /** + * Set the 'link' channel element + * + * @access public + * @param string $link value of 'link' channel tag + * @return self + */ + public function setLink($link) + { + if ($this->version == Feed::ATOM) + $this->setAtomLink($link); + else + $this->setChannelElement('link', $link); + + return $this; + } + + /** + * Set custom 'link' channel elements. + * + * In ATOM feeds, only one link with alternate relation and the same combination of + * type and hreflang values. + * + * @access public + * @param string $href URI of this link + * @param string $rel relation type of the resource + * @param string $type MIME type of the target resource + * @param string $hreflang language of the resource + * @param string $title human-readable information about the resource + * @param int $length length of the resource in bytes + * @link https://www.iana.org/assignments/link-relations/link-relations.xml + * @link https://tools.ietf.org/html/rfc4287#section-4.2.7 + * @return self + * @throws \InvalidArgumentException on multiple occasions. + * @throws InvalidOperationException if the same link with the same attributes was already added to the feed. + */ + public function setAtomLink($href, $rel = null, $type = null, $hreflang = null, $title = null, $length = null) + { + $data = array('href' => $href); + + if ($rel != null) { + if (!is_string($rel) || empty($rel)) + throw new \InvalidArgumentException('rel parameter must be a string and a valid relation identifier.'); + + $data['rel'] = $rel; + } + if ($type != null) { + // Regex used from RFC 4287, page 41 + if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1) + throw new \InvalidArgumentException('type parameter must be a string and a MIME type.'); + + $data['type'] = $type; + } + if ($hreflang != null) { + // Regex used from RFC 4287, page 41 + if (!is_string($hreflang) || preg_match('/[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*/', $hreflang) != 1) + throw new \InvalidArgumentException('hreflang parameter must be a string and a valid language code.'); + + $data['hreflang'] = $hreflang; + } + if ($title != null) { + if (!is_string($title) || empty($title)) + throw new \InvalidArgumentException('title parameter must be a string and not empty.'); + + $data['title'] = $title; + } + if ($length != null) { + if (!is_int($length) || $length < 0) + throw new \InvalidArgumentException('length parameter must be a positive integer.'); + + $data['length'] = (string) $length; + } + + // ATOM spec. has some restrictions on atom:link usage + // See RFC 4287, page 12 (4.1.1) + if ($this->version == Feed::ATOM) { + foreach ($this->channels as $key => $value) { + if ($key != 'atom:link') + continue; + + // $value is an array , so check every element + foreach ($value as $linkItem) { + $attrib = $linkItem['attributes']; + // Only one link with relation alternate and same hreflang & type is allowed. + if (@$attrib['rel'] == 'alternate' && @$attrib['hreflang'] == $hreflang && @$attrib['type'] == $type) + throw new InvalidOperationException('The feed must not contain more than one link element with a' + . ' relation of "alternate" that has the same combination of type and hreflang attribute values.'); + } + } + } + + return $this->setChannelElement('atom:link', '', $data, true); + } + + /** + * Set an 'atom:link' channel element with relation=self attribute. + * Needs the full URL to this feed. + * + * @link http://www.rssboard.org/rss-profile#namespace-elements-atom-link + * @access public + * @param string $url URL to this feed + * @return self + */ + public function setSelfLink($url) + { + return $this->setAtomLink($url, 'self', $this->getMIMEType()); + } + + /** + * Set the 'image' channel element + * + * @access public + * @param string $url URL of the image + * @param string $title Title of the image. RSS only. + * @param string $link Link target URL of the image. RSS only. + * @return self + * @throws \InvalidArgumentException if the url is invalid. + * @throws \InvalidArgumentException if the title and link parameter are not a string or empty. + */ + public function setImage($url, $title = null, $link = null) + { + if (!is_string($url) || empty($url)) + throw new \InvalidArgumentException('url parameter must be a string and may not be empty or NULL.'); + + // RSS feeds have support for a title & link element. + if ($this->version != Feed::ATOM) + { + if (!is_string($title) || empty($title)) + throw new \InvalidArgumentException('title parameter must be a string and may not be empty or NULL.'); + if (!is_string($link) || empty($link)) + throw new \InvalidArgumentException('link parameter must be a string and may not be empty or NULL.'); + + $data = array('title'=>$title, 'link'=>$link, 'url'=>$url); + $name = 'image'; + } + else + { + $name = 'logo'; + $data = $url; + } + + // Special handling for RSS1 again (since RSS1 is a bit strange...) + if ($this->version == Feed::RSS1) + { + $this->data['Image'] = $data; + return $this->setChannelElement($name, '', array('rdf:resource' => $url), false); + } + else + return $this->setChannelElement($name, $data); + } + + /** + * Set the channel 'rdf:about' attribute, which is used in RSS1 feeds only. + * + * @access public + * @param string $url value of 'rdf:about' attribute of the channel element + * @return self + * @throws InvalidOperationException if this method is called and the feed is not of type RSS1. + * @throws \InvalidArgumentException if the given URL is invalid. + */ + public function setChannelAbout($url) + { + if ($this->version != Feed::RSS1) + throw new InvalidOperationException("This method is only supported in RSS1 feeds."); + if (empty($url)) + throw new \InvalidArgumentException('The about URL may not be empty or NULL.'); + if (!is_string($url)) + throw new \InvalidArgumentException('The about URL must be a string.'); + + $this->data['ChannelAbout'] = $url; + + return $this; + } + + /** + * Generate an UUID. + * + * The UUID is based on an MD5 hash. If no key is given, a unique ID as the input + * for the MD5 hash is generated. + * + * @author Anis uddin Ahmad + * @access public + * @param string $key optional key on which the UUID is generated + * @param string $prefix an optional prefix + * @return string the formatted UUID + */ + public static function uuid($key = null, $prefix = '') + { + $key = ($key == null) ? uniqid(rand()) : $key; + $chars = md5($key); + $uuid = substr($chars,0,8) . '-'; + $uuid .= substr($chars,8,4) . '-'; + $uuid .= substr($chars,12,4) . '-'; + $uuid .= substr($chars,16,4) . '-'; + $uuid .= substr($chars,20,12); + + return $prefix . $uuid; + } + + /** + * Replace invalid XML characters. + * + * @link http://www.phpwact.org/php/i18n/charsets#xml See utf8_for_xml() function + * @link http://www.w3.org/TR/REC-xml/#charsets + * @link https://github.com/mibe/FeedWriter/issues/30 + * + * @access public + * @param string $string string which should be filtered + * @param string $replacement replace invalid characters with this string + * @return string the filtered string + */ + public static function filterInvalidXMLChars($string, $replacement = '_') // default to '\x{FFFD}' ??? + { + $result = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', $replacement, $string); + + // Did the PCRE replace failed because of bad UTF-8 data? + // If yes, try a non-multibyte regex and without the UTF-8 mode enabled. + if ($result == NULL && preg_last_error() == PREG_BAD_UTF8_ERROR) + $result = preg_replace('/[^\x09\x0a\x0d\x20-\xFF]+/', $replacement, $string); + + // In case the regex replacing failed completely, return the whole unfiltered string. + if ($result == NULL) + $result = $string; + + return $result; + } + // End # public functions ---------------------------------------------- + + // Start # private functions ---------------------------------------------- + + /** + * Returns all used XML namespace prefixes in this instance. + * This includes all channel elements and feed items. + * Unfortunately some namespace prefixes are not included, + * because they are hardcoded, e.g. rdf. + * + * @access private + * @return array Array with namespace prefix as value. + */ + private function getNamespacePrefixes() + { + $prefixes = array(); + + // Get all tag names from channel elements... + $tags = array_keys($this->channels); + + // ... and now all names from feed items + foreach ($this->items as $item) { + foreach (array_keys($item->getElements()) as $key) { + if (!in_array($key, $tags)) { + $tags[] = $key; + } + } + } + + // Look for prefixes in those tag names + foreach ($tags as $tag) { + $elements = explode(':', $tag); + + if (count($elements) != 2) + continue; + + $prefixes[] = $elements[0]; + } + + return array_unique($prefixes); + } + + /** + * Returns the XML header and root element, depending on the feed type. + * + * @access private + * @return string The XML header of the feed. + * @throws InvalidOperationException if an unknown XML namespace prefix is encountered. + */ + private function makeHeader() + { + $out = 'encoding.'" ?>' . PHP_EOL; + + $prefixes = $this->getNamespacePrefixes(); + $attributes = array(); + $tagName = ''; + $defaultNamespace = ''; + + if ($this->version == Feed::RSS2) { + $tagName = 'rss'; + $attributes['version'] = '2.0'; + } elseif ($this->version == Feed::RSS1) { + $tagName = 'rdf:RDF'; + $prefixes[] = 'rdf'; + $defaultNamespace = $this->namespaces['rss1']; + } elseif ($this->version == Feed::ATOM) { + $tagName = 'feed'; + $defaultNamespace = $this->namespaces['atom']; + + // Ugly hack to remove the 'atom' value from the prefixes array. + $prefixes = array_flip($prefixes); + unset($prefixes['atom']); + $prefixes = array_flip($prefixes); + } + + // Iterate through every namespace prefix and add it to the element attributes. + foreach ($prefixes as $prefix) { + if (!isset($this->namespaces[$prefix])) + throw new InvalidOperationException('Unknown XML namespace prefix: \'' . $prefix . '\'.' + . ' Use the addNamespace method to add support for this prefix.'); + else + $attributes['xmlns:' . $prefix] = $this->namespaces[$prefix]; + } + + // Include default namepsace, if required + if (!empty($defaultNamespace)) + $attributes['xmlns'] = $defaultNamespace; + + $out .= $this->makeNode($tagName, '', $attributes, true); + + return $out; + } + + /** + * Closes the open tags at the end of file + * + * @access private + * @return string The XML footer of the feed. + */ + private function makeFooter() + { + if ($this->version == Feed::RSS2) { + return '' . PHP_EOL . ''; + } elseif ($this->version == Feed::RSS1) { + return ''; + } elseif ($this->version == Feed::ATOM) { + return ''; + } + } + + /** + * Creates a single node in XML format + * + * @access private + * @param string $tagName name of the tag + * @param mixed $tagContent tag value as string or array of nested tags in 'tagName' => 'tagValue' format + * @param array $attributes Attributes (if any) in 'attrName' => 'attrValue' format + * @param bool $omitEndTag True if the end tag should be omitted. Defaults to false. + * @return string formatted xml tag + * @throws \InvalidArgumentException if the tagContent is not an array and not a string. + */ + private function makeNode($tagName, $tagContent, array $attributes = null, $omitEndTag = false) + { + $nodeText = ''; + $attrText = ''; + + if ($attributes != null) { + foreach ($attributes as $key => $value) { + $value = self::filterInvalidXMLChars($value); + $value = htmlspecialchars($value); + $attrText .= " $key=\"$value\""; + } + } + + $attrText .= (in_array($tagName, $this->CDATAEncoding) && $this->version == Feed::ATOM) ? ' type="html"' : ''; + $nodeText .= "<{$tagName}{$attrText}>"; + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? ' $value) { + if (is_array($value)) { + $nodeText .= PHP_EOL; + foreach ($value as $subValue) { + $nodeText .= $this->makeNode($key, $subValue); + } + } else if (is_string($value)) { + $nodeText .= $this->makeNode($key, $value); + } else { + throw new \InvalidArgumentException("Unknown node-value type for $key"); + } + } + } else { + $tagContent = self::filterInvalidXMLChars($tagContent); + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? $this->sanitizeCDATA($tagContent) : htmlspecialchars($tagContent); + } + + $nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? ']]>' : ''; + + if (!$omitEndTag) + $nodeText .= ""; + + $nodeText .= PHP_EOL; + + return $nodeText; + } + + /** + * Make the channels. + * + * @access private + * @return string The feed header as XML containing all the feed metadata. + */ + private function makeChannels() + { + $out = ''; + + //Start channel tag + switch ($this->version) { + case Feed::RSS2: + $out .= '' . PHP_EOL; + break; + case Feed::RSS1: + $out .= (isset($this->data['ChannelAbout']))? "data['ChannelAbout']}\">" : "channels['link']['content']}\">"; + break; + } + + //Print Items of channel + foreach ($this->channels as $key => $value) { + // In ATOM feeds, strip all ATOM namespace prefixes from the tag name. They are not needed here, + // because the ATOM namespace name is set as default namespace. + if ($this->version == Feed::ATOM && strncmp($key, 'atom', 4) == 0) { + $key = substr($key, 5); + } + + // The channel element can occur multiple times, when the key 'content' is not in the array. + if (!array_key_exists('content', $value)) { + // If this is the case, iterate through the array with the multiple elements. + foreach ($value as $singleElement) { + $out .= $this->makeNode($key, $singleElement['content'], $singleElement['attributes']); + } + } else { + $out .= $this->makeNode($key, $value['content'], $value['attributes']); + } + } + + if ($this->version == Feed::RSS1) { + //RSS 1.0 have special tag with channel + $out .= "" . PHP_EOL . "" . PHP_EOL; + foreach ($this->items as $item) { + $thisItems = $item->getElements(); + $out .= "" . PHP_EOL; + } + $out .= "" . PHP_EOL . "" . PHP_EOL . "" . PHP_EOL; + + // An image has its own element after the channel elements. + if (array_key_exists('image', $this->data)) + $out .= $this->makeNode('image', $this->data['Image'], array('rdf:about' => $this->data['Image']['url'])); + } else if ($this->version == Feed::ATOM) { + // ATOM feeds have a unique feed ID. Use the title channel element as key. + $out .= $this->makeNode('id', Feed::uuid($this->channels['title']['content'], 'urn:uuid:')); + } + + return $out; + } + + /** + * Prints formatted feed items + * + * @access private + * @return string The XML of every feed item. + */ + private function makeItems() + { + $out = ''; + + foreach ($this->items as $item) { + $thisItems = $item->getElements(); + + // The argument is printed as rdf:about attribute of item in RSS 1.0 + // We're using the link set in the item (which is mandatory) as the about attribute. + if ($this->version == Feed::RSS1) + $out .= $this->startItem($thisItems['link']['content']); + else + $out .= $this->startItem(); + + foreach ($thisItems as $feedItem) { + $name = $feedItem['name']; + + // Strip all ATOM namespace prefixes from tags when feed is an ATOM feed. + // Not needed here, because the ATOM namespace name is used as default namespace. + if ($this->version == Feed::ATOM && strncmp($name, 'atom', 4) == 0) + $name = substr($name, 5); + + $out .= $this->makeNode($name, $feedItem['content'], $feedItem['attributes']); + } + $out .= $this->endItem(); + } + + return $out; + } + + /** + * Make the starting tag of channels + * + * @access private + * @param string $about The value of about attribute which is used for RSS 1.0 only. + * @return string The starting XML tag of an feed item. + * @throws InvalidOperationException if this object misses the data for the about attribute. + */ + private function startItem($about = false) + { + $out = ''; + + if ($this->version == Feed::RSS2) { + $out .= '
' . PHP_EOL; + } elseif ($this->version == Feed::RSS1) { + if ($about) { + $out .= "" . PHP_EOL; + } else { + throw new InvalidOperationException("Missing data for about attribute. Call setChannelAbout method."); + } + } elseif ($this->version == Feed::ATOM) { + $out .= "" . PHP_EOL; + } + + return $out; + } + + /** + * Closes feed item tag + * + * @access private + * @return string The ending XML tag of an feed item. + */ + private function endItem() + { + if ($this->version == Feed::RSS2 || $this->version == Feed::RSS1) { + return '
' . PHP_EOL; + } elseif ($this->version == Feed::ATOM) { + return '' . PHP_EOL; + } + } + + /** + * Sanitizes data which will be later on returned as CDATA in the feed. + * + * A "]]>" respectively "", "]]>", $text); + $text = str_replace(" + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * The exception that is thrown when an invalid operation is performed on + * the object. + * + * @package UniversalFeedWriter + */ +class InvalidOperationException extends LogicException +{ +} diff --git a/module/download/vendor/FeedWriter/Item.php b/module/download/vendor/FeedWriter/Item.php new file mode 100644 index 00000000..c4f21a93 --- /dev/null +++ b/module/download/vendor/FeedWriter/Item.php @@ -0,0 +1,413 @@ + + * Copyright (C) 2010-2013, 2015-2016 Michael Bemmerl + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Universal Feed Writer + * + * Item class - Used as feed element in Feed class + * + * @package UniversalFeedWriter + * @author Anis uddin Ahmad + * @link http://www.ajaxray.com/projects/rss + */ +class Item +{ + /** + * Collection of feed item elements + */ + private $elements = array(); + + /** + * Contains the format of this feed. + */ + private $version; + + /** + * Is used as a suffix when multiple elements have the same name. + **/ + private $_cpt = 0; + + /** + * Constructor + * + * @param string $version constant (RSS1/RSS2/ATOM) RSS2 is default. + */ + public function __construct($version = Feed::RSS2) + { + $this->version = $version; + } + + /** + * Return an unique number + * + * @access private + * @return int + **/ + private function cpt() + { + return $this->_cpt++; + } + + /** + * Add an element to elements array + * + * @access public + * @param string $elementName The tag name of an element + * @param string $content The content of tag + * @param array $attributes Attributes (if any) in 'attrName' => 'attrValue' format + * @param boolean $overwrite Specifies if an already existing element is overwritten. + * @param boolean $allowMultiple Specifies if multiple elements of the same name are allowed. + * @return self + * @throws \InvalidArgumentException if the element name is not a string, empty or NULL. + */ + public function addElement($elementName, $content, array $attributes = null, $overwrite = FALSE, $allowMultiple = FALSE) + { + if (empty($elementName)) + throw new \InvalidArgumentException('The element name may not be empty or NULL.'); + if (!is_string($elementName)) + throw new \InvalidArgumentException('The element name must be a string.'); + + $key = $elementName; + + // return if element already exists & if overwriting is disabled + // & if multiple elements are not allowed. + if (isset($this->elements[$elementName]) && !$overwrite) { + if (!$allowMultiple) + return $this; + + $key .= '-' . $this->cpt(); + } + + $this->elements[$key]['name'] = $elementName; + $this->elements[$key]['content'] = $content; + $this->elements[$key]['attributes'] = $attributes; + + return $this; + } + + /** + * Set multiple feed elements from an array. + * Elements which have attributes cannot be added by this method + * + * @access public + * @param array array of elements in 'tagName' => 'tagContent' format. + * @return self + */ + public function addElementArray(array $elementArray) + { + foreach ($elementArray as $elementName => $content) { + $this->addElement($elementName, $content); + } + + return $this; + } + + /** + * Return the collection of elements in this feed item + * + * @access public + * @return array All elements of this item. + * @throws InvalidOperationException on ATOM feeds if either a content or link element is missing. + * @throws InvalidOperationException on RSS1 feeds if a title or link element is missing. + */ + public function getElements() + { + // ATOM feeds have some specific requirements... + if ($this->version == Feed::ATOM) + { + // Add an 'id' element, if it was not added by calling the setLink method. + // Use the value of the title element as key, since no link element was specified. + if (!array_key_exists('id', $this->elements)) + $this->setId(Feed::uuid($this->elements['title']['content'], 'urn:uuid:')); + + // Either a 'link' or 'content' element is needed. + if (!array_key_exists('content', $this->elements) && !array_key_exists('link', $this->elements)) + throw new InvalidOperationException('ATOM feed entries need a link or a content element. Call the setLink or setContent method.'); + } + // ...same with RSS1 feeds. + else if ($this->version == Feed::RSS1) + { + if (!array_key_exists('title', $this->elements)) + throw new InvalidOperationException('RSS1 feed entries need a title element. Call the setTitle method.'); + if (!array_key_exists('link', $this->elements)) + throw new InvalidOperationException('RSS1 feed entries need a link element. Call the setLink method.'); + } + + return $this->elements; + } + + /** + * Return the type of this feed item + * + * @access public + * @return string The feed type, as defined in Feed.php + */ + public function getVersion() + { + return $this->version; + } + + // Wrapper functions ------------------------------------------------------ + + /** + * Set the 'description' element of feed item + * + * @access public + * @param string $description The content of the 'description' or 'summary' element + * @return self + */ + public function setDescription($description) + { + $tag = ($this->version == Feed::ATOM) ? 'summary' : 'description'; + + return $this->addElement($tag, $description); + } + + /** + * Set the 'content' element of the feed item + * For ATOM feeds only + * + * @access public + * @param string $content Content for the item (i.e., the body of a download post). + * @return self + * @throws InvalidOperationException if this method is called on non-ATOM feeds. + */ + public function setContent($content) + { + if ($this->version != Feed::ATOM) + throw new InvalidOperationException('The content element is supported in ATOM feeds only.'); + + return $this->addElement('content', $content, array('type' => 'html')); + } + + /** + * Set the 'title' element of feed item + * + * @access public + * @param string $title The content of 'title' element + * @return self + */ + public function setTitle($title) + { + return $this->addElement('title', $title); + } + + /** + * Set the 'date' element of the feed item. + * + * The value of the date parameter can be either an instance of the + * DateTime class, an integer containing a UNIX timestamp or a string + * which is parseable by PHP's 'strtotime' function. + * + * @access public + * @param DateTime|int|string $date Date which should be used. + * @return self + * @throws \InvalidArgumentException if the given date was not parseable. + */ + public function setDate($date) + { + if (!is_numeric($date)) { + if ($date instanceof DateTime) + $date = $date->getTimestamp(); + else { + $date = strtotime($date); + + if ($date === FALSE) + throw new \InvalidArgumentException('The given date string was not parseable.'); + } + } elseif ($date < 0) + throw new \InvalidArgumentException('The given date is not an UNIX timestamp.'); + + if ($this->version == Feed::ATOM) { + $tag = 'updated'; + $value = date(\DATE_ATOM, $date); + } elseif ($this->version == Feed::RSS2) { + $tag = 'pubDate'; + $value = date(\DATE_RSS, $date); + } else { + $tag = 'dc:date'; + $value = date("Y-m-d", $date); + } + + return $this->addElement($tag, $value); + } + + /** + * Set the 'link' element of feed item + * + * @access public + * @param string $link The content of 'link' element + * @return self + */ + public function setLink($link) + { + if ($this->version == Feed::RSS2 || $this->version == Feed::RSS1) { + $this->addElement('link', $link); + } else { + $this->addElement('link','',array('href'=>$link)); + $this->setId(Feed::uuid($link,'urn:uuid:')); + } + + return $this; + } + + /** + * Attach a external media to the feed item. + * Not supported in RSS 1.0 feeds. + * + * See RFC 4288 for syntactical correct MIME types. + * + * Note that you should avoid the use of more than one enclosure in one item, + * since some RSS aggregators don't support it. + * + * @access public + * @param string $url The URL of the media. + * @param integer $length The length of the media. + * @param string $type The MIME type attribute of the media. + * @param boolean $multiple Specifies if multiple enclosures are allowed + * @return self + * @link https://tools.ietf.org/html/rfc4288 + * @throws \InvalidArgumentException if the length or type parameter is invalid. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function addEnclosure($url, $length, $type, $multiple = TRUE) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('Media attachment is not supported in RSS1 feeds.'); + + // the length parameter should be set to 0 if it can't be determined + // see http://www.rssboard.org/rss-profile#element-channel-item-enclosure + if (!is_numeric($length) || $length < 0) + throw new \InvalidArgumentException('The length parameter must be an integer and greater or equals to zero.'); + + // Regex used from RFC 4287, page 41 + if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1) + throw new \InvalidArgumentException('type parameter must be a string and a MIME type.'); + + $attributes = array('length' => $length, 'type' => $type); + + if ($this->version == Feed::RSS2) { + $attributes['url'] = $url; + $this->addElement('enclosure', '', $attributes, FALSE, $multiple); + } else { + $attributes['href'] = $url; + $attributes['rel'] = 'enclosure'; + $this->addElement('atom:link', '', $attributes, FALSE, $multiple); + } + + return $this; + } + + /** + * Set the 'author' element of feed item. + * Not supported in RSS 1.0 feeds. + * + * @access public + * @param string $author The author of this item + * @param string|null $email Optional email address of the author + * @param string|null $uri Optional URI related to the author + * @return self + * @throws \InvalidArgumentException if the provided email address is syntactically incorrect. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function setAuthor($author, $email = null, $uri = null) + { + if ($this->version == Feed::RSS1) + throw new InvalidOperationException('The author element is not supported in RSS1 feeds.'); + + // Regex from RFC 4287 page 41 + if ($email != null && preg_match('/.+@.+/', $email) != 1) + throw new \InvalidArgumentException('The email address is syntactically incorrect.'); + + if ($this->version == Feed::RSS2) + { + if ($email != null) + $author = $email . ' (' . $author . ')'; + + $this->addElement('author', $author); + } + else + { + $elements = array('name' => $author); + + if ($email != null) + $elements['email'] = $email; + + if ($uri != null) + $elements['uri'] = $uri; + + $this->addElement('author', $elements); + } + + return $this; + } + + /** + * Set the unique identifier of the feed item + * + * On ATOM feeds, the identifier must begin with an valid URI scheme. + * + * @access public + * @param string $id The unique identifier of this item + * @param boolean $permaLink The value of the 'isPermaLink' attribute in RSS 2 feeds. + * @return self + * @throws \InvalidArgumentException if the permaLink parameter is not boolean. + * @throws InvalidOperationException if this method is called on RSS1 feeds. + */ + public function setId($id, $permaLink = false) + { + if ($this->version == Feed::RSS2) { + if (!is_bool($permaLink)) + throw new \InvalidArgumentException('The permaLink parameter must be boolean.'); + + $permaLink = $permaLink ? 'true' : 'false'; + + $this->addElement('guid', $id, array('isPermaLink' => $permaLink)); + } elseif ($this->version == Feed::ATOM) { + // Check if the given ID is an valid URI scheme (see RFC 4287 4.2.6) + // The list of valid schemes was generated from http://www.iana.org/assignments/uri-schemes + // by using only permanent or historical schemes. + $validSchemes = array('aaa', 'aaas', 'about', 'acap', 'acct', 'cap', 'cid', 'coap', 'coaps', 'crid', 'data', 'dav', 'dict', 'dns', 'example', 'fax', 'file', 'filesystem', 'ftp', 'geo', 'go', 'gopher', 'h323', 'http', 'https', 'iax', 'icap', 'im', 'imap', 'info', 'ipp', 'ipps', 'iris', 'iris.beep', 'iris.lwz', 'iris.xpc', 'iris.xpcs', 'jabber', 'ldap', 'mailserver', 'mailto', 'mid', 'modem', 'msrp', 'msrps', 'mtqp', 'mupdate', 'news', 'nfs', 'ni', 'nih', 'nntp', 'opaquelocktoken', 'pack', 'pkcs11', 'pop', 'pres', 'prospero', 'reload', 'rtsp', 'rtsps', 'rtspu', 'service', 'session', 'shttp', 'sieve', 'sip', 'sips', 'sms', 'snews', 'snmp', 'soap.beep', 'soap.beeps', 'stun', 'stuns', 'tag', 'tel', 'telnet', 'tftp', 'thismessage', 'tip', 'tn3270', 'turn', 'turns', 'tv', 'urn', 'vemmi', 'videotex', 'vnc', 'wais', 'ws', 'wss', 'xcon', 'xcon-userid', 'xmlrpc.beep', 'xmlrpc.beeps', 'xmpp', 'z39.50', 'z39.50r', 'z39.50s'); + $found = FALSE; + $checkId = strtolower($id); + + foreach($validSchemes as $scheme) + if (strrpos($checkId, $scheme . ':', -strlen($checkId)) !== FALSE) + { + $found = TRUE; + break; + } + + if (!$found) + throw new \InvalidArgumentException("The ID must begin with an IANA-registered URI scheme."); + + $this->addElement('id', $id, NULL, TRUE); + } else + throw new InvalidOperationException('A unique ID is not supported in RSS1 feeds.'); + + return $this; + } + + } // end of class Item diff --git a/module/download/vendor/FeedWriter/README.md b/module/download/vendor/FeedWriter/README.md new file mode 100644 index 00000000..f630af99 --- /dev/null +++ b/module/download/vendor/FeedWriter/README.md @@ -0,0 +1,42 @@ +# Generate **RSS 1.0**, **RSS 2.0** or **ATOM** Formatted Feeds + +This package can be used to generate feeds in either **RSS 1.0**, **RSS 2.0** or **ATOM** format. + +Applications can create a feed object, several feed item objects, set several types of properties of either feed and feed items, and add items to the feed. + +Once a feed is fully composed with its items, the feed class can generate the necessary XML structure to describe the feed in **RSS** or **ATOM** format. This structure can be directly sent to the browser, or just returned as string. + +## Requirements + +- PHP 5.3 or higher + +If you don't have **PHP 5.3** available on your system there is a version supporting **PHP 5.0** and above. See the `legacy-php-5.0` branch. + +## Documentation + +The documentation can be found in the `gh-pages` branch, or on [GitHub Pages](https://mibe.github.io/FeedWriter/). + +See the `/examples` directory for usage examples. + +See the `CHANGELOG.md` file for changes between the different versions. + +## Authors + +In chronological order: + +- [Anis uddin Ahmad](https://github.com/ajaxray) +- [Michael Bemmerl](https://github.com/mibe) +- Phil Freo +- Paul Ferrett +- Brennen Bearnes +- Michael Robinson +- Baptiste Fontaine +- Kristián Valentín +- Brandtley McMinn +- Julian Bogdani +- Cedric Gampert +- Yamek +- Thielj +- Pavel Khakhlou +- Daniel +- Tino Goratsch diff --git a/module/download/vendor/FeedWriter/RSS1.php b/module/download/vendor/FeedWriter/RSS1.php new file mode 100644 index 00000000..a0465cf5 --- /dev/null +++ b/module/download/vendor/FeedWriter/RSS1.php @@ -0,0 +1,37 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating RSS1 feeds + * + * @package UniversalFeedWriter + */ +class RSS1 extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::RSS1); + } +} diff --git a/module/download/vendor/FeedWriter/RSS2.php b/module/download/vendor/FeedWriter/RSS2.php new file mode 100644 index 00000000..9e36a728 --- /dev/null +++ b/module/download/vendor/FeedWriter/RSS2.php @@ -0,0 +1,37 @@ + + * + * This file is part of the "Universal Feed Writer" project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Wrapper for creating RSS2 feeds + * + * @package UniversalFeedWriter + */ +class RSS2 extends Feed +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + parent::__construct(Feed::RSS2); + } +} diff --git a/module/download/view/add/add.css b/module/download/view/add/add.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/add/add.css @@ -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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/add/add.js.php b/module/download/view/add/add.js.php new file mode 100644 index 00000000..d88ff563 --- /dev/null +++ b/module/download/view/add/add.js.php @@ -0,0 +1,54 @@ +/** + * 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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Soumission du formulaire pour enregistrer en brouillon + */ +$("#downloadAddDraft").on("click", function() { + $("#downloadAddState").val(0); + $("#downloadAddForm").trigger("submit"); +}); + +/** + * Options de commentaires + */ +$("#downloadAddCommentClose").on("change", function() { + if ($(this).is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } +}); + +$("#downloadAddCommentNotification").on("change", function() { + if ($(this).is(':checked') ) { + $("#downloadAddCommentGroupNotification").slideDown(); + } else { + $("#downloadAddCommentGroupNotification").slideUp(); + } +}); + + +$( document).ready(function() { + + if ($("#downloadAddCloseComment").is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } + + if ($("#downloadAddCommentNotification").is(':checked') ) { + $("#downloadAddCommentGroupNotification").slideDown(); + } else { + $("#downloadAddCommentGroupNotification").slideUp(); + } +}); \ No newline at end of file diff --git a/module/download/view/add/add.php b/module/download/view/add/add.php new file mode 100644 index 00000000..e33f4df8 --- /dev/null +++ b/module/download/view/add/add.php @@ -0,0 +1,139 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ true, + 'value' => 'Enregistrer en brouillon' + ]); ?> + true + ]); ?> +
+
+ 'Publier' + ]); ?> +
+
+
+
+
+

Informations générales

+
+
+ 'Titre' + ]); ?> +
+
+ 'Version' + ]); ?> +
+
+ 'Date' + ]); ?> +
+
+
+
+ 'Archive du fichier' + ]); ?> +
+
+ 'Capture d\'écran', + 'type' => 1 + ]); ?> +
+
+
+
+ 'Auteur', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileAuthor']) + ]); ?> +
+
+ 'Licence', + 'selected' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileLicense']) + ]); ?> +
+
+
+
+
+ 'editorWysiwyg' + ]); ?> +
+
+
+

Options de publication

+
+
+ 'Auteur', + 'selected' => $this->getUser('id'), + 'disabled' => $this->getUser('group') !== self::GROUP_ADMIN ? true : false + ]); ?> +
+
+ 'L\'item n\'est visible qu\'après la date de publication prévue.', + 'label' => 'Date de publication', + 'value' => time() + ]); ?> +
+
+ 'Edition / Suppression', + 'selected' => $module::EDIT_ALL, + 'help' => 'Les utilisateurs des groupes supérieurs accèdent à l\'item sans restriction' + ]); ?> +
+
+
+
+
+
+
+
+

Commentaires

+
+
+ +
+
+ +
+
+ 'Choix du nombre maximum de caractères pour chaque commentaire de l\'item, mise en forme html comprise.', + 'label' => 'Caractères par commentaire' + ]); ?> +
+
+
+
+ +
+
+ +
+
+
+
+
+ diff --git a/module/download/view/comment/comment.css b/module/download/view/comment/comment.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/comment/comment.css @@ -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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/comment/comment.js.php b/module/download/view/comment/comment.js.php new file mode 100644 index 00000000..fe2f99d5 --- /dev/null +++ b/module/download/view/comment/comment.js.php @@ -0,0 +1,62 @@ +/** + * 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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** + * Confirmation de suppression + */ +$(".downloadCommentDelete").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Supprimer le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation d'approbation + */ +$(".downloadCommentApproved").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Approuver le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation de rejet + */ +$(".downloadCommentRejected").on("click", function() { + var _this = $(this); + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + return core.confirm("Rejeter le commentaire de l'item " + nom + " ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); + +/** + * Confirmation de suppression en masse + */ +$(".downloadCommentDeleteAll").on("click", function() { + var _this = $(this); + var nombre = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'comment' ])); ?>"; + var nom = "getData(['module', $this->getUrl(0), $this->getUrl(2), 'title' ]); ?>"; + if( nombre === "1"){ + var message = "Supprimer le commentaire de l'item " + nom + " ?"; + } else{ + var message = "Supprimer les " + nombre + " commentaires de l'item " + nom + " ?"; + } + return core.confirm(message, function() { + $(location).attr("href", _this.attr("href")); + }); +}); diff --git a/module/download/view/comment/comment.php b/module/download/view/comment/comment.php new file mode 100644 index 00000000..76c50a61 --- /dev/null +++ b/module/download/view/comment/comment.php @@ -0,0 +1,22 @@ +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+ + +
+ +
+ +
+ + '; ?> + + + + diff --git a/module/download/view/config/config.css b/module/download/view/config/config.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/config/config.css @@ -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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/config/config.js.php b/module/download/view/config/config.js.php new file mode 100644 index 00000000..bc462697 --- /dev/null +++ b/module/download/view/config/config.js.php @@ -0,0 +1,21 @@ +/** + * 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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Confirmation de suppression + */ +$(".downloadConfigDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer cet item ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/download/view/config/config.php b/module/download/view/config/config.php new file mode 100644 index 00000000..8ac3cd4d --- /dev/null +++ b/module/download/view/config/config.php @@ -0,0 +1,60 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . 'page/edit/' . $this->getUrl(0), 'items', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ helper::baseUrl() . $this->getUrl(0) . '/add', + 'ico' => 'plus', + 'value' => 'Fichier' + ]); ?> +
+
+ +
+
+
+
+
+

Paramètres du module

+
+
+ $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), + ]); ?> +
+
+ 'Etiquette du flux', + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) + ]); ?> +
+
+
+
+ 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
+
+
+
+
+ + + + + + + +
Version n° + +
+ diff --git a/module/download/view/edit/edit.css b/module/download/view/edit/edit.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/edit/edit.css @@ -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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/edit/edit.js.php b/module/download/view/edit/edit.js.php new file mode 100644 index 00000000..148e937a --- /dev/null +++ b/module/download/view/edit/edit.js.php @@ -0,0 +1,66 @@ +/** + * 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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +// Lien de connexion +$("#downloadEditMailNotification").on("change", function() { + if($(this).is(":checked")) { + $("#formConfigGroup").show(); + } + else { + $("#formConfigGroup").hide(); + } +}).trigger("change"); + + +/** + * Soumission du formulaire pour enregistrer en brouillon + */ +$("#downloadEditDraft").on("click", function() { + $("#downloadEditState").val(0); + $("#downloadEditForm").trigger("submit"); +}); + +/** + * Options de commentaires + */ +$("#downloadEditCommentClose").on("change", function() { + if ($(this).is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } +}); + +$("#downloadEditCommentNotification").on("change", function() { + if ($(this).is(':checked') ) { + $("#downloadEditCommentGroupNotification").slideDown(); + } else { + $("#downloadEditCommentGroupNotification").slideUp(); + } +}); + + +$( document).ready(function() { + + if ($("#downloadEditCloseComment").is(':checked') ) { + $(".commentOptionsWrapper").slideUp(); + } else { + $(".commentOptionsWrapper").slideDown(); + } + + if ($("#downloadEditCommentNotification").is(':checked') ) { + $("#downloadEditCommentGroupNotification").slideDown(); + } else { + $("#downloadEditCommentGroupNotification").slideUp(); + } +}); \ No newline at end of file diff --git a/module/download/view/edit/edit.php b/module/download/view/edit/edit.php new file mode 100644 index 00000000..db0b5477 --- /dev/null +++ b/module/download/view/edit/edit.php @@ -0,0 +1,159 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ true, + 'value' => 'Enregistrer en brouillon' + ]); ?> + true + ]); ?> +
+
+ 'Publier' + ]); ?> + +
+
+
+
+
+

Informations générales

+ +
+
+ 'Titre', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'title']) + ]); ?> +
+
+ 'Version', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileVersion']) + ]); ?> +
+
+ 'Date', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileDate']) + ]); ?> +
+
+
+
+ 'Archive du fichier', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'file']) + ]); ?> +
+
+ 'Capture d\'écran', + 'type' => 1, + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'picture']) + ]); ?> +
+
+
+
+ 'Auteur', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileAuthor']) + ]); ?> +
+
+ 'Licence', + 'selected' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'fileLicense']) + ]); ?> +
+
+
+
+
+ 'editorWysiwyg', + 'value' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'content']) + ]); ?> +
+
+
+

Options de publication

+
+
+ 'Auteur', + 'selected' => $this->getUser('id'), + 'disabled' => $this->getUser('group') !== self::GROUP_ADMIN ? true : false + ]); ?> +
+
+ 'L\'item n\'est visible qu\'après la date de publication prévue.', + 'label' => 'Date de publication', + 'value' => time() + ]); ?> +
+
+ 'Edition / Suppression', + 'selected' => is_numeric($this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'editConsent'])) ? $module::EDIT_GROUP : $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'editConsent']), + 'help' => 'Les utilisateurs des groupes supérieurs accèdent à l\'item sans restriction' + ]); ?> +
+
+
+
+
+
+
+
+

Commentaires

+
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentClose']) + ]); ?> +
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentApproved']), + '' + ]); ?> +
+
+ 'Choix du nombre maximum de caractères pour chaque commentaire de l\'item, mise en forme html comprise.', + 'label' => 'Caractères par commentaire', + 'selected' => $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentMaxlength']) + ]); ?> +
+ +
+
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentNotification']), + ]); ?> +
+
+ $this->getData(['module', $this->getUrl(0), 'items', $this->getUrl(2), 'commentGroupNotification']), + 'help' => 'Editeurs = éditeurs + administrateurs
Membres = membres + éditeurs + administrateurs' + ]); ?> +
+
+
+
+
+ diff --git a/module/download/view/index/index.css b/module/download/view/index/index.css new file mode 100644 index 00000000..b958b637 --- /dev/null +++ b/module/download/view/index/index.css @@ -0,0 +1,69 @@ +.rowitem { + margin-bottom: 10px !important; +} +.downloadPicture { + float: none; + border: 1px; +} +.downloadPicture img { + width: 100%; + height: auto; + /* + border:1px solid lightgray; + box-shadow: 1px 1px 5px darkgray; + */ +} + +.downloadPicture:hover { + opacity: .7; +} +.row:after { + content: " "; + display: table; + clear: both; +} +.downloadComment { + padding-right: 10px; + float: right; +} +h2{ + margin-bottom: 5px; + margin-top: 0px; + padding: 0px; + +} +.downloadContent { + float: left; + margin-top: 5px; +} +.downloadDate { + font-size:0.8em; + font-style: italic; + /* + color: grey; + */ +} +@media (max-width: 768px) { + .downloadContent { + display: none; + } + + .downloadPicture img { + width: 50% ; + display: block; + margin-left: auto; + margin-right: auto; + } +} + +/* +* Flux RSS +*/ +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} \ No newline at end of file diff --git a/module/download/view/item/item.css b/module/download/view/item/item.css new file mode 100644 index 00000000..445f719d --- /dev/null +++ b/module/download/view/item/item.css @@ -0,0 +1,63 @@ + +#sectionTitle { + margin-top: 0; + margin-bottom: 5px; +} +.downloaditemPicture { + height: auto; + border:1px solid lightgray; + box-shadow: 1px 1px 5px; +} +.downloaditemPictureleft { + float: left; + margin: 15px 10px 5px 0 ; +} +.downloaditemPictureright { + float: right; + margin: 15px 0 5px 10px ; +} + + +.pict20{ + width: 20%; +} +.pict30{ + width: 30%; +} +.pict40{ + width: 40%; +} +.pict50{ + width: 50%; +} +.pict100{ + width: 100%; + margin: 15px 0 20px 0 ; +} + +#downloaditemCommentShow { + cursor: text; +} +#downloaditemOr { + padding: 10px; +} +.downloadDate { + font-size:0.8em; + font-style: italic; + color: grey; +} +@media (max-width: 767px) { + .downloaditemPicture { + height:auto; + max-width: 100%;} + } + + +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} diff --git a/module/download/view/item/item.js.php b/module/download/view/item/item.js.php new file mode 100644 index 00000000..cb07dcd2 --- /dev/null +++ b/module/download/view/item/item.js.php @@ -0,0 +1,43 @@ +/** + * 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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Affiche le bloc pour rédiger un commentaire + */ +var commentShowDOM = $("#downloadItemCommentShow"); +commentShowDOM.on("click focus", function() { + $("#downloadItemCommentShowWrapper").fadeOut(function() { + $("#downloadItemCommentWrapper").fadeIn(); + $("#downloadItemCommentContent").trigger("focus"); + }); +}); +if($("#downloadItemCommentWrapper").find("textarea.notice,input.notice").length) { + commentShowDOM.trigger("click"); +} + +/** + * Cache le bloc pour rédiger un commentaire + */ +$("#downloadItemCommentHide").on("click focus", function() { + $("#downloadItemCommentWrapper").fadeOut(function() { + $("#downloadItemCommentShowWrapper").fadeIn(); + $("#downloadItemCommentContent").val(""); + $("#downloadItemCommentAuthor").val(""); + }); +}); + +/** + * Force le scroll vers les commentaires en cas d'erreur + */ +$("#downloadItemCommentForm").on("submit", function() { + $(location).attr("href", "#comment"); +}); \ No newline at end of file diff --git a/module/download/view/list/list.php b/module/download/view/list/list.php new file mode 100644 index 00000000..4b8f6d3c --- /dev/null +++ b/module/download/view/list/list.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/download/view/rss/rss.php b/module/download/view/rss/rss.php new file mode 100644 index 00000000..4b8f6d3c --- /dev/null +++ b/module/download/view/rss/rss.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/module/download/view/stats/stats.css b/module/download/view/stats/stats.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/module/download/view/stats/stats.css @@ -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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/module/download/view/stats/stats.js.php b/module/download/view/stats/stats.js.php new file mode 100644 index 00000000..fbeffea1 --- /dev/null +++ b/module/download/view/stats/stats.js.php @@ -0,0 +1,22 @@ +/** + * 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 + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** + * Confirmation de suppression + */ +$(".statsDeleteAll").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir purger les statistiques ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/module/download/view/stats/stats.php b/module/download/view/stats/stats.php new file mode 100644 index 00000000..5b778f3b --- /dev/null +++ b/module/download/view/stats/stats.php @@ -0,0 +1,36 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ 'statsDeleteAll buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/statsDeleteAll' . '/' . $this->getUrl(2) . '/'. $_SESSION['csrf'] , + 'ico' => 'cancel', + 'value' => 'Purger' + ]); ?> +
+
+ +
+
+

Nombre de téléchargements : + +

+
+
+ + + + + + +
Version n° + +
\ No newline at end of file diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index 9434387f..1da334b0 100755 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -17,7 +17,7 @@ class gallery extends common { - const VERSION = '2.6'; + const VERSION = '3.0'; const REALNAME = 'Galerie'; const DELETE = true; const UPDATE = '0.0'; @@ -143,6 +143,75 @@ class gallery extends common { '1px 1px 50px' => 'Très importante' ]; + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + + // Installation des données par défaut + $class = get_called_class(); + $moduleId = $this->getUrl(0); + if ( $this->getData(['module', $this->getUrl(0), 'config',]) === null ) { + require_once('module/gallery/ressource/defaultdata.php'); + $this->setData(['module', $this->getUrl(0), 'config', theme::$defaultData]); + + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + // Nom de la feuille de style + $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; + $this->setData(['module', $this->getUrl(0), 'config', 'style', $fileCSS]); + } + + // Générer la feuille de CSS + if (!file_exists(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' )) { + $content = file_get_contents('module/gallery/ressource/vartheme.css'); + $themeCss = file_get_contents('module/gallery/ressource/theme.css'); + // Injection des variables + $content = str_replace('#thumbAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbAlign']),$content ); + $content = str_replace('#thumbWidth#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbWidth']),$content ); + $content = str_replace('#thumbHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbHeight']),$content ); + $content = str_replace('#thumbMargin#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbMargin']),$content ); + $content = str_replace('#thumbBorder#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorder']),$content ); + $content = str_replace('#thumbBorderColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbBorderColor']),$content ); + $content = str_replace('#thumbOpacity#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbOpacity']),$content ); + $content = str_replace('#thumbShadows#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadows']),$content ); + $content = str_replace('#thumbShadowsColor#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbShadowsColor']),$content ); + $content = str_replace('#thumbRadius#',$this->getData(['module', $this->getUrl(0), 'config', 'thumbRadius']),$content ); + $content = str_replace('#legendAlign#',$this->getData(['module', $this->getUrl(0), 'config', 'legendAlign']),$content ); + $content = str_replace('#legendHeight#',$this->getData(['module', $this->getUrl(0), 'config', 'legendHeight']),$content ); + $content = str_replace('#legendTextColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendTextColor']),$content ); + $content = str_replace('#legendBgColor#',$this->getData(['module', $this->getUrl(0), 'config', 'legendBgColor']),$content ); + // Ecriture de la feuille de style + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $content . $themeCss); + } + + // Mise à jour d'une version inférieure + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '3.0', '<') ) { + // Changement de l'arborescence dans module.json + $data = $this->getData(['module', $this->getUrl(0)]); + $this->deleteData(['module', $this->getUrl(0)]); + $this->setData(['module', $this->getUrl(0), 'content', $data]); + // Effacer les fichiers CSS de l'ancienne version + if (file_exists('module/gallery/view/index/index.css')) { + unlink('module/gallery/view/index/index.css'); + } + if (file_exists('module/gallery/view/gallery/gallery.css')) { + unlink('module/gallery/view/gallery/gallery.css'); + } + // Stockage des données du thème de la gallery + $data = $this->getData(['theme','gallery']); + $this->deleteData(['theme','gallery']); + $this->setData(['module', $this->getUrl(0), 'config', $data]); + // Nouvelle version + $this->setData(['module', $this->getUrl(0), 'config', 'versionData', '3.0']); + } + } + + /** * Tri de la liste des galeries * @@ -152,7 +221,7 @@ class gallery extends common { $data = explode('&',$_POST['response']); $data = str_replace('galleryTable%5B%5D=','',$data); for($i=0;$isetData(['module', $this->getUrl(0), $data[$i], [ + $this->setData(['module', $this->getUrl(0), 'content', $data[$i], [ 'config' => [ 'name' => $this->getData(['module',$this->getUrl(0),$data[$i],'config','name']), 'directory' => $this->getData(['module',$this->getUrl(0),$data[$i],'config','directory']), @@ -179,7 +248,7 @@ class gallery extends common { $data = explode('&',$_POST['response']); $data = str_replace('galleryTable%5B%5D=','',$data); // Sauvegarder - $this->setData(['module', $this->getUrl(0), $galleryName, [ + $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']), @@ -200,8 +269,11 @@ class gallery extends common { * Configuration */ public function config() { + // Mise à jour des données de module + $this->update(); + //Affichage de la galerie triée - $g = $this->getData(['module', $this->getUrl(0)]); + $g = $this->getData(['module', $this->getUrl(0), 'content']); $p = helper::arrayCollumn(helper::arrayCollumn($g,'config'),'position'); asort($p,SORT_NUMERIC); $galleries = []; @@ -243,7 +315,7 @@ class gallery extends common { // Soumission du formulaire d'ajout d'une galerie if($this->isPost()) { if (!$this->getInput('galleryConfigFilterResponse')) { - $galleryId = helper::increment($this->getInput('galleryConfigName', helper::FILTER_ID, true), (array) $this->getData(['module', $this->getUrl(0)])); + $galleryId = helper::increment($this->getInput('galleryConfigName', helper::FILTER_ID, true), (array) $this->getData(['module', $this->getUrl(0), 'content'])); // définir une vignette par défaut $directory = $this->getInput('galleryConfigDirectory', helper::FILTER_STRING_SHORT, true); $iterator = new DirectoryIterator($directory); @@ -260,13 +332,13 @@ class gallery extends common { break; } } - $this->setData(['module', $this->getUrl(0), $galleryId, [ + $this->setData(['module', $this->getUrl(0), 'content', $galleryId, [ 'config' => [ '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), $galleryId,'config','position']), + 'position' => $this->getData(['module', $this->getUrl(0), 'content', $galleryId,'config','position']), 'fullScreen' => false ], 'legend' => [], @@ -296,7 +368,7 @@ class gallery extends common { public function delete() { // $url prend l'adresse sans le token // La galerie n'existe pas - if($this->getData(['module', $this->getUrl(0), $this->getUrl(2)]) === null) { + if($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false @@ -312,7 +384,7 @@ class gallery extends common { } // Suppression else { - $this->deleteData(['module', $this->getUrl(0), $this->getUrl(2)]); + $this->deleteData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]); // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', @@ -346,7 +418,7 @@ class gallery extends common { ]); } // La galerie n'existe pas - if($this->getData(['module', $this->getUrl(0), $this->getUrl(2)]) === null) { + if($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false @@ -360,11 +432,11 @@ class gallery extends common { $galleryId = !empty($this->getInput('galleryEditName')) ? $this->getInput('galleryEditName', helper::FILTER_ID, true) : $this->getUrl(2); if($galleryId !== $this->getUrl(2)) { // Incrémente le nouvel id de la galerie - $galleryId = helper::increment($galleryId, $this->getData(['module', $this->getUrl(0)])); + $galleryId = helper::increment($galleryId, $this->getData(['module', $this->getUrl(0), 'content'])); // Transférer la position des images $oldPositions = $this->getData(['module',$this->getUrl(0), $this->getUrl(2),'positions']); // Supprime l'ancienne galerie - $this->deleteData(['module', $this->getUrl(0), $this->getUrl(2)]); + $this->deleteData(['module', $this->getUrl(0), 'content', $this->getUrl(2)]); } // légendes $legends = []; @@ -382,19 +454,19 @@ class gallery extends common { } // Sauvegarder if ($this->getInput('galleryEditName')) { - $this->setData(['module', $this->getUrl(0), $galleryId, [ + $this->setData(['module', $this->getUrl(0), 'content', $galleryId, [ 'config' => [ 'name' => $this->getInput('galleryEditName', helper::FILTER_STRING_SHORT, true), 'directory' => $this->getInput('galleryEditDirectory', helper::FILTER_STRING_SHORT, true), 'homePicture' => $homePicture, // pas de positions, on active le tri alpha 'sort' => $this->getInput('galleryEditSort'), - 'position' => $this->getData(['module', $this->getUrl(0), $galleryId,'config','position']), + 'position' => $this->getData(['module', $this->getUrl(0), 'content', $galleryId,'config','position']), 'fullScreen' => $this->getInput('galleryEditFullscreen', helper::FILTER_BOOLEAN) ], 'legend' => $legends, - 'positions' => empty($oldPositions) ? $this->getdata(['module', $this->getUrl(0), $galleryId, 'positions']) : $oldPositions + 'positions' => empty($oldPositions) ? $this->getdata(['module', $this->getUrl(0), 'content', $galleryId, 'positions']) : $oldPositions ]]); } // Valeurs en sortie @@ -405,7 +477,7 @@ class gallery extends common { ]); } // Met en forme le tableau - $directory = $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'directory']); + $directory = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'directory']); if(is_dir($directory)) { $iterator = new DirectoryIterator($directory); @@ -421,11 +493,11 @@ class gallery extends common { template::ico('sort'), $fileInfos->getFilename(), template::checkbox( 'homePicture[' . $fileInfos->getFilename() . ']', true, '', [ - 'checked' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2),'config', 'homePicture']) === $fileInfos->getFilename() ? true : false, + 'checked' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2),'config', 'homePicture']) === $fileInfos->getFilename() ? true : false, 'class' => 'homePicture' ]), template::text('legend[' . $fileInfos->getFilename() . ']', [ - 'value' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'legend', str_replace('.','',$fileInfos->getFilename())]) + 'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'legend', str_replace('.','',$fileInfos->getFilename())]) ]), '' ]; @@ -433,7 +505,7 @@ class gallery extends common { } } // Tri des images - switch ($this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'sort'])) { + 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']); if ($positions) { @@ -466,7 +538,7 @@ class gallery extends common { } // Valeurs en sortie $this->addOutput([ - 'title' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'name']), + 'title' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'name']), 'view' => 'edit', 'vendor' => [ 'tablednd' @@ -479,10 +551,12 @@ class gallery extends common { * Accueil (deux affichages en un pour éviter une url à rallonge) */ public function index() { + // Mise à jour des données de module + $this->update(); // Images d'une galerie if($this->getUrl(1)) { // La galerie n'existe pas - if($this->getData(['module', $this->getUrl(0), $this->getUrl(1)]) === null) { + if($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1)]) === null) { // Valeurs en sortie $this->addOutput([ 'access' => false @@ -491,13 +565,13 @@ class gallery extends common { // La galerie existe else { // Images de la galerie - $directory = $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'config', 'directory']); + $directory = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), '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())) { - self::$pictures[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'legend', str_replace('.','',$fileInfos->getFilename())]); - $picturesSort[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'positions', str_replace('.','',$fileInfos->getFilename())]); + self::$pictures[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'legend', str_replace('.','',$fileInfos->getFilename())]); + $picturesSort[$directory . '/' . $fileInfos->getFilename()] = $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'positions', str_replace('.','',$fileInfos->getFilename())]); // 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(), @@ -511,7 +585,7 @@ class gallery extends common { } } // Tri des images par ordre alphabétique - switch ($this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'config', 'sort'])) { + switch ($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'config', 'sort'])) { case self::SORT_HAND: asort($picturesSort); if ($picturesSort) { @@ -535,8 +609,9 @@ class gallery extends common { // Valeurs en sortie $this->addOutput([ 'showBarEditButton' => true, - 'title' => $this->getData(['module', $this->getUrl(0), $this->getUrl(1), 'config', 'name']), - 'view' => 'gallery' + 'title' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(1), 'config', 'name']), + 'view' => 'gallery', + 'style' => $this->getData(['module', $this->getUrl(0), 'config', 'style']) ]); } // Pas d'image dans la galerie @@ -552,7 +627,7 @@ class gallery extends common { // Liste des galeries else { // Tri des galeries suivant l'ordre défini - $g = $this->getData(['module', $this->getUrl(0)]); + $g = $this->getData(['module', $this->getUrl(0), 'content']); $p = helper::arrayCollumn(helper::arrayCollumn($g,'config'),'position'); asort($p,SORT_NUMERIC); $galleries = []; @@ -598,7 +673,8 @@ class gallery extends common { $this->addOutput([ 'showBarEditButton' => true, 'showPageContent' => true, - 'view' => 'index' + 'view' => 'index', + 'style' => $this->getData(['module', $this->getUrl(0), 'config', 'style']) ]); } } @@ -615,16 +691,19 @@ class gallery extends common { 'notification' => 'Action non autorisée' ]); } - // Initialisation des données de thème de la galerie dasn theme.json - // Création des valeur par défaut absentes - if ( $this->getData(['theme', 'gallery']) === null ) { - require_once('module/gallery/ressource/defaultdata.php'); - $this->setData(['theme', 'gallery', theme::$defaultData]); - } // Soumission du formulaire - if($this->isPost()) { - $this->setData(['theme', 'gallery', [ + + // Générer la feuille de CSS + $class = get_called_class(); + $moduleId = $this->getUrl(0); + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + $fileCSS = self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' ; + // Fin feuille de style + $this->getData(['module', $this->getUrl(0), 'config', [ 'thumbAlign' => $this->getinput('galleryThemeThumbAlign'), 'thumbWidth' => $this->getinput('galleryThemeThumbWidth'), 'thumbHeight' => $this->getinput('galleryThemeThumbHeight'), @@ -638,7 +717,9 @@ class gallery extends common { 'legendHeight' => $this->getinput('galleryThemeLegendHeight'), 'legendAlign' => $this->getinput('galleryThemeLegendAlign'), 'legendTextColor' => $this->getinput('galleryThemeLegendTextColor'), - 'legendBgColor' => $this->getinput('galleryThemeLegendBgColor') + 'legendBgColor' => $this->getinput('galleryThemeLegendBgColor'), + 'style' => $fileCSS, + 'version' => $this->getData(['module', $this->getUrl(0), 'config', 'version']) ] ]); // Création des fichiers CSS @@ -659,12 +740,11 @@ class gallery extends common { $content = str_replace('#legendHeight#',$this->getinput('galleryThemeLegendHeight'),$content ); $content = str_replace('#legendTextColor#',$this->getinput('galleryThemeLegendTextColor'),$content ); $content = str_replace('#legendBgColor#',$this->getinput('galleryThemeLegendBgColor'),$content ); - $success = file_put_contents('module/gallery/view/index/index.css',$content . $themeCss); - $success = $success && file_put_contents('module/gallery/view/gallery/gallery.css',$content . $themeCss); + $success = file_put_contents($fileCSS, $content . $themeCss); // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl() . '/theme', - 'notification' => $success !== FALSE ? 'Modifications enregistrées' : 'Modifications non enregistées !', + 'notification' => $success !== FALSE ? 'Modifications enregistrées' : 'Modifications non enregistrées !', 'state' => $success !== FALSE ]); } diff --git a/module/gallery/ressource/defaultdata.php b/module/gallery/ressource/defaultdata.php index ff71bbc3..22777389 100755 --- a/module/gallery/ressource/defaultdata.php +++ b/module/gallery/ressource/defaultdata.php @@ -14,6 +14,7 @@ class theme extends gallery { 'legendHeight' => '.375em', 'legendAlign' => 'center', 'legendTextColor' => 'rgba(255, 255, 255, 1)', - 'legendBgColor' => 'rgba(0, 0, 0, .6)' + 'legendBgColor' => 'rgba(0, 0, 0, .6)', + 'versionData' => '3.0' ]; } diff --git a/module/gallery/view/edit/edit.php b/module/gallery/view/edit/edit.php index c745d1e5..c8f74f42 100755 --- a/module/gallery/view/edit/edit.php +++ b/module/gallery/view/edit/edit.php @@ -20,12 +20,12 @@
'Nom', - 'value' => $this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'name']) + 'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'name']) ]); ?>
$this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'directory']), + 'value' => $this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'directory']), 'noDirty' => true // Désactivé à cause des modifications en ajax ]); ?>
$this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', '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.' ]); ?> @@ -43,7 +43,7 @@
$this->getData(['module', $this->getUrl(0), $this->getUrl(2), 'config', 'fullScreen']), + '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.' ]); ?>
diff --git a/module/gallery/view/theme/theme.php b/module/gallery/view/theme/theme.php index 694ecaf9..5110b148 100755 --- a/module/gallery/view/theme/theme.php +++ b/module/gallery/view/theme/theme.php @@ -25,25 +25,25 @@
'Largeur', - 'selected' => $this->getData(['theme', 'gallery','thumbWidth']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbWidth']) ]); ?>
'Hauteur', - 'selected' => $this->getData(['theme', 'gallery','thumbHeight']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbHeight']) ]); ?>
'Alignement', - 'selected' => $this->getData(['theme', 'gallery','thumbAlign']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbAlign']) ]); ?>
'Marge', - 'selected' => $this->getData(['theme', 'gallery','thumbMargin']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbMargin']) ]); ?>
@@ -51,7 +51,7 @@
'Bordure', - 'selected' => $this->getData(['theme', 'gallery','thumbBorder']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbBorder']) ]); ?>
@@ -59,13 +59,13 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Couleur de la bordure', - 'value' => $this->getData(['theme', 'gallery','thumbBorderColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','thumbBorderColor']) ]); ?>
'Arrondi des angles', - 'selected' => $this->getData(['theme', 'gallery','thumbRadius']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbRadius']) ]); ?>
@@ -73,7 +73,7 @@
'Ombre', - 'selected' => $this->getData(['theme', 'gallery','thumbShadows']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbShadows']) ]); ?>
@@ -81,13 +81,13 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Couleur de l\'ombre', - 'value' => $this->getData(['theme', 'gallery','thumbShadowsColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','thumbShadowsColor']) ]); ?>
'Opacité au survol', - 'selected' => $this->getData(['theme', 'gallery','thumbOpacity']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','thumbOpacity']) ]); ?>
@@ -108,7 +108,7 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Texte', - 'value' => $this->getData(['theme', 'gallery','legendTextColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','legendTextColor']) ]); ?>
@@ -116,19 +116,19 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence.', 'label' => 'Fond', - 'value' => $this->getData(['theme', 'gallery','legendBgColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config','legendBgColor']) ]); ?>
'Hauteur', - 'selected' => $this->getData(['theme', 'gallery','legendHeight']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','legendHeight']) ]); ?>
'Alignement', - 'selected' => $this->getData(['theme', 'gallery','legendAlign']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config','legendAlign']) ]); ?>
diff --git a/module/news/news.php b/module/news/news.php index b3896b31..888571f8 100755 --- a/module/news/news.php +++ b/module/news/news.php @@ -15,7 +15,7 @@ class news extends common { - const VERSION = '2.3'; + const VERSION = '3.0'; const REALNAME = 'Actualités'; const DELETE = true; const UPDATE = '0.0'; @@ -43,11 +43,51 @@ class news extends common { public static $users = []; + // Nombre d'objets par page + public static $ItemsList = [ + 4 => '4 articles', + 8 => '8 articles', + 12 => '12 articles', + 16 => '16 articles', + 22 => '22 articles' + ]; + // Nombre de colone par page + public static $Columns = [ + 12 => '1 Colonne', + 6 => '2 Colonnes', + 4 => '3 Colonnes', + 2 => '4 Colonnes' + ]; + public static $nbrCol = 1; + + public static $ItemsHeight = [ + '200px' => 'Petit', + '300px' => 'Moyen', + '400px' => 'Grand' + ]; + + // Signature de l'article + public static $articleSignature = ''; + + + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Version 3.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '3.0', '<') ) { + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperPage', 16]); + $this->setData(['module', $this->getUrl(0), 'config', 'itemsperCol', 6]); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','3.0']); + } + } + + /** * Flux RSS */ public function rss() { - // Inclure les classes include_once 'module/news/vendor/FeedWriter/Item.php'; include_once 'module/news/vendor/FeedWriter/Feed.php'; @@ -68,7 +108,7 @@ class news extends common { // Corps des articles $newsIdsPublishedOns = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC'); // Articles de la première page uniquement - $newsIdsPublishedOns = array_slice($newsIdsPublishedOns, 0, $this->getData(['config', 'itemsperPage']) ); + $newsIdsPublishedOns = array_slice($newsIdsPublishedOns, 0, $this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) ); $newsIdsStates = helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'state', 'SORT_DESC'); foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) { if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) { @@ -95,7 +135,7 @@ class news extends common { } /** - * Édition + * Ajout d'un article */ public function add() { // Soumission du formulaire @@ -138,11 +178,32 @@ class news extends common { * Configuration */ public function config() { + // Mise à jour des données de module + $this->update(); + // Soumission du formulaire if($this->isPost()) { + + // Générer la feuille de CSS + $class = get_called_class(); + $moduleId = $this->getUrl(0); + $style = '.newsContent {height:' . $this->getInput('newsConfigItemsHeight',helper::FILTER_STRING_SHORT) . ';}'; + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $style ); + // Fin feuille de style + $this->setData(['module', $this->getUrl(0), 'config',[ 'feeds' => $this->getInput('newsConfigShowFeeds',helper::FILTER_BOOLEAN), - 'feedsLabel' => $this->getInput('newsConfigFeedslabel',helper::FILTER_STRING_SHORT) + 'feedsLabel' => $this->getInput('newsConfigFeedslabel',helper::FILTER_STRING_SHORT), + 'itemsperPage' => $this->getInput('newsConfigItemsperPage', helper::FILTER_INT,true), + 'itemsperCol' => $this->getInput('newsConfigItemsperCol', helper::FILTER_INT,true), + 'itemsHeight' => $this->getInput('newsConfigItemsHeight',helper::FILTER_STRING_SHORT), + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']), + 'style' => $success ? self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' : '' ]]); // Valeurs en sortie $this->addOutput([ @@ -154,7 +215,7 @@ class news extends common { // Ids des news par ordre de publication $newsIds = array_keys(helper::arrayCollumn($this->getData(['module', $this->getUrl(0), 'posts']), 'publishedOn', 'SORT_DESC')); // Pagination - $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0), 'config', 'itemsperPage']) ); // Liste des pages self::$pages = $pagination['pages']; // News en fonction de la pagination @@ -288,30 +349,64 @@ class news extends common { * Accueil */ public function 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'); - $newsIds = []; - foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) { - if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) { - $newsIds[] = $newsId; + // Mise à jour des données de module + $this->update(); + // Affichage d'un article + if( + $this->getUrl(1) + // Protection pour la pagination, un ID ne peut pas être un entier, une page oui + AND intval($this->getUrl(1)) === 0 + ) { + // L'article n'existe pas + if($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1)]) === null) { + // Valeurs en sortie + $this->addOutput([ + 'access' => false + ]); } + // L'article existe + else { + self::$articleSignature = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'userId'])); + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'title' => $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'title']), + 'view' => 'article' + ]); + + } + } 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'); + $newsIds = []; + foreach($newsIdsPublishedOns as $newsId => $newsPublishedOn) { + if($newsPublishedOn <= time() AND $newsIdsStates[$newsId]) { + $newsIds[] = $newsId; + } + } + // Pagination + //$pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); + $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['module', $this->getUrl(0),'config', 'itemsperPage'])); + // Nombre de colonnes + self::$nbrCol = $this->getData(['module', $this->getUrl(0),'config', 'itemsperCol']); + // Liste des pages + self::$pages = $pagination['pages']; + // News en fonction de la pagination + for($i = $pagination['first']; $i < $pagination['last']; $i++) { + self::$news[$newsIds[$i]] = $this->getData(['module', $this->getUrl(0),'posts', $newsIds[$i]]); + self::$news[$newsIds[$i]]['userId'] = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $newsIds[$i], 'userId'])); + } + // Valeurs en sortie + $this->addOutput([ + 'showBarEditButton' => true, + 'showPageContent' => true, + 'view' => 'index', + 'style' => $this->getData(['module', $this->getUrl(0),'config', 'style']) + ]); + } - // Pagination - $pagination = helper::pagination($newsIds, $this->getUrl(),$this->getData(['config','itemsperPage'])); - // Liste des pages - self::$pages = $pagination['pages']; - // News en fonction de la pagination - for($i = $pagination['first']; $i < $pagination['last']; $i++) { - self::$news[$newsIds[$i]] = $this->getData(['module', $this->getUrl(0),'posts', $newsIds[$i]]); - self::$news[$newsIds[$i]]['userId'] = $this->signature($this->getData(['module', $this->getUrl(0), 'posts', $newsIds[$i], 'userId'])); - } - // Valeurs en sortie - $this->addOutput([ - 'showBarEditButton' => true, - 'showPageContent' => true, - 'view' => 'index' - ]); } /** diff --git a/module/news/view/article/article.css b/module/news/view/article/article.css new file mode 100644 index 00000000..604e6d6f --- /dev/null +++ b/module/news/view/article/article.css @@ -0,0 +1,20 @@ + +/** +* @author Frédéric Tempez +* @copyright Copyright (C) 2018-2021, Frédéric Tempez +* @license GNU General Public License, version 3 +* @link http://zwiicms.fr/ +*/ + +/* +* Module news +*/ + +#rssFeed { + text-align: right; + float: right; +} +#rssFeed p { + display: inline; + vertical-align: top; +} diff --git a/module/news/view/config/config.php b/module/news/view/config/config.php index 73929b9d..b9cee0bd 100755 --- a/module/news/view/config/config.php +++ b/module/news/view/config/config.php @@ -20,26 +20,48 @@
-
-
-

Paramètres du module

-
-
- $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), - 'help' => 'Flux limité aux articles de la première page.' - ]); ?> -
-
- 'Texte de l\'étiquette', - 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) - ]); ?> -
+
+
+

Paramètres du module

+
+
+ $this->getData(['module', $this->getUrl(0), 'config', 'feeds']), + 'help' => 'Flux limité aux articles de la première page.' + ]); ?> +
+
+ 'Etiquette RSS', + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'feedsLabel']) + ]); ?> +
+
+ +
+
+ 'Pagination', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperCol']), + 'help' => 'Nombre de colonnes par page' + ]); ?> +
+
+ 'Articles par page', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsperPage']) + ]); ?> +
+
+ 'Hauteur', + 'selected' => $this->getData(['module', $this->getUrl(0),'config', 'itemsHeight']) + ]); ?>
+
diff --git a/module/news/view/index/index.css b/module/news/view/index/index.css index 48553448..c462ebbd 100755 --- a/module/news/view/index/index.css +++ b/module/news/view/index/index.css @@ -12,7 +12,7 @@ * @link http://zwiicms.fr/ */ -/* + /* * Module news */ @@ -21,10 +21,26 @@ background-color: #ECEFF1; padding:5px; }*/ +.newsContent { + overflow: hidden; /* les dépassements seront masqués */ + position: relative; +} + +.newsBlur { + position: absolute; + bottom: -5%; + margin: -10px; + height: 20%; + width: 110%; + backdrop-filter: blur(1px); + -webkit-backdrop-filter: blur(1px); +} + .newsContent { clear: left; margin-left: 10px; + margin-bottom: 5px; } .newsSignature { @@ -44,4 +60,26 @@ #rssFeed p { display: inline; vertical-align: top; -} \ No newline at end of file +} +@media (min-width: 769px) +{ + .col2 {width: 20%;} + .col3 {width: 24%;} + .col4 {width: 32%;} + .col6 {width: 49%;} + .col12 {width: 100%;} +} + +@media (max-width: 768px) +{ + .col2 {width: 49%;} + .col3 {width: 49%;} + .col4 {width: 49%;} +} +@media (max-width: 480px) +{ + .col2 {width: 100%;} + .col3 {width: 100%;} + .col4 {width: 100%;} +} + diff --git a/module/news/view/index/index.php b/module/news/view/index/index.php index 11c6150d..d71aba33 100755 --- a/module/news/view/index/index.php +++ b/module/news/view/index/index.php @@ -1,20 +1,19 @@
-
- $news): ?> -
-
-

- -

-
- -
-
- - + $news): ?> +
+

+ getUrl(0) . '/' . $newsId . '">' . $news['title'] . ''; ?> +

+
+ +
+
+
+ + - Editer -
-
-
+
getData(['module',$this->getUrl(0), 'config', 'feeds'])): ?>
- ' . $this->getData(['module',$this->getUrl(0), 'config', 'feedsLabel']) . '

' ; ?>
diff --git a/module/search/ressource/defaultdata.php b/module/search/ressource/defaultdata.php index d9d5a2a2..378c347c 100755 --- a/module/search/ressource/defaultdata.php +++ b/module/search/ressource/defaultdata.php @@ -5,6 +5,7 @@ class init extends search { 'resultHideContent' => false, 'placeHolder' => 'Un ou plusieurs mots-clés séparés par un espace ou par +', 'submitText' => 'Rechercher', - 'keywordColor' => 'rgba(229, 229, 1, 1)' + 'keywordColor' => 'rgba(229, 229, 1, 1)', + 'versionData' => '2.0' ]; } \ No newline at end of file diff --git a/module/search/search.php b/module/search/search.php index ed9a5815..9050a8a9 100755 --- a/module/search/search.php +++ b/module/search/search.php @@ -10,7 +10,8 @@ * @copyright Copyright (C) 2008-2018, Rémi Jean * @author Frédéric Tempez * @copyright Copyright (C) 2018-2021, Frédéric Tempez - * @copyright Sylvain Lelièvre + * @author Sylvain Lelièvre + * @copyright Copyright (C) 2020-2021, Sylvain Lelièvre * @license GNU General Public License, version 3 * @link http://zwiicms.fr/ * @@ -18,7 +19,7 @@ class search extends common { - const VERSION = '1.3'; + const VERSION = '2.0'; const REALNAME = 'Recherche'; const DELETE = true; const UPDATE = '0.0'; @@ -45,22 +46,66 @@ class search extends common { ]; + /** + * Mise à jour du module + * Appelée par les fonctions index et config + */ + private function update() { + // Création des valeurs de réglage par défaut + if ( !is_array($this->getData(['module', $this->getUrl(0), 'config']) ) ) { + require_once('module/search/ressource/defaultdata.php'); + $this->setData(['module', $this->getUrl(0), 'config', init::$defaultData]); + } + // Version 2.0 + if (version_compare($this->getData(['module', $this->getUrl(0), 'config', 'versionData']), '2.0', '<') ) { + + // Distinguer la config des autres données + $data = $this->getData(['module', $this->getUrl(0)]); + $this->setData(['module', $this->getUrl(0), 'config', [ + 'submitText' => $this->getData(['module', $this->getUrl(0), 'submitText']), + 'placeHolder' => $this->getData(['module', $this->getUrl(0), 'placeHolder']), + 'resultHideContent' => $this->getData(['module', $this->getUrl(0), 'resultHideContent']), + 'previewLength' => $this->getData(['module', $this->getUrl(0), 'previewLength']), + 'keywordColor' => $this->getData(['module', $this->getUrl(0), 'keywordColor']) + ]]); + $this->deleteData(['module', $this->getUrl(0), 'submitText']); + $this->deleteData(['module', $this->getUrl(0), 'placeHolder']); + $this->deleteData(['module', $this->getUrl(0), 'resultHideContent']); + $this->deleteData(['module', $this->getUrl(0), 'previewLength']); + $this->deleteData(['module', $this->getUrl(0), 'keywordColor']); + $this->setData(['module', $this->getUrl(0), 'config', 'versionData','2.0']); + } + } + // Configuration vide public function config() { - // Création des valeurs de réglage par défaut - if ( $this->getData(['module', $this->getUrl(0)]) === null ) { - require_once('module/search/ressource/defaultdata.php'); - $this->setData(['module', $this->getUrl(0), init::$defaultData]); - } + + // Mise à jour des données de module + $this->update(); if($this->isPost()) { + + // Générer la feuille de CSS + $class = get_called_class(); + $moduleId = $this->getUrl(0); + $style = '.searchItem {background:' . $this->getInput('searchKeywordColor') . ';}'; + // Dossier de l'instance + if (!is_dir(self::DATA_DIR . 'modules/' . $class)) { + mkdir (self::DATA_DIR . 'modules/' . $class, 0777, true); + } + + $success = file_put_contents(self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' , $style ); + // Fin feuille de style + // Soumission du formulaire - $this->setData(['module', $this->getUrl(0), [ + $this->setData(['module', $this->getUrl(0), 'config',[ 'submitText' => $this->getInput('searchSubmitText'), 'placeHolder' => $this->getInput('searchPlaceHolder'), 'resultHideContent' => $this->getInput('searchResultHideContent',helper::FILTER_BOOLEAN), 'previewLength' => $this->getInput('searchPreviewLength',helper::FILTER_INT), - 'keywordColor' => $this->getInput('searchKeywordColor') + 'keywordColor' => $this->getInput('searchKeywordColor'), + 'style' => $success ? self::DATA_DIR . 'modules/' . $class . '/' . $moduleId . '.css' : '', + 'versionData' => $this->getData(['module', $this->getUrl(0), 'config', 'versionData']) ]]); @@ -83,12 +128,8 @@ class search extends common { } public function index() { - - // Création des valeurs de réglage par défaut - if ( $this->getData(['module', $this->getUrl(0)]) === null ) { - require_once('module/search/ressource/defaultdata.php'); - $this->setData(['module', $this->getUrl(0), init::$defaultData]); - } + // Mise à jour des données de module + $this->update(); if($this->isPost()) { //Initialisations variables @@ -99,11 +140,59 @@ class search extends common { // Récupération du mot clef passé par le formulaire de ...view/index.php, avec caractères accentués self::$motclef=$this->getInput('searchMotphraseclef'); + // Variable de travail, on conserve la variable globale pour l'affichage du résultat + $motclef = self::$motclef; + + // Traduction du mot clé si le script Google Trad est actif + // Le multi langue est sélectionné + if ( $this->getData(['config','translate','scriptGoogle']) === true + AND + // et la traduction de la langue courante est automatique + ( isset($_COOKIE['googtrans']) + AND ( $this->getData(['config','translate', substr($_COOKIE['googtrans'],4,2)]) === 'script' + // Ou traduction automatique + OR $this->getData(['config','translate','autoDetect']) === true ) + ) + // Cas des pages d'administration + // Pas connecté + AND ( $this->getUser('password') !== $this->getInput('ZWII_USER_PASSWORD') + // Ou connecté avec option active + OR ($this->getUser('password') === $this->getInput('ZWII_USER_PASSWORD') + AND $this->getData(['config','translate','admin']) === true + ) + ) + AND !isset($_COOKIE['ZWII_I18N_SITE']) + ) + { + // Découper la chaîne + $f = str_getcsv($motclef, ' '); + // Supprimer les espaces et les guillemets + $f = str_replace(' ','',$f); + $f = str_replace('"','',$f); + // Lire le cookie GoogTrans et déterminer les langues cibles + $language['origin'] = substr($_COOKIE['googtrans'],4,2); + $language['target'] = substr($_COOKIE['googtrans'],1,2); + if ($language['target'] !== $language['origin']) { + foreach ($f as $key => $value) { + $e = $this->translate($language['origin'],$language['target'],$value); + $motclef = str_replace($value,$e,$motclef); + } + } + } + + // Suppression des mots < 3 caractères et des articles > 2 caractères de la chaîne $motclef + $arraymotclef = explode(' ', $motclef); + $motclef = ''; + foreach($arraymotclef as $key=>$value){ + if( strlen($value)>2 && $value!=='les' && $value!=='des' && $value!=='une' && $value!=='aux') $motclef.=$value.' '; + } + // Suppression du dernier ' ' + if($motclef !== '') $motclef = substr($motclef,0, strlen($motclef)-1); // Récupération de l'état de l'option mot entier passé par le même formulaire self::$motentier=$this->getInput('searchMotentier', helper::FILTER_BOOLEAN); - if (self::$motclef !== '' ) { + if ($motclef !== '' ) { foreach($this->getHierarchy(null,false,null) as $parentId => $childIds) { if ($this->getData(['page', $parentId, 'disable']) === false && $this->getUser('group') >= $this->getData(['page', $parentId, 'group']) && @@ -112,7 +201,7 @@ class search extends common { $titre = $this->getData(['page', $parentId, 'title']); $contenu = ' ' . $titre . ' ' . $this->getData(['page', $parentId, 'content']); // Pages sauf pages filles et articles de blog - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } @@ -127,14 +216,15 @@ class search extends common { $titre = $this->getData(['page', $childId, 'title']); $contenu = ' ' . $titre . ' ' . $this->getData(['page', $childId, 'content']); //Pages filles - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } } // Articles d'une sous-page blog - if ($this->getData(['page', $childId, 'moduleId']) === 'blog') + if ($this->getData(['page', $childId, 'moduleId']) === 'blog' && + $this->getData(['module',$parentId,'posts']) ) { foreach($this->getData(['module',$childId,'posts']) as $articleId => $article) { if($this->getData(['module',$childId,'posts',$articleId,'state']) === true) { @@ -142,7 +232,7 @@ class search extends common { $titre = $article['title']; $contenu = ' ' . $titre . ' ' . $article['content']; // Articles de sous-page de type blog - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } @@ -152,7 +242,8 @@ class search extends common { } // Articles d'un blog - if ($this->getData(['page', $parentId, 'moduleId']) === 'blog' ) { + if ($this->getData(['page', $parentId, 'moduleId']) === 'blog' && + $this->getData(['module',$parentId,'posts']) ) { foreach($this->getData(['module',$parentId,'posts']) as $articleId => $article) { if($this->getData(['module',$parentId,'posts',$articleId,'state']) === true) { @@ -160,7 +251,7 @@ class search extends common { $titre = $article['title']; $contenu = ' ' . $titre . ' ' . $article['content']; // Articles de Blog - $tempData = $this->occurrence($url, $titre, $contenu, self::$motclef, self::$motentier); + $tempData = $this->occurrence($url, $titre, $contenu, $motclef, self::$motentier); if (is_array($tempData) ) { $result [] = $tempData; } @@ -189,7 +280,8 @@ class search extends common { $this->addOutput([ 'view' => 'index', 'showBarEditButton' => true, - 'showPageContent' => !$this->getData(['module', $this->getUrl(0),'resultHideContent']) + 'showPageContent' => !$this->getData(['module', $this->getUrl(0), 'config', 'resultHideContent']), + 'style' => $this->getData(['module', $this->getUrl(0), 'config', 'style']) ]); } else { // Valeurs en sortie, affichage du formulaire @@ -216,7 +308,9 @@ class search extends common { // Construire la clé de recherche selon options de recherche $keywords = '/('; + foreach ($a as $key => $value) { + $keywords .= $motentier === true ? $value . '|' : '\b' . $value . '\b|' ; } $keywords = substr($keywords,0,strlen($keywords) - 1); @@ -234,9 +328,9 @@ class search extends common { // Rechercher l'espace le plus proche $d = $d >= 1 ? strpos($contenu,' ',$d) : $d; // Découper l'aperçu - $t = substr($contenu, $d ,$this->getData(['module',$this->getUrl(0),'previewLength'])); + $t = substr($contenu, $d ,$this->getData(['module',$this->getUrl(0), 'config', 'previewLength'])); // Applique une mise en évidence - $t = preg_replace($keywords, '\1',$t); + $t = preg_replace($keywords, '\1',$t); // Sauver résultat $resultat .= '

'.$t.'...

'; $resultat .= '

' . count($matches[0]) . (count($matches[0]) === 1 ? ' correspondance

' : ' correspondances

'); @@ -248,4 +342,10 @@ class search extends common { } } } + + // Requête de traduction avec le script Google + private function translate($from_lan, $to_lan, $text) { + $arrayjson = json_decode(file_get_contents('https://translate.googleapis.com/translate_a/single?client=gtx&sl='.$from_lan.'&tl=fr&dt=t&q='.$text),true); + return $arrayjson[0][0][0]; + } } diff --git a/module/search/view/config/config.php b/module/search/view/config/config.php index f54674d7..06d22285 100755 --- a/module/search/view/config/config.php +++ b/module/search/view/config/config.php @@ -20,13 +20,13 @@

'Texte du bouton', - 'value' => $this->getData(['module', $this->getUrl(0), 'submitText']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'submitText']) ]); ?>
'Dimension de l\'aperçu', - 'selected' => $this->getData(['module', $this->getUrl(0),'previewLength']) + 'selected' => $this->getData(['module', $this->getUrl(0), 'config', 'previewLength']) ]); ?>
@@ -34,12 +34,12 @@
'Aide dans la zone de saisie', - 'value' => $this->getData(['module', $this->getUrl(0), 'placeHolder']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'placeHolder']) ]); ?>
$this->getData(['module', $this->getUrl(0), 'resultHideContent']), + 'checked' => $this->getData(['module', $this->getUrl(0), 'config', 'resultHideContent']), ]); ?>
@@ -59,7 +59,7 @@ 'class' => 'colorPicker', 'help' => 'Le curseur horizontal règle le niveau de transparence, le placer tout à la gauche pour un surlignement invisible.', 'label' => 'Surlignement', - 'value' => $this->getData(['module', $this->getUrl(0), 'keywordColor']) + 'value' => $this->getData(['module', $this->getUrl(0), 'config', 'keywordColor']) ]); ?>
diff --git a/module/search/view/index/index.php b/module/search/view/index/index.php index 5fa91623..06434a7e 100755 --- a/module/search/view/index/index.php +++ b/module/search/view/index/index.php @@ -4,7 +4,7 @@
$this->getData(['module', $this->getUrl(0), 'placeHolder']), + 'placeholder' => isset($_COOKIE['ZWII_I18N_SITE'] ) ? $this->getData(['module', $this->getUrl(0), 'placeHolder']):'Un ou plusieurs mots clef séparés par un espace', 'value' => $module::$motclef ]); ?>