Compare commits

...

67 Commits

Author SHA1 Message Date
Maïeul 68a29f09a8 change: inutile de supprimer un paramètre d'une url si on peut ne pas le mettre dès le début 4 months ago
Maïeul ee90bfddab perf: plutôt que d'avoir un filtre, utiliser directement un appel PHP 4 months ago
Maïeul debe3fd1df fix: appliquer_filtre est défini dans inc/filtres 4 months ago
Maïeul 42e7ce3b44 change: on laisse tomber ces dans les fonctions de génération des jsons 4 months ago
Maïeul 16de36c9e8 perf: le json est demandé avec appel du cache, mais on ne cache pas le fichier principal. On a ainsi des infos fraiches, mais un peu de gain de temps par rapport aux caches des fichiers de vue individuels 4 months ago
Maïeul 556b474216 fix: s'assurer qu'il n'y ait pas deux fois la même colonne 4 months ago
Maïeul b9b5ecbab1 fix: appeler correctement les autorisation 4 months ago
Maïeul 508ce6bfbc feat: une méthode PHP pour les exports vers tableur, sur laquelle on 4 months ago
Maïeul a5066ad564 style: espacement 4 months ago
Maïeul 29de203e51 feat: réinitialisation des paramètres côté PHP 4 months ago
Maïeul c81314bbb8 perf: inutile de retrouver les infos que l'on vient de poster 4 months ago
Maïeul ed1cce9061 remove: on ne stocke plus rien du tout en local 4 months ago
Maïeul 6480fad149 feat: stocker côté PHP la largeur des colonnes 4 months ago
Maïeul 77cb881f01 change: les méthodes get_xx n'ont pas besoin de recevoir xx en param 4 months ago
Maïeul a90f4bd7c3 fix: ne pas demander des pages cachées, seuls les vues des saisies le sont 4 months ago
Maïeul af4d44310e feat: faire fonctionner la reinitialisation des filtres 4 months ago
Maïeul 829e762de6 style: un peu d'espacement 4 months ago
Maïeul efba740442 style: pas d'espace avant les deux points 4 months ago
Maïeul 98eea0e9ff fix: ne pas stocker des filtres vide 4 months ago
Maïeul b195c49fbe change: Modification de la manière dont sont gérés les ajouts / 4 months ago
Maïeul 1839fa1f8d docs: correction PHPdoc 4 months ago
Maïeul 8b57bc4230 style: espacement manquant 4 months ago
Maïeul 63b242ce0a style: coquille phpdoc 4 months ago
Maïeul a294f466c2 change: une méthode qui aurait du être privé 4 months ago
Maïeul 89af46b363 style: mise en forme de commentaire pré méthode 4 months ago
Maïeul 81015ccb96 change: éviter d'avoir des variables globales qui trainent en JS (ou : Maïeul découvre la portéer des variables JS) 4 months ago
Maïeul 0e75c096e5 feat: stocker côté serveur les colonnes visibles/invisibles 4 months ago
Maïeul 3c51d85b58 style: espaces manquantes 4 months ago
Maïeul ad32b7b15d change: deux méthodes qui auraient du être privées 4 months ago
Maïeul 819b699e2b remove: suppression de la fonction d'impression, qui ne marchait pas très bien, et désormais peu utile avec les exports en tableur 4 months ago
Maïeul 4ea5a3f799 feat: Lorsqu'on déplace une colonne, déplacer également le tri. 4 months ago
Maïeul ba1de7ef2f style: espacement 4 months ago
Maïeul ea3db0686f style: indentation 4 months ago
Maïeul 7ef867317f Passage du tri des colonnes en 'une colonne par une colonne' 4 months ago
Maïeul ac68a27ac3 reprise de 6552bcbf91 4 months ago
Maïeul 646fe4eb4a reprise de code de master 4 months ago
Maïeul 2f96777b23 Notice PHP 8 4 months ago
Maïeul 394ee0124f Stocker les filtres en associant aux identifiants de colonnes, plutot qu'à l'order, pour gérer les deplacement de colonnes 4 months ago
Maïeul 5a695b5bc5 Permettre d'annuler les filtres sur la colonne 0 4 months ago
Maïeul 6334eb5950 ne pas renvoyer tout les paramètres à chaque nouvelle requete du json 4 months ago
Maïeul 683cb57aa7 deplacement des colonnes en stockage base 4 months ago
Maïeul 4874260312 simplification 4 months ago
Maïeul ef4fecb886 declaration morte 4 months ago
Maïeul c0755df6e5 surcharger la désactivation du cache par tablesorter 4 months ago
Maïeul 676e44add9 Passage du tri des colonnes en 'une colonne par une colonne' 4 months ago
Maïeul 8cf8ff17ed on ne supportera plus le storage local 4 months ago
Maïeul 9f5bb3ed13 commentaire inutile 4 months ago
Maïeul 1692419902 oups, rétablir le tri des champs standards 4 months ago
Maïeul 67632c49c2 stockage des filtres côté serveur, plus besoin de renvoyer la liste à chaque fois dans les params, mais par contre il faut la récuperer au retour du json 4 months ago
Maïeul d284daf8b3 Le `id_formulaire` passe du `$env` au `$setting` 4 months ago
Maïeul 5719569b74 Page de départ et taille de la page utilise désormais la classe Settings 4 months ago
Maïeul 807035da2f ne pas se tromper sur la page par défaut 4 months ago
Maïeul f9d792b179 Une méthode pour réinitialiser les réglages 4 months ago
Maïeul 2fef87c526 Cohérence : 4 months ago
Maïeul ed1dbfdde9 code mort 4 months ago
Maïeul 738a28a53e indiquer les réglages par défaut 4 months ago
Maïeul c4d0baf409 méthode privée 4 months ago
Maïeul 86ed161144 Une classe pour gérer les réglages par paire internaute/formulaire (gère 4 months ago
Maïeul d6953a351f une table en base pour stocker les réglages de visualisation des tableaux, par paire formulaire/auteur 4 months ago
Maïeul f85aff03be séparation et renommage des classes pour suivres les conventions + autoload + un trick pour récupérer la , et un gros bigup à @marcimat pour son aide 4 months ago
Maïeul 0c7ebbf9bd passer en GET, avant d'oublier 4 months ago
Maïeul 8bc6f45d36 Si une seules cellules dans la ligne ne remplie pas la condition, inutile de chercher les autres cellules de la ligne 4 months ago
Maïeul 64753b1452 Éviter de generer un pseudo afficher_si pour rien 4 months ago
Maïeul c2b461ad66 un peu de cohérence dans l'imbrication des tests 4 months ago
Maïeul 247e40cc9b On rendra cette v3 compatible SPIP 4.0 uniquement, et formidable v5.2.0 uniquement 4 months ago
Maïeul 22a68bafa8 Une v3 pour revoir intégralement le stockage des réglages d'affichage. 4 months ago
Maïeul 77a9c7cdd9 retour partiel sur 2edd0f9, dans formidable_tablesorter, les schemas ont juste un numero d'ordre, pas de x.y.z (et c'est bien plus simple) 4 months ago
  1. 90
      Formidable_ts/Cell.php
  2. 20
      Formidable_ts/Header.php
  3. 303
      Formidable_ts/Setting.php
  4. 420
      Formidable_ts/Table.php
  5. 41
      action/formidable_ts_export.php
  6. 38
      base/formidable_ts.php
  7. 42
      formidable_ts.json.html
  8. 6
      formidable_ts_administrations.php
  9. 21
      formidable_ts_autoload.php
  10. 3
      formidable_ts_columnSelector.json.html
  11. 30
      formidable_ts_columnSelector.json_fonctions.php
  12. 3
      formidable_ts_resetAll.json.html
  13. 11
      formidable_ts_resetAll.json_fonctions.php
  14. 3
      formidable_ts_resizable_widths.json.html
  15. 21
      formidable_ts_resizable_widths.json_fonctions.php
  16. 3
      formidable_ts_sortList.json.html
  17. 26
      formidable_ts_sortList.json_fonctions.php
  18. 3
      inclure/formidable_ts_boutons.html
  19. 8
      inclure/formidable_ts_entete.html
  20. 310
      javascript/formidable_ts.js
  21. 1
      javascript/formidable_ts.json.html
  22. 6
      modeles/formidable_ts_fonctions.php
  23. 11
      paquet.xml

90
Formidable_ts/Cell.php

@ -0,0 +1,90 @@
<?php
namespace Formidable_ts;
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Classe représentant une cellule
* @var str|int $id_formulaire
* @var str|int $id_formulaires_reponse
* @var str|int $nom
* @var str $value valeur de la cellule,
* @var str $sort_value valeur de la cellule, pour le tri
* @var bool $crayons est-ce crayonnable?
* @var string $type natif|extra|champ
**/
class Cell implements \JsonSerializable{
private $table;
private $id_formulaires_reponse;
private $nom;
private $column_range;
private $value;
private $sort_value;
private $filter_value;
private $crayons;
private $type;
public function __construct($param = array()) {
$this->table = $param['table'] ?? false;
$this->id_formulaires_reponse = $param['id_formulaires_reponse'] ?? false;
$this->column_range = $param['column_range'] ?? 'nope';
$this->nom = $param['nom'];
$this->value = $param['value'];
$this->sort_value = $param['sort_value'] ?? \textebrut($this->value);
$this->filter_value = strtolower($param['filter_value'] ?? \textebrut($this->value));
$this->crayons= $param['crayons'] ?? false;
$this->type = $param['type'] ?? 'champ';
}
/**
* Returne la valeur string, avec le span englobant, pour les crayons
**/
public function jsonSerialize() :string {
if ($this->crayons) {
if ($this->type == 'extra') {
$class = classe_boucle_crayon('formulaires_reponse', $this->nom, $this->id_formulaires_reponse);
} elseif ($this->type == 'champ') {
$class = \calculer_voir_reponse($this->id_formulaires_reponse, $this->table->id_formulaire, $this->nom, '', 'edit');
}
$value = $this->value ? $this->value : '&nbsp;';
return "<div class='$class'>$value</div>";
} else {
return $this->value;
}
}
/**
* Return la propriété, permet d'y accéder mais pas de la modifier
* @param string $prop
**/
public function __get($prop) {
return $this->$prop;
}
/**
* Vérifie si la cellule passe le filtre
* @return bool
**/
public function checkFilter() {
$filter = $this->table->filters;
$column_range = $this->column_range;
if (!isset($filter[$column_range]) or !$filter[$column_range]) {
return true;
} else {
return saisies_evaluer_afficher_si(
$filter[$column_range],
array(),
array(),
$this->filter_value
);
return false;
}
}
/**
* Exporte sous forme de chaine
* @return string
**/
public function __toString() {
return \textebrut($this->value ?? '');
}
}

20
Formidable_ts/Header.php

@ -0,0 +1,20 @@
<?php
namespace Formidable_ts;
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Classe implémentant un entete
* C'est comme une cellule, mais ca donne en plus les flèches de déplacement + des datas attributs sur le nom
**/
class Header extends Cell {
/**
* Returne la valeur string, avec le span englobant, pour les crayons
**/
public function jsonSerialize() :string {
$data_col = "$this->type-$this->nom";
$arrows = "<div data-col='$data_col' class='move-arrows'><a class='left'>&#x2B05;</a> <a class='right'>&#x27A1;</a></div>";
return "$arrows\n\r<div class='header-title'>$this->value</div>";
}
}

303
Formidable_ts/Setting.php

@ -0,0 +1,303 @@
<?php
namespace Formidable_ts;
/*
* Une classe permettant de gérer le Setting d'affichage de formidable_ts
* associé à un formulaire
*/
include_spip('inc/session');
include_spip('inc/sql');
class Setting {
// Note, pas de typage des propriétés de class, car doit pouvoir encore fonction en PHP 7.3
private $id_auteur;
private $setting;
private $id_formulaire;
private $where_base;
/**
* @param string|int $id_formulaire le formulaire
* L'env du squelette
**/
public function __construct(int $id_formulaire) {
$this->id_formulaire = $id_formulaire;
if ($id_auteur = \session_get('id_auteur')) {
$this->id_auteur = $id_auteur;
$this->where_base = [
'id_auteur' => $id_auteur,
'id_formulaire' => $id_formulaire
];
$base = sql_getfetsel(
'setting',
'spip_formidable_ts_settings',
$this->where_base
);
if ($base) {
$this->setting = json_decode($base, true);
} else {
$this->set(['action' => 'default']);
sql_insertq(
'spip_formidable_ts_settings',
array_merge(
['setting' => \json_encode($this->setting)],
$this->where_base
),
);
}
} else {
$this->id_auteur = 0;
$this->setting = \session_get("formidable_ts_$id_formulaire");
if (!$this->setting) {
$this->set(['action' => 'default']);
}
}
}
/**
* Modifie la configuration
* @param array $description
* 'action' => une action à faire, appelle la methode "$set_action" si existe, sinon se rabat sur un truc par défaut
* 'value' => pour les cas simple, juste la valeur à mettre (donc sans methode "$set_action")
* 'params' => paramètres détaillé
* Cette méthode se contente de :
* 1. appeler une méthode privée spécifique à l'action, laquelle doit modifier $this->setting
* 2. Enregistrer à la fin le résultat en session (si non connecté) ou en base (si connecté)
**/
public function set(array $description): void{
$action = $description['action'] ?? null;
if (!$action) {
return;
}
$f = "set_$action";
if (method_exists($this, $f)) {
$this->$f($description);
} else {
$this->setting[$description['action']] = $description['value'];
}
$this->save();
}
/**
* Enregistre les réglages
**/
private function save(): void {
if ($this->id_auteur) {
sql_updateq('spip_formidable_ts_settings', ['setting' => \json_encode($this->setting)], $this->where_base);
} else {
\session_set("formidable_ts_$this->id_formulaire", $this->setting);
}
}
/**
* Reinitialise tous les réglages
**/
public function reset(): void {
$this->setting = array();
$this->set_default();
$this->save();
}
/**
* Reinitialise les filtres
**/
public function reset_filters() {
$this->setting['filters'] = [];
}
/**
* Après l'initialisation, complète les réglages avec les réglages par défaut
**/
private function set_default(array $nope = array()) {
if ($this->setting ?? false) {
return;
}
$setting = &$this->setting;
$setting['size'] = 100;
$setting['page'] = 0;
$setting['filters'] = array();
$setting['sort'] = array();
$setting['order'] = array();
$setting['resizable_widths'] = [
'natif-statut' => 80,
'natif-id_formulaires_reponse' => 80
];
}
/**
* Modifie les filtres
* @param $setting
**/
private function set_filters(array $setting) {
if (!$this->setting['filters'] ?? false) {
$this->setting['filters'] = [];
}
if ($setting['filter'] === '') {
unset($this->setting['filters'][$this->setting['order'][$setting['filter_column']]]);
} else {
$this->setting['filters'][$this->setting['order'][$setting['filter_column']]] = $setting['filter'];
}
}
/**
* Modifie les tris
* @param $setting
**/
private function set_sort(array $setting) {
if (!$this->setting['sort'] ?? false or $setting['sort_only_one']) {
$this->setting['sort'] = [];
}
$this->setting['sort'][$this->setting['order'][$setting['sort_column']]] = $setting['sort'];
}
/**
* Modifie les largeur de colonne
* @param $setting
**/
private function set_resizable_widths(array $setting) {
foreach ($setting['value'] as $i => $v) {
$this->setting['resizable_widths'][$this->setting['order'][$i]] = $v;//Passer de clé numérique a valeur indexée
}
}
/**
* Lorsqu'un tableau est construit pour la première fois,
* stocker l'ordre initial des colonnes.
* Lorsqu'il est construit une nouvelle fois, ajuster les champs ajoutés/supprimés
**/
private function set_columns(array $columns) {
if (!$this->setting['order']) {
$this->setting['order'] = $columns['value'];
} else {
$diff = array_diff($columns['value'], $this->setting['order']);
$this->setting['order'] = array_merge($this->setting['order'], $diff);
$this->setting['order'] = array_intersect($this->setting['order'], $columns['value']);
$this->set_consistency();
}
}
/**
* Ajuste la consistence des données
* entre les colonnes définies dans `order`
* et les colonnes qui possède des réglages spéciaux dans l'une ou l'autre des clés
**/
public function set_consistency() {
$this->setting['order'] = array_unique($this->setting['order']);
$existing_columns = array_flip($this->setting['order']);
foreach (['filters', 'sort','disabled_columns'] as $s) {
foreach ($this->setting[$s] ?? [] as $k => $v) {
if (!isset($existing_columns[$k])) {
unset($this->setting[$s][$k]);
}
}
}
$this->save();
}
/**
* Modifie l'ordre des colonnes
*
**/
private function set_move(array $set) {
$position = array_search($set['col'], $this->setting['order']);
$old = $this->setting['order'];
// Changer l'ordre des colonnes
if ($set['direction'] === 'left') {
$new = array_merge(
array_slice($old, 0, $position -1),
[$set['col']],
[$old[$position-1]],
array_slice($old, $position + 1)
);
} elseif ($set['direction'] === 'right') {
$new = array_merge(
array_slice($old, 0, $position),
[$old[$position+1]],
[$set['col']],
array_slice($old, $position + 2)
);
}
$this->setting['order'] = $new;
}
/**
* Modifier les colonnes masquées
**/
private function set_columnSelector(array $set) {
if ($set['column'] !== 'all') {
$disabled_columns = $this->setting['disabled_columns'] ?? [];
$column = $this->setting['order'][$set['column']];
if ($set['change'] === 'disable') {
$disabled_columns[] = $column;
} elseif ($set['change'] === 'enable') {
$disabled_columns = array_diff($disabled_columns, [$column]);
}
} else {
if ($set['change'] === 'disable') {
$disabled_columns = $this->setting['order'];
} elseif ($set['change'] === 'enable') {
$disabled_columns = [];
}
}
$this->setting['disabled_columns'] = array_unique($disabled_columns);
}
/**
* Renvoie les settings
* @param string $param
* @return array
**/
public function get(string $param) {
$f = "get_$param";
if (method_exists($this, $f)) {
return $this->$f();
}
return $this->setting[$param] ?? ($this->$param ?? null);
}
/**
* Renvoie l'information sur le tri des colonnes
* En base on stocke par identifiant textuel
* Mais tablesorter a besoin d'avoir les infos par identifiant numérique
* On fait donc la conversion
* @return array
**/
private function get_sort(): array {
$order = array_flip($this->setting['order']);
$return = [];
foreach ($this->setting['sort'] as $c => $v) {
$return[$order[$c]] = $v;
}
return $return;
}
/**
* Renvoie les colonnes visibles
* avec numéro
**/
private function get_columnSelector(): array {
$disabled_columns = $this->setting['disabled_columns'] ?? [];
$enabled_columns = array_diff($this->get('order'), $disabled_columns);
return array_keys($enabled_columns);
}
/**
* Renvoie la taille des colonnes
* @return array tableau indexé des tailles
***/
private function get_resizable_widths(): array {
$return = [];
foreach ($this->setting['order'] as $col) {
$return[] = $this->setting['resizable_widths'][$col] ?? 'auto';
}
return $return;
}
}

420
javascript/formidable_ts.json_fonctions.php → Formidable_ts/Table.php

@ -1,23 +1,23 @@
<?php
namespace formidable_ts;
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/sql');
namespace Formidable_ts;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Common\Entity\Style\Color;
include_spip('inc/saisies');
include_spip('inc/cextras');
include_spip('saisies/afficher_si_php');
include_spip('public/fonctions');
include_spip('inc/filtres');
/*
* La classe principale
* qui cherche les données en base
* et retourne un tableau json si besoin
*/
class table {
class Table {
private $size;
private $page;
private $id_formulaire;
private $filter;
private $sort;
private $filters;
private $rows;
private $headers;
private $champs;
@ -29,42 +29,28 @@ class table {
private $statut;
private $totalRows;
private $columns;
private $setting;
private $identifiant;
/**
* @param array $env
* @param array $statut
* L'env du squelette
**/
public function __construct($env) {
$this->id_formulaire = sql_quote($env['id_formulaire'] ?? null);
public function __construct($statut, $setting) {
$this->id_formulaire = $setting->get('id_formulaire');
$this->setting = $setting;
$this->totalRows=0;
// Transformer les filtres en pseudo afficher_si
$this->filter = $env['filter'] ?? array();
if (!$this->filter) {// Peut être ''
$this->filter = array();
}
$this->filter = array_map(function($a) {
$a = strtolower($a);
if (!preg_match('#(=|>|<|MATCH)#', $a)) {
$a = " MATCH '/$a/'";
}
$a = rawurldecode($a);
return $a;
},
$this->filter
);
$this->sort = $env['sort'] ?? array();
$this->sort = $setting->get('sort') ?? array();
if (!$this->sort) {
$this->sort = array();//Ne pas autoriser ''
}
$env['statut'] = $env['statut'] ?? null;
$this->statut = \sql_quote($env['statut'] ? $env['statut'] : '.*');
$this->statut = \sql_quote($statut ? $statut : '.*');
$formulaire_detail = sql_fetsel('saisies, traitements, identifiant', 'spip_formulaires', "id_formulaire=$this->id_formulaire");
$this->identifiant = $formulaire_detail['identifiant'];
$formulaire_detail = sql_fetsel('saisies, traitements', 'spip_formulaires', "id_formulaire=$this->id_formulaire");
include_spip('formidable_fonctions');
if (function_exists('\formidable_deserialize')) {
$this->champs = \formidable_deserialize($formulaire_detail['saisies']);
} else {
$this->champs = \unserialize($formulaire_detail['saisies']);
}
$this->champs = \formidable_deserialize($formulaire_detail['saisies']);
// Afficher les ip ?
if (lire_config('formidable/exporter_adresses_ip')) {
$this->ip = true;
@ -94,17 +80,41 @@ class table {
}
$this->rows = array();
$this->headers = array();
$this->page = $env['page_ts'] ?? 1 ;
$this->size = $env['size'] ?? 100;
$this->setColumns($env['order'] ?? array());
$this->page = $setting->get('page');
$this->size = $setting->get('size');
$this->setColumns();
$this->setFilters();
}
/**
* Ajuster les filtres
**/
private function setFilters() : void {
// En base les filtres sont stockés par nom de column, mais pour tablesorter il faut les indiquer par position de column -> on converti
$filters = $this->setting->get('filters') ?? array();
$this->raw_filters = array();
foreach ($filters as $f => $filter) {
$this->raw_filters[array_search($f, $this->columns)] = $filter;
}
// Transformer les filtres en pseudo afficher_si
$this->filters = array_map(function($a) {
$a = strtolower($a);
if (!preg_match('#(=|>|<|MATCH)#', $a) and $a) {
$a = " MATCH '/$a/'";
}
$a = rawurldecode($a);
return $a;
},
$this->raw_filters
);
}
/**
* Définir les colonnes et leur ordre
* @param array $order ordre des colonnes envoyé;
* @return array
**/
function setColumns($order = array()) {
private function setColumns() : void {
$columns = array();
$columns[] = 'natif-statut';
$columns[] = 'natif-id_formulaires_reponse';
@ -124,14 +134,17 @@ continue;
}
$columns[] = 'champ-'.$champ['options']['nom'];
}
// Ajouter les nouvelles colonnes à la fin, et soustraire celles qui n'existent plus
$diff = array_diff($columns, $order);
$this->columns = array_merge($order, $diff);
$this->columns = array_intersect($this->columns, $columns);
$this->setting->set(
[
'action' => 'columns',
'value' => $columns
]
);
$this->columns = $this->setting->get('order');
}
/**
* Peupler headers et rows
* Peupler Headers et rows
**/
public function setData() {
$this->setRows();
@ -139,7 +152,7 @@ continue;
}
/**
* Peupler les headers à partir de la base SQL
* Peupler les Headers à partir de la base SQL
**/
public function setHeaders() {
$headers = &$this->headers;
@ -147,28 +160,28 @@ continue;
list($type, $nom) = explode('-', $column);
if ($type === 'natif') {
if ($nom === 'statut') {
$headers[] = new header([
$headers[] = new Header([
'table' => $this,
'type' => 'natif',
'nom' => 'statut',
'value' => '#'
]);
} elseif ($nom === 'id_formulaires_reponse') {
$headers[] = new header([
$headers[] = new Header([
'table' => $this,
'type' => 'natif',
'nom' => 'id_formulaires_reponse',
'value' => _T('info_numero_abbreviation')
]);
} elseif ($nom === 'date_envoi') {
$headers[] = new header ([
$headers[] = new Header ([
'table' => $this,
'type' => 'natif',
'nom' => 'date_envoi',
'value' => _T('formidable:date_envoi')
]);
} elseif ($nom === 'ip') {
$headers[] = new header ([
$headers[] = new Header ([
'table' => $this,
'type' => 'natif',
'nom' => 'ip',
@ -193,7 +206,7 @@ continue;
if ($fieldset) {
$label .= " <span class='fieldset_label'>($fieldset)</span>";
}
$headers[] = new header ([
$headers[] = new Header ([
'table' => $this,
'type' => $type,
'nom' => $saisie['options']['nom'],
@ -222,13 +235,16 @@ continue;
$id_formulaires_reponse = $row_reponse['id_formulaires_reponse'];
$row_ts = [];
$this->totalRows++;
$column_range = -1;
foreach ($this->columns as $column) {
list($type, $nom) = explode('-', $column);
$column_range++;
if ($type === 'natif') {
if ($nom === 'statut') {
$value = \liens_absolus(\appliquer_filtre($row_reponse['statut'], 'puce_statut', 'formulaires_reponse', $row_reponse['id_formulaires_reponse'], true));
$row_ts[] = new cell([
$Cell = new Cell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'statut',
'value' => $value,
@ -239,8 +255,9 @@ continue;
]);
} elseif ($nom === 'id_formulaires_reponse') {
$value = '<a href="'.\generer_url_ecrire('formulaires_reponse', 'id_formulaires_reponse='.$row_reponse['id_formulaires_reponse']).'">'.$row_reponse['id_formulaires_reponse'].'</a>';
$row_ts[] = new cell([
$Cell = new Cell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'id_formulaires_reponse',
'value' => $value,
@ -251,8 +268,9 @@ continue;
]);
} elseif ($nom === 'date_envoi') {
$value = \affdate_heure($row_reponse['date_envoi']);
$row_ts[] = new cell([
$Cell = new Cell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'date_envoi',
'value' => $value,
@ -263,8 +281,9 @@ continue;
]);
} elseif ($nom === 'ip') {
$value = $row_reponse['ip'];
$row_ts[] = new cell([
$Cell = new Cell([
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => 'date_envoi',
'value' => $value,
@ -274,8 +293,7 @@ continue;
'type' =>'natif'
]);
}
} else {
if ($type === 'extra') {
} elseif ($type === 'extra') {
$champ = $this->cextras_finaux_par_nom[$nom];
$crayons = false;
$nom = $champ['options']['nom'];
@ -295,63 +313,106 @@ continue;
} else {
$value = implode(\calculer_balise_LISTER_VALEURS('formulaires_reponses', $nom, $row_reponse[$nom]), ', ');
}
$row_ts[] = new cell(
$Cell = new Cell(
[
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => $nom,
'value' => $value,
'sort_value' => sort_value($value, $champ, 'extra'),
'sort_value' => $this->sort_value($value, $champ, 'extra'),
'filter_value' => null,
'crayons' => $crayons,
'type' => 'extra'
]
);
} else { // Réponse de l'internaute
$value = \calculer_voir_reponse($id_formulaires_reponse, $this->id_formulaire, $nom, '', 'valeur_uniquement');
$value_raw = \calculer_voir_reponse($id_formulaires_reponse, $this->id_formulaire, $nom, '', 'brut');
$champ = $this->champs_finaux_par_nom[$nom];
$row_ts[] = new cell(
[
'table' => $this,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => $nom,
'value' => $value,
'sort_value' => sort_value($value_raw, $champ, 'champ'),
'filter_value' => null,
'crayons' => true,
'type' => 'champ'
]
);
}
} else { // Réponse de l'internaute
$value = \calculer_voir_reponse($id_formulaires_reponse, $this->id_formulaire, $nom, '', 'valeur_uniquement');
$value_raw = \calculer_voir_reponse($id_formulaires_reponse, $this->id_formulaire, $nom, '', 'brut');
$champ = $this->champs_finaux_par_nom[$nom];
$Cell = new Cell(
[
'table' => $this,
'column_range' => $column_range,
'id_formulaires_reponse' => $id_formulaires_reponse,
'nom' => $nom,
'value' => $value,
'sort_value' => $this->sort_value($value_raw, $champ, 'champ'),
'filter_value' => null,
'crayons' => true,
'type' => 'champ'
]
);
}
// Verifier si la Cellulle passe le test
if ($Cell->checkFilter()) {
$row_ts[] = $Cell;
} else {
continue 2;
}
}
// Vérifier si cela passe le filtres:
if ($this->checkFilter($row_ts)) {
$this->rows[] = $row_ts;
}
$this->rows[] = $row_ts;
}
$this->sortRows();
}
/**
* Vérifier si une ligne passe les tests de filtre
* @param array $row
* @return bool
* Appelle le pipeline formidable_ts_sort_value
* Pour trouver le type de tri
* @param str|int $valeur valeur brute du champ de formulaire
* @param array $saisie decrit la saisie
* @param string $type='champ' ou bien 'extra'
* @return string valeur du data-sort-attribut
**/
private function checkFilter($row) {
foreach ($this->filter as $col=>$filter) {
$result = saisies_evaluer_afficher_si(
$filter,
array(),
array(),
$row[$col]->filter_value
);
if ($result == false) {
return false;
private function sort_value($valeur, $saisie, $type = 'champ') {
if ($saisie['saisie'] === 'evenements' and $valeur) {
if (!is_array($valeur)) {
$data = \sql_getfetsel('date_debut', 'spip_evenements', 'id_evenement='.$valeur);
} else {
$data = \sql_getfetsel('date_debut', 'spip_evenements', sql_in('id_evenement', $valeur), '', 'date_debut', '0,1');
}
} else {
$data = $valeur;
}
if ($type === 'extra') {
if (strpos($saisie['options']['sql'], 'INT') !== false
or
strpos($saisie['options']['sql'], 'FLOAT') !== false
or
strpos($saisie['options']['sql'], 'DATE') !== false
) {
$data = $valeur;
}
}
return true;
$array = false;
if (is_array($data)) {
$data = \json_encode($data);
$array = true;
}
$data = trim($data);
if (function_exists('mb_strtolower')) {
$data = mb_strtolower($data);
} else {
include_spip('inc/charsets');
$data = \strtolower(\translitteration($data));
}
if ($array) {
$data = \json_decode($data, true);
}
if (is_numeric($data)) {
$data = floatval($data);
}
return pipeline ('formidable_ts_sort_value', array(
'args' => array(
'valeur' => $valeur,
'saisie' => $saisie,
'type' => $type
),
'data' => $data
));
}
/**
@ -364,7 +425,7 @@ continue;
include_spip('inc/charsets');
}
usort($this->rows, function ($a, $b) {
// Trouver les cellules sur lesquelles trier
// Trouver les Cellules sur lesquelles trier
foreach ($this->sort as $column => $sort) {
$sort = intval($sort);
$a_sort = $a[$column]->sort_value;
@ -401,9 +462,11 @@ continue;
'rows' => array_slice($this->rows, $this->page*$this->size, $this->size),
'headers' => $this->headers,
'total' => $this->totalRows,
'filters' => array_replace(array_fill(0, count($this->headers), ''), $this->raw_filters)
);
return \json_encode($json);
}
/**
* Compte le nombre d'entetes
* @return int
@ -420,151 +483,42 @@ continue;
return $this->$prop;
}
}
/**
* Classe représentant une cellule
* @var str|int $id_formulaire
* @var str|int $id_formulaires_reponse
* @var str|int $nom
* @var str $value valeur de la cellule,
* @var str $sort_value valeur de la cellule, pour le tri
* @var bool $crayons est-ce crayonnable?
* @var string $type natif|extra|champ
**/
class cell implements \JsonSerializable{
private $table;
private $id_formulaires_reponse;
private $nom;
private $value;
private $sort_value;
private $filter_value;
private $crayons;
private $type;
public function __construct($param = array()) {
$this->table = $param['table'] ?? false;
$this->id_formulaires_reponse = $param['id_formulaires_reponse'] ?? false;
$this->nom = $param['nom'];
$this->value = $param['value'];
$this->sort_value = $param['sort_value'] ?? \textebrut($this->value);
if (function_exists('mb_strtolower')) {
$this->filter_value = \mb_strtolower($param['filter_value'] ?? \textebrut($this->value));
} else {
include_spip('inc/charsets');
$this->filter_value = \strtolower(\translitteration($param['filter_value'] ?? \textebrut($this->value)));
}
$this->crayons= $param['crayons'] ?? false;
$this->type = $param['type'] ?? 'champ';
}
/**
* Returne la valeur string, avec le span englobant, pour les crayons
* Exporte les données sous forme de tableu
* @param string type: csv|xlsx|ods
* @return void
**/
public function jsonSerialize(): string{
if ($this->crayons) {
if ($this->type == 'extra') {
$class = classe_boucle_crayon('formulaires_reponse', $this->nom, $this->id_formulaires_reponse);
} elseif ($this->type == 'champ') {
$class = \calculer_voir_reponse($this->id_formulaires_reponse, $this->table->id_formulaire, $this->nom, '', 'edit');
}
$value = $this->value ? $this->value : '&nbsp;';
return "<div class='$class'>$value</div>";
} else {
return $this->value;
}
}
/**
* Return la propriété, permet d'y accéder mais pas de la modifier
* @param string $prop
**/
public function __get($prop) {
return $this->$prop;
}
}
public function export(string $type = 'csv') {
/**
* Classe implémentant un entete
* C'est comme une cellule, mais ca donne en plus les flèches de déplacement + des datas attributs sur le nom
**/
class header extends cell {
require_once find_in_path('lib/Spout/Autoloader/autoload.php');
$filename = $this->identifiant;
/**
* Returne la valeur string, avec le span englobant, pour les crayons
**/
public function jsonSerialize(): string {
$data_col = "$this->type-$this->nom";
$arrows = "<div data-col='$data_col' class='move-arrows'><a class='left'>&#x2B05;</a> <a class='right'>&#x27A1;</a></div>";
return "$arrows\n\r<div class='header-title'>$this->value</div>";
}
}
/**
* Depuis le #ENV de l'ajax appelé détermine le json à retourner
* Un simple wrapper pour une classe en fait
* @param array $env
* @return string json
**/
function formidable_ts_json($env) {
$formidable_ts = new table($env);
$formidable_ts->setData();
return $formidable_ts->getJson();
}
$style_headers = (new StyleBuilder())
->setFontBold()
->build();
/**
* Appelle le pipeline formidable_ts_sort_value
* Pour trouver le type de tri
* @param str|int $valeur valeur brute du champ de formulaire
* @param array $saisie decrit la saisie
* @param string $type='champ' ou bien 'extra'
* @return string valeur du data-sort-attribut
**/
function sort_value($valeur, $saisie, $type = 'champ') {
if ($saisie['saisie'] === 'evenements' and $valeur) {
if (!is_array($valeur)) {
$data = \sql_getfetsel('date_debut', 'spip_evenements', 'id_evenement='.$valeur);
} else {
$data = \sql_getfetsel('date_debut', 'spip_evenements', sql_in('id_evenement', $valeur), '', 'date_debut', '0,1');
}
if ($type == 'csv') {
$writer = WriterEntityFactory::createCSVWriter();
} elseif ($type == 'ods') {
$writer = WriterEntityFactory::createODSWriter();
} else {
$data = $valeur;
}
if ($type === 'extra') {
if (strpos($saisie['options']['sql'], 'INT') !== false
or
strpos($saisie['options']['sql'], 'FLOAT') !== false
or
strpos($saisie['options']['sql'], 'DATE') !== false
) {
$data = $valeur;
}
$writer = WriterEntityFactory::createXLSXWriter();
}
$array = false;
if (is_array($data)) {
$data = \json_encode($data);
$array = true;
}
$data = trim($data);
if (function_exists('mb_strtolower')) {
$data = mb_strtolower($data);
$writer->openToBrowser("$filename.$type_export");
$headers = array_map('strval', $this->headers);
if ($type === 'csv') {
$writer->addRow(WriterEntityFactory::createRowFromArray($headers));
} else {
include_spip('inc/charsets');
$data = \strtolower(\translitteration($data));
$writer->addRow(WriterEntityFactory::createRowFromArray($headers, $style_headers));
}
if ($array) {
$data = \json_decode($data, true);
foreach ($this->rows as $content) {
$content = array_map('strval', $content);
if ($type === 'csv') {
$writer->addRow(WriterEntityFactory::createRowFromArray($content));
} else {
$writer->addRow(WriterEntityFactory::createRowFromArray($content, $style_entete));
}
}
if (is_numeric($data)) {
$data = floatval($data);
$writer->close();
}
return pipeline ('formidable_ts_sort_value', array(
'args' => array(
'valeur' => $valeur,
'saisie' => $saisie,
'type' => $type
),
'data' => $data
));
}

41
action/formidable_ts_export.php

@ -2,38 +2,23 @@
if (!defined("_ECRIRE_INC_VERSION")) return;
require_once find_in_path('lib/Spout/Autoloader/autoload.php');
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
use Box\Spout\Common\Entity\Style\Color;
include_spip('formidable_ts_autoload');
function action_formidable_ts_export() {
$data = json_decode(_request('data'));
$type_export = _request('type_export');
$filename = _request('filename');
$id_formulaire = _request('id_formulaire');
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
if (autoriser('voir', 'formulairesreponse', $id_formulaire)) {
$statut = _request('statut');
$type = _request('type');
$style_entete = (new StyleBuilder())
->setFontBold()
->build();
$s = new Formidable_ts\Setting($id_formulaire);
$t = new Formidable_ts\Table(['statut' => $statut], $s);
if ($type_export == 'csv') {
$writer = WriterEntityFactory::createCSVWriter();
} elseif ($type_export == 'ods') {
$writer = WriterEntityFactory::createODSWriter();
$t->setData();
$t->export($type);
} else {
$writer = WriterEntityFactory::createXLSXWriter();
}
$writer->openToBrowser("$filename.$type_export");
//
$i = 0;
foreach ($data as $row => $content) {
$i++;
if ($i == 1 and $type_export != 'csv') {
$writer->addRow(WriterEntityFactory::createRowFromArray($content, $style_entete));
} else {
$writer->addRow(WriterEntityFactory::createRowFromArray($content));
}
include_spip('inc/filtres');
sinon_interdire_acces(false);
}
$writer->close();
}

38
base/formidable_ts.php

@ -0,0 +1,38 @@
<?php
/**
* Déclarations relatives à la base de données
*
* @package SPIP\Formidable_ts\Pipelines
**/
// Sécurité
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Déclarer les tables principales de formidable_ts
*
* @pipeline declarer_tables_principales
* @param array $tables_principales
* Description des tables
* @return array
* Description complétée des tables
**/
function formidable_ts_declarer_tables_principales($tables_principales) {
// Table formulaires_reponses_champs
$formidable_ts_settings = array(
'id_formulaire' => 'bigint(21) NOT NULL default 0',
'id_auteur' => 'bigint(21) NOT NULL default 0',
'setting' => "text NOT NULL DEFAULT ''",
);
$formidable_ts_settings_key = array(
'PRIMARY KEY' => 'id_formulaire, id_auteur',
);
$tables_principales['spip_formidable_ts_settings'] = array(
'field' => &$formidable_ts_settings,
'key' => &$formidable_ts_settings_key
);
return $tables_principales;
}

42
formidable_ts.json.html

@ -1,3 +1,43 @@
#HTTP_HEADER{Content-type:application/json;charset=#CHARSET}
[(#AUTORISER{voir,formulairesreponse,#ID_FORMULAIRE}|sinon_interdire_acces)]
<INCLURE{fond=javascript/formidable_ts.json,env} />
<?php
include_spip('formidable_ts_autoload');
function formidable_ts_json() {
$id_formulaire = _request('id_formulaire');
$setting = new \Formidable_ts\Setting($id_formulaire);
$setting->set(['action' => 'size', 'value' => _request('size')]);
$setting->set(['action' => 'page', 'value' => _request('page_ts')]);
$statut = _request('statut');
if (($filter_column = _request('filter_column')) !== null) {
$filter = _request('filter');
$setting->set([
'action' => 'filters',
'filter_column' => $filter_column,
'filter' => $filter
]);
}
if ($sort_column = _request('sort_column')) {
$sort = _request('sort');
$sort_only_one = _request('sort_only_one');
$setting->set([
'action' => 'sort',
'sort_column' => $sort_column,
'sort' => $sort,
'sort_only_one' => $sort_only_one
]);
}
if (_request('reset_filters')) {
$setting->reset_filters();
}
$formidable_ts = new Formidable_ts\Table($statut, $setting);
$formidable_ts->setData();
return $formidable_ts->getJson();
}
echo(formidable_ts_json());

6
formidable_ts_administrations.php

@ -22,14 +22,19 @@ if (!defined('_ECRIRE_INC_VERSION')) {
*/
function formidable_ts_upgrade($nom_meta_base_version, $version_cible) {
// Création des tables
include_spip('base/create');
$maj = array();
$maj['create'] = array(
array('formidable_ts_configurer_crayons'),
array('maj_tables',array('spip_formidable_ts_settings'))
);
$maj['1'] = array(
array('formidable_ts_configurer_crayons'),
);
$maj['2'] = array(
array('maj_tables',array('spip_formidable_ts_settings'))
);
include_spip('base/upgrade');
maj_plugin($nom_meta_base_version, $version_cible, $maj);
}
@ -57,6 +62,7 @@ function formidable_ts_configurer_crayons() {
*/
function formidable_ts_vider_tables($nom_meta_base_version) {
// On efface la version enregistrée
sql_drop_table('spip_formidable_ts_settings');
effacer_meta($nom_meta_base_version);
}

21
formidable_ts_autoload.php

@ -0,0 +1,21 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
if (!class_exists('Formidable_ts\Table')) {
spl_autoload_register(function ($class) {
$prefix = 'Formidable_ts\\';
$base_dir = _DIR_PLUGIN_FORMIDABLE_TS . 'Formidable_ts/';
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
if (file_exists($file)) {
require $file;
}
});
}

3
formidable_ts_columnSelector.json.html

@ -0,0 +1,3 @@
#HTTP_HEADER{Content-type:application/json;charset=#CHARSET}
[(#AUTORISER{voir,formulairesreponse,#ID_FORMULAIRE}|sinon_interdire_acces)]
[(#NULL|formidable_ts_json_columnSelector)]

30
formidable_ts_columnSelector.json_fonctions.php

@ -0,0 +1,30 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('formidable_ts_autoload');
/**
* Modifie la liste des colonnes désactivés
* le _request('change') peut avoir pour valeur 'disable' ou 'enable'
* le _request('column') est un indentifiant numérique de colonne
**/
function formidable_ts_json_columnSelector() {
$id_formulaire = _request('id_formulaire');
$setting = new \Formidable_ts\Setting($id_formulaire);
if (($column = _request('column')) !== null and ($change = _request('change'))) {
$setting->set([
'action' => 'columnSelector',
'change' => $change,
'column' => $column
]
);
return json_encode([]);
} else {
return json_encode($setting->get('columnSelector'));
}
}

3
formidable_ts_resetAll.json.html

@ -0,0 +1,3 @@
#HTTP_HEADER{Content-type:application/json;charset=#CHARSET}
[(#AUTORISER{voir,formulairesreponse,#ID_FORMULAIRE}|sinon_interdire_acces)]
[(#NULL|formidable_ts_json_resetAll)]

11
formidable_ts_resetAll.json_fonctions.php

@ -0,0 +1,11 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('formidable_ts_autoload');
function formidable_ts_json_resetAll() {
$id_formulaire = _request('id_formulaire');
$setting = new \Formidable_ts\Setting($id_formulaire);
$setting->reset();
return json_encode([]);
}

3
formidable_ts_resizable_widths.json.html

@ -0,0 +1,3 @@
#HTTP_HEADER{Content-type:application/json;charset=#CHARSET}
[(#AUTORISER{voir,formulairesreponse,#ID_FORMULAIRE}|sinon_interdire_acces)]
[(#NULL|formidable_ts_json_resizable_widths)]

21
formidable_ts_resizable_widths.json_fonctions.php

@ -0,0 +1,21 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('formidable_ts_autoload');
function formidable_ts_json_resizable_widths() {
$id_formulaire = _request('id_formulaire');
$setting = new \Formidable_ts\Setting($id_formulaire);
if ($resizable_widths = _request('resizable_widths')) {
$setting->set([
'action' => 'resizable_widths',
'value' => $resizable_widths
]
);
return json_encode([]);
} else {
return json_encode($setting->get('resizable_widths'));
}
}

3
formidable_ts_sortList.json.html

@ -0,0 +1,3 @@
#HTTP_HEADER{Content-type:application/json;charset=#CHARSET}
[(#AUTORISER{voir,formulairesreponse,#ID_FORMULAIRE}|sinon_interdire_acces)]
[(#NULL|formidable_ts_json_sortList)]

26
formidable_ts_sortList.json_fonctions.php

@ -0,0 +1,26 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('formidable_ts_autoload');
function formidable_ts_json_sortList() {
$id_formulaire = _request('id_formulaire');
$setting = new \Formidable_ts\Setting($id_formulaire);
if ($move_direction = _request('move_direction') and $move_col = _request('move_col')) {
$setting->set([
'action' => 'move',
'col' => $move_col,
'direction' => $move_direction
]
);
}
$sorton = [];
foreach ($setting->get('sort') as $s => $sort) {
$sorton[] = [$s, $sort];
}
return json_encode($sorton);